Skip to content

Commit 7bf9280

Browse files
committed
change logic for application signals dimensions in awsemf
1 parent d905478 commit 7bf9280

File tree

6 files changed

+187
-173
lines changed

6 files changed

+187
-173
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
_logger: Logger = getLogger(__name__)
1212

1313
AGENT_OBSERVABILITY_ENABLED = "AGENT_OBSERVABILITY_ENABLED"
14+
OTEL_METRICS_ADD_APPLICATION_SIGNALS_DIMENSIONS = "OTEL_METRICS_ADD_APPLICATION_SIGNALS_DIMENSIONS"
1415

1516

1617
def is_installed(req: str) -> bool:
@@ -38,6 +39,11 @@ def is_agent_observability_enabled() -> bool:
3839
return os.environ.get(AGENT_OBSERVABILITY_ENABLED, "false").lower() == "true"
3940

4041

42+
def should_add_application_signals_dimensions() -> bool:
43+
"""Should Service and Environment Application Signals dimensions be added to EMF logs?"""
44+
return os.environ.get(OTEL_METRICS_ADD_APPLICATION_SIGNALS_DIMENSIONS, "true").lower() == "true"
45+
46+
4147
IS_BOTOCORE_INSTALLED: bool = is_installed("botocore")
4248

4349

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -897,4 +897,4 @@ def _create_aws_otlp_exporter(endpoint: str, service: str, region: str):
897897
# pylint: disable=broad-exception-caught
898898
except Exception as errors:
899899
_logger.error("Failed to create AWS OTLP exporter: %s", errors)
900-
return None
900+
return None

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@
1616
import sys
1717
from logging import ERROR, Logger, getLogger
1818

19-
from amazon.opentelemetry.distro._utils import get_aws_region, is_agent_observability_enabled, is_installed
19+
from amazon.opentelemetry.distro._utils import (
20+
OTEL_METRICS_ADD_APPLICATION_SIGNALS_DIMENSIONS,
21+
get_aws_region,
22+
is_agent_observability_enabled,
23+
is_installed,
24+
)
2025
from amazon.opentelemetry.distro.aws_opentelemetry_configurator import (
2126
APPLICATION_SIGNALS_ENABLED_CONFIG,
2227
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT,
@@ -158,6 +163,7 @@ def _configure(self, **kwargs):
158163

159164
# Disable AWS Application Signals by default
160165
os.environ.setdefault(APPLICATION_SIGNALS_ENABLED_CONFIG, "false")
166+
os.environ.setdefault(OTEL_METRICS_ADD_APPLICATION_SIGNALS_DIMENSIONS, "false")
161167

162168
super(AwsOpenTelemetryDistro, self)._configure()
163169

aws-opentelemetry-distro/src/amazon/opentelemetry/distro/exporter/aws/metrics/base_emf_exporter.py

Lines changed: 60 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@
66
import json
77
import logging
88
import math
9-
import os
109
import time
1110
from abc import ABC, abstractmethod
1211
from collections import defaultdict
1312
from typing import Any, Dict, List, Optional, Tuple
1413

15-
from amazon.opentelemetry.distro._aws_resource_attribute_configurator import get_service_attribute
14+
from amazon.opentelemetry.distro._utils import should_add_application_signals_dimensions
1615
from opentelemetry.sdk.metrics import Counter
1716
from opentelemetry.sdk.metrics import Histogram as HistogramInstr
1817
from opentelemetry.sdk.metrics import ObservableCounter, ObservableGauge, ObservableUpDownCounter, UpDownCounter
@@ -30,6 +29,7 @@
3029
)
3130
from opentelemetry.sdk.metrics.view import ExponentialBucketHistogramAggregation
3231
from opentelemetry.sdk.resources import Resource
32+
from opentelemetry.semconv._incubating.attributes.cloud_attributes import CloudPlatformValues
3333
from opentelemetry.semconv.resource import ResourceAttributes
3434
from opentelemetry.util.types import Attributes
3535

@@ -39,9 +39,19 @@
3939
SERVICE_DIMENSION_NAME: str = "Service"
4040
ENVIRONMENT_DIMENSION_NAME: str = "Environment"
4141

42+
# Resource attribute constant for deployment.environment.name
43+
# deployment.environment is deprecated in favor of deployment.environment.name
44+
# but not yet available in current OTel Python version
45+
# https://github.com/open-telemetry/opentelemetry.io/commit/b04507d7be1e916f6705126c56d66dbe9536503e
46+
DEPLOYMENT_ENVIRONMENT_NAME: str = "deployment.environment.name"
47+
4248
# Constants
43-
LAMBDA_DEFAULT: str = "lambda:default"
4449
UNKNOWN_SERVICE: str = "UnknownService"
50+
UNKNOWN_ENVIRONMENT: str = "generic:default"
51+
EC2_DEFAULT: str = "ec2:default"
52+
ECS_DEFAULT: str = "ecs:default"
53+
EKS_DEFAULT: str = "eks:default"
54+
LAMBDA_DEFAULT: str = "lambda:default"
4555

4656

4757
class MetricRecord:
@@ -195,52 +205,59 @@ def _get_dimension_names(self, attributes: Attributes) -> List[str]:
195205
# For now, use all attributes as dimensions
196206
return list(attributes.keys())
197207

