Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit fb08d15

Browse files
authored
Add logger configuration hook (#10440)
* Initial poc Signed-off-by: Andrei Sandu <[email protected]> * Make config available to logger hook Signed-off-by: Andrei Sandu <[email protected]> * fmt Signed-off-by: Andrei Sandu <[email protected]> * Fix tests Signed-off-by: Andrei Sandu <[email protected]> * fmt Signed-off-by: Andrei Sandu <[email protected]> * Add metric prefix option in sc_cli::RunCmd Signed-off-by: Andrei Sandu <[email protected]> * Remove print Signed-off-by: Andrei Sandu <[email protected]> * Review fixes Signed-off-by: Andrei Sandu <[email protected]> * fmt Signed-off-by: Andrei Sandu <[email protected]> * fix docs Signed-off-by: Andrei Sandu <[email protected]>
1 parent 2db9ecc commit fb08d15

File tree

7 files changed

+148
-41
lines changed

7 files changed

+148
-41
lines changed

client/cli/src/config.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -581,10 +581,40 @@ pub trait CliConfiguration<DCV: DefaultConfigurationValues = ()>: Sized {
581581
/// This method:
582582
///
583583
/// 1. Sets the panic handler
584+
/// 2. Optionally customize logger/profiling
584585
/// 2. Initializes the logger
585586
/// 3. Raises the FD limit
586-
fn init<C: SubstrateCli>(&self) -> Result<()> {
587-
sp_panic_handler::set(&C::support_url(), &C::impl_version());
587+
///
588+
/// The `logger_hook` closure is executed before the logger is constructed
589+
/// and initialized. It is useful for setting up a custom profiler.
590+
///
591+
/// Example:
592+
/// ```
593+
/// use sc_tracing::{SpanDatum, TraceEvent};
594+
/// struct TestProfiler;
595+
///
596+
/// impl sc_tracing::TraceHandler for TestProfiler {
597+
/// fn handle_span(&self, sd: &SpanDatum) {}
598+
/// fn handle_event(&self, _event: &TraceEvent) {}
599+
/// };
600+
///
601+
/// fn logger_hook() -> impl FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration) -> () {
602+
/// |logger_builder, config| {
603+
/// logger_builder.with_custom_profiling(Box::new(TestProfiler{}));
604+
/// }
605+
/// }
606+
/// ```
607+
fn init<F>(
608+
&self,
609+
support_url: &String,
610+
impl_version: &String,
611+
logger_hook: F,
612+
config: &Configuration,
613+
) -> Result<()>
614+
where
615+
F: FnOnce(&mut LoggerBuilder, &Configuration),
616+
{
617+
sp_panic_handler::set(support_url, impl_version);
588618

589619
let mut logger = LoggerBuilder::new(self.log_filters()?);
590620
logger
@@ -600,6 +630,9 @@ pub trait CliConfiguration<DCV: DefaultConfigurationValues = ()>: Sized {
600630
logger.with_colors(false);
601631
}
602632

633+
// Call hook for custom profiling setup.
634+
logger_hook(&mut logger, &config);
635+
603636
logger.init()?;
604637

605638
if let Some(new_limit) = fdlimit::raise_fd_limit() {

client/cli/src/lib.rs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,10 +224,46 @@ pub trait SubstrateCli: Sized {
224224
/// Create a runner for the command provided in argument. This will create a Configuration and
225225
/// a tokio runtime
226226
fn create_runner<T: CliConfiguration>(&self, command: &T) -> error::Result<Runner<Self>> {
227-
command.init::<Self>()?;
228-
Runner::new(self, command)
227+
let tokio_runtime = build_runtime()?;
228+
let config = command.create_configuration(self, tokio_runtime.handle().clone())?;
229+
230+
command.init(&Self::support_url(), &Self::impl_version(), |_, _| {}, &config)?;
231+
Runner::new(config, tokio_runtime)
229232
}
230233

234+
/// Create a runner for the command provided in argument. The `logger_hook` can be used to setup
235+
/// a custom profiler or update the logger configuration before it is initialized.
236+
///
237+
/// Example:
238+
/// ```
239+
/// use sc_tracing::{SpanDatum, TraceEvent};
240+
/// struct TestProfiler;
241+
///
242+
/// impl sc_tracing::TraceHandler for TestProfiler {
243+
/// fn handle_span(&self, sd: &SpanDatum) {}
244+
/// fn handle_event(&self, _event: &TraceEvent) {}
245+
/// };
246+
///
247+
/// fn logger_hook() -> impl FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration) -> () {
248+
/// |logger_builder, config| {
249+
/// logger_builder.with_custom_profiling(Box::new(TestProfiler{}));
250+
/// }
251+
/// }
252+
/// ```
253+
fn create_runner_with_logger_hook<T: CliConfiguration, F>(
254+
&self,
255+
command: &T,
256+
logger_hook: F,
257+
) -> error::Result<Runner<Self>>
258+
where
259+
F: FnOnce(&mut LoggerBuilder, &Configuration),
260+
{
261+
let tokio_runtime = build_runtime()?;
262+
let config = command.create_configuration(self, tokio_runtime.handle().clone())?;
263+
264+
command.init(&Self::support_url(), &Self::impl_version(), logger_hook, &config)?;
265+
Runner::new(config, tokio_runtime)
266+
}
231267
/// Native runtime version.
232268
fn native_runtime_version(chain_spec: &Box<dyn ChainSpec>) -> &'static RuntimeVersion;
233269
}

client/cli/src/runner.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
// You should have received a copy of the GNU General Public License
1717
// along with this program. If not, see <https://www.gnu.org/licenses/>.
1818

19-
use crate::{error::Error as CliError, CliConfiguration, Result, SubstrateCli};
19+
use crate::{error::Error as CliError, Result, SubstrateCli};
2020
use chrono::prelude::*;
2121
use futures::{future, future::FutureExt, pin_mut, select, Future};
2222
use log::info;
@@ -112,15 +112,8 @@ pub struct Runner<C: SubstrateCli> {
112112

113113
impl<C: SubstrateCli> Runner<C> {
114114
/// Create a new runtime with the command provided in argument
115-
pub fn new<T: CliConfiguration>(cli: &C, command: &T) -> Result<Runner<C>> {
116-
let tokio_runtime = build_runtime()?;
117-
let runtime_handle = tokio_runtime.handle().clone();
118-
119-
Ok(Runner {
120-
config: command.create_configuration(cli, runtime_handle)?,
121-
tokio_runtime,
122-
phantom: PhantomData,
123-
})
115+
pub fn new(config: Configuration, tokio_runtime: tokio::runtime::Runtime) -> Result<Runner<C>> {
116+
Ok(Runner { config, tokio_runtime, phantom: PhantomData })
124117
}
125118

126119
/// Log information about the node itself.

client/executor/src/integration_tests/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -622,11 +622,11 @@ fn wasm_tracing_should_work(wasm_method: WasmExecutionMethod) {
622622
struct TestTraceHandler(Arc<Mutex<Vec<SpanDatum>>>);
623623

624624
impl sc_tracing::TraceHandler for TestTraceHandler {
625-
fn handle_span(&self, sd: SpanDatum) {
626-
self.0.lock().unwrap().push(sd);
625+
fn handle_span(&self, sd: &SpanDatum) {
626+
self.0.lock().unwrap().push(sd.clone());
627627
}
628628

629-
fn handle_event(&self, _event: TraceEvent) {}
629+
fn handle_event(&self, _event: &TraceEvent) {}
630630
}
631631

632632
let traces = Arc::new(Mutex::new(Vec::new()));

client/service/src/config.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,6 @@ pub struct PrometheusConfig {
188188

189189
impl PrometheusConfig {
190190
/// Create a new config using the default registry.
191-
///
192-
/// The default registry prefixes metrics with `substrate`.
193191
pub fn new_with_default_registry(port: SocketAddr, chain_id: String) -> Self {
194192
let param = iter::once((String::from("chain"), chain_id)).collect();
195193
Self {

client/tracing/src/lib.rs

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const ZERO_DURATION: Duration = Duration::from_nanos(0);
5858
/// Responsible for assigning ids to new spans, which are not re-used.
5959
pub struct ProfilingLayer {
6060
targets: Vec<(String, Level)>,
61-
trace_handler: Box<dyn TraceHandler>,
61+
trace_handlers: Vec<Box<dyn TraceHandler>>,
6262
}
6363

6464
/// Used to configure how to receive the metrics
@@ -76,14 +76,14 @@ impl Default for TracingReceiver {
7676

7777
/// A handler for tracing `SpanDatum`
7878
pub trait TraceHandler: Send + Sync {
79-
/// Process a `SpanDatum`
80-
fn handle_span(&self, span: SpanDatum);
81-
/// Process a `TraceEvent`
82-
fn handle_event(&self, event: TraceEvent);
79+
/// Process a `SpanDatum`.
80+
fn handle_span(&self, span: &SpanDatum);
81+
/// Process a `TraceEvent`.
82+
fn handle_event(&self, event: &TraceEvent);
8383
}
8484

8585
/// Represents a tracing event, complete with values
86-
#[derive(Debug)]
86+
#[derive(Debug, Clone)]
8787
pub struct TraceEvent {
8888
/// Name of the event.
8989
pub name: String,
@@ -98,7 +98,7 @@ pub struct TraceEvent {
9898
}
9999

100100
/// Represents a single instance of a tracing span
101-
#[derive(Debug)]
101+
#[derive(Debug, Clone)]
102102
pub struct SpanDatum {
103103
/// id for this span
104104
pub id: Id,
@@ -213,6 +213,15 @@ impl fmt::Display for Values {
213213
}
214214
}
215215

216+
/// Trace handler event types.
217+
#[derive(Debug)]
218+
pub enum TraceHandlerEvents {
219+
/// An event.
220+
Event(TraceEvent),
221+
/// A span.
222+
Span(SpanDatum),
223+
}
224+
216225
impl ProfilingLayer {
217226
/// Takes a `TracingReceiver` and a comma separated list of targets,
218227
/// either with a level: "pallet=trace,frame=debug"
@@ -231,7 +240,12 @@ impl ProfilingLayer {
231240
/// wasm_tracing indicates whether to enable wasm traces
232241
pub fn new_with_handler(trace_handler: Box<dyn TraceHandler>, targets: &str) -> Self {
233242
let targets: Vec<_> = targets.split(',').map(|s| parse_target(s)).collect();
234-
Self { targets, trace_handler }
243+
Self { targets, trace_handlers: vec![trace_handler] }
244+
}
245+
246+
/// Attach additional handlers to allow handling of custom events/spans.
247+
pub fn add_handler(&mut self, trace_handler: Box<dyn TraceHandler>) {
248+
self.trace_handlers.push(trace_handler);
235249
}
236250

237251
fn check_target(&self, target: &str, level: &Level) -> bool {
@@ -242,6 +256,18 @@ impl ProfilingLayer {
242256
}
243257
false
244258
}
259+
260+
/// Sequentially dispatch a trace event to all handlers.
261+
fn dispatch_event(&self, event: TraceHandlerEvents) {
262+
match &event {
263+
TraceHandlerEvents::Span(span_datum) => {
264+
self.trace_handlers.iter().for_each(|handler| handler.handle_span(span_datum));
265+
},
266+
TraceHandlerEvents::Event(event) => {
267+
self.trace_handlers.iter().for_each(|handler| handler.handle_event(event));
268+
},
269+
}
270+
}
245271
}
246272

247273
// Default to TRACE if no level given or unable to parse Level
@@ -320,7 +346,7 @@ where
320346
values,
321347
parent_id,
322348
};
323-
self.trace_handler.handle_event(trace_event);
349+
self.dispatch_event(TraceHandlerEvents::Event(trace_event));
324350
}
325351

326352
fn on_enter(&self, span: &Id, ctx: Context<S>) {
@@ -348,10 +374,10 @@ where
348374
span_datum.target = t;
349375
}
350376
if self.check_target(&span_datum.target, &span_datum.level) {
351-
self.trace_handler.handle_span(span_datum);
377+
self.dispatch_event(TraceHandlerEvents::Span(span_datum));
352378
}
353379
} else {
354-
self.trace_handler.handle_span(span_datum);
380+
self.dispatch_event(TraceHandlerEvents::Span(span_datum));
355381
}
356382
}
357383
}
@@ -374,7 +400,7 @@ fn log_level(level: Level) -> log::Level {
374400
}
375401

376402
impl TraceHandler for LogTraceHandler {
377-
fn handle_span(&self, span_datum: SpanDatum) {
403+
fn handle_span(&self, span_datum: &SpanDatum) {
378404
if span_datum.values.is_empty() {
379405
log::log!(
380406
log_level(span_datum.level),
@@ -383,7 +409,7 @@ impl TraceHandler for LogTraceHandler {
383409
span_datum.name,
384410
span_datum.overall_time.as_nanos(),
385411
span_datum.id.into_u64(),
386-
span_datum.parent_id.map(|s| s.into_u64()),
412+
span_datum.parent_id.as_ref().map(|s| s.into_u64()),
387413
);
388414
} else {
389415
log::log!(
@@ -393,18 +419,18 @@ impl TraceHandler for LogTraceHandler {
393419
span_datum.name,
394420
span_datum.overall_time.as_nanos(),
395421
span_datum.id.into_u64(),
396-
span_datum.parent_id.map(|s| s.into_u64()),
422+
span_datum.parent_id.as_ref().map(|s| s.into_u64()),
397423
span_datum.values,
398424
);
399425
}
400426
}
401427

402-
fn handle_event(&self, event: TraceEvent) {
428+
fn handle_event(&self, event: &TraceEvent) {
403429
log::log!(
404430
log_level(event.level),
405431
"{}, parent_id: {:?}, {}",
406432
event.target,
407-
event.parent_id.map(|s| s.into_u64()),
433+
event.parent_id.as_ref().map(|s| s.into_u64()),
408434
event.values,
409435
);
410436
}
@@ -447,12 +473,12 @@ mod tests {
447473
}
448474

449475
impl TraceHandler for TestTraceHandler {
450-
fn handle_span(&self, sd: SpanDatum) {
451-
self.spans.lock().push(sd);
476+
fn handle_span(&self, sd: &SpanDatum) {
477+
self.spans.lock().push(sd.clone());
452478
}
453479

454-
fn handle_event(&self, event: TraceEvent) {
455-
self.events.lock().push(event);
480+
fn handle_event(&self, event: &TraceEvent) {
481+
self.events.lock().push(event.clone());
456482
}
457483
}
458484

client/tracing/src/logging/mod.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ where
193193
pub struct LoggerBuilder {
194194
directives: String,
195195
profiling: Option<(crate::TracingReceiver, String)>,
196+
custom_profiler: Option<Box<dyn crate::TraceHandler>>,
196197
log_reloading: bool,
197198
force_colors: Option<bool>,
198199
detailed_output: bool,
@@ -204,6 +205,7 @@ impl LoggerBuilder {
204205
Self {
205206
directives: directives.into(),
206207
profiling: None,
208+
custom_profiler: None,
207209
log_reloading: false,
208210
force_colors: None,
209211
detailed_output: false,
@@ -220,6 +222,15 @@ impl LoggerBuilder {
220222
self
221223
}
222224

225+
/// Add a custom profiler.
226+
pub fn with_custom_profiling(
227+
&mut self,
228+
custom_profiler: Box<dyn crate::TraceHandler>,
229+
) -> &mut Self {
230+
self.custom_profiler = Some(custom_profiler);
231+
self
232+
}
233+
223234
/// Wether or not to disable log reloading.
224235
pub fn with_log_reloading(&mut self, enabled: bool) -> &mut Self {
225236
self.log_reloading = enabled;
@@ -256,7 +267,12 @@ impl LoggerBuilder {
256267
self.detailed_output,
257268
|builder| enable_log_reloading!(builder),
258269
)?;
259-
let profiling = crate::ProfilingLayer::new(tracing_receiver, &profiling_targets);
270+
let mut profiling =
271+
crate::ProfilingLayer::new(tracing_receiver, &profiling_targets);
272+
273+
self.custom_profiler
274+
.into_iter()
275+
.for_each(|profiler| profiling.add_handler(profiler));
260276

261277
tracing::subscriber::set_global_default(subscriber.with(profiling))?;
262278

@@ -269,7 +285,12 @@ impl LoggerBuilder {
269285
self.detailed_output,
270286
|builder| builder,
271287
)?;
272-
let profiling = crate::ProfilingLayer::new(tracing_receiver, &profiling_targets);
288+
let mut profiling =
289+
crate::ProfilingLayer::new(tracing_receiver, &profiling_targets);
290+
291+
self.custom_profiler
292+
.into_iter()
293+
.for_each(|profiler| profiling.add_handler(profiler));
273294

274295
tracing::subscriber::set_global_default(subscriber.with(profiling))?;
275296

0 commit comments

Comments
 (0)