12
12
// See the License for the specific language governing permissions and
13
13
// limitations under the License.
14
14
15
- use std:: env;
16
15
use std:: sync:: Arc ;
16
+ use std:: { env, fmt} ;
17
17
18
18
use anyhow:: Context ;
19
19
use opentelemetry:: trace:: TracerProvider ;
20
20
use opentelemetry:: { global, KeyValue } ;
21
21
use opentelemetry_sdk:: propagation:: TraceContextPropagator ;
22
22
use opentelemetry_sdk:: trace:: BatchConfigBuilder ;
23
23
use opentelemetry_sdk:: { trace, Resource } ;
24
- use quickwit_common:: get_bool_from_env;
24
+ use quickwit_common:: { get_bool_from_env, get_from_env_opt } ;
25
25
use 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
+ } ;
27
32
use tracing_subscriber:: fmt:: time:: UtcTime ;
33
+ use tracing_subscriber:: fmt:: FmtContext ;
28
34
use tracing_subscriber:: layer:: SubscriberExt ;
29
35
use tracing_subscriber:: prelude:: * ;
36
+ use tracing_subscriber:: registry:: LookupSpan ;
30
37
use tracing_subscriber:: EnvFilter ;
31
38
32
39
use crate :: QW_ENABLE_OPENTELEMETRY_OTLP_EXPORTER_ENV_KEY ;
@@ -52,18 +59,6 @@ pub fn setup_logging_and_tracing(
52
59
global:: set_text_map_propagator ( TraceContextPropagator :: new ( ) ) ;
53
60
let ( reloadable_env_filter, reload_handle) = tracing_subscriber:: reload:: Layer :: new ( env_filter) ;
54
61
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
- ) ;
67
62
// Note on disabling ANSI characters: setting the ansi boolean on event format is insufficient.
68
63
// It is thus set on layers, see https://github.com/tokio-rs/tracing/issues/1817
69
64
if get_bool_from_env ( QW_ENABLE_OPENTELEMETRY_OTLP_EXPORTER_ENV_KEY , false ) {
@@ -91,20 +86,28 @@ pub fn setup_logging_and_tracing(
91
86
let tracer = provider. tracer ( "quickwit" ) ;
92
87
let telemetry_layer = tracing_opentelemetry:: layer ( ) . with_tracer ( tracer) ;
93
88
89
+ let event_format = EventFormat :: get_from_env ( ) ;
90
+ let fmt_fields = event_format. format_fields ( ) ;
91
+
94
92
registry
95
93
. with ( telemetry_layer)
96
94
. with (
97
95
tracing_subscriber:: fmt:: layer ( )
98
96
. event_format ( event_format)
97
+ . fmt_fields ( fmt_fields)
99
98
. with_ansi ( ansi_colors) ,
100
99
)
101
100
. try_init ( )
102
101
. context ( "failed to register tracing subscriber" ) ?;
103
102
} else {
103
+ let event_format = EventFormat :: get_from_env ( ) ;
104
+ let fmt_fields = event_format. format_fields ( ) ;
105
+
104
106
registry
105
107
. with (
106
108
tracing_subscriber:: fmt:: layer ( )
107
109
. event_format ( event_format)
110
+ . fmt_fields ( fmt_fields)
108
111
. with_ansi ( ansi_colors) ,
109
112
)
110
113
. try_init ( )
@@ -116,3 +119,75 @@ pub fn setup_logging_and_tracing(
116
119
Ok ( ( ) )
117
120
} ) )
118
121
}
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