198-
def _has_dimension_case_insensitive(self, dimension_names: List[str], dimension_to_check: str) -> bool:
199-
"""Check if dimension already exists (case-insensitive match)."""
200-
dimension_lower = dimension_to_check.lower()
201-
return any(dim.lower() == dimension_lower for dim in dimension_names)
202-
203-
@staticmethod
204-
def _is_application_signals_emf_export_enabled() -> bool:
205-
"""Check if Application Signals EMF export is enabled.
206-
207-
Returns True only if BOTH:
208-
- OTEL_AWS_APPLICATION_SIGNALS_ENABLED is true
209-
- OTEL_AWS_APPLICATION_SIGNALS_EMF_EXPORT_ENABLED is true
210-
"""
211-
app_signals_enabled = os.environ.get("OTEL_AWS_APPLICATION_SIGNALS_ENABLED", "false").lower() == "true"
212-
emf_export_enabled = (
213-
os.environ.get("OTEL_AWS_APPLICATION_SIGNALS_EMF_EXPORT_ENABLED", "false").lower() == "true"
214-
)
215-
return app_signals_enabled and emf_export_enabled
216-
217208
def _add_application_signals_dimensions(
218-
self, dimension_names: List[str], emf_log: Dict, resource: Resource
209+
self, dimension_names: List[str], emf_log: Dict, resource_attributes: Optional[Attributes]
219210
) -> None:
220-
"""Add Service and Environment dimensions if not already present (case-insensitive)."""
221-
if not self._is_application_signals_emf_export_enabled():
211+
"""Add Service and Environment dimensions if not already present."""
212+
if not should_add_application_signals_dimensions():
222213
return
223214

224-
# Add Service dimension if not already set by user
225215
if not self._has_dimension_case_insensitive(dimension_names, SERVICE_DIMENSION_NAME):
226-
if resource:
227-
service_name, _ = get_service_attribute(resource)
228-
else:
216+
service_name = resource_attributes.get(ResourceAttributes.SERVICE_NAME) if resource_attributes else None
217+
service_name_str = str(service_name) if service_name else ""
218+
# https://github.com/open-telemetry/opentelemetry-python/blob/102fec2be1fe9d0a8e299598a21ad6ec3b96dcca/opentelemetry-semantic-conventions/src/opentelemetry/semconv/attributes/service_attributes.py#L20
219+
if (
220+
not service_name
221+
or service_name_str == "unknown_service"
222+
or service_name_str.startswith("unknown_service:")
223+
):
229224
service_name = UNKNOWN_SERVICE
230-
dimension_names.insert(0, SERVICE_DIMENSION_NAME)
231-
emf_log[SERVICE_DIMENSION_NAME] = str(service_name)
225+
dimension_names.append(SERVICE_DIMENSION_NAME)
226+
emf_log[SERVICE_DIMENSION_NAME] = service_name
232227

233-
# Add Environment dimension if not already set by user
234228
if not self._has_dimension_case_insensitive(dimension_names, ENVIRONMENT_DIMENSION_NAME):
235-
environment_value = None
236-
if resource and resource.attributes:
237-
environment_value = resource.attributes.get(ResourceAttributes.DEPLOYMENT_ENVIRONMENT)
238-
if not environment_value:
239-
environment_value = LAMBDA_DEFAULT
240-
# Insert after Service if it exists, otherwise at the beginning
241-
insert_pos = 1 if SERVICE_DIMENSION_NAME in dimension_names else 0
242-
dimension_names.insert(insert_pos, ENVIRONMENT_DIMENSION_NAME)
243-
emf_log[ENVIRONMENT_DIMENSION_NAME] = str(environment_value)
229+
environment_name = self._get_deployment_environment(resource_attributes)
230+
dimension_names.append(ENVIRONMENT_DIMENSION_NAME)
231+
emf_log[ENVIRONMENT_DIMENSION_NAME] = environment_name
232+
233+
def _has_dimension_case_insensitive(self, dimension_names: List[str], dimension_to_check: str) -> bool:
234+
"""Check if dimension already exists."""
235+
dimension_lower = dimension_to_check.lower()
236+
return any(dim.lower() == dimension_lower for dim in dimension_names)
237+
238+
def _get_deployment_environment(self, resource_attributes: Optional[Attributes]) -> str:
239+
"""Get deployment environment from resource attributes or cloud platform."""
240+
if not resource_attributes:
241+
return UNKNOWN_ENVIRONMENT
242+
243+
environment_name = resource_attributes.get(DEPLOYMENT_ENVIRONMENT_NAME)
244+
if not environment_name:
245+
environment_name = resource_attributes.get(ResourceAttributes.DEPLOYMENT_ENVIRONMENT)
246+
247+
if not environment_name:
248+
platform = resource_attributes.get(ResourceAttributes.CLOUD_PLATFORM)
249+
if platform:
250+
if platform == CloudPlatformValues.AWS_EC2.value:
251+
return EC2_DEFAULT
252+
if platform == CloudPlatformValues.AWS_ECS.value:
253+
return ECS_DEFAULT
254+
if platform == CloudPlatformValues.AWS_EKS.value:
255+
return EKS_DEFAULT
256+
if platform == CloudPlatformValues.AWS_LAMBDA.value:
257+
return LAMBDA_DEFAULT
258+
return UNKNOWN_ENVIRONMENT
259+
return UNKNOWN_ENVIRONMENT
260+
return str(environment_name)
244261

245262
def _get_attributes_key(self, attributes: Attributes) -> str:
246263
"""
@@ -552,7 +569,8 @@ def _create_emf_log(
552569
emf_log[name] = str(value)
553570

554571
# Add Service and Environment dimensions if Application Signals EMF export is enabled
555-
self._add_application_signals_dimensions(dimension_names, emf_log, resource)
572+
resource_attributes = resource.attributes if resource else {}
573+
self._add_application_signals_dimensions(dimension_names, emf_log, resource_attributes)
556574

557575
# Add CloudWatch Metrics if we have metrics, include dimensions only if they exist
558576
if metric_definitions:

0 commit comments

Comments
 (0)