1
1
use std:: { fmt, io:: Write } ;
2
2
3
3
use 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 ,
8
12
} ;
9
- use tracing_subscriber:: registry:: LookupSpan ;
10
13
11
- use crate :: utils:: notify:: NotificationLevel ;
14
+ use crate :: {
15
+ currentprocess:: { filesource:: StderrSource as _, varsource:: VarSource as _, Process } ,
16
+ utils:: notify:: NotificationLevel ,
17
+ } ;
12
18
13
19
macro_rules! debug {
14
20
( $ ( $ arg : tt ) * ) => ( :: tracing:: trace ! ( $ ( $ arg ) * ) )
@@ -30,6 +36,74 @@ macro_rules! err {
30
36
( $ ( $ arg : tt ) * ) => ( :: tracing:: error ! ( $ ( $ arg ) * ) )
31
37
}
32
38
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
+
33
107
// Adapted from
34
108
// https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/trait.FormatEvent.html#examples
35
109
pub struct EventFormatter ;
0 commit comments