11use std:: { fmt, io:: Write } ;
22
33use termcolor:: { Color , ColorSpec , WriteColor } ;
4- use tracing:: { Event , Subscriber } ;
5- use tracing_subscriber:: fmt:: {
6- format:: { self , FormatEvent , FormatFields } ,
7- FmtContext ,
4+ use tracing:: { level_filters:: LevelFilter , Event , Subscriber } ;
5+ use tracing_subscriber:: {
6+ fmt:: {
7+ format:: { self , FormatEvent , FormatFields } ,
8+ FmtContext ,
9+ } ,
10+ registry:: LookupSpan ,
11+ EnvFilter , Layer ,
812} ;
9- use tracing_subscriber:: registry:: LookupSpan ;
1013
11- use crate :: utils:: notify:: NotificationLevel ;
14+ use crate :: {
15+ currentprocess:: { filesource:: StderrSource as _, varsource:: VarSource as _, Process } ,
16+ utils:: notify:: NotificationLevel ,
17+ } ;
1218
1319macro_rules! debug {
1420 ( $ ( $ arg : tt ) * ) => ( :: tracing:: trace ! ( $ ( $ arg ) * ) )
@@ -30,6 +36,74 @@ macro_rules! err {
3036 ( $ ( $ arg : tt ) * ) => ( :: tracing:: error ! ( $ ( $ arg ) * ) )
3137}
3238
39+ /// A [`tracing::Subscriber`] [`Layer`][`tracing_subscriber::Layer`] that prints out the log
40+ /// lines to the current [`Process`]' `stderr`.
41+ ///
42+ /// When the `RUST_LOG` environment variable is present, a standard [`tracing_subscriber`]
43+ /// formatter will be used according to the filtering directives set in its value.
44+ /// Otherwise, this logger will use [`EventFormatter`] to mimic "classic" Rustup `stderr` output.
45+ pub fn console_logger < S > ( process : Process , with_ansi : bool ) -> impl Layer < S >
46+ where
47+ S : Subscriber + for < ' span > LookupSpan < ' span > ,
48+ {
49+ let maybe_rust_log_directives = process. var_os ( "RUST_LOG" ) . clone ( ) ;
50+ let logger = tracing_subscriber:: fmt:: layer ( )
51+ . with_writer ( move || process. stderr ( ) )
52+ . with_ansi ( with_ansi) ;
53+ if let Some ( directives) = maybe_rust_log_directives {
54+ let env_filter = EnvFilter :: builder ( )
55+ . with_default_directive ( LevelFilter :: INFO . into ( ) )
56+ . parse_lossy ( directives. to_string_lossy ( ) ) ;
57+ logger. compact ( ) . with_filter ( env_filter) . boxed ( )
58+ } else {
59+ // Receive log lines from Rustup only.
60+ let env_filter = EnvFilter :: new ( "rustup=DEBUG" ) ;
61+ logger
62+ . event_format ( EventFormatter )
63+ . with_filter ( env_filter)
64+ . boxed ( )
65+ }
66+ }
67+
68+ /// A [`tracing::Subscriber`] [`Layer`][`tracing_subscriber::Layer`] that corresponds to Rustup's
69+ /// optional `opentelemetry` (a.k.a. `otel`) feature.
70+ #[ cfg( feature = "otel" ) ]
71+ pub fn telemetry < S > ( ) -> anyhow:: Result < impl Layer < S > >
72+ where
73+ S : Subscriber + for < ' span > LookupSpan < ' span > ,
74+ {
75+ use std:: time:: Duration ;
76+
77+ use opentelemetry:: { global, KeyValue } ;
78+ use opentelemetry_otlp:: WithExportConfig ;
79+ use opentelemetry_sdk:: {
80+ propagation:: TraceContextPropagator ,
81+ trace:: { self , Sampler } ,
82+ Resource ,
83+ } ;
84+
85+ global:: set_text_map_propagator ( TraceContextPropagator :: new ( ) ) ;
86+
87+ let tracer = opentelemetry_otlp:: new_pipeline ( )
88+ . tracing ( )
89+ . with_exporter (
90+ opentelemetry_otlp:: new_exporter ( )
91+ . tonic ( )
92+ . with_timeout ( Duration :: from_secs ( 3 ) ) ,
93+ )
94+ . with_trace_config (
95+ trace:: config ( )
96+ . with_sampler ( Sampler :: AlwaysOn )
97+ . with_resource ( Resource :: new ( vec ! [ KeyValue :: new( "service.name" , "rustup" ) ] ) ) ,
98+ )
99+ . install_batch ( opentelemetry_sdk:: runtime:: Tokio ) ?;
100+ // NOTE: This reads from the real environment variables instead of `process().var_os()`.
101+ let env_filter = EnvFilter :: try_from_default_env ( ) . unwrap_or ( EnvFilter :: new ( "INFO" ) ) ;
102+ Ok ( tracing_opentelemetry:: layer ( )
103+ . with_tracer ( tracer)
104+ . with_filter ( env_filter) )
105+ }
106+
33107// Adapted from
34108// https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/trait.FormatEvent.html#examples
35109pub struct EventFormatter ;
0 commit comments