-
Notifications
You must be signed in to change notification settings - Fork 2.6k
RPC to allow setting the log filter #7474
Changes from 4 commits
0c480ef
767f61a
5643e7e
cd8815e
eb429e1
884c1db
57ae457
297e75f
7960ebb
8ca1301
2b11d45
86ad90a
1406207
2d8dfa0
992e69c
65ad10d
d9a815a
f2c57fb
1906cc9
714eb48
3d7d458
d82a74a
437295b
ae4a0ac
f81577f
b18002d
57bc9ac
1e8b115
dbd3a12
8f4810f
fd82f68
89f615d
65f58b7
4c51a08
04e1786
c0996c5
68f208e
cd51835
f41b93f
23938a4
f90443a
37565c1
d827037
08c8753
59ad63e
2d96c18
3d49c2a
098e730
b5d4378
5da34f0
728ed21
990c0c9
1a7cf5c
b941066
1207ef7
042e4fe
397b09c
0489d8a
5baa021
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,7 +27,6 @@ pub mod arg_enums; | |
| mod commands; | ||
| mod config; | ||
| mod error; | ||
| mod logging; | ||
| mod params; | ||
| mod runner; | ||
|
|
||
|
|
@@ -50,10 +49,14 @@ use structopt::{ | |
| #[doc(hidden)] | ||
| pub use tracing; | ||
| use tracing_subscriber::{ | ||
| filter::Directive, fmt::time::ChronoLocal, layer::SubscriberExt, FmtSubscriber, Layer, | ||
| filter::Directive, fmt::time::ChronoLocal, layer::SubscriberExt, FmtSubscriber, Layer, fmt::Formatter, reload::Handle, EnvFilter | ||
| }; | ||
| pub use sc_tracing::logging; | ||
|
|
||
| pub use logging::PREFIX_LOG_SPAN; | ||
| use tracing_subscriber::layer::Layered; | ||
| use crate::logging::{NodeNameLayer, EventFormat}; | ||
| use tracing_subscriber::fmt::format::DefaultFields; | ||
|
|
||
| /// Substrate client CLI | ||
| /// | ||
|
|
@@ -243,21 +246,17 @@ pub fn init_logger( | |
| pattern: &str, | ||
| tracing_receiver: sc_tracing::TracingReceiver, | ||
| profiling_targets: Option<String>, | ||
| ) -> std::result::Result<(), String> { | ||
| fn parse_directives(dirs: impl AsRef<str>) -> Vec<Directive> { | ||
| dirs.as_ref() | ||
| .split(',') | ||
| .filter_map(|s| s.parse().ok()) | ||
| .collect() | ||
| } | ||
| ) -> std::result::Result<(), String> | ||
| { | ||
| use sc_tracing::parse_directives; | ||
|
|
||
| if let Err(e) = tracing_log::LogTracer::init() { | ||
| return Err(format!( | ||
| "Registering Substrate logger failed: {:}!", e | ||
| )) | ||
| } | ||
|
|
||
| let mut env_filter = tracing_subscriber::EnvFilter::default() | ||
| let mut env_filter: EnvFilter = tracing_subscriber::EnvFilter::default() | ||
| // Disable info logging by default for some modules. | ||
| .add_directive("ws=off".parse().expect("provided directive is valid")) | ||
| .add_directive("yamux=off".parse().expect("provided directive is valid")) | ||
|
|
@@ -316,18 +315,24 @@ pub fn init_logger( | |
| "%Y-%m-%d %H:%M:%S%.3f".to_string() | ||
| }); | ||
|
|
||
| let subscriber = FmtSubscriber::builder() | ||
| let subscriber_builder = FmtSubscriber::builder() | ||
| .with_env_filter(env_filter) | ||
| .with_writer(std::io::stderr) | ||
| .event_format(logging::EventFormat { | ||
| timer, | ||
| ansi: enable_color, | ||
| display_target: !simple, | ||
| display_level: !simple, | ||
| display_thread_name: !simple, | ||
| }) | ||
| .finish().with(logging::NodeNameLayer); | ||
|
|
||
| // TODO: Q - There's a small cost to this, do we make it opt-in/out with cli flag? | ||
| .with_filter_reloading(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I investigated this and I think we should enable this by default until it can be proven to be significant for our use-case. In an artificial context the performance impact is significant: it's twice as slow, but we're talking about ~35ns –> ~70ns for the worst case. Once you add in all the filtering and other options we use the impact is negligible. Benchmarks for a "complex" setup very similar to our own (but using a noop writer):
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK - nice to have some figures for that. In that case I'll just add an opt-out CLI option
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One reason for leaving it on by default is that making it optional is nasty; the reloading changes the types such that I think we'd have to duplicate a lot of code (essentially everything from here to the end of the method). I don't think it's worth it.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, that's a good point. But if it's not too ugly then IMO I think it's worth having - simply because if it's an optional performance configuration option implemented in
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll try it out and we can see in review
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just added a commit to do this - it worked out OK, only requiring 2 lines of duplicated code - one to finish the builder, another to call a new function that accepts a generic Subscriber. I don't think there is any downside to having this feature. |
||
| let handle = subscriber_builder.reload_handle(); | ||
| let subscriber = subscriber_builder | ||
| // TODO: re-enable this | ||
| // .with_writer(std::io::stderr) | ||
| // .event_format(logging::EventFormat { | ||
| // timer, | ||
| // ansi: enable_color, | ||
| // display_target: !simple, | ||
| // display_level: !simple, | ||
| // display_thread_name: !simple, | ||
| // }) | ||
| .finish() | ||
| .with(logging::NodeNameLayer); | ||
| sc_tracing::set_reload_handle(handle); | ||
| if let Some(profiling_targets) = profiling_targets { | ||
| let profiling = sc_tracing::ProfilingLayer::new(tracing_receiver, &profiling_targets); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,6 +23,7 @@ | |
| //! See `sp-tracing` for examples on how to use tracing. | ||
| //! | ||
| //! Currently we provide `Log` (default), `Telemetry` variants for `Receiver` | ||
| pub mod logging; | ||
|
mattrutherford marked this conversation as resolved.
|
||
|
|
||
| use rustc_hash::FxHashMap; | ||
| use std::fmt; | ||
|
|
@@ -37,12 +38,44 @@ use tracing::{ | |
| span::{Attributes, Id, Record}, | ||
| subscriber::Subscriber, | ||
| }; | ||
| use tracing_subscriber::{CurrentSpan, layer::{Layer, Context}}; | ||
| use tracing_subscriber::{CurrentSpan, layer::{Layer, Context}, EnvFilter}; | ||
|
|
||
| use sc_telemetry::{telemetry, SUBSTRATE_INFO}; | ||
| use sp_tracing::{WASM_NAME_KEY, WASM_TARGET_KEY, WASM_TRACE_IDENTIFIER}; | ||
| use tracing_subscriber::reload::Handle; | ||
| use tracing_subscriber::fmt::Formatter; | ||
| use once_cell::sync::OnceCell; | ||
| use tracing_subscriber::filter::Directive; | ||
|
|
||
| const ZERO_DURATION: Duration = Duration::from_nanos(0); | ||
|
|
||
| static FILTER_RELOAD_HANDLE: OnceCell<Handle<EnvFilter, Formatter>> = OnceCell::new(); | ||
|
|
||
| /// Initialize FILTER_RELOAD_HANDLE, only possible once | ||
| pub fn set_reload_handle(handle: Handle<EnvFilter, Formatter>) { | ||
| let _ = FILTER_RELOAD_HANDLE.set(handle); | ||
| } | ||
|
|
||
| /// Reload the logging filter with the supplied directives | ||
| pub fn reload_filter(directives: String) -> Result<(), String> { | ||
| let mut env_filter = tracing_subscriber::EnvFilter::default(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This means we oerride the default filters we always set in cli or not?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be fixed.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the most sane way to do this is to get rid of all current filters and then supply all new ones required; from the POV of user practicality this makes sense to me (rather than have to submit multiple RPC calls to add or remove directives) - also it is the way the underlying tracing system works - there is no way to do this piecemeal in I think an RPC to get the current log directives could be useful. If you think it's worth having we could also add 2 new RPCs
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or we can have a raw_reload_log_filter and a reload_log_filter which uses the defaults. And this should be done in this pr.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok that sounds good, I'll try it out...
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be resolved now |
||
| for directive in parse_directives(directives) { | ||
| env_filter = env_filter.add_directive(directive); | ||
| } | ||
| FILTER_RELOAD_HANDLE.get() | ||
| .ok_or("No reload handle present".to_string())? | ||
| .reload(env_filter) | ||
| .map_err(|e| format!("{}", e)) | ||
| } | ||
|
|
||
| /// Parse the supplied text directives into `Vec<tracing_subscriber::filter::Directive>` | ||
| pub fn parse_directives(dirs: impl AsRef<str>) -> Vec<Directive> { | ||
| dirs.as_ref() | ||
| .split(',') | ||
| .filter_map(|s| s.parse().ok()) | ||
|
dvdplm marked this conversation as resolved.
Outdated
|
||
| .collect() | ||
| } | ||
|
|
||
| /// Responsible for assigning ids to new spans, which are not re-used. | ||
| pub struct ProfilingLayer { | ||
| targets: Vec<(String, Level)>, | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.