-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
std.log: add generic tracing support with std.log.span #26054
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
Conversation
|
Minor aesthetic suggestion: let var work = log.span(.info, "scheduling work", .{}).begin();
defer work.end(); |
|
let me caveat this with that I would really like to enable a simpler syntax, but have yet to find a way to do it with the current first, we must not allocate since this is performance sensitive code. a child span needs to be able to revert to the parent span, so I arrived on a linked list with a threadlocal head. second, Span is generic over its now, to answer your question, since we store a pointer to the Span as threadlocal state, its location must be stable when so then the question comes down to whether every event should have access to those fields. if not -- specifically, in the events emitted from the
to paraphrase @MasonRemaley; the tradeoff here seems to be introducing overhead while doing performance analysis, versus potentially playing better with incremental compilation when I originally approached this, my expectation was that @src() would be passed to there's an argument for removing |
|
This pull request is not ready for review because:
Since we have moved development to Codeberg, please open your pull request there if you would like to continue these efforts. |
this PR introduces a
std.log.span()method, following the existing patterns forstd.log:traceFnimplementationUsage
There are three different APIs being exposed here.
Instrumenting code
Anyone who wants to instrument their code (application and library authors) can add spans to their code like this:
Implementing a tracing backend
Application authors can provide a
traceFnonstd.Optionsthat consumes the events. Here's a stupid one that I used to test when developing; it prints a column for each thread and visualizes the spansImplementing a
std.IoThis requires support by any implementation of
std.Io. You can look at how I implemented it inThreaded, but the idea is simple:ExecutorIdexecutor_id.enter()andexecutor_id.exit()on that threadstd.log.current_spanspan.link(), linking the original span to this executorspan.unlink(), unlinking the original span to this executorspan.exit()andspan.enter()accordinglyMisc Details
Userdata
Some tracing backends might need userdata to be stored on the span.
std.Optionshas aSpanUserdata: typefield (defaultvoid). when the span is created, itsuserdata: SpanUserdatais unintialized. thetraceFnimplementation canstore user data on it as
SpanEvents are handled.Source location
I'm conflicted on whether to include
SourceLocationas part of the API. For a middleground, I am tracking the@returnAddress()of the call tostd.log.span(); the implementation can decide if they would like to use this to gather theSourceLocationfrom debug data.if we do include it in the API, it will make the
span()calls slightly more verbose.Timing data
I opted not to include timing data. Some backends use their own timing, some don't. It seemed like something that the
traceFnimplementation should handle.Caveats
The biggest caveat to my design is that it depends on a linked list of stack allocated data. Each
Spanstores a pointer to its previousSpan. What that means is that moving the span after you have calledbegin()is an illegal operation:I don't love it, but I also think it's kind of ok - the split design of initializing a span and beginning it allows you to move the span where it needs to be stored before beginning it.
Open Questions
Status of IoUring/Kqueue?
I started working on IoUring but quickly found out that it looks like it's not currently complete. Is it? Let me know what's up here. Until I can test on IoUring/Kqueue I can't validate this design against a fiber model
Should std.log.ExecutorId be part of std.Io?
To me this concept feels pretty intrinsically tied to Io implementations; it's essentially a monotonic identifier for native threads/green threads/fibers/whatever.
Should this be moved to a new module, like
std.trace?I go back and forth on this, but it shares a lot with
std.log, so I left it there.Should we create a default executor ID in start(), or leave it as .none?
std.log.current_executordefaults to a.none. this helps catch implementation errors instd.Iowhen adding support. if you're not usingstd.Io, all your executors will benone-- which I think is ok. but there could be an argument to automatically set the main thread's "executor ID"Should we update
logFnto include span information?People often like to tie logs to the spans, right now I don't have that wired. It would be a breaking change, but may be valuable.
Default
traceFn?I put a default
traceFnthat logs the beginning and end of the trace. Should there even be a default? If there is, what should it do?Various bikeshedding on names, etc.
I have spent a lot of time on naming but I am still not sure what the best names for a lot of these concepts are. I am very open to suggestions.
Issues
implements #5987