@@ -361,7 +361,7 @@ impl HasTonicConfig for TonicExporterBuilder {
361
361
/// ```
362
362
/// # #[cfg(all(feature = "trace", feature = "grpc-tonic"))]
363
363
/// # {
364
- /// use crate:: opentelemetry_otlp::{WithExportConfig, WithTonicConfig};
364
+ /// use opentelemetry_otlp::{WithExportConfig, WithTonicConfig};
365
365
/// let exporter_builder = opentelemetry_otlp::SpanExporter::builder()
366
366
/// .with_tonic()
367
367
/// .with_compression(opentelemetry_otlp::Compression::Gzip);
@@ -373,6 +373,32 @@ pub trait WithTonicConfig {
373
373
fn with_tls_config ( self , tls_config : ClientTlsConfig ) -> Self ;
374
374
375
375
/// Set custom metadata entries to send to the collector.
376
+ ///
377
+ /// **Note**: This method is additive - calling it multiple times will merge
378
+ /// the metadata entries. If the same key is provided in multiple calls,
379
+ /// the last value will override previous ones.
380
+ ///
381
+ /// # Example
382
+ /// ```no_run
383
+ /// # #[cfg(feature = "grpc-tonic")]
384
+ /// # {
385
+ /// use tonic::metadata::MetadataMap;
386
+ /// use opentelemetry_otlp::WithTonicConfig;
387
+ ///
388
+ /// let mut metadata1 = MetadataMap::new();
389
+ /// metadata1.insert("key1", "value1".parse().unwrap());
390
+ ///
391
+ /// let mut metadata2 = MetadataMap::new();
392
+ /// metadata2.insert("key2", "value2".parse().unwrap());
393
+ ///
394
+ /// let exporter = opentelemetry_otlp::SpanExporter::builder()
395
+ /// .with_tonic()
396
+ /// .with_metadata(metadata1) // Adds key1=value1
397
+ /// .with_metadata(metadata2) // Adds key2=value2 (both are present)
398
+ /// .build()?;
399
+ /// # }
400
+ /// # Ok::<(), Box<dyn std::error::Error>>(())
401
+ /// ```
376
402
fn with_metadata ( self , metadata : MetadataMap ) -> Self ;
377
403
378
404
/// Set the compression algorithm to use when communicating with the collector.
@@ -387,8 +413,65 @@ pub trait WithTonicConfig {
387
413
fn with_channel ( self , channel : tonic:: transport:: Channel ) -> Self ;
388
414
389
415
/// Use a custom `interceptor` to modify each outbound request.
390
- /// this can be used to modify the grpc metadata, for example
416
+ /// This can be used to modify the gRPC metadata, for example
391
417
/// to inject auth tokens.
418
+ ///
419
+ /// **Note**: Calling this method multiple times will replace the previous
420
+ /// interceptor. If you need multiple interceptors, chain them together
421
+ /// before passing to this method.
422
+ ///
423
+ /// # Examples
424
+ ///
425
+ /// ## Single interceptor
426
+ /// ```no_run
427
+ /// # #[cfg(feature = "grpc-tonic")]
428
+ /// # {
429
+ /// use tonic::{Request, Status};
430
+ /// use opentelemetry_otlp::WithTonicConfig;
431
+ ///
432
+ /// fn auth_interceptor(mut req: Request<()>) -> Result<Request<()>, Status> {
433
+ /// req.metadata_mut().insert("authorization", "Bearer token".parse().unwrap());
434
+ /// Ok(req)
435
+ /// }
436
+ ///
437
+ /// let exporter = opentelemetry_otlp::SpanExporter::builder()
438
+ /// .with_tonic()
439
+ /// .with_interceptor(auth_interceptor)
440
+ /// .build()?;
441
+ /// # }
442
+ /// # Ok::<(), Box<dyn std::error::Error>>(())
443
+ /// ```
444
+ ///
445
+ /// ## Multiple interceptors (chaining)
446
+ /// ```no_run
447
+ /// # #[cfg(feature = "grpc-tonic")]
448
+ /// # {
449
+ /// use tonic::{Request, Status};
450
+ /// use opentelemetry_otlp::WithTonicConfig;
451
+ ///
452
+ /// fn auth_interceptor(mut req: Request<()>) -> Result<Request<()>, Status> {
453
+ /// req.metadata_mut().insert("authorization", "Bearer token".parse().unwrap());
454
+ /// Ok(req)
455
+ /// }
456
+ ///
457
+ /// fn logging_interceptor(req: Request<()>) -> Result<Request<()>, Status> {
458
+ /// println!("Sending gRPC request with metadata: {:?}", req.metadata());
459
+ /// Ok(req)
460
+ /// }
461
+ ///
462
+ /// // Chain interceptors by wrapping them
463
+ /// fn combined_interceptor(req: Request<()>) -> Result<Request<()>, Status> {
464
+ /// let req = logging_interceptor(req)?;
465
+ /// auth_interceptor(req)
466
+ /// }
467
+ ///
468
+ /// let exporter = opentelemetry_otlp::SpanExporter::builder()
469
+ /// .with_tonic()
470
+ /// .with_interceptor(combined_interceptor)
471
+ /// .build()?;
472
+ /// # }
473
+ /// # Ok::<(), Box<dyn std::error::Error>>(())
474
+ /// ```
392
475
fn with_interceptor < I > ( self , interceptor : I ) -> Self
393
476
where
394
477
I : tonic:: service:: Interceptor + Clone + Send + Sync + ' static ;
0 commit comments