-
Notifications
You must be signed in to change notification settings - Fork 734
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_subscriber: Expose .with_ansi() to custom event/field formatters #1651
Comments
I agree that your proposed approach, wrapping the @lilyball, are you able to work on a PR for this change in the near future? We're currently working on preparing |
@hawkw Perhaps. I'm not sure yet. I'll see if it's something I can do. |
If you're not able to work on it, that's totally fine --- no pressure! I just figured I'd ask because it would certainly be nice to be able to get this change into 0.3, but if not, we can do it in the next breaking release. |
Sounds like based on the intended release time of 0.3 that there's not enough time for me to even find out if I can do a PR. |
@lilyball PR #1661 implements the breaking API change necessary for your proposed solution so that it can be merged in time for 0.3. Please feel free to take a look, if you like! The actual propagation of the ANSI color configuration can be added in a non-breaking change once #1661 has been released as part of 0.3, so there's no rush for that part. |
## Motivation Currently, the `FormatEvent` and `FormatFields` traits in `tracing-subscriber` are passed a `&mut dyn fmt::Write` trait object to write formatted representations of events and fields to. This is fine, but it doesn't give us the ability to easily provide additional configuration to the formatter, such as whether ANSI color codes are supported. Issue #1651 describes some approaches for adding a way to expose the ANSI color code configuration to custom formatters. In particular, the proposed solution involves wrapping the `fmt::Write` trait object in an opaque struct, which can then implement additional methods for exposing information like "are ANSI colors enabled" to the formatter. Since this changes the signature of the `FormatEvent::format_event` and `FormatFields::format_fields` methods, it's a breaking change. Therefore, we need to make this change _now_ if we want to get the API change in for `tracing-subscriber` 0.3. ## Solution This branch adds a `Writer` struct that wraps the `&mut dyn fmt::Write` trait object, and changes the various method signatures as appropriate. It does **not** actually implement the change related to ANSI color formatting. Once we change these methods' signatures to accept a `Writer` struct, we can add as many methods to that struct as we like without making additional breaking API changes. Therefore, this branch _just_ makes the breaking change that's necessary to get in before v0.3 is released. Propagating the ANSI color configuration can be implemented in a future branch. Signed-off-by: Eliza Weisman <[email protected]>
## Motivation Currently, the `FormatEvent` and `FormatFields` traits in `tracing-subscriber` are passed a `&mut dyn fmt::Write` trait object to write formatted representations of events and fields to. This is fine, but it doesn't give us the ability to easily provide additional configuration to the formatter, such as whether ANSI color codes are supported. Issue #1651 describes some approaches for adding a way to expose the ANSI color code configuration to custom formatters. In particular, the proposed solution involves wrapping the `fmt::Write` trait object in an opaque struct, which can then implement additional methods for exposing information like "are ANSI colors enabled" to the formatter. Since this changes the signature of the `FormatEvent::format_event` and `FormatFields::format_fields` methods, it's a breaking change. Therefore, we need to make this change _now_ if we want to get the API change in for `tracing-subscriber` 0.3. ## Solution This branch adds a `Writer` struct that wraps the `&mut dyn fmt::Write` trait object, and changes the various method signatures as appropriate. It does **not** actually implement the change related to ANSI color formatting. Once we change these methods' signatures to accept a `Writer` struct, we can add as many methods to that struct as we like without making additional breaking API changes. Therefore, this branch _just_ makes the breaking change that's necessary to get in before v0.3 is released. Propagating the ANSI color configuration can be implemented in a future branch. Signed-off-by: Eliza Weisman <[email protected]>
## Motivation Currently, the `FormatEvent` and `FormatFields` traits in `tracing-subscriber` are passed a `&mut dyn fmt::Write` trait object to write formatted representations of events and fields to. This is fine, but it doesn't give us the ability to easily provide additional configuration to the formatter, such as whether ANSI color codes are supported. Issue #1651 describes some approaches for adding a way to expose the ANSI color code configuration to custom formatters. In particular, the proposed solution involves wrapping the `fmt::Write` trait object in an opaque struct, which can then implement additional methods for exposing information like "are ANSI colors enabled" to the formatter. Since this changes the signature of the `FormatEvent::format_event` and `FormatFields::format_fields` methods, it's a breaking change. Therefore, we need to make this change _now_ if we want to get the API change in for `tracing-subscriber` 0.3. ## Solution This branch adds a `Writer` struct that wraps the `&mut dyn fmt::Write` trait object, and changes the various method signatures as appropriate. It does **not** actually implement the change related to ANSI color formatting. Once we change these methods' signatures to accept a `Writer` struct, we can add as many methods to that struct as we like without making additional breaking API changes. Therefore, this branch _just_ makes the breaking change that's necessary to get in before v0.3 is released. Propagating the ANSI color configuration can be implemented in a future branch. Signed-off-by: Eliza Weisman <[email protected]>
## Motivation Currently, whether `tracing-subscriber`'s `fmt` subscriber will ANSI formatting escape codes use is configured on the `Format` type. This means that the configuration is honored by the event formatters implemented in `tracing-subscriber`, but is not easily exposed to those in other crates. Additionally, it's not currently easy to expose the configuration to the field formatter, so it's difficult to implement field formatters that use ANSI escape codes conditionally. Issue #1651 suggested a new API for this, where the writer that's passed in to the event and field formatters provides a method for checking if ANSI escape codes are supported. ## Solution This branch adds a new method to the `Writer` type added in #1661. The `FormatEvent` and `FormatFields` implementations can call `Writer::has_ansi_escapes` to determine whether ANSI escape codes are supported. This is also propagated to `FormattedFields`, so that it can be determined when adding new fields to a preexisting set of formatted fields. Fixes #1661 Signed-off-by: Eliza Weisman <[email protected]>
Implemented in #1696 |
This backports PR #1696 to v0.1.x. ## Motivation Currently, whether `tracing-subscriber`'s `fmt` subscriber will ANSI formatting escape codes use is configured on the `Format` type. This means that the configuration is honored by the event formatters implemented in `tracing-subscriber`, but is not easily exposed to those in other crates. Additionally, it's not currently easy to expose the configuration to the field formatter, so it's difficult to implement field formatters that use ANSI escape codes conditionally. Issue #1651 suggested a new API for this, where the writer that's passed in to the event and field formatters provides a method for checking if ANSI escape codes are supported. ## Solution This branch adds a new method to the `Writer` type added in #1661. The `FormatEvent` and `FormatFields` implementations can call `Writer::has_ansi_escapes` to determine whether ANSI escape codes are supported. This is also propagated to `FormattedFields`, so that it can be determined when adding new fields to a preexisting set of formatted fields. Fixes #1651 Signed-off-by: Eliza Weisman <[email protected]>
## Motivation Currently, the `FormatEvent` and `FormatFields` traits in `tracing-subscriber` are passed a `&mut dyn fmt::Write` trait object to write formatted representations of events and fields to. This is fine, but it doesn't give us the ability to easily provide additional configuration to the formatter, such as whether ANSI color codes are supported. Issue tokio-rs#1651 describes some approaches for adding a way to expose the ANSI color code configuration to custom formatters. In particular, the proposed solution involves wrapping the `fmt::Write` trait object in an opaque struct, which can then implement additional methods for exposing information like "are ANSI colors enabled" to the formatter. Since this changes the signature of the `FormatEvent::format_event` and `FormatFields::format_fields` methods, it's a breaking change. Therefore, we need to make this change _now_ if we want to get the API change in for `tracing-subscriber` 0.3. ## Solution This branch adds a `Writer` struct that wraps the `&mut dyn fmt::Write` trait object, and changes the various method signatures as appropriate. It does **not** actually implement the change related to ANSI color formatting. Once we change these methods' signatures to accept a `Writer` struct, we can add as many methods to that struct as we like without making additional breaking API changes. Therefore, this branch _just_ makes the breaking change that's necessary to get in before v0.3 is released. Propagating the ANSI color configuration can be implemented in a future branch. Signed-off-by: Eliza Weisman <[email protected]>
This backports PR tokio-rs#1696 to v0.1.x. ## Motivation Currently, whether `tracing-subscriber`'s `fmt` subscriber will ANSI formatting escape codes use is configured on the `Format` type. This means that the configuration is honored by the event formatters implemented in `tracing-subscriber`, but is not easily exposed to those in other crates. Additionally, it's not currently easy to expose the configuration to the field formatter, so it's difficult to implement field formatters that use ANSI escape codes conditionally. Issue tokio-rs#1651 suggested a new API for this, where the writer that's passed in to the event and field formatters provides a method for checking if ANSI escape codes are supported. ## Solution This branch adds a new method to the `Writer` type added in tokio-rs#1661. The `FormatEvent` and `FormatFields` implementations can call `Writer::has_ansi_escapes` to determine whether ANSI escape codes are supported. This is also propagated to `FormattedFields`, so that it can be determined when adding new fields to a preexisting set of formatted fields. Fixes tokio-rs#1651 Signed-off-by: Eliza Weisman <[email protected]>
Feature Request
Crates
tracing-subscriber
Motivation
The
SubscriberBuilder::with_ansi()
method only affects the default event formatter (tracing_subscriber::fmt::format::Format
). This meanstracing_subscriber::fmt().with_ansi(true).event_format(fmt_event).init()
silently throws away thewith_ansi
flag. It also means that this flag isn't available to custom event formatters. And this flag isn't exposed to field formatters (not even the default field formatter, thoughDefaultFields
doesn't currently care about this).It would be great if instead of being a property of the default event formatter, it was a flag that was exposed to arbitrary
FormatEvent
andFormatFields
implementations. This way if I do have a custom field formatter that cares about ANSI, there's a single source of truth for this, as well as having.event_format()
not silently overwrite the.with_ansi()
flag. This also makes it easier to integrate logic for only outputting colors to terminals as anything provided bytracing_subscriber
directly would then propagate to custom event/field formatters.Proposal
The simplest solution is probably to change
FormatEvent
andFormatFields
to take a custom wrapper type instead of a fork&mut dyn Write
. This wrapper type would still implementWrite
but would also expose the ansi flag. This way the event and field formatters will get the same flag, controlled by the.with_ansi()
method, and custom field formatters can now be provided by crates as drop-in replacements easily.Alternatives
The proposed change is a breaking one, but is the cleanest solution that comes to mind. A couple of alternatives come to mind:
Change
Write
to a trait with more semantic meaningRight now, changing things like terminal colors requires replacing the event and field formatters, potentially discarding any custom logic there (e.g. if I have a field formatter that handles certain fields specially, and another one that adds color to fields, I can't combine the two). We could consider replacing
Write
with a trait that requires you to specify the nature of the data you're writing, such aswrite_key(_: &fmt::Arguments<'_>)
,write_value(_: &fmt::Arguments<'_>)
,write_separator(_: &fmt::Arguments<'_>)
,write_delimiter(_: &fmt::Arguments<'_>)
, etc. Then we can have a separate configurable "format decorator" that provides these implementations and picks appropriate escapes to use. Seeslog_term::RecordDecorator
for an example of this approach. The complexity here is we'd need to figure out all possible semantic meanings that a format decorator would want to distinguish, but it would also allow a format decorator to e.g. emit XML instead (although such a decorator would have to handle e.g. a value with no key, and there's a bit of confusion there over who controls delimiter/separator strings, as an XML decorator would likely want to just use tags there but terminal output wants strings).This is of course also a breaking change, and a much more significant one. It's unclear to me if it's worth the complexity in order to separate colors from text, though at the moment I would actually love to be able to do this as I'd like to change colors without losing any default behavior around custom handling of fields (such as
DefaultFields
skippinglog.*
fields and strippingr#
prefixes and including error sources).Expose the ansi flag via additional defaulted trait methods
We could extend
RecordFields
andFormatEvent
with an additional defaultedfn set_ansi(enabled: Bool)
(default impl doing nothing). This is classified as a "possibly breaking" change, in that code that has the trait in scope might throw ambiguity errors when calling the method if another in-scope trait defines the same method, and I suspect this is unlikely to affect downstream code. It's also not a particularly great API as it requires the implementation to maintain state.Switch traits with a compatibility shim
We could do the original proposal but only expose this in new traits that replace
FormatEvents
andFormatFields
. The new traits could have blanket impls for anything that implements the old traits, thus allowing existing code to keep working, and anything that cares about the ANSI flag would implement the new trait instead.This should be backwards-compatible but is potentially confusing and requires coming up with new trait names.
The text was updated successfully, but these errors were encountered: