-
Notifications
You must be signed in to change notification settings - Fork 29
Add CloudWatch EMF exporter foundation with basic Gauge support #382
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add CloudWatch EMF exporter foundation with basic Gauge support #382
Conversation
bc2ce38 to
8491507
Compare
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Outdated
Show resolved
Hide resolved
22ab59b to
5b6d407
Compare
This PR introduces the core structure for the CloudWatch EMF (Embedded Metric Format) exporter for OpenTelemetry Python. This foundation includes: Core Features: - CloudWatchEMFExporter class with full initialization - Basic EMF log structure creation - Gauge metric conversion and export - Unit mapping from OTel to CloudWatch units - CloudWatch Logs integration with log group/stream management - Metric grouping by attributes and timestamps - Basic error handling and logging Architecture: - Follows OTel MetricExporter interface - Uses boto3 for CloudWatch Logs integration - Implements proper resource attribute handling - Supports DELTA temporality for CloudWatch compatibility Testing: - Comprehensive unit tests for core functionality - Mock-based testing to avoid AWS dependencies - Tests for initialization, conversion, and basic export flow Future PRs will add: - Support for Sum, Histogram, and ExponentialHistogram metrics - Advanced batching and CloudWatch Logs constraints - Enhanced error handling and validation
5b6d407 to
1b34c6f
Compare
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Outdated
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Outdated
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Outdated
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Outdated
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Outdated
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Outdated
Show resolved
Hide resolved
thpierce
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did not review _create_emf_log, _send_log_event, export, or unit tests. Will try to take another crack at this this week.
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Outdated
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Outdated
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Outdated
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Outdated
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Outdated
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Outdated
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Outdated
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Outdated
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Outdated
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Outdated
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Outdated
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Outdated
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Outdated
Show resolved
Hide resolved
f44f3be to
34a406c
Compare
34a406c to
7de65e4
Compare
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Outdated
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Outdated
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Outdated
Show resolved
Hide resolved
...ry-distro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/otlp_aws_emf_exporter.py
Outdated
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Outdated
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Outdated
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Outdated
Show resolved
Hide resolved
195e95a to
a0da19f
Compare
srprash
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did not look at the unit tests. Will do so in the next pass.
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Outdated
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Outdated
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Outdated
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Outdated
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Outdated
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Outdated
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Outdated
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Outdated
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Outdated
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Outdated
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Outdated
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Show resolved
Hide resolved
...tro/src/amazon/opentelemetry/distro/exporter/otlp/aws/metrics/aws_cloudwatch_emf_exporter.py
Outdated
Show resolved
Hide resolved
|
LGTM. Thanks for addressing the comments. :) |
...y-distro/src/amazon/opentelemetry/distro/exporter/aws/metrics/aws_cloudwatch_emf_exporter.py
Show resolved
Hide resolved
...y-distro/src/amazon/opentelemetry/distro/exporter/aws/metrics/aws_cloudwatch_emf_exporter.py
Show resolved
Hide resolved
) *Issue #, if available:* JS Equivalent of: - aws-observability/aws-otel-python-instrumentation#382 - aws-observability/aws-otel-python-instrumentation#409 - aws-observability/aws-otel-python-instrumentation#410 *Description of changes:* By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
*Description of changes:* Java Version of these PRs: - aws-observability/aws-otel-python-instrumentation#382 - aws-observability/aws-otel-python-instrumentation#409 - aws-observability/aws-otel-python-instrumentation#410 - aws-observability/aws-otel-python-instrumentation#434 This PR introduces the complete CloudWatch EMF (Embedded Metric Format) exporter implementation for sending OpenTelemetry metrics directly to CloudWatch without requiring a Collector or Agent. In order to enable this exporter, users MUST set the following environment variables: - `OTEL_METRICS_EXPORTER=awsemf` - - `OTEL_EXPORTER_OTLP_LOGS_HEADERS=x-aws-log-group=<log-group-name>,x-aws-log-stream=<log-stream-name>, x-aws-metric-namespace=<namespace>` - `AWS_REGION=<region>` OR `AWS_DEFAULT_REGION=<region>` This PR includes: - EMF MetricRecord translation for for unified representation of all OTel metric types with log creation with unit mapping from OpenTelemetry to CloudWatch-compatible units - Automatic log group and stream creation with retry logic - Supported CloudWatch Logs integration with batching and constraint handling (256KB event limit, 1MB request limit, timestamp limits) - Support for metric grouping by attributes and timestamps for EMF log generation - Support for Gauge, Sum, Histogram, and ExponentialHistogram metric types **TODO**: - On the next PR, will integrate the Console EMF exporter into AWS Lambda environments to validate EMF log formatting and ensure consistent behavior in Lambda runtime: aws-observability/aws-otel-python-instrumentation#437 **Testing**: - Added unit tests to validate EMF exporter configuration scenarios, including parameterized tests for both valid configurations (supporting AWS_REGION and AWS_DEFAULT_REGION) and invalid configurations (missing headers, wrong exporter type, missing region). The tests ensure the EMF exporter is correctly enabled only when all required environment variables are properly configured. - Manual end to end testing with the following environment variables to ensure the EMF logs show up: - `AWS_REGION=us-east-1` - `OTEL_METRICS_EXPORTER=awsemf` - `OTEL_EXPORTER_OTLP_LOGS_HEADERS=x-aws-log-group=test,x-aws-log-stream=default,x-aws-metric-namespace=testNamespace` - `OTEL_RESOURCE_ATTRIBUTES=service.name=testService,aws.log.group.names=test,cloud.resource_id=agent-12345` - `OTEL_LOGS_EXPORTER=none` - `OTEL_TRACES_EXPORTER=none` Example EMF log emitted: ``` { "otel.resource.process.command_args": "[/Library/Java/JavaVirtualMachines/amazon-corretto-21.jdk/Contents/Home/bin/java, -javaagent:/Users/liustve/aws-otel-java-instrumentation/otelagent/build/libs/aws-opentelemetry-agent-2.18.0-SNAPSHOT.jar, -Dfile.encoding=UTF-8, -Dsun.stdout.encoding=UTF-8, -Dsun.stderr.encoding=UTF-8, -jar, /Users/liustve/aws-otel-java-instrumentation/sample-apps/springboot/build/libs/springboot-2.11.0-SNAPSHOT.jar]", "otel.resource.host.arch": "aarch64", "otel.resource.host.name": "7cf34dd812df", "otel.resource.service.instance.id": "a0399d3c-b856-43ae-b374-fe66dee41ce8", "otel.resource.aws.log.group.names": "test", "jvm.class.unloaded": 1, "otel.resource.service.name": "testSErvice", "_aws": { "CloudWatchMetrics": [ { "Metrics": [ { "Unit": "Count", "Name": "jvm.cpu.count" }, { "Unit": "Count", "Name": "jvm.class.loaded" }, { "Name": "jvm.cpu.recent_utilization" }, { "Unit": "Seconds", "Name": "jvm.cpu.time" }, { "Unit": "Count", "Name": "jvm.class.count" }, { "Unit": "Count", "Name": "jvm.class.unloaded" } ], "Namespace": "testNamespace" } ], "Timestamp": 1758761023497 }, "otel.resource.cloud.resource_id": "agent-12345", "jvm.class.count": 14264, "Version": "1", "otel.resource.process.pid": "46822", "otel.resource.os.description": "Mac OS X 15.6.1", "otel.resource.telemetry.distro.name": "opentelemetry-java-instrumentation", "otel.resource.os.type": "darwin", "otel.resource.telemetry.sdk.name": "opentelemetry", "otel.resource.telemetry.distro.version": "2.18.0-aws-SNAPSHOT", "otel.resource.process.runtime.description": "Amazon.com Inc. OpenJDK 64-Bit Server VM 21.0.8+9-LTS", "otel.resource.process.runtime.version": "21.0.8+9-LTS", "jvm.cpu.recent_utilization": 0, "otel.resource.process.executable.path": "/Library/Java/JavaVirtualMachines/amazon-corretto-21.jdk/Contents/Home/bin/java", "otel.resource.telemetry.sdk.version": "1.52.0", "jvm.cpu.count": 12, "jvm.class.loaded": 14265, "otel.resource.process.runtime.name": "OpenJDK Runtime Environment", "otel.resource.telemetry.sdk.language": "java", "jvm.cpu.time": 7.756965 } ``` By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
This PR introduces the core structure for the CloudWatch EMF exporter for sending custom metrics. So for some specific customers they can send their own custom OTel metrics to CloudWatch metrics backend without requiring any Collector or Agent installed at this moment.
This PR includes:
Changes:
Future PRs will add:
Testing:
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.