Skip to content

Commit 0d10a82

Browse files
committed
Merge branch 'MCP-Instrumentor' of github.com:JohnnyL202/aws-otel-python-instrumentation into MCP-Instrumentor
2 parents 0af52d9 + 5f4f773 commit 0d10a82

File tree

15 files changed

+1953
-697
lines changed

15 files changed

+1953
-697
lines changed

.github/workflows/daily_scan.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,15 @@ jobs:
8282
id: high_scan
8383
uses: ./.github/actions/image_scan
8484
with:
85-
image-ref: "public.ecr.aws/aws-observability/adot-autoinstrumentation-python:v0.10.0"
85+
image-ref: "public.ecr.aws/aws-observability/adot-autoinstrumentation-python:v0.10.1"
8686
severity: 'CRITICAL,HIGH'
8787

8888
- name: Perform low image scan
8989
if: always()
9090
id: low_scan
9191
uses: ./.github/actions/image_scan
9292
with:
93-
image-ref: "public.ecr.aws/aws-observability/adot-autoinstrumentation-python:v0.10.0"
93+
image-ref: "public.ecr.aws/aws-observability/adot-autoinstrumentation-python:v0.10.1"
9494
severity: 'MEDIUM,LOW,UNKNOWN'
9595

9696
- name: Configure AWS Credentials for emitting metrics

aws-opentelemetry-distro/src/amazon/opentelemetry/distro/aws_opentelemetry_configurator.py

