forked from microsoft/ApplicationInsights-Python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path_configure.py
172 lines (151 loc) · 6.88 KB
/
_configure.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for
# license information.
# --------------------------------------------------------------------------
from logging import getLogger
from typing import Dict
from azure.core.settings import settings
from azure.core.tracing.ext.opentelemetry_span import OpenTelemetrySpan
from azure.monitor.opentelemetry._constants import (
DISABLE_AZURE_CORE_TRACING_ARG,
DISABLE_LOGGING_ARG,
DISABLE_METRICS_ARG,
DISABLE_TRACING_ARG,
DISABLED_INSTRUMENTATIONS_ARG,
SAMPLING_RATIO_ARG,
)
from azure.monitor.opentelemetry._types import ConfigurationValue
from azure.monitor.opentelemetry._vendor.v0_39b0.opentelemetry.instrumentation.dependencies import (
get_dependency_conflicts,
)
from azure.monitor.opentelemetry._vendor.v0_39b0.opentelemetry.instrumentation.instrumentor import (
BaseInstrumentor,
)
from azure.monitor.opentelemetry.exporter import (
ApplicationInsightsSampler,
AzureMonitorLogExporter,
AzureMonitorMetricExporter,
AzureMonitorTraceExporter,
)
from azure.monitor.opentelemetry.util.configurations import _get_configurations
from opentelemetry._logs import get_logger_provider, set_logger_provider
from opentelemetry.metrics import set_meter_provider
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.trace import get_tracer_provider, set_tracer_provider
from pkg_resources import iter_entry_points
_logger = getLogger(__name__)
_SUPPORTED_INSTRUMENTED_LIBRARIES_DEPENDENCIES_MAP = {
"django": ("django >= 1.10",),
"fastapi": ("fastapi ~= 0.58",),
"flask": ("flask >= 1.0, < 3.0",),
"psycopg2": ("psycopg2 >= 2.7.3.1",),
"requests": ("requests ~= 2.0",),
"urllib": tuple(),
"urllib3": ("urllib3 >= 1.0.0, < 2.0.0",),
}
def configure_azure_monitor(**kwargs) -> None:
"""
This function works as a configuration layer that allows the
end user to configure OpenTelemetry and Azure monitor components. The
configuration can be done via arguments passed to this function.
:keyword str connection_string: Connection string for your Application Insights resource.
:keyword ManagedIdentityCredential/ClientSecretCredential credential: Token credential, such as
ManagedIdentityCredential or ClientSecretCredential, used for Azure Active Directory (AAD) authentication. Defaults
to None.
:keyword bool disable_offline_storage: Boolean value to determine whether to disable storing failed telemetry
records for retry. Defaults to `False`.
:keyword str storage_directory: Storage directory in which to store retry files. Defaults to
`<tempfile.gettempdir()>/Microsoft/AzureMonitor/opentelemetry-python-<your-instrumentation-key>`.
:rtype: None
"""
configurations = _get_configurations(**kwargs)
disable_tracing = configurations[DISABLE_TRACING_ARG]
disable_logging = configurations[DISABLE_LOGGING_ARG]
disable_metrics = configurations[DISABLE_METRICS_ARG]
# Setup tracing pipeline
if not disable_tracing:
_setup_tracing(configurations)
# Setup logging pipeline
if not disable_logging:
_setup_logging(configurations)
# Setup metrics pipeline
if not disable_metrics:
_setup_metrics(configurations)
# Setup instrumentations
# Instrumentations need to be setup last so to use the global providers
# instanstiated in the other setup steps
_setup_instrumentations(configurations)
def _setup_tracing(configurations: Dict[str, ConfigurationValue]):
sampling_ratio = configurations[SAMPLING_RATIO_ARG]
tracer_provider = TracerProvider(
sampler=ApplicationInsightsSampler(sampling_ratio=sampling_ratio),
)
set_tracer_provider(tracer_provider)
trace_exporter = AzureMonitorTraceExporter(**configurations)
span_processor = BatchSpanProcessor(
trace_exporter,
)
get_tracer_provider().add_span_processor(span_processor)
disable_azure_core_tracing = configurations[DISABLE_AZURE_CORE_TRACING_ARG]
if not disable_azure_core_tracing:
settings.tracing_implementation = OpenTelemetrySpan
def _setup_logging(configurations: Dict[str, ConfigurationValue]):
logger_provider = LoggerProvider()
set_logger_provider(logger_provider)
log_exporter = AzureMonitorLogExporter(**configurations)
log_record_processor = BatchLogRecordProcessor(
log_exporter,
)
get_logger_provider().add_log_record_processor(log_record_processor)
handler = LoggingHandler(logger_provider=get_logger_provider())
getLogger().addHandler(handler)
def _setup_metrics(configurations: Dict[str, ConfigurationValue]):
metric_exporter = AzureMonitorMetricExporter(**configurations)
reader = PeriodicExportingMetricReader(metric_exporter)
meter_provider = MeterProvider(
metric_readers=[reader],
)
set_meter_provider(meter_provider)
def _setup_instrumentations(configurations: Dict[str, ConfigurationValue]):
disabled_instrumentations = configurations[DISABLED_INSTRUMENTATIONS_ARG]
# use pkg_resources for now until https://github.com/open-telemetry/opentelemetry-python/pull/3168 is merged
for entry_point in iter_entry_points(
"azure_monitor_opentelemetry_instrumentor"
):
lib_name = entry_point.name
if lib_name not in _SUPPORTED_INSTRUMENTED_LIBRARIES_DEPENDENCIES_MAP:
continue
if entry_point.name in disabled_instrumentations:
_logger.debug(
"Instrumentation skipped for library %s", entry_point.name
)
continue
try:
# Check if dependent libraries/version are installed
instruments = _SUPPORTED_INSTRUMENTED_LIBRARIES_DEPENDENCIES_MAP[
lib_name
]
conflict = get_dependency_conflicts(instruments)
if conflict:
_logger.debug(
"Skipping instrumentation %s: %s",
entry_point.name,
conflict,
)
continue
# Load the instrumentor via entrypoint
instrumentor: BaseInstrumentor = entry_point.load()
# tell instrumentation to not run dep checks again as we already did it above
instrumentor().instrument(skip_dep_check=True)
except Exception as ex: # pylint: disable=broad-except
_logger.warning(
"Exception occurred when instrumenting: %s.",
lib_name,
exc_info=ex,
)