Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to emit fields as text associated with span #87

Merged
merged 2 commits into from
Jan 2, 2024
Merged

Add option to emit fields as text associated with span #87

merged 2 commits into from
Jan 2, 2024

Conversation

SUPERCILEX
Copy link
Contributor

Depends on #86.


This is desirable because otherwise you cannot get meaningful statistics when tracing functions:

#[cfg_attr(
    feature = "tracing",
    tracing::instrument(level = "trace", skip(contents))
)]
fn create_files(
    num_files: u64,
    offset: u64,
    file: &mut FastPathBuf,
    contents: &mut impl FileContentsGenerator,
)

will turn into separate zones which can't be analyzed as a whole:
Screenshot from 2023-12-27 11-14-52

After this change, you get nice clean zones:
Screenshot from 2023-12-27 11-14-38

And the debug data is still present:
Screenshot from 2023-12-27 11-14-00


Of course as a bonus we save an allocation and formatting time.

@nagisa
Copy link
Owner

nagisa commented Dec 27, 2023

Conversely, it is commonplace in tracing to use KVs extensively to construct semantically distinct spans, to the point where message field is omitted entirely (in which case after your PR we're looking at combining multiple spans that have no business being combined.)

Even in your case I would possibly see create_files{num_files=1000} as having meaningfully distinct performance characteristics compared to create_files{num_files=10000}, to the point where I might be interested in in having the two be separated in order to aid insights between the different sizes of batches. Unfortunately tracy does not provide tools to aid in such investigation out of the box. It is either the one extreme we have implemented right now, or the other extreme that your PR suggests (it is also what has been implemented in the past way back.) These kinds of considerations unfortunately only serve to highlight the many different ways where tracing’s view of… tracing is just much more complex than what tracy is willing to accommodate.

That said, I don’t disagree that in some applications the suggested rendition might be preferable, but I suspect it will need to be a setting/option to land, rather than an unconditional change as proposed.

@SUPERCILEX
Copy link
Contributor Author

Great points, you're absolutely right that the current behavior is still desirable. I went ahead and added a flag at the Layer level. This is somewhat unfortunate in that you can't decide per span whether or not you want combining, but having a layer level default is still useful and so if we do figure out how to do per span flags that feature will be in addition to this one.

tracing-tracy/src/lib.rs Outdated Show resolved Hide resolved
@SUPERCILEX SUPERCILEX changed the title Emit fields as text associated with span rather than span name Add option to emit fields as text associated with span Jan 1, 2024
Comment on lines 283 to 304
if let Some(fields) = self
.fields_in_zone_name
.then_some(fields)
.flatten()
.filter(|f| !f.fields.is_empty())
{
CACHE.with(|cache| {
let mut buf = cache.acquire();
let _ = write!(buf, "{}{{{}}}", metadata.name(), fields.fields);
span(&buf)
})
} else {
span(metadata.name())
}
};
if let Some(fields) = (!self.fields_in_zone_name).then_some(fields).flatten() {
stack_frame.0.emit_text(self.truncate_to_length(
(u16::MAX - 1).into(),
&fields.fields,
"span field values are too long and were truncated",
));
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW then_some(()).and(fields) might have been nicer and avoids constructing doubly-nested option.

Alternatively, you could write

Suggested change
if let Some(fields) = self
.fields_in_zone_name
.then_some(fields)
.flatten()
.filter(|f| !f.fields.is_empty())
{
CACHE.with(|cache| {
let mut buf = cache.acquire();
let _ = write!(buf, "{}{{{}}}", metadata.name(), fields.fields);
span(&buf)
})
} else {
span(metadata.name())
}
};
if let Some(fields) = (!self.fields_in_zone_name).then_some(fields).flatten() {
stack_frame.0.emit_text(self.truncate_to_length(
(u16::MAX - 1).into(),
&fields.fields,
"span field values are too long and were truncated",
));
}
match fields {
None => span(metadata.name()),
// NOTE: the current proposed code will `emit_text` even for empty fields!
Some(fields) if fields.is_empty() => span(metadata.name()),
Some(fields) if self.fields_in_zone_name => {
CACHE.with(|cache| {
let mut buf = cache.acquire();
let _ = write!(buf, "{}{{{}}}", metadata.name(), fields.fields);
span(&buf)
})
}
Some(fields) => {
let span = span(metadata.name());
span.emit_text(...);
span
}
}

which seems a more straightforward read, isn’t it?

Copy link
Contributor Author

@SUPERCILEX SUPERCILEX Jan 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's quite a bit clearer, thanks! And great catch on the empty fields bug. :)

@nagisa nagisa merged commit cd135c0 into nagisa:main Jan 2, 2024
36 checks passed
@SUPERCILEX SUPERCILEX deleted the fields branch January 3, 2024 00:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants