@@ -122,7 +122,14 @@ class OtlpLogHeaderSetting(NamedTuple):
122
122
log_group : Optional [str ]
123
123
log_stream : Optional [str ]
124
124
namespace : Optional [str ]
125
- is_valid : bool
125
+
126
+ def is_valid (self ) -> bool :
127
+ """Check if the log header setting is valid by ensuring both log_group and log_stream are present."""
128
+ return self .log_group is not None and self .log_stream is not None
129
+
130
+
131
+ # Singleton cache for OtlpLogHeaderSetting
132
+ _otlp_log_header_setting_cache : Optional [OtlpLogHeaderSetting ] = None
126
133
127
134
128
135
class AwsOpenTelemetryConfigurator (_OTelSDKConfigurator ):
@@ -440,7 +447,7 @@ def _customize_logs_exporter(log_exporter: LogExporter) -> LogExporter:
440
447
441
448
if isinstance (log_exporter , OTLPLogExporter ):
442
449
443
- if _validate_and_fetch_logs_header ().is_valid :
450
+ if _fetch_logs_header ().is_valid () :
444
451
endpoint , region = _extract_endpoint_and_region_from_otlp_endpoint (logs_endpoint )
445
452
# Setting default compression mode to Gzip as this is the behavior in upstream's
446
453
# collector otlp http exporter:
@@ -627,9 +634,12 @@ def _extract_endpoint_and_region_from_otlp_endpoint(endpoint: str):
627
634
return endpoint , region
628
635
629
636
630
- def _validate_and_fetch_logs_header () -> OtlpLogHeaderSetting :
631
- """Checks if x-aws-log-group and x-aws-log-stream are present in the headers in order to send logs to
632
- AWS OTLP Logs endpoint."""
637
+ def _fetch_logs_header () -> OtlpLogHeaderSetting :
638
+ """Returns the OTLP log header setting as a singleton instance."""
639
+ global _otlp_log_header_setting_cache # pylint: disable=global-statement
640
+
641
+ if _otlp_log_header_setting_cache is not None :
642
+ return _otlp_log_header_setting_cache
633
643
634
644
logs_headers = os .environ .get (OTEL_EXPORTER_OTLP_LOGS_HEADERS )
635
645
@@ -639,7 +649,8 @@ def _validate_and_fetch_logs_header() -> OtlpLogHeaderSetting:
639
649
"Improper configuration: Please configure the environment variable OTEL_EXPORTER_OTLP_LOGS_HEADERS "
640
650
"to include x-aws-log-group and x-aws-log-stream"
641
651
)
642
- return OtlpLogHeaderSetting (None , None , None , False )
652
+ _otlp_log_header_setting_cache = OtlpLogHeaderSetting (None , None , None )
653
+ return _otlp_log_header_setting_cache
643
654
644
655
log_group = None
645
656
log_stream = None
@@ -657,9 +668,14 @@ def _validate_and_fetch_logs_header() -> OtlpLogHeaderSetting:
657
668
elif key == AWS_EMF_METRICS_NAMESPACE and value :
658
669
namespace = value
659
670
660
- is_valid = log_group is not None and log_stream is not None
671
+ _otlp_log_header_setting_cache = OtlpLogHeaderSetting (log_group , log_stream , namespace )
672
+ return _otlp_log_header_setting_cache
661
673
662
- return OtlpLogHeaderSetting (log_group , log_stream , namespace , is_valid )
674
+
675
+ def _clear_logs_header_cache ():
676
+ """Clear the singleton cache for OtlpLogHeaderSetting. Used primarily for testing."""
677
+ global _otlp_log_header_setting_cache # pylint: disable=global-statement
678
+ _otlp_log_header_setting_cache = None
663
679
664
680
665
681
def _get_metric_export_interval ():
@@ -772,26 +788,26 @@ def _check_emf_exporter_enabled() -> bool:
772
788
773
789
return True
774
790
791
+
775
792
def _create_emf_exporter ():
776
793
"""
777
794
Create the appropriate EMF exporter based on the environment and configuration.
778
795
796
+ Returns:
797
+ ConsoleEmfExporter for Lambda without log headers log group and stream
798
+ AwsCloudWatchEmfExporter for other cases (when conditions are met)
799
+ None if CloudWatch exporter cannot be created
779
800
"""
780
- log_header_setting = _validate_and_fetch_logs_header ()
781
-
782
- if _is_lambda_environment () and not log_header_setting . is_valid :
801
+ try :
802
+ log_header_setting = _fetch_logs_header ()
803
+
783
804
# Lambda without valid logs http headers - use Console EMF exporter
784
- from amazon .opentelemetry .distro .exporter .aws .metrics .console_emf_exporter import (
785
- ConsoleEmfExporter ,
786
- )
787
- return ConsoleEmfExporter (namespace = log_header_setting .namespace )
788
- else :
789
- # Non-Lambda environment - use CloudWatch EMF exporter
790
- return _create_cloudwatch_emf_exporter ()
805
+ if _is_lambda_environment () and not log_header_setting .is_valid ():
806
+ # pylint: disable=import-outside-toplevel
807
+ from amazon .opentelemetry .distro .exporter .aws .metrics .console_emf_exporter import ConsoleEmfExporter
808
+ return ConsoleEmfExporter (namespace = log_header_setting .namespace )
791
809
792
- def _create_cloudwatch_emf_exporter ():
793
- """Create and configure the CloudWatch EMF exporter."""
794
- try :
810
+ # For non-Lambda environment or Lambda with valid headers - use CloudWatch EMF exporter
795
811
session = get_aws_session ()
796
812
# Check if botocore is available before importing the EMF exporter
797
813
if not session :
@@ -803,9 +819,7 @@ def _create_cloudwatch_emf_exporter():
803
819
AwsCloudWatchEmfExporter ,
804
820
)
805
821
806
- log_header_setting = _validate_and_fetch_logs_header ()
807
-
808
- if not log_header_setting .is_valid :
822
+ if not log_header_setting .is_valid ():
809
823
return None
810
824
811
825
return AwsCloudWatchEmfExporter (
0 commit comments