33# Modifications Copyright The OpenTelemetry Authors. Licensed under the Apache License 2.0 License.
44import os
55from logging import Logger , getLogger
6- from typing import ClassVar , Dict , Type
6+ from typing import ClassVar , Dict , List , Type , Union
77
88from importlib_metadata import version
99from typing_extensions import override
1010
11+ from amazon .opentelemetry .distro ._aws_attribute_keys import AWS_LOCAL_SERVICE
12+ from amazon .opentelemetry .distro ._aws_resource_attribute_configurator import get_service_attribute
1113from amazon .opentelemetry .distro .always_record_sampler import AlwaysRecordSampler
1214from amazon .opentelemetry .distro .attribute_propagating_span_processor_builder import (
1315 AttributePropagatingSpanProcessorBuilder ,
1921from amazon .opentelemetry .distro .aws_span_metrics_processor_builder import AwsSpanMetricsProcessorBuilder
2022from amazon .opentelemetry .distro .otlp_udp_exporter import OTLPUdpSpanExporter
2123from amazon .opentelemetry .distro .sampler .aws_xray_remote_sampler import AwsXRayRemoteSampler
24+ from amazon .opentelemetry .distro .scope_based_exporter import ScopeBasedPeriodicExportingMetricReader
2225from opentelemetry .exporter .otlp .proto .http .metric_exporter import OTLPMetricExporter as OTLPHttpOTLPMetricExporter
2326from opentelemetry .exporter .otlp .proto .http .trace_exporter import OTLPSpanExporter
27+ from opentelemetry .metrics import set_meter_provider
2428from opentelemetry .sdk ._configuration import (
2529 _get_exporter_names ,
2630 _get_id_generator ,
2933 _import_id_generator ,
3034 _import_sampler ,
3135 _init_logging ,
32- _init_metrics ,
3336 _OTelSDKConfigurator ,
3437)
3538from opentelemetry .sdk .environment_variables import (
5053 ObservableUpDownCounter ,
5154 UpDownCounter ,
5255)
53- from opentelemetry .sdk .metrics .export import AggregationTemporality , PeriodicExportingMetricReader
56+ from opentelemetry .sdk .metrics .export import (
57+ AggregationTemporality ,
58+ MetricExporter ,
59+ MetricReader ,
60+ PeriodicExportingMetricReader ,
61+ )
62+ from opentelemetry .sdk .metrics .view import DefaultAggregation , DropAggregation , View
5463from opentelemetry .sdk .resources import Resource , get_aggregated_resources
5564from opentelemetry .sdk .trace import TracerProvider
5665from opentelemetry .sdk .trace .export import BatchSpanProcessor , SpanExporter
5968from opentelemetry .semconv .resource import ResourceAttributes
6069from opentelemetry .trace import set_tracer_provider
6170
62- APP_SIGNALS_ENABLED_CONFIG = "OTEL_AWS_APP_SIGNALS_ENABLED"
71+ DEPRECATED_APP_SIGNALS_ENABLED_CONFIG = "OTEL_AWS_APP_SIGNALS_ENABLED"
6372APPLICATION_SIGNALS_ENABLED_CONFIG = "OTEL_AWS_APPLICATION_SIGNALS_ENABLED"
64- APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG = "OTEL_AWS_APP_SIGNALS_EXPORTER_ENDPOINT"
73+ APPLICATION_SIGNALS_RUNTIME_ENABLED_CONFIG = "OTEL_AWS_APPLICATION_SIGNALS_RUNTIME_ENABLED"
74+ DEPRECATED_APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG = "OTEL_AWS_APP_SIGNALS_EXPORTER_ENDPOINT"
6575APPLICATION_SIGNALS_EXPORTER_ENDPOINT_CONFIG = "OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT"
6676METRIC_EXPORT_INTERVAL_CONFIG = "OTEL_METRIC_EXPORT_INTERVAL"
6777DEFAULT_METRIC_EXPORT_INTERVAL = 60000.0
@@ -171,6 +181,27 @@ def _init_tracing(
171181 set_tracer_provider (trace_provider )
172182
173183
184+ def _init_metrics (
185+ exporters_or_readers : Dict [str , Union [Type [MetricExporter ], Type [MetricReader ]]],
186+ resource : Resource = None ,
187+ ):
188+ metric_readers = []
189+ views = []
190+
191+ for _ , exporter_or_reader_class in exporters_or_readers .items ():
192+ exporter_args = {}
193+
194+ if issubclass (exporter_or_reader_class , MetricReader ):
195+ metric_readers .append (exporter_or_reader_class (** exporter_args ))
196+ else :
197+ metric_readers .append (PeriodicExportingMetricReader (exporter_or_reader_class (** exporter_args )))
198+
199+ _customize_metric_exporters (metric_readers , views )
200+
201+ provider = MeterProvider (resource = resource , metric_readers = metric_readers , views = views )
202+ set_meter_provider (provider )
203+
204+
174205# END The OpenTelemetry Authors code
175206
176207
@@ -303,14 +334,9 @@ def _customize_span_processors(provider: TracerProvider, resource: Resource) ->
303334 # Construct meterProvider
304335 _logger .info ("AWS Application Signals enabled" )
305336 otel_metric_exporter = ApplicationSignalsExporterProvider ().create_exporter ()
306- export_interval_millis = float (os .environ .get (METRIC_EXPORT_INTERVAL_CONFIG , DEFAULT_METRIC_EXPORT_INTERVAL ))
307- _logger .debug ("Span Metrics export interval: %s" , export_interval_millis )
308- # Cap export interval to 60 seconds. This is currently required for metrics-trace correlation to work correctly.
309- if export_interval_millis > DEFAULT_METRIC_EXPORT_INTERVAL :
310- export_interval_millis = DEFAULT_METRIC_EXPORT_INTERVAL
311- _logger .info ("AWS Application Signals metrics export interval capped to %s" , export_interval_millis )
337+
312338 periodic_exporting_metric_reader = PeriodicExportingMetricReader (
313- exporter = otel_metric_exporter , export_interval_millis = export_interval_millis
339+ exporter = otel_metric_exporter , export_interval_millis = _get_metric_export_interval ()
314340 )
315341 meter_provider : MeterProvider = MeterProvider (resource = resource , metric_readers = [periodic_exporting_metric_reader ])
316342 # Construct and set application signals metrics processor
@@ -319,25 +345,68 @@ def _customize_span_processors(provider: TracerProvider, resource: Resource) ->
319345 return
320346
321347
348+ def _customize_metric_exporters (metric_readers : List [MetricReader ], views : List [View ]) -> None :
349+ if _is_application_signals_runtime_enabled ():
350+ system_metrics_scope_name = "opentelemetry.instrumentation.system_metrics"
351+ if 0 == len (metric_readers ):
352+ _logger .info ("Registered scope %s" , system_metrics_scope_name )
353+ views .append (View (meter_name = system_metrics_scope_name , aggregation = DefaultAggregation ()))
354+ views .append (View (instrument_name = "*" , aggregation = DropAggregation ()))
355+
356+ otel_metric_exporter = ApplicationSignalsExporterProvider ().create_exporter ()
357+ scope_based_periodic_exporting_metric_reader = ScopeBasedPeriodicExportingMetricReader (
358+ exporter = otel_metric_exporter ,
359+ export_interval_millis = _get_metric_export_interval (),
360+ registered_scope_names = {system_metrics_scope_name },
361+ )
362+ metric_readers .append (scope_based_periodic_exporting_metric_reader )
363+
364+
322365def _customize_versions (auto_resource : Dict [str , any ]) -> Dict [str , any ]:
323366 distro_version = version ("aws-opentelemetry-distro" )
324367 auto_resource [ResourceAttributes .TELEMETRY_AUTO_VERSION ] = distro_version + "-aws"
325368 _logger .debug ("aws-opentelementry-distro - version: %s" , auto_resource [ResourceAttributes .TELEMETRY_AUTO_VERSION ])
326369 return auto_resource
327370
328371
372+ def _customize_resource (resource : Resource ) -> Resource :
373+ service_name , is_unknown = get_service_attribute (resource )
374+ if is_unknown :
375+ _logger .debug ("No valid service name found" )
376+
377+ return resource .merge (Resource .create ({AWS_LOCAL_SERVICE : service_name }))
378+
379+
329380def _is_application_signals_enabled ():
330381 return (
331- os .environ .get (APPLICATION_SIGNALS_ENABLED_CONFIG , os .environ .get (APP_SIGNALS_ENABLED_CONFIG , "false" )).lower ()
382+ os .environ .get (
383+ APPLICATION_SIGNALS_ENABLED_CONFIG , os .environ .get (DEPRECATED_APP_SIGNALS_ENABLED_CONFIG , "false" )
384+ ).lower ()
332385 == "true"
333386 )
334387
335388
389+ def _is_application_signals_runtime_enabled ():
390+ return _is_application_signals_enabled () and (
391+ os .environ .get (APPLICATION_SIGNALS_RUNTIME_ENABLED_CONFIG , "true" ).lower () == "true"
392+ )
393+
394+
336395def _is_lambda_environment ():
337396 # detect if running in AWS Lambda environment
338397 return AWS_LAMBDA_FUNCTION_NAME_CONFIG in os .environ
339398
340399
400+ def _get_metric_export_interval ():
401+ export_interval_millis = float (os .environ .get (METRIC_EXPORT_INTERVAL_CONFIG , DEFAULT_METRIC_EXPORT_INTERVAL ))
402+ _logger .debug ("Span Metrics export interval: %s" , export_interval_millis )
403+ # Cap export interval to 60 seconds. This is currently required for metrics-trace correlation to work correctly.
404+ if export_interval_millis > DEFAULT_METRIC_EXPORT_INTERVAL :
405+ export_interval_millis = DEFAULT_METRIC_EXPORT_INTERVAL
406+ _logger .info ("AWS Application Signals metrics export interval capped to %s" , export_interval_millis )
407+ return export_interval_millis
408+
409+
341410def _span_export_batch_size ():
342411 return LAMBDA_SPAN_EXPORT_BATCH_SIZE if _is_lambda_environment () else None
343412
@@ -372,7 +441,7 @@ def create_exporter(self):
372441 if protocol == "http/protobuf" :
373442 application_signals_endpoint = os .environ .get (
374443 APPLICATION_SIGNALS_EXPORTER_ENDPOINT_CONFIG ,
375- os .environ .get (APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG , "http://localhost:4316/v1/metrics" ),
444+ os .environ .get (DEPRECATED_APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG , "http://localhost:4316/v1/metrics" ),
376445 )
377446 _logger .debug ("AWS Application Signals export endpoint: %s" , application_signals_endpoint )
378447 return OTLPHttpOTLPMetricExporter (
@@ -388,7 +457,7 @@ def create_exporter(self):
388457
389458 application_signals_endpoint = os .environ .get (
390459 APPLICATION_SIGNALS_EXPORTER_ENDPOINT_CONFIG ,
391- os .environ .get (APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG , "localhost:4315" ),
460+ os .environ .get (DEPRECATED_APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG , "localhost:4315" ),
392461 )
393462 _logger .debug ("AWS Application Signals export endpoint: %s" , application_signals_endpoint )
394463 return OTLPGrpcOTLPMetricExporter (
0 commit comments