# tokio task spawn metadata So far, this is collecting the various strategies for including metadata, such as for `tracing`, when spawning a new task in Tokio. ## status-quo ### `future.instrument()` A user can currently manually create a tracing `Span`, and instrument any future before calling `tokio::spawn`. Something like: ```rust let span = tracing::debug_span("yolo"); let future = async { yeet().await; }; tokio::spawn(future.instrument(span)); ``` - **Pros**: - already works just fine - very flexible if you want to add many fields to the span - **Cons**: - kind of onorous if all you want is a name for the task - definitely not obvious ### `--cfg tokio_unstable` This is an _unstable_ Tokio feature, which will automatically make a span for all tasks that go through `spawn`. Introduced in [this PR](https://github.com/tokio-rs/tokio/pull/2655). - **Pros**: - Automatically includes useful data without the user having to figure it out - `spawn`, `spawn_local`, `spawn_blocking` - The `std::any::type_name()` of the future - With `#[track_caller]`, could include the file, line, and function name of exactly _where_ the task was spawned from. - **Cons**: - It's unstable. - It doesn't allow customizing the span at all. Part the instability of this feature is that Tokio can't be emitting `tracing` spans that people depend on, while `tracing` is pre-1.0, because if Tokio upgrades to `tracing` 1.0, those people would suddenly no longer receive the emitted spans. It seems likely that to support the suggestions below, we'd at the very least need to have reaching `tracing` 1.0. Or, the alternative would be to mark the proposed APIs as _also_ unstable. ## `task::Builder` This would be a parallel type to `std::thread::Builder`. ```rust pub struct Builder { id: TaskId, // unique id, similar to ThreadId // .. } ``` - **Pros**: - Is a natural way to specific a "name", since it mimics `std::thread`. - Provides a place to add any other "meta" stuff to a task. - There's `stack_size` for threads, not sure that particularly works for `task`s, but maybe there's other things to configure - Priority? - "CPU affinity"? - **Cons**: - One downside is that it's possible to combine using the builder for metadata, *and* `future.instrument`. Maybe that's not a big deal :shrug: ### `Builder.name` The `std::thread` builder has the ability to set the thread name. We could allow setting the "task name", which could be used to create the tracing `span`. One difference is that the "thread name" can be a `String`, and so can be dynamically created. The "span name" requires a `&' static str`. ### `Builder.span`? If we wanted to expose `tracing-core`, we could allow allow configuring a span outside the builder, and then just passing it directly. However, it's not clear how this is much better than just `future.instrument(span)`. ### `Builder.local`? If we have a builder, we _could_ consider allowing configuring of "task locals" directly on the builder. This is a question mark, could be considered later. ### `Builder.tag`? This is basically `Span::record(field, value)`. We could either expose the traits directly (`valuable`?), or define custom traits (which can get hairy). I picked the method name `tag` since `record` didn't seem to make as much sense for a `task::Builder`. The name `tag` is used in other languages/libraries to store arbitrary opaque data. ## `spawn!` macro Initially [proposed](https://github.com/tokio-rs/tokio/issues/1180) with for two purposes: - Return a `JoinHandle` - Allow decorating a task with `tracing` metadata. Tokio 1.0 already returns `JoinHandle`s by default, and thus the issue was closed. However, the idea is at least worth considering, even if we decide against it. ```rust let task = tokio::spawn!(async { toge().await }, "we_are", stronger=&together); ``` This could expand either to just `tokio::spawn(future.instrument(tracing::span!(..)))`, or to using the proposed `task::Builder`. - **Pros**: - Convenient way to combine spawning and tracing fields. - Perhaps easier to include `file!()`, `line!()`, and `function!()` automatically. - However, with `#[track_caller]`, we could perhaps get this stuff automatically on `Builder::new()`. - **Cons**: - Some people don't like macros, since they can seem magical. - It becomes _yet another_ way to do the same thing. - But then again, macros usually are doing a thing that's already possible, just making it more convenient.