1
1
use std:: env;
2
2
use std:: fmt:: { Debug , Formatter } ;
3
+ use std:: str:: FromStr ;
3
4
use std:: time:: Duration ;
4
5
6
+ use http:: { HeaderMap , HeaderName , HeaderValue } ;
5
7
use tonic:: codec:: CompressionEncoding ;
6
8
use tonic:: metadata:: { KeyAndValueRef , MetadataMap } ;
7
9
use tonic:: service:: Interceptor ;
8
10
use tonic:: transport:: Channel ;
9
11
#[ cfg( feature = "tls" ) ]
10
12
use tonic:: transport:: ClientTlsConfig ;
11
13
12
- use super :: default_headers;
14
+ use super :: { default_headers, parse_header_string } ;
13
15
use crate :: exporter:: Compression ;
14
16
use crate :: {
15
17
ExportConfig , OTEL_EXPORTER_OTLP_COMPRESSION , OTEL_EXPORTER_OTLP_ENDPOINT ,
16
- OTEL_EXPORTER_OTLP_TIMEOUT ,
18
+ OTEL_EXPORTER_OTLP_HEADERS , OTEL_EXPORTER_OTLP_TIMEOUT ,
17
19
} ;
18
20
19
21
#[ cfg( feature = "logs" ) ]
@@ -213,11 +215,17 @@ impl TonicExporterBuilder {
213
215
signal_endpoint_path : & str ,
214
216
signal_timeout_var : & str ,
215
217
signal_compression_var : & str ,
218
+ signal_headers_var : & str ,
216
219
) -> Result < ( Channel , BoxInterceptor , Option < CompressionEncoding > ) , crate :: Error > {
217
220
let tonic_config = self . tonic_config ;
218
221
let compression = resolve_compression ( & tonic_config, signal_compression_var) ?;
219
222
220
- let metadata = tonic_config. metadata . unwrap_or_default ( ) ;
223
+ let headers_from_env = parse_headers_from_env ( signal_headers_var) ;
224
+ let metadata = merge_metadata_with_headers_from_env (
225
+ tonic_config. metadata . unwrap_or_default ( ) ,
226
+ headers_from_env,
227
+ ) ;
228
+
221
229
let add_metadata = move |mut req : tonic:: Request < ( ) > | {
222
230
for key_and_value in metadata. iter ( ) {
223
231
match key_and_value {
@@ -294,6 +302,7 @@ impl TonicExporterBuilder {
294
302
"/v1/logs" ,
295
303
crate :: logs:: OTEL_EXPORTER_OTLP_LOGS_TIMEOUT ,
296
304
crate :: logs:: OTEL_EXPORTER_OTLP_LOGS_COMPRESSION ,
305
+ crate :: logs:: OTEL_EXPORTER_OTLP_LOGS_HEADERS ,
297
306
) ?;
298
307
299
308
let client = TonicLogsClient :: new ( channel, interceptor, compression) ;
@@ -316,6 +325,7 @@ impl TonicExporterBuilder {
316
325
"/v1/metrics" ,
317
326
crate :: metric:: OTEL_EXPORTER_OTLP_METRICS_TIMEOUT ,
318
327
crate :: metric:: OTEL_EXPORTER_OTLP_METRICS_COMPRESSION ,
328
+ crate :: metric:: OTEL_EXPORTER_OTLP_METRICS_HEADERS ,
319
329
) ?;
320
330
321
331
let client = TonicMetricsClient :: new ( channel, interceptor, compression) ;
@@ -339,6 +349,7 @@ impl TonicExporterBuilder {
339
349
"/v1/traces" ,
340
350
crate :: span:: OTEL_EXPORTER_OTLP_TRACES_TIMEOUT ,
341
351
crate :: span:: OTEL_EXPORTER_OTLP_TRACES_COMPRESSION ,
352
+ crate :: span:: OTEL_EXPORTER_OTLP_TRACES_HEADERS ,
342
353
) ?;
343
354
344
355
let client = TonicTracesClient :: new ( channel, interceptor, compression) ;
@@ -347,11 +358,44 @@ impl TonicExporterBuilder {
347
358
}
348
359
}
349
360
361
+ fn merge_metadata_with_headers_from_env (
362
+ metadata : MetadataMap ,
363
+ headers_from_env : HeaderMap ,
364
+ ) -> MetadataMap {
365
+ if headers_from_env. is_empty ( ) {
366
+ metadata
367
+ } else {
368
+ let mut existing_headers: HeaderMap = metadata. into_headers ( ) ;
369
+ existing_headers. extend ( headers_from_env) ;
370
+
371
+ MetadataMap :: from_headers ( existing_headers)
372
+ }
373
+ }
374
+
375
+ fn parse_headers_from_env ( signal_headers_var : & str ) -> HeaderMap {
376
+ env:: var ( signal_headers_var)
377
+ . or_else ( |_| env:: var ( OTEL_EXPORTER_OTLP_HEADERS ) )
378
+ . map ( |input| {
379
+ parse_header_string ( & input)
380
+ . filter_map ( |( key, value) | {
381
+ Some ( (
382
+ HeaderName :: from_str ( key) . ok ( ) ?,
383
+ HeaderValue :: from_str ( value) . ok ( ) ?,
384
+ ) )
385
+ } )
386
+ . collect :: < HeaderMap > ( )
387
+ } )
388
+ . unwrap_or_default ( )
389
+ }
390
+
350
391
#[ cfg( test) ]
351
392
mod tests {
393
+ use crate :: exporter:: tests:: run_env_test;
352
394
#[ cfg( feature = "gzip-tonic" ) ]
353
395
use crate :: exporter:: Compression ;
354
396
use crate :: TonicExporterBuilder ;
397
+ use crate :: { OTEL_EXPORTER_OTLP_HEADERS , OTEL_EXPORTER_OTLP_TRACES_HEADERS } ;
398
+ use http:: { HeaderMap , HeaderName , HeaderValue } ;
355
399
use tonic:: metadata:: { MetadataMap , MetadataValue } ;
356
400
357
401
#[ test]
@@ -393,4 +437,62 @@ mod tests {
393
437
let builder = TonicExporterBuilder :: default ( ) . with_compression ( Compression :: Gzip ) ;
394
438
assert_eq ! ( builder. tonic_config. compression. unwrap( ) , Compression :: Gzip ) ;
395
439
}
440
+
441
+ #[ test]
442
+ fn test_parse_headers_from_env ( ) {
443
+ run_env_test (
444
+ vec ! [
445
+ ( OTEL_EXPORTER_OTLP_TRACES_HEADERS , "k1=v1,k2=v2" ) ,
446
+ ( OTEL_EXPORTER_OTLP_HEADERS , "k3=v3" ) ,
447
+ ] ,
448
+ || {
449
+ assert_eq ! (
450
+ super :: parse_headers_from_env( OTEL_EXPORTER_OTLP_TRACES_HEADERS ) ,
451
+ HeaderMap :: from_iter( [
452
+ (
453
+ HeaderName :: from_static( "k1" ) ,
454
+ HeaderValue :: from_static( "v1" )
455
+ ) ,
456
+ (
457
+ HeaderName :: from_static( "k2" ) ,
458
+ HeaderValue :: from_static( "v2" )
459
+ ) ,
460
+ ] )
461
+ ) ;
462
+
463
+ assert_eq ! (
464
+ super :: parse_headers_from_env( "EMPTY_ENV" ) ,
465
+ HeaderMap :: from_iter( [ (
466
+ HeaderName :: from_static( "k3" ) ,
467
+ HeaderValue :: from_static( "v3" )
468
+ ) ] )
469
+ ) ;
470
+ } ,
471
+ )
472
+ }
473
+
474
+ #[ test]
475
+ fn test_merge_metadata_with_headers_from_env ( ) {
476
+ run_env_test (
477
+ vec ! [ ( OTEL_EXPORTER_OTLP_TRACES_HEADERS , "k1=v1,k2=v2" ) ] ,
478
+ || {
479
+ let headers_from_env =
480
+ super :: parse_headers_from_env ( OTEL_EXPORTER_OTLP_TRACES_HEADERS ) ;
481
+
482
+ let mut metadata = MetadataMap :: new ( ) ;
483
+ metadata. insert ( "foo" , "bar" . parse ( ) . unwrap ( ) ) ;
484
+ metadata. insert ( "k1" , "v0" . parse ( ) . unwrap ( ) ) ;
485
+
486
+ let result =
487
+ super :: merge_metadata_with_headers_from_env ( metadata, headers_from_env) ;
488
+
489
+ assert_eq ! (
490
+ result. get( "foo" ) . unwrap( ) ,
491
+ MetadataValue :: from_static( "bar" )
492
+ ) ;
493
+ assert_eq ! ( result. get( "k1" ) . unwrap( ) , MetadataValue :: from_static( "v1" ) ) ;
494
+ assert_eq ! ( result. get( "k2" ) . unwrap( ) , MetadataValue :: from_static( "v2" ) ) ;
495
+ } ,
496
+ ) ;
497
+ }
396
498
}
0 commit comments