1212// See the License for the specific language governing permissions and
1313// limitations under the License.
1414
15+ use std:: str:: FromStr ;
1516use std:: sync:: Arc ;
1617use std:: { env, fmt} ;
1718
1819use anyhow:: Context ;
1920use opentelemetry:: trace:: TracerProvider ;
2021use opentelemetry:: { KeyValue , global} ;
2122use opentelemetry_appender_tracing:: layer:: OpenTelemetryTracingBridge ;
23+ use opentelemetry_otlp:: {
24+ LogExporter , Protocol as OtlpWireProtocol , SpanExporter , WithExportConfig ,
25+ } ;
2226use opentelemetry_sdk:: logs:: SdkLoggerProvider ;
2327use opentelemetry_sdk:: propagation:: TraceContextPropagator ;
2428use opentelemetry_sdk:: trace:: { BatchConfigBuilder , SdkTracerProvider } ;
2529use opentelemetry_sdk:: { Resource , trace} ;
26- use quickwit_common:: { get_bool_from_env, get_from_env_opt} ;
30+ use quickwit_common:: { get_bool_from_env, get_from_env , get_from_env_opt} ;
2731use quickwit_serve:: { BuildInfo , EnvFilterReloadFn } ;
2832use time:: format_description:: BorrowedFormatItem ;
2933use tracing:: { Event , Level , Subscriber } ;
@@ -39,6 +43,67 @@ use tracing_subscriber::prelude::*;
3943use tracing_subscriber:: registry:: LookupSpan ;
4044
4145use crate :: QW_ENABLE_OPENTELEMETRY_OTLP_EXPORTER_ENV_KEY ;
46+
47+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
48+ enum OtlpProtocol {
49+ Grpc ,
50+ HttpProtobuf ,
51+ HttpJson ,
52+ }
53+
54+ impl OtlpProtocol {
55+ fn log_exporter ( & self ) -> anyhow:: Result < LogExporter > {
56+ match self {
57+ OtlpProtocol :: Grpc => LogExporter :: builder ( ) . with_tonic ( ) . build ( ) ,
58+ OtlpProtocol :: HttpProtobuf => LogExporter :: builder ( )
59+ . with_http ( )
60+ . with_protocol ( OtlpWireProtocol :: HttpBinary )
61+ . build ( ) ,
62+ OtlpProtocol :: HttpJson => LogExporter :: builder ( )
63+ . with_http ( )
64+ . with_protocol ( OtlpWireProtocol :: HttpJson )
65+ . build ( ) ,
66+ }
67+ . context ( "failed to initialize OTLP logs exporter" )
68+ }
69+
70+ fn span_exporter ( & self ) -> anyhow:: Result < SpanExporter > {
71+ match self {
72+ OtlpProtocol :: Grpc => SpanExporter :: builder ( ) . with_tonic ( ) . build ( ) ,
73+ OtlpProtocol :: HttpProtobuf => SpanExporter :: builder ( )
74+ . with_http ( )
75+ . with_protocol ( OtlpWireProtocol :: HttpBinary )
76+ . build ( ) ,
77+ OtlpProtocol :: HttpJson => SpanExporter :: builder ( )
78+ . with_http ( )
79+ . with_protocol ( OtlpWireProtocol :: HttpJson )
80+ . build ( ) ,
81+ }
82+ . context ( "failed to initialize OTLP traces exporter" )
83+ }
84+ }
85+
86+ impl FromStr for OtlpProtocol {
87+ type Err = anyhow:: Error ;
88+
89+ fn from_str ( protocol_str : & str ) -> anyhow:: Result < Self > {
90+ const OTLP_PROTOCOL_GRPC : & str = "grpc" ;
91+ const OTLP_PROTOCOL_HTTP_PROTOBUF : & str = "http/protobuf" ;
92+ const OTLP_PROTOCOL_HTTP_JSON : & str = "http/json" ;
93+
94+ match protocol_str {
95+ OTLP_PROTOCOL_GRPC => Ok ( OtlpProtocol :: Grpc ) ,
96+ OTLP_PROTOCOL_HTTP_PROTOBUF => Ok ( OtlpProtocol :: HttpProtobuf ) ,
97+ OTLP_PROTOCOL_HTTP_JSON => Ok ( OtlpProtocol :: HttpJson ) ,
98+ other => anyhow:: bail!(
99+ "unsupported OTLP protocol `{other}`, supported values are \
100+ `{OTLP_PROTOCOL_GRPC}`, `{OTLP_PROTOCOL_HTTP_PROTOBUF}` and \
101+ `{OTLP_PROTOCOL_HTTP_JSON}`"
102+ ) ,
103+ }
104+ }
105+ }
106+
42107#[ cfg( feature = "tokio-console" ) ]
43108use crate :: QW_ENABLE_TOKIO_CONSOLE_ENV_KEY ;
44109
@@ -98,10 +163,19 @@ pub fn setup_logging_and_tracing(
98163 // Note on disabling ANSI characters: setting the ansi boolean on event format is insufficient.
99164 // It is thus set on layers, see https://github.com/tokio-rs/tracing/issues/1817
100165 let provider_opt = if get_bool_from_env ( QW_ENABLE_OPENTELEMETRY_OTLP_EXPORTER_ENV_KEY , false ) {
101- let span_exporter = opentelemetry_otlp:: SpanExporter :: builder ( )
102- . with_tonic ( )
103- . build ( )
104- . context ( "failed to initialize OpenTelemetry OTLP exporter" ) ?;
166+ let global_protocol_str =
167+ get_from_env ( "OTEL_EXPORTER_OTLP_PROTOCOL" , "grpc" . to_string ( ) , false ) ;
168+ let global_protocol = OtlpProtocol :: from_str ( & global_protocol_str) ?;
169+
170+ let traces_protocol_opt =
171+ get_from_env_opt :: < String > ( "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL" , false ) ;
172+ let traces_protocol = traces_protocol_opt
173+ . as_deref ( )
174+ . map ( OtlpProtocol :: from_str)
175+ . transpose ( ) ?
176+ . unwrap_or ( global_protocol) ;
177+
178+ let span_exporter = traces_protocol. span_exporter ( ) ?;
105179 let span_processor = trace:: BatchSpanProcessor :: builder ( span_exporter)
106180 . with_batch_config (
107181 BatchConfigBuilder :: default ( )
@@ -117,14 +191,17 @@ pub fn setup_logging_and_tracing(
117191 . with_attribute ( KeyValue :: new ( "service.version" , build_info. version . clone ( ) ) )
118192 . build ( ) ;
119193
120- let logs_exporter = opentelemetry_otlp:: LogExporter :: builder ( )
121- . with_tonic ( )
122- . build ( )
123- . context ( "failed to initialize OpenTelemetry OTLP logs" ) ?;
124-
194+ let logs_protocol_opt =
195+ get_from_env_opt :: < String > ( "OTEL_EXPORTER_OTLP_LOGS_PROTOCOL" , false ) ;
196+ let logs_protocol = logs_protocol_opt
197+ . as_deref ( )
198+ . map ( OtlpProtocol :: from_str)
199+ . transpose ( ) ?
200+ . unwrap_or ( global_protocol) ;
201+ let log_exporter = logs_protocol. log_exporter ( ) ?;
125202 let logger_provider = SdkLoggerProvider :: builder ( )
126203 . with_resource ( resource. clone ( ) )
127- . with_batch_exporter ( logs_exporter )
204+ . with_batch_exporter ( log_exporter )
128205 . build ( ) ;
129206
130207 let tracing_provider = opentelemetry_sdk:: trace:: SdkTracerProvider :: builder ( )
@@ -430,6 +507,20 @@ mod tests {
430507
431508 use super :: * ;
432509
510+ #[ test]
511+ fn test_otlp_protocol_from_str ( ) {
512+ assert_eq ! ( OtlpProtocol :: from_str( "grpc" ) . unwrap( ) , OtlpProtocol :: Grpc ) ;
513+ assert_eq ! (
514+ OtlpProtocol :: from_str( "http/protobuf" ) . unwrap( ) ,
515+ OtlpProtocol :: HttpProtobuf
516+ ) ;
517+ assert_eq ! (
518+ OtlpProtocol :: from_str( "http/json" ) . unwrap( ) ,
519+ OtlpProtocol :: HttpJson
520+ ) ;
521+ assert ! ( OtlpProtocol :: from_str( "http/xml" ) . is_err( ) ) ;
522+ }
523+
433524 /// A shared buffer writer for capturing log output in tests.
434525 #[ derive( Clone , Default ) ]
435526 struct TestMakeWriter ( Arc < Mutex < Vec < u8 > > > ) ;
0 commit comments