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

tracing-core, tracing-subscriber: Add {Collect,Subscriber}::on_register_dispatch #2269

Merged
merged 3 commits into from Aug 23, 2022

Conversation

jswrenn
Copy link
Contributor

@jswrenn jswrenn commented Aug 8, 2022

The on_register_dispatch method is invoked when a Collect is registered as a Dispatch. This method can be overridden to perform actions upon the installation of a collector/subscriber; for instance, to send a copy of the collector's Dispatch to a worker thread.

Unresolved questions:

  • Is the signature of on_register_dispatch correct?
    • Should it take &self, or &mut self?
    • Should it take &self, or only the &Dispatch parameter (which can then, if desired, be downcasted to &self)?

…er_dispatch`

The `on_register_dispatch` method is invoked when a `Collect` is
registered as a `Dispatch`. This method should be overridden to
perform actions upon the installation of a collector/subscriber;
for instance, to send a copy of the collector's `Dispatch` to a
worker thread.
@bryangarza
Copy link
Member

* [ ]  Is the signature of `on_register_dispatch` correct?
  
  * Should it take `&Dispatch`, or `&mut Dispatch`?
  * Should it take `&self`, or _only_ the `&Dispatch` parameter (which can then, if desired, be downcasted to `&self`)?

I think it can't be &mut Dispatch if multiple Layers are going to receive it.

For the &self question, for now it seems fine to use it. We can remove it later if we see it was unnecessary?

@bryangarza
Copy link
Member

@jswrenn I think it's failing CI cause of clippy

@davidbarsky
Copy link
Member

I'm not opposed to this change (it is rather small...), but I'd like a little more detail about the motivations for this use-case, as I'm somewhat hesitant to make changes to tracing-core. For instance, I'm curious as to why the use-case of sending a copy of the Collector's Dispatch to a worker thread can't be achieved through, e.g., an Instrument-style extension trait or setting a global collect/dispatch or if there are other motivations at play.

@hawkw
Copy link
Member

hawkw commented Aug 16, 2022

  • Should it take &Dispatch, or &mut Dispatch?

it should not take &mut Dispatch --- there are no methods on Dispatch which require mutable access, so the only thing an &mut Dispatch would allow is for the layer/subscriber to reassign the Dispatch with a different value...which, as far as I can imagine, could only cause problems, and has no practical use case.

@jswrenn
Copy link
Contributor Author

jswrenn commented Aug 17, 2022

@hawkw, whoops, I definitely meant to write:

Should it take &self, or &mut self?

An argument in favor of the method consuming &mut self is that it'd mirror Layer::on_layer, which also consumes &mut self. However, the PR currently has the method consume &self, because one way a Dispatch can be created is from Dispatch::from_static, which consumes an &'static (dyn Collect + Send + Sync).

@hawkw
Copy link
Member

hawkw commented Aug 17, 2022

@hawkw, whoops, I definitely meant to write:

Should it take &self, or &mut self?

An argument in favor of the method consuming &mut self is that it'd mirror Layer::on_layer, which also consumes &mut self. However, the PR currently has the method consume &self, because one way a Dispatch can be created is from Dispatch::from_static, which consumes an &'static (dyn Collect + Send + Sync).

I think the receiver should probably be &self --- there's been some discussion about changing the on_layer API to take &self in 0.4 anyway: #2101.

It's a bummer that we can't just use an &mut self receiver, and would have to introduce locking to store the Dispatch, but I think we need to be able to support Dispatch::from_static. Alternatively, we could consider changing where register_dispatch is actually called: rather than calling it in Dispatch::new, we could call it the first time the Dispatch is set as the default (using Arc::get_mut to access it mutably), but that would fail if other clones exist, which would also be weird and confusing. I think it has to be &self for that reason.

@hawkw
Copy link
Member

hawkw commented Aug 17, 2022

It occurs to me that adding an API like this has the unfortunate consequence of making it quite easy to accidentally write memory leaks. In your specific use-case in tokio-console, you're sending a clone of the Dispatch to a worker thread, which is fine; however, perhaps the most obvious use of this API would be to create a self-referential Layer that stores a Dispatch referencing the whole stack, so that it can call into the subscriber stack containing it. If this is done, an Arc cycle would be created, and the subscriber would never be dropped.

Currently, there's no public API for turning a Dispatch into a weak reference that could break these cycles, so any use of this API to create a self-referential Layer or Collect implementation is inherently a memory leak...

@jswrenn
Copy link
Contributor Author

jswrenn commented Aug 18, 2022

My feeling is that it's probably uncommon to have many complex subscribers initialized and installed over a program's lifetime, so the risk is low. In the near-term, it's sufficient to document this risk. In the long-term, we could add Dispatch::downgrade() to support that use-case.

Copy link
Member

@davidbarsky davidbarsky left a comment

Choose a reason for hiding this comment

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

stamped; needed for console, but this might be removed in 0.2 because of other collector changes.

@davidbarsky
Copy link
Member

@hawkw mentioned in discord that she'd like a way to get a weak ref to a dispatcher, but noted that can be done in followup PR.

@hawkw
Copy link
Member

hawkw commented Aug 23, 2022

@hawkw mentioned in discord that she'd like a way to get a weak ref to a dispatcher, but noted that can be done in followup PR.

Yeah. I would prefer to not release this feature without some way of breaking Dispatch cycles, but I'm happy to merge the PR as-is and add that separately.

@hawkw hawkw enabled auto-merge (squash) August 23, 2022 16:41
@hawkw hawkw merged commit 41337ba into tokio-rs:master Aug 23, 2022
davidbarsky pushed a commit that referenced this pull request Sep 8, 2022
The `on_register_dispatch` method is invoked when a `Collect` is
registered as a `Dispatch`. This method should be overridden to
perform actions upon the installation of a collector/subscriber;
for instance, to send a copy of the collector's `Dispatch` to a
worker thread.
hawkw pushed a commit that referenced this pull request Sep 19, 2022
The `on_register_dispatch` method is invoked when a `Subscriber` is
registered as a `Dispatch`. This method should be overridden to
perform actions upon the installation of a subscriber/layer;
for instance, to send a copy of the subscriber's `Dispatch` to a
worker thread.
hawkw pushed a commit that referenced this pull request Sep 19, 2022
The `on_register_dispatch` method is invoked when a `Subscriber` is
registered as a `Dispatch`. This method should be overridden to
perform actions upon the installation of a subscriber/layer;
for instance, to send a copy of the subscriber's `Dispatch` to a
worker thread.
hawkw added a commit that referenced this pull request Sep 24, 2022
Allows collectors and subscribers to stash their own `Dispatch` without
causing a memory leak.

## Motivation

Resolves a shortcoming of #2269: that it's impossible for collectors or
subscribers to stash a copy of their own `Dispatch` without creating a
reference cycle that would prevent them from being dropped.

## Solution

Introduces `WeakDispatch` (analogous to `std::sync::Weak`) that holds a
weak pointer to a collector. `WeakDispatch` can be created via
`Dispatch::downgrade`, and can be transformed into a `Dispatch` via
`WeakDispatch::upgrade`.

Co-authored-by: Eliza Weisman <eliza@buoyant.io>
hawkw added a commit that referenced this pull request Sep 24, 2022
Allows `Subscriber`s and `Layer`s to stash their own `Dispatch` without
causing a memory leak.

## Motivation

Resolves a shortcoming of #2269: that it's impossible for `Subscriber`s
or `Layer`s to stash a copy of their own `Dispatch` without creating a
reference cycle that would prevent them from being dropped.

## Solution

Introduces `WeakDispatch` (analogous to `std::sync::Weak`) that holds a
weak pointer to a `Subscriber`. `WeakDispatch` can be created via
`Dispatch::downgrade`, and can be transformed into a `Dispatch` via
`WeakDispatch::upgrade`.

Co-authored-by: Eliza Weisman <eliza@buoyant.io>
hawkw added a commit that referenced this pull request Sep 24, 2022
Allows `Subscriber`s and `Layer`s to stash their own `Dispatch` without
causing a memory leak.

## Motivation

Resolves a shortcoming of #2269: that it's impossible for `Subscriber`s
or `Layer`s to stash a copy of their own `Dispatch` without creating a
reference cycle that would prevent them from being dropped.

## Solution

Introduces `WeakDispatch` (analogous to `std::sync::Weak`) that holds a
weak pointer to a `Subscriber`. `WeakDispatch` can be created via
`Dispatch::downgrade`, and can be transformed into a `Dispatch` via
`WeakDispatch::upgrade`.

Co-authored-by: Eliza Weisman <eliza@buoyant.io>
hawkw added a commit that referenced this pull request Sep 30, 2022
Allows `Subscriber`s and `Layer`s to stash their own `Dispatch` without
causing a memory leak.

## Motivation

Resolves a shortcoming of #2269: that it's impossible for `Subscriber`s
or `Layer`s to stash a copy of their own `Dispatch` without creating a
reference cycle that would prevent them from being dropped.

## Solution

Introduces `WeakDispatch` (analogous to `std::sync::Weak`) that holds a
weak pointer to a `Subscriber`. `WeakDispatch` can be created via
`Dispatch::downgrade`, and can be transformed into a `Dispatch` via
`WeakDispatch::upgrade`.

Co-authored-by: Eliza Weisman <eliza@buoyant.io>
hawkw added a commit that referenced this pull request Sep 30, 2022
Allows `Subscriber`s and `Layer`s to stash their own `Dispatch` without
causing a memory leak.

## Motivation

Resolves a shortcoming of #2269: that it's impossible for `Subscriber`s
or `Layer`s to stash a copy of their own `Dispatch` without creating a
reference cycle that would prevent them from being dropped.

## Solution

Introduces `WeakDispatch` (analogous to `std::sync::Weak`) that holds a
weak pointer to a `Subscriber`. `WeakDispatch` can be created via
`Dispatch::downgrade`, and can be transformed into a `Dispatch` via
`WeakDispatch::upgrade`.

Co-authored-by: Eliza Weisman <eliza@buoyant.io>
hawkw added a commit that referenced this pull request Oct 6, 2022
# 0.1.30 (October 6, 2022)

This release of `tracing-core` adds a new `on_register_dispatch` method
to the `Subscriber` trait to allow the `Subscriber` to perform
initialization after being registered as a `Dispatch`, and a
`WeakDispatch` type to allow a `Subscriber` to store its own `Dispatch`
without creating reference count cycles.

### Added

- `Subscriber::on_register_dispatch` method ([#2269])
- `WeakDispatch` type and `Dispatch::downgrade()` function ([#2293])

Thanks to @jswrenn for contributing to this release!

[#2269]: #2269
[#2293]: #2293
hawkw added a commit that referenced this pull request Oct 6, 2022
# 0.1.30 (October 6, 2022)

This release of `tracing-core` adds a new `on_register_dispatch` method
to the `Subscriber` trait to allow the `Subscriber` to perform
initialization after being registered as a `Dispatch`, and a
`WeakDispatch` type to allow a `Subscriber` to store its own `Dispatch`
without creating reference count cycles.

### Added

- `Subscriber::on_register_dispatch` method ([#2269])
- `WeakDispatch` type and `Dispatch::downgrade()` function ([#2293])

Thanks to @jswrenn for contributing to this release!

[#2269]: #2269
[#2293]: #2293
hawkw added a commit that referenced this pull request Oct 6, 2022
# 0.1.37 (October 6, 2022)

This release of `tracing` incorporates changes from `tracing-core`
[v0.1.30][core-0.1.30] and `tracing-attributes` [v0.1.23][0.1.23],
including the new `Subscriber::on_register_dispatch` method for
performing late initialization after a `Subscriber` is registered as a
`Dispatch`, and bugfixes for the `#[instrument]` attribute.
Additionally, it fixes instances of the `bare_trait_objects` lint, which
is now a warning on `tracing`'s MSRV and will become an error in the
next edition.

