@@ -382,6 +382,32 @@ pub trait WithTonicConfig {
382382 fn with_tls_config ( self , tls_config : ClientTlsConfig ) -> Self ;
383383
384384 /// Set custom metadata entries to send to the collector.
385+ ///
386+ /// **Note**: This method is additive - calling it multiple times will merge
387+ /// the metadata entries. If the same key is provided in multiple calls,
388+ /// the last value will override previous ones.
389+ ///
390+ /// # Example
391+ /// ```no_run
392+ /// # #[cfg(feature = "grpc-tonic")]
393+ /// # {
394+ /// use tonic::metadata::MetadataMap;
395+ /// use crate::opentelemetry_otlp::WithTonicConfig;
396+ ///
397+ /// let mut metadata1 = MetadataMap::new();
398+ /// metadata1.insert("key1", "value1".parse().unwrap());
399+ ///
400+ /// let mut metadata2 = MetadataMap::new();
401+ /// metadata2.insert("key2", "value2".parse().unwrap());
402+ ///
403+ /// let exporter = opentelemetry_otlp::SpanExporter::builder()
404+ /// .with_tonic()
405+ /// .with_metadata(metadata1) // Adds key1=value1
406+ /// .with_metadata(metadata2) // Adds key2=value2 (both are present)
407+ /// .build()?;
408+ /// # }
409+ /// # Ok::<(), Box<dyn std::error::Error>>(())
410+ /// ```
385411 fn with_metadata ( self , metadata : MetadataMap ) -> Self ;
386412
387413 /// Set the compression algorithm to use when communicating with the collector.
@@ -396,8 +422,65 @@ pub trait WithTonicConfig {
396422 fn with_channel ( self , channel : tonic:: transport:: Channel ) -> Self ;
397423
398424 /// Use a custom `interceptor` to modify each outbound request.
399- /// this can be used to modify the grpc metadata, for example
425+ /// This can be used to modify the gRPC metadata, for example
400426 /// to inject auth tokens.
427+ ///
428+ /// **Note**: Calling this method multiple times will replace the previous
429+ /// interceptor. If you need multiple interceptors, chain them together
430+ /// before passing to this method.
431+ ///
432+ /// # Examples
433+ ///
434+ /// ## Single interceptor
435+ /// ```no_run
436+ /// # #[cfg(feature = "grpc-tonic")]
437+ /// # {
438+ /// use tonic::{Request, Status};
439+ /// use crate::opentelemetry_otlp::WithTonicConfig;
440+ ///
441+ /// fn auth_interceptor(mut req: Request<()>) -> Result<Request<()>, Status> {
442+ /// req.metadata_mut().insert("authorization", "Bearer token".parse().unwrap());
443+ /// Ok(req)
444+ /// }
445+ ///
446+ /// let exporter = opentelemetry_otlp::SpanExporter::builder()
447+ /// .with_tonic()
448+ /// .with_interceptor(auth_interceptor)
449+ /// .build()?;
450+ /// # }
451+ /// # Ok::<(), Box<dyn std::error::Error>>(())
452+ /// ```
453+ ///
454+ /// ## Multiple interceptors (chaining)
455+ /// ```no_run
456+ /// # #[cfg(feature = "grpc-tonic")]
457+ /// # {
458+ /// use tonic::{Request, Status};
459+ /// use crate::opentelemetry_otlp::WithTonicConfig;
460+ ///
461+ /// fn auth_interceptor(mut req: Request<()>) -> Result<Request<()>, Status> {
462+ /// req.metadata_mut().insert("authorization", "Bearer token".parse().unwrap());
463+ /// Ok(req)
464+ /// }
465+ ///
466+ /// fn logging_interceptor(req: Request<()>) -> Result<Request<()>, Status> {
467+ /// println!("Sending gRPC request with metadata: {:?}", req.metadata());
468+ /// Ok(req)
469+ /// }
470+ ///
471+ /// // Chain interceptors by wrapping them
472+ /// fn combined_interceptor(req: Request<()>) -> Result<Request<()>, Status> {
473+ /// let req = logging_interceptor(req)?;
474+ /// auth_interceptor(req)
475+ /// }
476+ ///
477+ /// let exporter = opentelemetry_otlp::SpanExporter::builder()
478+ /// .with_tonic()
479+ /// .with_interceptor(combined_interceptor)
480+ /// .build()?;
481+ /// # }
482+ /// # Ok::<(), Box<dyn std::error::Error>>(())
483+ /// ```
401484 fn with_interceptor < I > ( self , interceptor : I ) -> Self
402485 where
403486 I : tonic:: service:: Interceptor + Clone + Send + Sync + ' static ;
0 commit comments