@@ -29,6 +29,13 @@ pub const OTEL_EXPORTER_OTLP_PROTOCOL: &str = "OTEL_EXPORTER_OTLP_PROTOCOL";
2929/// Compression algorithm to use, defaults to none.
3030pub const OTEL_EXPORTER_OTLP_COMPRESSION : & str = "OTEL_EXPORTER_OTLP_COMPRESSION" ;
3131
32+ /// Protocol value for HTTP with protobuf encoding
33+ pub const OTEL_EXPORTER_OTLP_PROTOCOL_HTTP_PROTOBUF : & str = "http/protobuf" ;
34+ /// Protocol value for gRPC
35+ pub const OTEL_EXPORTER_OTLP_PROTOCOL_GRPC : & str = "grpc" ;
36+ /// Protocol value for HTTP with JSON encoding
37+ pub const OTEL_EXPORTER_OTLP_PROTOCOL_HTTP_JSON : & str = "http/json" ;
38+
3239/// Max waiting time for the backend to process each signal batch, defaults to 10 seconds.
3340pub const OTEL_EXPORTER_OTLP_TIMEOUT : & str = "OTEL_EXPORTER_OTLP_TIMEOUT" ;
3441/// Default max waiting time for the backend to process each signal batch.
@@ -66,7 +73,7 @@ pub struct ExportConfig {
6673#[ cfg( any( feature = "grpc-tonic" , feature = "http-proto" , feature = "http-json" ) ) ]
6774impl Default for ExportConfig {
6875 fn default ( ) -> Self {
69- let protocol = default_protocol ( ) ;
76+ let protocol = Protocol :: default ( ) ;
7077
7178 Self {
7279 endpoint : None ,
@@ -170,25 +177,34 @@ fn resolve_compression_from_env(
170177 }
171178}
172179
173- /// Returns the default protocol based on enabled features.
180+ /// Returns the default protocol based on environment variable or enabled features.
174181///
175182/// Priority order (first available wins):
176- /// 1. http-json (if enabled)
177- /// 2. http-proto (if enabled)
178- /// 3. grpc-tonic (if enabled)
183+ /// 1. OTEL_EXPORTER_OTLP_PROTOCOL environment variable (if set and feature is enabled)
184+ /// 2. http-json (if enabled)
185+ /// 3. http-proto (if enabled)
186+ /// 4. grpc-tonic (if enabled)
179187#[ cfg( any( feature = "grpc-tonic" , feature = "http-proto" , feature = "http-json" ) ) ]
180- fn default_protocol ( ) -> Protocol {
181- #[ cfg( feature = "http-json" ) ]
182- return Protocol :: HttpJson ;
183-
184- #[ cfg( all( feature = "http-proto" , not( feature = "http-json" ) ) ) ]
185- return Protocol :: HttpBinary ;
186-
187- #[ cfg( all(
188- feature = "grpc-tonic" ,
189- not( any( feature = "http-proto" , feature = "http-json" ) )
190- ) ) ]
191- return Protocol :: Grpc ;
188+ impl Default for Protocol {
189+ fn default ( ) -> Self {
190+ // Check environment variable first
191+ if let Some ( protocol) = Protocol :: from_env ( ) {
192+ return protocol;
193+ }
194+
195+ // Fall back to feature-based defaults
196+ #[ cfg( feature = "http-json" ) ]
197+ return Protocol :: HttpJson ;
198+
199+ #[ cfg( all( feature = "http-proto" , not( feature = "http-json" ) ) ) ]
200+ return Protocol :: HttpBinary ;
201+
202+ #[ cfg( all(
203+ feature = "grpc-tonic" ,
204+ not( any( feature = "http-proto" , feature = "http-json" ) )
205+ ) ) ]
206+ return Protocol :: Grpc ;
207+ }
192208}
193209
194210/// default user-agent headers
@@ -451,21 +467,15 @@ mod tests {
451467 not( any( feature = "grpc-tonic" , feature = "http-proto" ) )
452468 ) ) ]
453469 {
454- assert_eq ! (
455- crate :: exporter:: default_protocol( ) ,
456- crate :: Protocol :: HttpJson
457- ) ;
470+ assert_eq ! ( crate :: Protocol :: default ( ) , crate :: Protocol :: HttpJson ) ;
458471 }
459472
460473 #[ cfg( all(
461474 feature = "http-proto" ,
462475 not( any( feature = "grpc-tonic" , feature = "http-json" ) )
463476 ) ) ]
464477 {
465- assert_eq ! (
466- crate :: exporter:: default_protocol( ) ,
467- crate :: Protocol :: HttpBinary
468- ) ;
478+ assert_eq ! ( crate :: Protocol :: default ( ) , crate :: Protocol :: HttpBinary ) ;
469479 }
470480
471481 #[ cfg( all(
@@ -477,6 +487,58 @@ mod tests {
477487 }
478488 }
479489
490+ #[ test]
491+ fn test_protocol_from_env ( ) {
492+ use crate :: { Protocol , OTEL_EXPORTER_OTLP_PROTOCOL } ;
493+
494+ // Test with no env var set - should return None
495+ temp_env:: with_var_unset ( OTEL_EXPORTER_OTLP_PROTOCOL , || {
496+ assert_eq ! ( Protocol :: from_env( ) , None ) ;
497+ } ) ;
498+
499+ // Test with grpc protocol
500+ #[ cfg( feature = "grpc-tonic" ) ]
501+ run_env_test ( vec ! [ ( OTEL_EXPORTER_OTLP_PROTOCOL , "grpc" ) ] , || {
502+ assert_eq ! ( Protocol :: from_env( ) , Some ( Protocol :: Grpc ) ) ;
503+ } ) ;
504+
505+ // Test with http/protobuf protocol
506+ #[ cfg( feature = "http-proto" ) ]
507+ run_env_test ( vec ! [ ( OTEL_EXPORTER_OTLP_PROTOCOL , "http/protobuf" ) ] , || {
508+ assert_eq ! ( Protocol :: from_env( ) , Some ( Protocol :: HttpBinary ) ) ;
509+ } ) ;
510+
511+ // Test with http/json protocol
512+ #[ cfg( feature = "http-json" ) ]
513+ run_env_test ( vec ! [ ( OTEL_EXPORTER_OTLP_PROTOCOL , "http/json" ) ] , || {
514+ assert_eq ! ( Protocol :: from_env( ) , Some ( Protocol :: HttpJson ) ) ;
515+ } ) ;
516+
517+ // Test with invalid protocol - should return None
518+ run_env_test ( vec ! [ ( OTEL_EXPORTER_OTLP_PROTOCOL , "invalid" ) ] , || {
519+ assert_eq ! ( Protocol :: from_env( ) , None ) ;
520+ } ) ;
521+ }
522+
523+ #[ test]
524+ fn test_default_protocol_respects_env ( ) {
525+ // Test that env var takes precedence over feature-based defaults
526+ #[ cfg( all( feature = "http-json" , feature = "http-proto" ) ) ]
527+ run_env_test (
528+ vec ! [ ( crate :: OTEL_EXPORTER_OTLP_PROTOCOL , "http/protobuf" ) ] ,
529+ || {
530+ // Even though http-json would be the default, env var should override
531+ assert_eq ! ( crate :: Protocol :: default ( ) , crate :: Protocol :: HttpBinary ) ;
532+ } ,
533+ ) ;
534+
535+ #[ cfg( all( feature = "grpc-tonic" , feature = "http-json" ) ) ]
536+ run_env_test ( vec ! [ ( crate :: OTEL_EXPORTER_OTLP_PROTOCOL , "grpc" ) ] , || {
537+ // Even though http-json would be the default, env var should override
538+ assert_eq ! ( crate :: Protocol :: default ( ) , crate :: Protocol :: Grpc ) ;
539+ } ) ;
540+ }
541+
480542 #[ test]
481543 fn test_url_decode ( ) {
482544 let test_cases = vec ! [
0 commit comments