Lines changed: 53 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
AwsMetricAttributesSpanExporterBuilder,
2424
)
2525
from amazon.opentelemetry.distro.aws_span_metrics_processor_builder import AwsSpanMetricsProcessorBuilder
26+
from amazon.opentelemetry.distro.exporter.console.logs.compact_console_log_exporter import CompactConsoleLogExporter
2627
from amazon.opentelemetry.distro.otlp_udp_exporter import OTLPUdpSpanExporter
2728
from amazon.opentelemetry.distro.sampler.aws_xray_remote_sampler import AwsXRayRemoteSampler
2829
from amazon.opentelemetry.distro.scope_based_exporter import ScopeBasedPeriodicExportingMetricReader
@@ -46,7 +47,7 @@
4647
)
4748
from opentelemetry.sdk._events import EventLoggerProvider
4849
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
49-
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor, LogExporter
50+
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor, ConsoleLogExporter, LogExporter
5051
from opentelemetry.sdk.environment_variables import (
5152
_OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED,
5253
OTEL_EXPORTER_OTLP_METRICS_PROTOCOL,
@@ -122,7 +123,14 @@ class OtlpLogHeaderSetting(NamedTuple):
122123
log_group: Optional[str]
123124
log_stream: Optional[str]
124125
namespace: Optional[str]
125-
is_valid: bool
126+
127+
def is_valid(self) -> bool:
128+
"""Check if the log header setting is valid by ensuring both log_group and log_stream are present."""
129+
return self.log_group is not None and self.log_stream is not None
130+
131+
132+
# Singleton cache for OtlpLogHeaderSetting
133+
_otlp_log_header_setting_cache: Optional[OtlpLogHeaderSetting] = None
126134

127135

128136
class AwsOpenTelemetryConfigurator(_OTelSDKConfigurator):
@@ -209,6 +217,9 @@ def _init_logging(
209217
set_logger_provider(provider)
210218

211219
for _, exporter_class in exporters.items():
220+
if exporter_class is ConsoleLogExporter and _is_lambda_environment():
221+
exporter_class = CompactConsoleLogExporter
222+
_logger.debug("Lambda environment detected, using CompactConsoleLogExporter instead of ConsoleLogExporter")
212223
exporter_args = {}
213224
_customize_log_record_processor(
214225
logger_provider=provider, log_exporter=_customize_logs_exporter(exporter_class(**exporter_args))
@@ -440,7 +451,7 @@ def _customize_logs_exporter(log_exporter: LogExporter) -> LogExporter:
440451

441452
if isinstance(log_exporter, OTLPLogExporter):
442453

443-
if _validate_and_fetch_logs_header().is_valid:
454+
if _fetch_logs_header().is_valid():
444455
endpoint, region = _extract_endpoint_and_region_from_otlp_endpoint(logs_endpoint)
445456
# Setting default compression mode to Gzip as this is the behavior in upstream's
446457
# collector otlp http exporter:
@@ -627,18 +638,23 @@ def _extract_endpoint_and_region_from_otlp_endpoint(endpoint: str):
627638
return endpoint, region
628639

629640

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."""
641+
def _fetch_logs_header() -> OtlpLogHeaderSetting:
642+
"""Returns the OTLP log header setting as a singleton instance."""
643+
global _otlp_log_header_setting_cache # pylint: disable=global-statement
644+
645+
if _otlp_log_header_setting_cache is not None:
646+
return _otlp_log_header_setting_cache
633647

634648
logs_headers = os.environ.get(OTEL_EXPORTER_OTLP_LOGS_HEADERS)
635649

636650
if not logs_headers:
637-
_logger.warning(
638-
"Improper configuration: Please configure the environment variable OTEL_EXPORTER_OTLP_LOGS_HEADERS "
639-
"to include x-aws-log-group and x-aws-log-stream"
640-
)
641-
return OtlpLogHeaderSetting(None, None, None, False)
651+
if not _is_lambda_environment():
652+
_logger.warning(
653+
"Improper configuration: Please configure the environment variable OTEL_EXPORTER_OTLP_LOGS_HEADERS "
654+
"to include x-aws-log-group and x-aws-log-stream"
655+
)
656+
_otlp_log_header_setting_cache = OtlpLogHeaderSetting(None, None, None)
657+
return _otlp_log_header_setting_cache
642658

643659
log_group = None
644660
log_stream = None
@@ -656,9 +672,14 @@ def _validate_and_fetch_logs_header() -> OtlpLogHeaderSetting:
656672
elif key == AWS_EMF_METRICS_NAMESPACE and value:
657673
namespace = value
658674

659-
is_valid = log_group is not None and log_stream is not None
675+
_otlp_log_header_setting_cache = OtlpLogHeaderSetting(log_group, log_stream, namespace)
676+
return _otlp_log_header_setting_cache
677+
660678

661-
return OtlpLogHeaderSetting(log_group, log_stream, namespace, is_valid)
679+
def _clear_logs_header_cache():
680+
"""Clear the singleton cache for OtlpLogHeaderSetting. Used primarily for testing."""
681+
global _otlp_log_header_setting_cache # pylint: disable=global-statement
682+
_otlp_log_header_setting_cache = None
662683

663684

664685
def _get_metric_export_interval():
@@ -773,8 +794,25 @@ def _check_emf_exporter_enabled() -> bool:
773794

774795

775796
def _create_emf_exporter():
776-
"""Create and configure the CloudWatch EMF exporter."""
797+
"""
798+
Create the appropriate EMF exporter based on the environment and configuration.
799+
800+
Returns:
801+
ConsoleEmfExporter for Lambda without log headers log group and stream
802+
AwsCloudWatchEmfExporter for other cases (when conditions are met)
803+
None if CloudWatch exporter cannot be created
804+
"""
777805
try:
806+
log_header_setting = _fetch_logs_header()
807+
808+
# Lambda without valid logs http headers - use Console EMF exporter
809+
if _is_lambda_environment() and not log_header_setting.is_valid():
810+
# pylint: disable=import-outside-toplevel
811+
from amazon.opentelemetry.distro.exporter.aws.metrics.console_emf_exporter import ConsoleEmfExporter
812+
813+
return ConsoleEmfExporter(namespace=log_header_setting.namespace)
814+
815+
# For non-Lambda environment or Lambda with valid headers - use CloudWatch EMF exporter
778816
session = get_aws_session()
779817
# Check if botocore is available before importing the EMF exporter
780818
if not session:
@@ -786,9 +824,7 @@ def _create_emf_exporter():
786824
AwsCloudWatchEmfExporter,
787825
)
788826

789-
log_header_setting = _validate_and_fetch_logs_header()
790-
791-
if not log_header_setting.is_valid:
827+
if not log_header_setting.is_valid():
792828
return None
793829

794830
return AwsCloudWatchEmfExporter(

0 commit comments

Comments
 (0)