1212// See the License for the specific language governing permissions and
1313// limitations under the License.
1414
15- use std:: env;
1615use std:: sync:: Arc ;
16+ use std:: { env, fmt} ;
1717
1818use anyhow:: Context ;
1919use opentelemetry:: trace:: TracerProvider ;
2020use opentelemetry:: { global, KeyValue } ;
2121use opentelemetry_sdk:: propagation:: TraceContextPropagator ;
2222use opentelemetry_sdk:: trace:: BatchConfigBuilder ;
2323use opentelemetry_sdk:: { trace, Resource } ;
24- use quickwit_common:: get_bool_from_env;
24+ use quickwit_common:: { get_bool_from_env, get_from_env_opt } ;
2525use quickwit_serve:: { BuildInfo , EnvFilterReloadFn } ;
26- use tracing:: Level ;
26+ use time:: format_description:: BorrowedFormatItem ;
27+ use tracing:: { Event , Level , Subscriber } ;
28+ use tracing_subscriber:: field:: RecordFields ;
29+ use tracing_subscriber:: fmt:: format:: {
30+ DefaultFields , Format , FormatEvent , FormatFields , Full , Json , JsonFields , Writer ,
31+ } ;
2732use tracing_subscriber:: fmt:: time:: UtcTime ;
33+ use tracing_subscriber:: fmt:: FmtContext ;
2834use tracing_subscriber:: layer:: SubscriberExt ;
2935use tracing_subscriber:: prelude:: * ;
36+ use tracing_subscriber:: registry:: LookupSpan ;
3037use tracing_subscriber:: EnvFilter ;
3138
3239use crate :: QW_ENABLE_OPENTELEMETRY_OTLP_EXPORTER_ENV_KEY ;
@@ -52,18 +59,6 @@ pub fn setup_logging_and_tracing(
5259 global:: set_text_map_propagator ( TraceContextPropagator :: new ( ) ) ;
5360 let ( reloadable_env_filter, reload_handle) = tracing_subscriber:: reload:: Layer :: new ( env_filter) ;
5461 let registry = tracing_subscriber:: registry ( ) . with ( reloadable_env_filter) ;
55- let event_format = tracing_subscriber:: fmt:: format ( )
56- . with_target ( true )
57- . with_timer (
58- // We do not rely on the Rfc3339 implementation, because it has a nanosecond precision.
59- // See discussion here: https://github.com/time-rs/time/discussions/418
60- UtcTime :: new (
61- time:: format_description:: parse (
62- "[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:3]Z" ,
63- )
64- . expect ( "Time format invalid." ) ,
65- ) ,
66- ) ;
6762 // Note on disabling ANSI characters: setting the ansi boolean on event format is insufficient.
6863 // It is thus set on layers, see https://github.com/tokio-rs/tracing/issues/1817
6964 if get_bool_from_env ( QW_ENABLE_OPENTELEMETRY_OTLP_EXPORTER_ENV_KEY , false ) {
@@ -91,20 +86,28 @@ pub fn setup_logging_and_tracing(
9186 let tracer = provider. tracer ( "quickwit" ) ;
9287 let telemetry_layer = tracing_opentelemetry:: layer ( ) . with_tracer ( tracer) ;
9388
89+ let event_format = EventFormat :: get_from_env ( ) ;
90+ let fmt_fields = event_format. format_fields ( ) ;
91+
9492 registry
9593 . with ( telemetry_layer)
9694 . with (
9795 tracing_subscriber:: fmt:: layer ( )
9896 . event_format ( event_format)
97+ . fmt_fields ( fmt_fields)
9998 . with_ansi ( ansi_colors) ,
10099 )
101100 . try_init ( )
102101 . context ( "failed to register tracing subscriber" ) ?;
103102 } else {
103+ let event_format = EventFormat :: get_from_env ( ) ;
104+ let fmt_fields = event_format. format_fields ( ) ;
105+
104106 registry
105107 . with (
106108 tracing_subscriber:: fmt:: layer ( )
107109 . event_format ( event_format)
110+ . fmt_fields ( fmt_fields)
108111 . with_ansi ( ansi_colors) ,
109112 )
110113 . try_init ( )
@@ -116,3 +119,75 @@ pub fn setup_logging_and_tracing(
116119 Ok ( ( ) )
117120 } ) )
118121}
122+
123+ enum EventFormat < ' a > {
124+ Full ( Format < Full , UtcTime < Vec < BorrowedFormatItem < ' a > > > > ) ,
125+ Json ( Format < Json > ) ,
126+ }
127+
128+ impl EventFormat < ' _ > {
129+ /// Gets the log format from the environment variable `QW_LOG_FORMAT`. Returns a JSON
130+ /// formatter if the variable is set to `json`, otherwise returns a full formatter.
131+ fn get_from_env ( ) -> Self {
132+ if get_from_env_opt :: < String > ( "QW_LOG_FORMAT" )
133+ . map ( |log_format| log_format. eq_ignore_ascii_case ( "json" ) )
134+ . unwrap_or ( false )
135+ {
136+ let json_format = tracing_subscriber:: fmt:: format ( ) . json ( ) ;
137+ EventFormat :: Json ( json_format)
138+ } else {
139+ // We do not rely on the RFC3339 implementation, because it has a nanosecond precision.
140+ // See discussion here: https://github.com/time-rs/time/discussions/418
141+ let timer_format = time:: format_description:: parse (
142+ "[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:3]Z" ,
143+ )
144+ . expect ( "time format description should be valid" ) ;
145+ let timer = UtcTime :: new ( timer_format) ;
146+
147+ let full_format = tracing_subscriber:: fmt:: format ( )
148+ . with_target ( true )
149+ . with_timer ( timer) ;
150+
151+ EventFormat :: Full ( full_format)
152+ }
153+ }
154+
155+ fn format_fields ( & self ) -> FieldFormat {
156+ match self {
157+ EventFormat :: Full ( _) => FieldFormat :: Default ( DefaultFields :: new ( ) ) ,
158+ EventFormat :: Json ( _) => FieldFormat :: Json ( JsonFields :: new ( ) ) ,
159+ }
160+ }
161+ }
162+
163+ impl < S , N > FormatEvent < S , N > for EventFormat < ' _ >
164+ where
165+ S : Subscriber + for < ' a > LookupSpan < ' a > ,
166+ N : for < ' a > FormatFields < ' a > + ' static ,
167+ {
168+ fn format_event (
169+ & self ,
170+ ctx : & FmtContext < ' _ , S , N > ,
171+ writer : Writer < ' _ > ,
172+ event : & Event < ' _ > ,
173+ ) -> fmt:: Result {
174+ match self {
175+ EventFormat :: Full ( format) => format. format_event ( ctx, writer, event) ,
176+ EventFormat :: Json ( format) => format. format_event ( ctx, writer, event) ,
177+ }
178+ }
179+ }
180+
181+ enum FieldFormat {
182+ Default ( DefaultFields ) ,
183+ Json ( JsonFields ) ,
184+ }
185+
186+ impl < ' a > FormatFields < ' a > for FieldFormat {
187+ fn format_fields < R : RecordFields > ( & self , writer : Writer < ' _ > , fields : R ) -> fmt:: Result {
188+ match self {
189+ FieldFormat :: Default ( default_fields) => default_fields. format_fields ( writer, fields) ,
190+ FieldFormat :: Json ( json_fields) => json_fields. format_fields ( writer, fields) ,
191+ }
192+ }
193+ }
0 commit comments