1- use std:: { collections:: HashMap , str:: FromStr } ;
2-
31use opentelemetry:: trace:: TraceError ;
4- use opentelemetry_otlp:: { SpanExporter , WithHttpConfig } ;
5- use opentelemetry_sdk:: { trace:: Sampler , trace :: TracerProvider , Resource } ;
2+ use opentelemetry_otlp:: SpanExporter ;
3+ use opentelemetry_sdk:: { trace:: TracerProvider , Resource } ;
64#[ cfg( feature = "tls" ) ]
75use { opentelemetry_otlp:: WithTonicConfig , tonic:: transport:: ClientTlsConfig } ;
86
@@ -19,62 +17,44 @@ pub fn init_tracerprovider<F>(
1917where
2018 F : FnOnce ( opentelemetry_sdk:: trace:: Builder ) -> opentelemetry_sdk:: trace:: Builder ,
2119{
22- use opentelemetry_otlp:: WithExportConfig ;
23-
20+ debug_env ( ) ;
2421 let ( maybe_protocol, maybe_endpoint) = read_protocol_and_endpoint_from_env ( ) ;
25- let ( protocol, endpoint) =
26- infer_protocol_and_endpoint ( maybe_protocol. as_deref ( ) , maybe_endpoint. as_deref ( ) ) ;
27- tracing:: debug!( target: "otel::setup" , OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = endpoint) ;
28- tracing:: debug!( target: "otel::setup" , OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = protocol) ;
29- let exporter: SpanExporter = match protocol. as_str ( ) {
30- "http/protobuf" => SpanExporter :: builder ( )
31- . with_http ( )
32- . with_endpoint ( endpoint)
33- . with_headers ( read_headers_from_env ( ) )
34- . build ( ) ?,
22+ let protocol = infer_protocol ( maybe_protocol. as_deref ( ) , maybe_endpoint. as_deref ( ) ) ;
23+
24+ let exporter: Option < SpanExporter > = match protocol. as_deref ( ) {
25+ Some ( "http/protobuf" ) => Some ( SpanExporter :: builder ( ) . with_http ( ) . build ( ) ?) ,
3526 #[ cfg( feature = "tls" ) ]
36- "grpc/tls" => SpanExporter :: builder ( )
37- . with_tonic ( )
38- . with_tls_config ( ClientTlsConfig :: new ( ) . with_native_roots ( ) )
39- . with_endpoint ( endpoint)
40- . build ( ) ?,
41- _ => SpanExporter :: builder ( )
42- . with_tonic ( )
43- . with_endpoint ( endpoint)
44- . build ( ) ?,
27+ Some ( "grpc/tls" ) => Some (
28+ SpanExporter :: builder ( )
29+ . with_tonic ( )
30+ . with_tls_config ( ClientTlsConfig :: new ( ) . with_native_roots ( ) )
31+ . build ( ) ?,
32+ ) ,
33+ Some ( "grpc" ) => Some ( SpanExporter :: builder ( ) . with_tonic ( ) . build ( ) ?) ,
34+ Some ( x) => {
35+ tracing:: warn!( "unknown '{x}' env var set or infered for OTEL_EXPORTER_OTLP_TRACES_PROTOCOL or OTEL_EXPORTER_OTLP_PROTOCOL; no span exporter will be created" ) ;
36+ None
37+ }
38+ None => {
39+ tracing:: warn!( "no env var set or infered for OTEL_EXPORTER_OTLP_TRACES_PROTOCOL or OTEL_EXPORTER_OTLP_PROTOCOL; no span exporter will be created" ) ;
40+ None
41+ }
4542 } ;
46-
47- let mut trace_provider: opentelemetry_sdk:: trace:: Builder = TracerProvider :: builder ( )
48- . with_config (
49- opentelemetry_sdk:: trace:: Config :: default ( )
50- . with_resource ( resource)
51- . with_sampler ( read_sampler_from_env ( ) ) ,
52- )
53- . with_batch_exporter ( exporter, opentelemetry_sdk:: runtime:: Tokio ) ;
43+ let mut trace_provider: opentelemetry_sdk:: trace:: Builder =
44+ TracerProvider :: builder ( ) . with_resource ( resource) ;
45+ if let Some ( exporter) = exporter {
46+ trace_provider =
47+ trace_provider. with_batch_exporter ( exporter, opentelemetry_sdk:: runtime:: Tokio ) ;
48+ }
5449
5550 trace_provider = transform ( trace_provider) ;
5651 Ok ( trace_provider. build ( ) )
5752}
5853
59- /// turn a string of "k1=v1,k2=v2,..." into an iterator of (key, value) tuples
60- fn parse_headers ( val : & str ) -> impl Iterator < Item = ( String , String ) > + ' _ {
61- val. split ( ',' ) . filter_map ( |kv| {
62- let s = kv
63- . split_once ( '=' )
64- . map ( |( k, v) | ( k. to_owned ( ) , v. to_owned ( ) ) ) ;
65- s
66- } )
67- }
68-
69- fn read_headers_from_env ( ) -> HashMap < String , String > {
70- let mut headers = HashMap :: new ( ) ;
71- headers. extend ( parse_headers (
72- & std:: env:: var ( "OTEL_EXPORTER_OTLP_HEADERS" ) . unwrap_or_default ( ) ,
73- ) ) ;
74- headers. extend ( parse_headers (
75- & std:: env:: var ( "OTEL_EXPORTER_OTLP_TRACES_HEADERS" ) . unwrap_or_default ( ) ,
76- ) ) ;
77- headers
54+ pub fn debug_env ( ) {
55+ std:: env:: vars ( )
56+ . filter ( |( k, _) | k. starts_with ( "OTEL_" ) )
57+ . for_each ( |( k, v) | tracing:: debug!( target: "otel::setup::env" , key = %k, value = %v) ) ;
7858}
7959
8060fn read_protocol_and_endpoint_from_env ( ) -> ( Option < String > , Option < String > ) {
@@ -94,68 +74,27 @@ fn read_protocol_and_endpoint_from_env() -> (Option<String>, Option<String>) {
9474 ( maybe_protocol, maybe_endpoint)
9575}
9676
97- /// see <https://opentelemetry.io/docs/reference/specification/sdk-environment-variables/#general-sdk-configuration>
98- /// TODO log error and infered sampler
99- fn read_sampler_from_env ( ) -> Sampler {
100- let mut name = std:: env:: var ( "OTEL_TRACES_SAMPLER" )
101- . ok ( )
102- . unwrap_or_default ( )
103- . to_lowercase ( ) ;
104- let v = match name. as_str ( ) {
105- "always_on" => Sampler :: AlwaysOn ,
106- "always_off" => Sampler :: AlwaysOff ,
107- "traceidratio" => Sampler :: TraceIdRatioBased ( read_sampler_arg_from_env ( 1f64 ) ) ,
108- "parentbased_always_on" => Sampler :: ParentBased ( Box :: new ( Sampler :: AlwaysOn ) ) ,
109- "parentbased_always_off" => Sampler :: ParentBased ( Box :: new ( Sampler :: AlwaysOff ) ) ,
110- "parentbased_traceidratio" => Sampler :: ParentBased ( Box :: new ( Sampler :: TraceIdRatioBased (
111- read_sampler_arg_from_env ( 1f64 ) ,
112- ) ) ) ,
113- "jaeger_remote" => todo ! ( "unsupported: OTEL_TRACES_SAMPLER='jaeger_remote'" ) ,
114- "xray" => todo ! ( "unsupported: OTEL_TRACES_SAMPLER='xray'" ) ,
115- _ => {
116- name = "parentbased_always_on" . to_string ( ) ;
117- Sampler :: ParentBased ( Box :: new ( Sampler :: AlwaysOn ) )
77+ #[ allow( unused_mut) ]
78+ fn infer_protocol ( maybe_protocol : Option < & str > , maybe_endpoint : Option < & str > ) -> Option < String > {
79+ let mut maybe_protocol = match ( maybe_protocol, maybe_endpoint) {
80+ ( Some ( protocol) , _) => Some ( protocol. to_string ( ) ) ,
81+ ( None , Some ( endpoint) ) => {
82+ if endpoint. contains ( ":4317" ) {
83+ Some ( "grpc" . to_string ( ) )
84+ } else {
85+ Some ( "http/protobuf" . to_string ( ) )
86+ }
11887 }
88+ _ => None ,
11989 } ;
120- tracing:: debug!( target: "otel::setup" , OTEL_TRACES_SAMPLER = name) ;
121- v
122- }
123-
124- fn read_sampler_arg_from_env < T > ( default : T ) -> T
125- where
126- T : FromStr + Copy + std:: fmt:: Debug ,
127- {
128- //TODO Log for invalid value (how to log)
129- let v = std:: env:: var ( "OTEL_TRACES_SAMPLER_ARG" )
130- . map_or ( default, |s| T :: from_str ( & s) . unwrap_or ( default) ) ;
131- tracing:: debug!( target: "otel::setup" , OTEL_TRACES_SAMPLER_ARG = ?v) ;
132- v
133- }
134-
135- fn infer_protocol_and_endpoint (
136- maybe_protocol : Option < & str > ,
137- maybe_endpoint : Option < & str > ,
138- ) -> ( String , String ) {
139- #[ cfg_attr( not( feature = "tls" ) , allow( unused_mut) ) ]
140- let mut protocol = maybe_protocol. unwrap_or_else ( || {
141- if maybe_endpoint. map_or ( false , |e| e. contains ( ":4317" ) ) {
142- "grpc"
143- } else {
144- "http/protobuf"
145- }
146- } ) ;
147-
14890 #[ cfg( feature = "tls" ) ]
149- if protocol == "grpc" && maybe_endpoint. unwrap_or ( "" ) . starts_with ( "https" ) {
150- protocol = "grpc/tls" ;
91+ if maybe_protocol. as_deref ( ) == Some ( "grpc" )
92+ && maybe_endpoint. is_some_and ( |e| e. starts_with ( "https" ) )
93+ {
94+ maybe_protocol = Some ( "grpc/tls" . to_string ( ) ) ;
15195 }
15296
153- let endpoint = match protocol {
154- "http/protobuf" => maybe_endpoint. unwrap_or ( "http://localhost:4318/v1/traces" ) , //Devskim: ignore DS137138
155- _ => maybe_endpoint. unwrap_or ( "http://localhost:4317" ) , //Devskim: ignore DS137138
156- } ;
157-
158- ( protocol. to_string ( ) , endpoint. to_string ( ) )
97+ maybe_protocol
15998}
16099
161100#[ cfg( test) ]
@@ -166,60 +105,38 @@ mod tests {
166105 use super :: * ;
167106
168107 #[ rstest]
169- #[ case( None , None , "http/protobuf" , "http://localhost:4318/v1/traces" ) ] //Devskim: ignore DS137138
170- #[ case(
171- Some ( "http/protobuf" ) ,
172- None ,
173- "http/protobuf" ,
174- "http://localhost:4318/v1/traces"
175- ) ] //Devskim: ignore DS137138
176- #[ case( Some ( "grpc" ) , None , "grpc" , "http://localhost:4317" ) ] //Devskim: ignore DS137138
177- #[ case( None , Some ( "http://localhost:4317" ) , "grpc" , "http://localhost:4317" ) ] //Devskim: ignore DS137138
108+ #[ case( None , None , None ) ] //Devskim: ignore DS137138
109+ #[ case( Some ( "http/protobuf" ) , None , Some ( "http/protobuf" ) ) ] //Devskim: ignore DS137138
110+ #[ case( Some ( "grpc" ) , None , Some ( "grpc" ) ) ] //Devskim: ignore DS137138
111+ #[ case( None , Some ( "http://localhost:4317" ) , Some ( "grpc" ) ) ] //Devskim: ignore DS137138
178112 #[ cfg_attr(
179113 feature = "tls" ,
180- case(
181- None ,
182- Some ( "https://localhost:4317" ) ,
183- "grpc/tls" ,
184- "https://localhost:4317"
185- )
114+ case( None , Some ( "https://localhost:4317" ) , Some ( "grpc/tls" ) )
186115 ) ]
187116 #[ cfg_attr(
188117 feature = "tls" ,
189- case(
190- Some ( "grpc/tls" ) ,
191- Some ( "https://localhost:4317" ) ,
192- "grpc/tls" ,
193- "https://localhost:4317"
194- )
118+ case( Some ( "grpc/tls" ) , Some ( "https://localhost:4317" ) , Some ( "grpc/tls" ) )
195119 ) ]
196120 #[ case(
197121 Some ( "http/protobuf" ) ,
198122 Some ( "http://localhost:4318/v1/traces" ) , //Devskim: ignore DS137138
199- "http/protobuf" ,
200- "http://localhost:4318/v1/traces" //Devskim: ignore DS137138
123+ Some ( "http/protobuf" ) ,
201124 ) ]
202125 #[ case(
203126 Some ( "http/protobuf" ) ,
204127 Some ( "https://examples.com:4318/v1/traces" ) ,
205- "http/protobuf" ,
206- "https://examples.com:4318/v1/traces"
128+ Some ( "http/protobuf" )
207129 ) ]
208130 #[ case(
209131 Some ( "http/protobuf" ) ,
210132 Some ( "https://examples.com:4317" ) ,
211- "http/protobuf" ,
212- "https://examples.com:4317"
133+ Some ( "http/protobuf" )
213134 ) ]
214- fn test_infer_protocol_and_endpoint (
135+ fn test_infer_protocol (
215136 #[ case] traces_protocol : Option < & str > ,
216137 #[ case] traces_endpoint : Option < & str > ,
217- #[ case] expected_protocol : & str ,
218- #[ case] expected_endpoint : & str ,
138+ #[ case] expected_protocol : Option < & str > ,
219139 ) {
220- assert ! (
221- infer_protocol_and_endpoint( traces_protocol, traces_endpoint)
222- == ( expected_protocol. to_string( ) , expected_endpoint. to_string( ) )
223- ) ;
140+ assert ! ( infer_protocol( traces_protocol, traces_endpoint) . as_deref( ) == expected_protocol) ;
224141 }
225142}
0 commit comments