1
- use std:: { collections:: HashMap , str:: FromStr } ;
2
-
3
1
use 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 } ;
6
4
#[ cfg( feature = "tls" ) ]
7
5
use { opentelemetry_otlp:: WithTonicConfig , tonic:: transport:: ClientTlsConfig } ;
8
6
@@ -19,62 +17,44 @@ pub fn init_tracerprovider<F>(
19
17
where
20
18
F : FnOnce ( opentelemetry_sdk:: trace:: Builder ) -> opentelemetry_sdk:: trace:: Builder ,
21
19
{
22
- use opentelemetry_otlp:: WithExportConfig ;
23
-
20
+ debug_env ( ) ;
24
21
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 ( ) ?) ,
35
26
#[ 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
+ }
45
42
} ;
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
+ }
54
49
55
50
trace_provider = transform ( trace_provider) ;
56
51
Ok ( trace_provider. build ( ) )
57
52
}
58
53
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) ) ;
78
58
}
79
59
80
60
fn 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>) {
94
74
( maybe_protocol, maybe_endpoint)
95
75
}
96
76
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
+ }
118
87
}
88
+ _ => None ,
119
89
} ;
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
-
148
90
#[ 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 ( ) ) ;
151
95
}
152
96
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
159
98
}
160
99
161
100
#[ cfg( test) ]
@@ -166,60 +105,38 @@ mod tests {
166
105
use super :: * ;
167
106
168
107
#[ 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
178
112
#[ cfg_attr(
179
113
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" ) )
186
115
) ]
187
116
#[ cfg_attr(
188
117
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" ) )
195
119
) ]
196
120
#[ case(
197
121
Some ( "http/protobuf" ) ,
198
122
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" ) ,
201
124
) ]
202
125
#[ case(
203
126
Some ( "http/protobuf" ) ,
204
127
Some ( "https://examples.com:4318/v1/traces" ) ,
205
- "http/protobuf" ,
206
- "https://examples.com:4318/v1/traces"
128
+ Some ( "http/protobuf" )
207
129
) ]
208
130
#[ case(
209
131
Some ( "http/protobuf" ) ,
210
132
Some ( "https://examples.com:4317" ) ,
211
- "http/protobuf" ,
212
- "https://examples.com:4317"
133
+ Some ( "http/protobuf" )
213
134
) ]
214
- fn test_infer_protocol_and_endpoint (
135
+ fn test_infer_protocol (
215
136
#[ case] traces_protocol : Option < & str > ,
216
137
#[ case] traces_endpoint : Option < & str > ,
217
- #[ case] expected_protocol : & str ,
218
- #[ case] expected_endpoint : & str ,
138
+ #[ case] expected_protocol : Option < & str > ,
219
139
) {
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) ;
224
141
}
225
142
}
0 commit comments