Skip to content

Allow (static) custom source locations for spans#151

Open
moulins wants to merge 2 commits intonagisa:mainfrom
moulins:fancy-stack-location
Open

Allow (static) custom source locations for spans#151
moulins wants to merge 2 commits intonagisa:mainfrom
moulins:fancy-stack-location

Conversation

@moulins
Copy link
Copy Markdown

@moulins moulins commented Nov 21, 2025

Closes #108 by expanding span_location! to allow overriding source locations:

let location: &'static SpanLocation = span_location! {
    name: "another name",
    function: "my::fake::function",
    file: "path/to/fake/file.rs",
    line: 42,
    color: 0x99CC66, // in RGB format
};

As an optimization, when the function name is provided statically, the Lazy wrapper is skipped.

EDIT: Also closes #106 by adding color support to static spans


I considered adding a const SpanLocation::new constructor, but this would mean adding a way of making static nul-terminated strings outside of FrameName/PlotName::new_leak, so I skipped this for now. What do you think about adding an unified StaticName/static_name! type/macro that could be used everywhere Tracy expects such strings?

Tracy requires that `SpanLocation`s live effectively forever, so
`make_span_location` can just leak the string buffer here.
@Ralith
Copy link
Copy Markdown
Contributor

Ralith commented Nov 22, 2025

this would mean adding a way of making static nul-terminated strings

This crate predates it, but rust now has C-string literals which can be used for this.

@moulins
Copy link
Copy Markdown
Author

moulins commented Nov 22, 2025

This crate predates it, but rust now has C-string literals which can be used for this.

Oh, duh! Still, unlike a bare &'static CStr, a StaticName type has the advantage of being completely cfg'd out when the "enable" feature isn't set.

Copy link
Copy Markdown
Owner

@nagisa nagisa left a comment

Choose a reason for hiding this comment

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

Hm, I believe it should now be possible to construct a \0 terminated byte arrays from strings without going through Lazy, even without forcing use of c"" literals on them. Let me think about that a 'lil more.

Comment on lines +228 to +232
$([name $name: expr])?
[function $function: expr]
$([file $file: expr])?
$([line $line: expr])?
$([color $color: expr])?
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This approach forces the order of fields, which is sorta unfortunate. I feel like this limitation could be lifted if we went through a struct to construct the span location. That is have the span location look something like this:

macro_rules! span_location {
    ...
    ($($field: ident: $value: expr),* $(,)?) => {
        $crate::internal::SpanLocationArgs {
            $($field: $value),*
            ..SpanLocationArgs::const_default(),
        }
    }

Copy link
Copy Markdown
Author

@moulins moulins Nov 23, 2025

Choose a reason for hiding this comment

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

Interesting, I'll have to think on how to do it while preserving the special-casing when defaulting the function field.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Gave it a try, and unfortunately I couldn't make it to work without using Lazy even when function is specified:

  • the const_default() approach needs to use #[track_caller] and Location::caller(), which is const only from Rust 1.79.0 onwards (forcing a MSRV bump);
  • Even then, I couldn't find a nice way of detecting the absence of function: "..." in the macro input (the special-case is still needed as Location::caller() doesn't give use the caller's function name); it's probably possible with tt-munching tricks but that complexifies things massively.

@moulins
Copy link
Copy Markdown
Author

moulins commented Nov 23, 2025

Hm, I believe it should now be possible to construct a \0 terminated byte arrays from strings without going through Lazy, even without forcing use of c"" literals on them. Let me think about that a 'lil more.

It's true that const is now powerful enough to do some limited string processing, but unfortunately that doesn't help here because std::any::type_name isn't const.

@Ralith
Copy link
Copy Markdown
Contributor

Ralith commented Nov 23, 2025

a StaticName type has the advantage of being completely cfg'd out when the "enable" feature isn't set.

I don't think this is a meaningful advantage. This isn't a significant amount of space use, and the linker should do just fine at dropping unreferenced symbols anyway.

@moulins moulins force-pushed the fancy-stack-location branch from ca9bec9 to 0d90d91 Compare November 24, 2025 21:41
@nagisa
Copy link
Copy Markdown
Owner

nagisa commented Nov 30, 2025

Just a heads up that I won't be able to look at this for at least a few weeks. I'll keep a notification in my mailbox for this though, so this should be roughly the first thing I return to when I'm less occupied.

Copy link
Copy Markdown
Owner

@nagisa nagisa left a comment

Choose a reason for hiding this comment

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

Having thought about it, I feel like trying to avoid the Lazy right now is making things more difficult than strictly necessary. If there is proof that it is causing a significant overhead, we can think about alternative approaches other than span_location potentially, but in absence of such proof (or in absence of significant impact) I'd rather wait until we get const-stable ways to obtain the function name instead.

Until then I think keeping Lazy will make it much more straightforward to provide a neat API. I reworked some code in #155 to that effect. Please take a look...

line,
color,
},
_function_name: function_name,
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Although you're right that tracy requires function names to be effectively 'static, I think this change makes things strictly worse from the resilience and maintainability perspective.

While there is no practical use for having SpanLocation be dropped at all, I can imagine that in the future there may be use-cases that would drop SpanLocation (e.g. because it never got used actually, or maybe in some on-demand tracing scenarios...)

I think the first commit should be removed or adjusted to make the CString field an Option.

) => {{
static LOC: $crate::internal::SpanLocation =
$crate::internal::static_span_location(
concat!($function, "\0").as_ptr(),
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Lets have users supply &'static CStr (via c"literals".) You can force this by doing a

CStr::as_ptr($argument)

SAme for when user provides a custom name, filename.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Requiring C-string literals would make the macro different from all other literal-taking macros in the crate (span!, plot_name!, etc) so I'm not sure this is a good idea?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

+1, this seems like an unnecessary step backwards in ergonomics. The only upside I can see is if someone might need to pass a non-literal &'static CStr, but it still has to be a constant, so I'm not sure how that could arise.

Comment on lines +230 to +231
$([file $file: expr])?
$([line $line: expr])?
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I feel like it makes little sense to allow overriding just the file, or just the line individually, but at the same time I have a hard time justifying why the library should prevent users from doing so 🤷

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.

Define custom source location for spans Support span colours

3 participants