### Fixed

- **attributes**: Incorrect handling of inner attributes in
  `#[instrument]`ed functions (#2307)
- **attributes**: Incorrect location of compiler diagnostic spans
  generated for type errors in `#[instrument]`ed `async fn`s (#2270)
- **attributes**: Updated `syn` dependency to fix compilation with `-Z
  minimal-versions` (#2246)
- `bare_trait_objects` warning in `valueset!` macro expansion (#2308)

### Added

- **core**: `Subscriber::on_register_dispatch` method (#2269)
- **core**: `WeakDispatch` type and `Dispatch::downgrade()` function
  (#2293)

### Changed

- `tracing-core`: updated to [0.1.30][core-0.1.30]
- `tracing-attributes`: updated to [0.1.23][attrs-0.1.23]

### Documented

- Added [`tracing-web`] and [`reqwest-tracing`] to related crates
  (#2283], [#2331)

Thanks to new contributors @compiler-errors, @e-nomem, @WorldSEnder,
@Xiami2012, and @tl-rodrigo-gryzinski, as well as @jswrenn and @CAD97,
for contributing to this release!

[core-0.1.30]:
    https://github.com/tokio-rs/tracing/releases/tag/tracing-core-0.1.30
[attrs-0.1.23]:
    https://github.com/tokio-rs/tracing/releases/tag/tracing-attributes-0.1.23
[`tracing-web`]: https://crates.io/crates/tracing-web/
[`reqwest-tracing`]: https://crates.io/crates/reqwest-tracing/
hawkw added a commit that referenced this pull request Oct 6, 2022
# 0.1.37 (October 6, 2022)

This release of `tracing` incorporates changes from `tracing-core`
[v0.1.30][core-0.1.30] and `tracing-attributes` [v0.1.23][attrs-0.1.23],
including the new `Subscriber::on_register_dispatch` method for
performing late initialization after a `Subscriber` is registered as a
`Dispatch`, and bugfixes for the `#[instrument]` attribute.
Additionally, it fixes instances of the `bare_trait_objects` lint, which
is now a warning on `tracing`'s MSRV and will become an error in the
next edition.

### Fixed

- **attributes**: Incorrect handling of inner attributes in
  `#[instrument]`ed functions (#2307)
- **attributes**: Incorrect location of compiler diagnostic spans
  generated for type errors in `#[instrument]`ed `async fn`s (#2270)
- **attributes**: Updated `syn` dependency to fix compilation with `-Z
  minimal-versions` (#2246)
- `bare_trait_objects` warning in `valueset!` macro expansion (#2308)

### Added

- **core**: `Subscriber::on_register_dispatch` method (#2269)
- **core**: `WeakDispatch` type and `Dispatch::downgrade()` function
  (#2293)

### Changed

- `tracing-core`: updated to [0.1.30][core-0.1.30]
- `tracing-attributes`: updated to [0.1.23][attrs-0.1.23]

### Documented

- Added [`tracing-web`] and [`reqwest-tracing`] to related crates
  (#2283, #2331)

Thanks to new contributors @compiler-errors, @e-nomem, @WorldSEnder,
@Xiami2012, and @tl-rodrigo-gryzinski, as well as @jswrenn and @CAD97,
for contributing to this release!

[core-0.1.30]:
    https://github.com/tokio-rs/tracing/releases/tag/tracing-core-0.1.30
[attrs-0.1.23]:
    https://github.com/tokio-rs/tracing/releases/tag/tracing-attributes-0.1.23
[`tracing-web`]: https://crates.io/crates/tracing-web/
[`reqwest-tracing`]: https://crates.io/crates/reqwest-tracing/
hawkw added a commit that referenced this pull request Oct 6, 2022
)"

This reverts commit a0824d3 (PR #2247).
As discussed in [this comment][1], the implementation for `Arc`s may
cause subtly incorrect behavior if actually used, due to the `&mut self`
receiver of the `LookupSpan::register_filter` method, since the `Arc`
cannot be mutably borrowed if any clones of it exist.

The APIs added in PRs #2269 and #2293 offer an alternative solution to
the same problems this change was intended to solve, and --- since this
change hasn't been published yet --- it can safely be reverted.

[1]:
    https://giethub.com/tokio-rs/tracing/pull/2247#issuecomment-1199924876
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.

None yet

4 participants