3
3
# Modifications Copyright The OpenTelemetry Authors. Licensed under the Apache License 2.0 License.
4
4
import os
5
5
from logging import Logger , getLogger
6
- from typing import ClassVar , Dict , Type
6
+ from typing import ClassVar , Dict , List , Type , Union
7
7
8
8
from importlib_metadata import version
9
9
from typing_extensions import override
10
10
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
11
13
from amazon .opentelemetry .distro .always_record_sampler import AlwaysRecordSampler
12
14
from amazon .opentelemetry .distro .attribute_propagating_span_processor_builder import (
13
15
AttributePropagatingSpanProcessorBuilder ,
19
21
from amazon .opentelemetry .distro .aws_span_metrics_processor_builder import AwsSpanMetricsProcessorBuilder
20
22
from amazon .opentelemetry .distro .otlp_udp_exporter import OTLPUdpSpanExporter
21
23
from amazon .opentelemetry .distro .sampler .aws_xray_remote_sampler import AwsXRayRemoteSampler
24
+ from amazon .opentelemetry .distro .scope_based_exporter import ScopeBasedPeriodicExportingMetricReader
25
+ from amazon .opentelemetry .distro .scope_based_filtering_view import ScopeBasedRetainingView
22
26
from opentelemetry .exporter .otlp .proto .http .metric_exporter import OTLPMetricExporter as OTLPHttpOTLPMetricExporter
23
27
from opentelemetry .exporter .otlp .proto .http .trace_exporter import OTLPSpanExporter
28
+ from opentelemetry .metrics import set_meter_provider
24
29
from opentelemetry .sdk ._configuration import (
25
30
_get_exporter_names ,
26
31
_get_id_generator ,
29
34
_import_id_generator ,
30
35
_import_sampler ,
31
36
_init_logging ,
32
- _init_metrics ,
33
37
_OTelSDKConfigurator ,
34
38
)
35
39
from opentelemetry .sdk .environment_variables import (
50
54
ObservableUpDownCounter ,
51
55
UpDownCounter ,
52
56
)
53
- from opentelemetry .sdk .metrics .export import AggregationTemporality , PeriodicExportingMetricReader
57
+ from opentelemetry .sdk .metrics .export import (
58
+ AggregationTemporality ,
59
+ MetricExporter ,
60
+ MetricReader ,
61
+ PeriodicExportingMetricReader ,
62
+ )
63
+ from opentelemetry .sdk .metrics .view import LastValueAggregation , View
54
64
from opentelemetry .sdk .resources import Resource , get_aggregated_resources
55
65
from opentelemetry .sdk .trace import TracerProvider
56
66
from opentelemetry .sdk .trace .export import BatchSpanProcessor , SpanExporter
59
69
from opentelemetry .semconv .resource import ResourceAttributes
60
70
from opentelemetry .trace import set_tracer_provider
61
71
62
- APP_SIGNALS_ENABLED_CONFIG = "OTEL_AWS_APP_SIGNALS_ENABLED"
72
+ DEPRECATED_APP_SIGNALS_ENABLED_CONFIG = "OTEL_AWS_APP_SIGNALS_ENABLED"
63
73
APPLICATION_SIGNALS_ENABLED_CONFIG = "OTEL_AWS_APPLICATION_SIGNALS_ENABLED"
64
- APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG = "OTEL_AWS_APP_SIGNALS_EXPORTER_ENDPOINT"
74
+ APPLICATION_SIGNALS_RUNTIME_ENABLED_CONFIG = "OTEL_AWS_APPLICATION_SIGNALS_RUNTIME_ENABLED"
75
+ DEPRECATED_APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG = "OTEL_AWS_APP_SIGNALS_EXPORTER_ENDPOINT"
65
76
APPLICATION_SIGNALS_EXPORTER_ENDPOINT_CONFIG = "OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT"
66
77
METRIC_EXPORT_INTERVAL_CONFIG = "OTEL_METRIC_EXPORT_INTERVAL"
67
78
DEFAULT_METRIC_EXPORT_INTERVAL = 60000.0
68
79
AWS_LAMBDA_FUNCTION_NAME_CONFIG = "AWS_LAMBDA_FUNCTION_NAME"
69
80
AWS_XRAY_DAEMON_ADDRESS_CONFIG = "AWS_XRAY_DAEMON_ADDRESS"
70
81
OTEL_AWS_PYTHON_DEFER_TO_WORKERS_ENABLED_CONFIG = "OTEL_AWS_PYTHON_DEFER_TO_WORKERS_ENABLED"
82
+ SYSTEM_METRICS_INSTRUMENTATION_SCOPE_NAME = "opentelemetry.instrumentation.system_metrics"
71
83
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"
72
84
# UDP package size is not larger than 64KB
73
85
LAMBDA_SPAN_EXPORT_BATCH_SIZE = 10
@@ -127,7 +139,7 @@ def _initialize_components():
127
139
else []
128
140
)
129
141
130
- resource = get_aggregated_resources (resource_detectors ).merge (Resource .create (auto_resource ))
142
+ resource = _customize_resource ( get_aggregated_resources (resource_detectors ).merge (Resource .create (auto_resource ) ))
131
143
132
144
sampler_name = _get_sampler ()
133
145
sampler = _custom_import_sampler (sampler_name , resource )
@@ -171,6 +183,27 @@ def _init_tracing(
171
183
set_tracer_provider (trace_provider )
172
184
173
185
186
+ def _init_metrics (
187
+ exporters_or_readers : Dict [str , Union [Type [MetricExporter ], Type [MetricReader ]]],
188
+ resource : Resource = None ,
189
+ ):
190
+ metric_readers = []
191
+ views = []
192
+
193
+ for _ , exporter_or_reader_class in exporters_or_readers .items ():
194
+ exporter_args = {}
195
+
196
+ if issubclass (exporter_or_reader_class , MetricReader ):
197
+ metric_readers .append (exporter_or_reader_class (** exporter_args ))
198
+ else :
199
+ metric_readers .append (PeriodicExportingMetricReader (exporter_or_reader_class (** exporter_args )))
200
+
201
+ _customize_metric_exporters (metric_readers , views )
202
+
203
+ provider = MeterProvider (resource = resource , metric_readers = metric_readers , views = views )
204
+ set_meter_provider (provider )
205
+
206
+
174
207
# END The OpenTelemetry Authors code
175
208
176
209
@@ -303,14 +336,9 @@ def _customize_span_processors(provider: TracerProvider, resource: Resource) ->
303
336
# Construct meterProvider
304
337
_logger .info ("AWS Application Signals enabled" )
305
338
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 )
339
+
312
340
periodic_exporting_metric_reader = PeriodicExportingMetricReader (
313
- exporter = otel_metric_exporter , export_interval_millis = export_interval_millis
341
+ exporter = otel_metric_exporter , export_interval_millis = _get_metric_export_interval ()
314
342
)
315
343
meter_provider : MeterProvider = MeterProvider (resource = resource , metric_readers = [periodic_exporting_metric_reader ])
316
344
# Construct and set application signals metrics processor
@@ -319,25 +347,106 @@ def _customize_span_processors(provider: TracerProvider, resource: Resource) ->
319
347
return
320
348
321
349
350
+ def _customize_metric_exporters (metric_readers : List [MetricReader ], views : List [View ]) -> None :
351
+ if _is_application_signals_runtime_enabled ():
352
+ _get_runtime_metric_views (views , 0 == len (metric_readers ))
353
+
354
+ application_signals_metric_exporter = ApplicationSignalsExporterProvider ().create_exporter ()
355
+ scope_based_periodic_exporting_metric_reader = ScopeBasedPeriodicExportingMetricReader (
356
+ exporter = application_signals_metric_exporter ,
357
+ export_interval_millis = _get_metric_export_interval (),
358
+ registered_scope_names = {SYSTEM_METRICS_INSTRUMENTATION_SCOPE_NAME },
359
+ )
360
+ metric_readers .append (scope_based_periodic_exporting_metric_reader )
361
+
362
+
363
+ def _get_runtime_metric_views (views : List [View ], retain_runtime_only : bool ) -> None :
364
+ runtime_metrics_scope_name = SYSTEM_METRICS_INSTRUMENTATION_SCOPE_NAME
365
+ _logger .info ("Registered scope %s" , runtime_metrics_scope_name )
366
+ views .append (
367
+ View (
368
+ instrument_name = "system.network.connections" ,
369
+ meter_name = runtime_metrics_scope_name ,
370
+ aggregation = LastValueAggregation (),
371
+ )
372
+ )
373
+ views .append (
374
+ View (
375
+ instrument_name = "process.open_file_descriptor.count" ,
376
+ meter_name = runtime_metrics_scope_name ,
377
+ aggregation = LastValueAggregation (),
378
+ )
379
+ )
380
+ views .append (
381
+ View (
382
+ instrument_name = "process.runtime.*.memory" ,
383
+ meter_name = runtime_metrics_scope_name ,
384
+ aggregation = LastValueAggregation (),
385
+ )
386
+ )
387
+ views .append (
388
+ View (
389
+ instrument_name = "process.runtime.*.gc_count" ,
390
+ meter_name = runtime_metrics_scope_name ,
391
+ aggregation = LastValueAggregation (),
392
+ )
393
+ )
394
+ views .append (
395
+ View (
396
+ instrument_name = "process.runtime.*.thread_count" ,
397
+ meter_name = runtime_metrics_scope_name ,
398
+ aggregation = LastValueAggregation (),
399
+ )
400
+ )
401
+ if retain_runtime_only :
402
+ views .append (ScopeBasedRetainingView (meter_name = runtime_metrics_scope_name ))
403
+
404
+
322
405
def _customize_versions (auto_resource : Dict [str , any ]) -> Dict [str , any ]:
323
406
distro_version = version ("aws-opentelemetry-distro" )
324
407
auto_resource [ResourceAttributes .TELEMETRY_AUTO_VERSION ] = distro_version + "-aws"
325
408
_logger .debug ("aws-opentelementry-distro - version: %s" , auto_resource [ResourceAttributes .TELEMETRY_AUTO_VERSION ])
326
409
return auto_resource
327
410
328
411
412
+ def _customize_resource (resource : Resource ) -> Resource :
413
+ service_name , is_unknown = get_service_attribute (resource )
414
+ if is_unknown :
415
+ _logger .debug ("No valid service name found" )
416
+
417
+ return resource .merge (Resource .create ({AWS_LOCAL_SERVICE : service_name }))
418
+
419
+
329
420
def _is_application_signals_enabled ():
330
421
return (
331
- os .environ .get (APPLICATION_SIGNALS_ENABLED_CONFIG , os .environ .get (APP_SIGNALS_ENABLED_CONFIG , "false" )).lower ()
422
+ os .environ .get (
423
+ APPLICATION_SIGNALS_ENABLED_CONFIG , os .environ .get (DEPRECATED_APP_SIGNALS_ENABLED_CONFIG , "false" )
424
+ ).lower ()
332
425
== "true"
333
426
)
334
427
335
428
429
+ def _is_application_signals_runtime_enabled ():
430
+ return _is_application_signals_enabled () and (
431
+ os .environ .get (APPLICATION_SIGNALS_RUNTIME_ENABLED_CONFIG , "true" ).lower () == "true"
432
+ )
433
+
434
+
336
435
def _is_lambda_environment ():
337
436
# detect if running in AWS Lambda environment
338
437
return AWS_LAMBDA_FUNCTION_NAME_CONFIG in os .environ
339
438
340
439
440
+ def _get_metric_export_interval ():
441
+ export_interval_millis = float (os .environ .get (METRIC_EXPORT_INTERVAL_CONFIG , DEFAULT_METRIC_EXPORT_INTERVAL ))
442
+ _logger .debug ("Span Metrics export interval: %s" , export_interval_millis )
443
+ # Cap export interval to 60 seconds. This is currently required for metrics-trace correlation to work correctly.
444
+ if export_interval_millis > DEFAULT_METRIC_EXPORT_INTERVAL :
445
+ export_interval_millis = DEFAULT_METRIC_EXPORT_INTERVAL
446
+ _logger .info ("AWS Application Signals metrics export interval capped to %s" , export_interval_millis )
447
+ return export_interval_millis
448
+
449
+
341
450
def _span_export_batch_size ():
342
451
return LAMBDA_SPAN_EXPORT_BATCH_SIZE if _is_lambda_environment () else None
343
452
@@ -372,7 +481,7 @@ def create_exporter(self):
372
481
if protocol == "http/protobuf" :
373
482
application_signals_endpoint = os .environ .get (
374
483
APPLICATION_SIGNALS_EXPORTER_ENDPOINT_CONFIG ,
375
- os .environ .get (APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG , "http://localhost:4316/v1/metrics" ),
484
+ os .environ .get (DEPRECATED_APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG , "http://localhost:4316/v1/metrics" ),
376
485
)
377
486
_logger .debug ("AWS Application Signals export endpoint: %s" , application_signals_endpoint )
378
487
return OTLPHttpOTLPMetricExporter (
@@ -388,7 +497,7 @@ def create_exporter(self):
388
497
389
498
application_signals_endpoint = os .environ .get (
390
499
APPLICATION_SIGNALS_EXPORTER_ENDPOINT_CONFIG ,
391
- os .environ .get (APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG , "localhost:4315" ),
500
+ os .environ .get (DEPRECATED_APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG , "localhost:4315" ),
392
501
)
393
502
_logger .debug ("AWS Application Signals export endpoint: %s" , application_signals_endpoint )
394
503
return OTLPGrpcOTLPMetricExporter (
0 commit comments