Skip to content

Commit 0954ba4

Browse files
authored
Merge pull request #262 from jeremydvoss/env-var
Enable env var configuration, defaulting, validation
2 parents fd58832 + e9965dc commit 0954ba4

File tree

8 files changed

+333
-77
lines changed

8 files changed

+333
-77
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@
6868
([#247](https://github.com/microsoft/ApplicationInsights-Python/pull/247))
6969
- Updating documents for new namespace
7070
([#249](https://github.com/microsoft/ApplicationInsights-Python/pull/249))
71+
- Configuration via env vars and argument validation.
72+
([#262](https://github.com/microsoft/ApplicationInsights-Python/pull/262))
7173

7274
## [1.0.0b8](https://github.com/microsoft/ApplicationInsights-Python/releases/tag/v1.0.0b8) - 2022-09-26
7375

azure-monitor-opentelemetry/README.md

+21-18
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ This distro automatically installs the following libraries:
1111

1212
OpenTelemetry instrumentations allow automatic collection of requests sent from underlying instrumented libraries. The following is a list of OpenTelemetry instrumentations that come bundled in with the Azure monitor distro. If you would like to add support for another OpenTelemetry instrumentation, please submit a feature [request][distro_feature_request]. In the meantime, you can use the OpenTelemetry instrumentation manually via it's own APIs (i.e. `instrument()`) in your code. See [this][samples_manual] for an example.
1313

14-
| Instrumentation | Supported library | Supported versions |
14+
| Instrumentation | Supported library | Supported versions |
1515
| ------------------------------------- | ----------------- | ------------------ |
1616
| [OpenTelemetry Django Instrumentation][ot_instrumentation_django] | [django][pypi_django] | [link][ot_instrumentation_django_version]
1717
| [OpenTelemetry FastApi Instrumentation][ot_instrumentation_fastapi] | [fastapi][pypi_fastapi] | [link][ot_instrumentation_fastapi_version]
@@ -52,14 +52,24 @@ pip install azure-monitor-opentelemetry --pre
5252

5353
You can use `configure_azure_monitor` to set up instrumentation for your app to Azure Monitor. `configure_azure_monitor` supports the following optional arguments:
5454

55-
* connection_string - The [connection string][connection_string_doc] for your Application Insights resource. The connection string will be automatically populated from the `APPLICATIONINSIGHTS_CONNECTION_STRING` environment variable if not explicitly passed in.
56-
* disable_logging - If set to `True`, disables collection and export of logging telemetry. Defaults to `False`.
57-
* disable_metrics - If set to `True`, disables collection and export of metric telemetry. Defaults to `False`.
58-
* disable_tracing - If set to `True`, disables collection and export of distributed tracing telemetry. Defaults to `False`.
59-
* exclude_instrumentations - By default, all supported [instrumentations](#officially-supported-instrumentations) are enabled to collect telemetry. Specify instrumentations you do not want to enable to collect telemetry by passing in a comma separated list of instrumented library names. e.g. `["requests", "flask"]`
60-
* instrumentation_config - Specifies a dictionary of kwargs that will be applied to instrumentation configuration. You can specify which instrumentation you want to configure by name in the key field and value as a dictionary representing `kwargs` for the corresponding instrumentation.
61-
Refer to the `Supported Library` section [above](#officially-supported-instrumentations) for the list of suppoprted library names.
62-
55+
| Parameter | Description | Environment Variable |
56+
|-------------------|----------------------------------------------------|----------------------|
57+
| `connection_string` | The [connection string][connection_string_doc] for your Application Insights resource. The connection string will be automatically populated from the `APPLICATIONINSIGHTS_CONNECTION_STRING` environment variable if not explicitly passed in. | `APPLICATIONINSIGHTS_CONNECTION_STRING` |
58+
| `exclude_instrumentations` | By default, all supported [instrumentations](#officially-supported-instrumentations) are enabled to collect telemetry. Specify instrumentations you do not want to enable to collect telemetry by passing in a comma separated list of instrumented library names. e.g. `["requests", "flask"]` | |
59+
| `resource` | Specifies the OpenTelemetry [resource][opentelemetry_spec_resource] associated with your application. See [this][ot_sdk_python_resource] for default behavior. | [OTEL_SERVICE_NAME][opentelemetry_spec_service_name], [OTEL_RESOURCE_ATTRIBUTES][opentelemetry_spec_resource_attributes] |
60+
| `disable_logging` | If set to `True`, disables collection and export of logging telemetry. Defaults to `False`. | |
61+
| `disable_metrics` | If set to `True`, disables collection and export of metric telemetry. Defaults to `False`. | |
62+
| `disable_tracing` | If set to `True`, disables collection and export of distributed tracing telemetry. Defaults to `False`. | |
63+
| `logging_level` | Specifies the [logging level][logging_level] of the logs you would like to collect for your logging pipeline. Defaults to 0 which is `logging.NOTSET`. | |
64+
| `logger_name` | Specifies the [logger name][logger_name_hierarchy_doc] under which logging will be instrumented. Defaults to "" which corresponds to the root logger. | |
65+
| `logging_export_interval_ms`| Specifies the logging export interval in milliseconds. Defaults to 5000. | `OTEL_BLRP_SCHEDULE_DELAY` |
66+
| `metric_readers` | Specifies the [metric readers][ot_metric_reader] that you would like to use for your metric pipeline. Accepts a list of [metric readers][ot_sdk_python_metric_reader]. | |
67+
| `views` | Specifies the list of [views][opentelemetry_spec_view] to configure for the metric pipeline. See [here][ot_sdk_python_view_examples] for example usage. | |
68+
| `sampling_ratio` | Specifies the ratio of distributed tracing telemetry to be [sampled][application_insights_sampling]. Accepted values are in the range [0,1]. Defaults to 1.0, meaning no telemetry is sampled out. | `OTEL_TRACES_SAMPLER_ARG` |
69+
| `tracing_export_interval_ms`| Specifies the distributed tracing export interval in milliseconds. Defaults to 5000. | `OTEL_BSP_SCHEDULE_DELAY` |
70+
| `instrumentation_config` | Specifies a dictionary of kwargs that will be applied to instrumentation configuration. You can specify which instrumentation you want to configure by name in the key field and value as a dictionary representing `kwargs` for the corresponding instrumentation. Refer to the `Supported Library` section [above](#officially-supported-instrumentations) for the list of supported library names. | |
71+
72+
Example for use of `instrumentation_config`:
6373
```python
6474
...
6575
configure_azure_monitor(
@@ -78,15 +88,6 @@ configure_azure_monitor(
7888

7989
Take a look at the specific [instrumenation][ot_instrumentations] documentation for available configurations.
8090

81-
* resource - Specified the OpenTelemetry [resource][opentelemetry_spec_resource] associated with your application. See [this][ot_sdk_python_resource] for default behavior.
82-
* logging_level - Specifies the [logging level][logging_level] of the logs you would like to collect for your logging pipeline. Defaults to logging.NOTSET.
83-
* logger_name = Specifies the [logger name][logger_name_hierarchy_doc] under which logging will be instrumented. Defaults to "" which corresponds to the root logger.
84-
* logging_export_interval_ms - Specifies the logging export interval in milliseconds. Defaults to 5000.
85-
* metric_readers - Specifies the [metric readers][ot_metric_reader] that you would like to use for your metric pipeline. Accepts a list of [metric readers][ot_sdk_python_metric_reader].
86-
* views - Specifies the list of [views][opentelemetry_spec_view] to configure for the metric pipeline. See [here][ot_sdk_python_view_examples] for example usage.
87-
* sampling_ratio - Specifies the ratio of distributed tracing telemetry to be [sampled][application_insights_sampling]. Accepted values are in the range [0,1]. Defaults to 1.0, meaning no telemetry is sampled out.
88-
* tracing_export_interval_ms - Specifies the distributed tracing export interval in milliseconds. Defaults to 5000.
89-
9091
#### Azure monitor OpenTelemetry Exporter configurations
9192

9293
You can pass Azure monitor OpenTelemetry exporter configuration parameters directly into `configure_azure_monitor`. See additional [configuration related to exporting here][exporter_configuration_docs].
@@ -143,6 +144,8 @@ Samples are available [here][samples] to demonstrate how to utilize the above co
143144
[ot_instrumentation_urllib3]: https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation/opentelemetry-instrumentation-urllib3
144145
[ot_instrumentation_urllib3_version]: https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/package.py#L16
145146
[opentelemetry_spec_resource]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/sdk.md#resource-sdk
147+
[opentelemetry_spec_resource_attributes]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/sdk.md#specifying-resource-information-via-an-environment-variable
148+
[opentelemetry_spec_service_name]: https://github.com/open-telemetry/opentelemetry-specification/tree/main/specification/resource/semantic_conventions#semantic-attributes-with-sdk-provided-default-value
146149
[opentelemetry_spec_view]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#view
147150
[pip]: https://pypi.org/project/pip/
148151
[pypi_django]: https://pypi.org/project/Django/

azure-monitor-opentelemetry/azure/monitor/opentelemetry/_configure.py

+30-21
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,24 @@
33
# Licensed under the MIT License. See License in the project root for
44
# license information.
55
# --------------------------------------------------------------------------
6-
from logging import NOTSET, getLogger
6+
from logging import getLogger
77
from typing import Any, Dict
88

9+
from azure.monitor.opentelemetry._constants import (
10+
DISABLE_LOGGING_ARG,
11+
DISABLE_METRICS_ARG,
12+
DISABLE_TRACING_ARG,
13+
EXCLUDE_INSTRUMENTATIONS_ARG,
14+
INSTRUMENTATION_CONFIG_ARG,
15+
LOGGER_NAME_ARG,
16+
LOGGING_EXPORT_INTERVAL_MS_ARG,
17+
LOGGING_LEVEL_ARG,
18+
METRIC_READERS_ARG,
19+
RESOURCE_ARG,
20+
SAMPLING_RATIO_ARG,
21+
TRACING_EXPORT_INTERVAL_MS_ARG,
22+
VIEWS_ARG,
23+
)
924
from azure.monitor.opentelemetry._types import ConfigurationValue
1025
from azure.monitor.opentelemetry.exporter import (
1126
ApplicationInsightsSampler,
@@ -53,7 +68,7 @@ def configure_azure_monitor(**kwargs) -> None:
5368
end user to configure OpenTelemetry and Azure monitor components. The
5469
configuration can be done via arguments passed to this function.
5570
:keyword str connection_string: Connection string for your Application Insights resource.
56-
:keyword Sequence[str] connection_string: Specifies the libraries with instrumentations to be enabled.
71+
:keyword Sequence[str] exclude_instrumentations: Specifies instrumentations you want to disable.
5772
:keyword Resource resource: Specified the OpenTelemetry [resource][opentelemetry_spec_resource] associated with your application.
5873
:keyword bool disable_logging: If set to `True`, disables collection and export of logging telemetry. Defaults to `False`.
5974
:keyword bool disable_metrics: If set to `True`, disables collection and export of metric telemetry. Defaults to `False`.
@@ -75,9 +90,9 @@ def configure_azure_monitor(**kwargs) -> None:
7590

7691
configurations = _get_configurations(**kwargs)
7792

78-
disable_tracing = configurations.get("disable_tracing", False)
79-
disable_logging = configurations.get("disable_logging", False)
80-
disable_metrics = configurations.get("disable_metrics", False)
93+
disable_tracing = configurations[DISABLE_TRACING_ARG]
94+
disable_logging = configurations[DISABLE_LOGGING_ARG]
95+
disable_metrics = configurations[DISABLE_METRICS_ARG]
8196

8297
resource = None
8398
if not disable_logging or not disable_tracing or not disable_metrics:
@@ -102,16 +117,14 @@ def configure_azure_monitor(**kwargs) -> None:
102117

103118

104119
def _get_resource(configurations: Dict[str, ConfigurationValue]) -> Resource:
105-
return configurations.get("resource", Resource.create())
120+
return configurations.get(RESOURCE_ARG, Resource.create())
106121

107122

108123
def _setup_tracing(
109124
resource: Resource, configurations: Dict[str, ConfigurationValue]
110125
):
111-
sampling_ratio = configurations.get("sampling_ratio", 1.0)
112-
tracing_export_interval_ms = configurations.get(
113-
"tracing_export_interval_ms", 5000
114-
)
126+
sampling_ratio = configurations[SAMPLING_RATIO_ARG]
127+
tracing_export_interval_ms = configurations[TRACING_EXPORT_INTERVAL_MS_ARG]
115128
tracer_provider = TracerProvider(
116129
sampler=ApplicationInsightsSampler(sampling_ratio=sampling_ratio),
117130
resource=resource,
@@ -128,11 +141,9 @@ def _setup_tracing(
128141
def _setup_logging(
129142
resource: Resource, configurations: Dict[str, ConfigurationValue]
130143
):
131-
logger_name = configurations.get("logger_name", "")
132-
logging_level = configurations.get("logging_level", NOTSET)
133-
logging_export_interval_ms = configurations.get(
134-
"logging_export_interval_ms", 5000
135-
)
144+
logger_name = configurations[LOGGER_NAME_ARG]
145+
logging_level = configurations[LOGGING_LEVEL_ARG]
146+
logging_export_interval_ms = configurations[LOGGING_EXPORT_INTERVAL_MS_ARG]
136147
logger_provider = LoggerProvider(resource=resource)
137148
set_logger_provider(logger_provider)
138149
log_exporter = AzureMonitorLogExporter(**configurations)
@@ -150,8 +161,8 @@ def _setup_logging(
150161
def _setup_metrics(
151162
resource: Resource, configurations: Dict[str, ConfigurationValue]
152163
):
153-
views = configurations.get("views", ())
154-
metric_readers = configurations.get("metric_readers", [])
164+
views = configurations[VIEWS_ARG]
165+
metric_readers = configurations[METRIC_READERS_ARG]
155166
metric_exporter = AzureMonitorMetricExporter(**configurations)
156167
reader = PeriodicExportingMetricReader(metric_exporter)
157168
meter_provider = MeterProvider(
@@ -163,10 +174,8 @@ def _setup_metrics(
163174

164175

165176
def _setup_instrumentations(configurations: Dict[str, ConfigurationValue]):
166-
exclude_instrumentations = configurations.get(
167-
"exclude_instrumentations", []
168-
)
169-
instrumentation_configs = configurations.get("instrumentation_config", {})
177+
exclude_instrumentations = configurations[EXCLUDE_INSTRUMENTATIONS_ARG]
178+
instrumentation_configs = configurations[INSTRUMENTATION_CONFIG_ARG]
170179

171180
# use pkg_resources for now until https://github.com/open-telemetry/opentelemetry-python/pull/3168 is merged
172181
for entry_point in iter_entry_points("opentelemetry_instrumentor"):

azure-monitor-opentelemetry/azure/monitor/opentelemetry/_constants.py

+19
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,25 @@
1313
ConnectionStringParser,
1414
)
1515

16+
# --------------------Configuration------------------------------------------
17+
18+
CONNECTION_STRING_ARG = "connection_string"
19+
EXCLUDE_INSTRUMENTATIONS_ARG = "exclude_instrumentations"
20+
RESOURCE_ARG = "resource"
21+
DISABLE_LOGGING_ARG = "disable_logging"
22+
DISABLE_METRICS_ARG = "disable_metrics"
23+
DISABLE_TRACING_ARG = "disable_tracing"
24+
# TODO: Consider Log Level to match env var
25+
LOGGING_LEVEL_ARG = "logging_level"
26+
LOGGER_NAME_ARG = "logger_name"
27+
LOGGING_EXPORT_INTERVAL_MS_ARG = "logging_export_interval_ms"
28+
METRIC_READERS_ARG = "metric_readers"
29+
VIEWS_ARG = "views"
30+
SAMPLING_RATIO_ARG = "sampling_ratio"
31+
TRACING_EXPORT_INTERVAL_MS_ARG = "tracing_export_interval_ms"
32+
INSTRUMENTATION_CONFIG_ARG = "instrumentation_config"
33+
34+
1635
# --------------------Diagnostic/status logging------------------------------
1736

1837
_LOG_PATH_LINUX = "/var/log/applicationinsights"

azure-monitor-opentelemetry/azure/monitor/opentelemetry/util/configurations.py

+115-1
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,37 @@
44
# license information.
55
# --------------------------------------------------------------------------
66

7+
from logging import NOTSET, getLogger
8+
from os import environ
79
from typing import Dict
810

11+
from azure.monitor.opentelemetry._constants import (
12+
DISABLE_LOGGING_ARG,
13+
DISABLE_METRICS_ARG,
14+
DISABLE_TRACING_ARG,
15+
EXCLUDE_INSTRUMENTATIONS_ARG,
16+
INSTRUMENTATION_CONFIG_ARG,
17+
LOGGER_NAME_ARG,
18+
LOGGING_EXPORT_INTERVAL_MS_ARG,
19+
LOGGING_LEVEL_ARG,
20+
METRIC_READERS_ARG,
21+
SAMPLING_RATIO_ARG,
22+
TRACING_EXPORT_INTERVAL_MS_ARG,
23+
VIEWS_ARG,
24+
)
925
from azure.monitor.opentelemetry._types import ConfigurationValue
26+
from opentelemetry.sdk.environment_variables import OTEL_TRACES_SAMPLER_ARG
27+
28+
_INVALID_FLOAT_MESSAGE = "Value of %s must be a float. Defaulting to %s: %s"
29+
30+
31+
# Speced out but unused by OTel SDK as of 1.15.0
32+
LOGGING_EXPORT_INTERVAL_MS_ENV_VAR = "OTEL_BLRP_SCHEDULE_DELAY"
33+
# TODO: remove when sampler uses env var instead
34+
SAMPLING_RATIO_ENV_VAR = OTEL_TRACES_SAMPLER_ARG
35+
36+
37+
_logger = getLogger(__name__)
1038

1139

1240
def _get_configurations(**kwargs) -> Dict[str, ConfigurationValue]:
@@ -15,7 +43,93 @@ def _get_configurations(**kwargs) -> Dict[str, ConfigurationValue]:
1543
for key, val in kwargs.items():
1644
configurations[key] = val
1745

46+
_default_exclude_instrumentations(configurations)
47+
_default_disable_logging(configurations)
48+
_default_disable_metrics(configurations)
49+
_default_disable_tracing(configurations)
50+
_default_logging_level(configurations)
51+
_default_logger_name(configurations)
52+
_default_logging_export_interval_ms(configurations)
53+
_default_metric_readers(configurations)
54+
_default_views(configurations)
55+
_default_sampling_ratio(configurations)
56+
_default_tracing_export_interval_ms(configurations)
57+
_default_instrumentation_config(configurations)
58+
59+
# TODO: remove when validation added to BLRP
60+
if configurations[LOGGING_EXPORT_INTERVAL_MS_ARG] <= 0:
61+
raise ValueError(
62+
"%s must be positive." % LOGGING_EXPORT_INTERVAL_MS_ARG
63+
)
64+
1865
return configurations
1966

2067

21-
# TODO: Add env var configuration
68+
def _default_exclude_instrumentations(configurations):
69+
if EXCLUDE_INSTRUMENTATIONS_ARG not in configurations:
70+
configurations[EXCLUDE_INSTRUMENTATIONS_ARG] = []
71+
72+
73+
def _default_disable_logging(configurations):
74+
if DISABLE_LOGGING_ARG not in configurations:
75+
configurations[DISABLE_LOGGING_ARG] = False
76+
77+
78+
def _default_disable_metrics(configurations):
79+
if DISABLE_METRICS_ARG not in configurations:
80+
configurations[DISABLE_METRICS_ARG] = False
81+
82+
83+
def _default_disable_tracing(configurations):
84+
if DISABLE_TRACING_ARG not in configurations:
85+
configurations[DISABLE_TRACING_ARG] = False
86+
87+
88+
def _default_logging_level(configurations):
89+
if LOGGING_LEVEL_ARG not in configurations:
90+
configurations[LOGGING_LEVEL_ARG] = NOTSET
91+
92+
93+
def _default_logger_name(configurations):
94+
if LOGGER_NAME_ARG not in configurations:
95+
configurations[LOGGER_NAME_ARG] = ""
96+
97+
98+
def _default_logging_export_interval_ms(configurations):
99+
if LOGGING_EXPORT_INTERVAL_MS_ARG not in configurations:
100+
configurations[LOGGING_EXPORT_INTERVAL_MS_ARG] = 5000
101+
102+
103+
def _default_metric_readers(configurations):
104+
if METRIC_READERS_ARG not in configurations:
105+
configurations[METRIC_READERS_ARG] = []
106+
107+
108+
def _default_views(configurations):
109+
if VIEWS_ARG not in configurations:
110+
configurations[VIEWS_ARG] = ()
111+
112+
113+
# TODO: remove when sampler uses env var instead
114+
def _default_sampling_ratio(configurations):
115+
if SAMPLING_RATIO_ARG not in configurations:
116+
default = 1.0
117+
if SAMPLING_RATIO_ENV_VAR in environ:
118+
try:
119+
default = float(environ[SAMPLING_RATIO_ENV_VAR])
120+
except ValueError as e:
121+
_logger.error(
122+
_INVALID_FLOAT_MESSAGE
123+
% (SAMPLING_RATIO_ENV_VAR, default, e)
124+
)
125+
configurations[SAMPLING_RATIO_ARG] = default
126+
127+
128+
def _default_tracing_export_interval_ms(configurations):
129+
if TRACING_EXPORT_INTERVAL_MS_ARG not in configurations:
130+
configurations[TRACING_EXPORT_INTERVAL_MS_ARG] = None
131+
132+
133+
def _default_instrumentation_config(configurations):
134+
if INSTRUMENTATION_CONFIG_ARG not in configurations:
135+
configurations[INSTRUMENTATION_CONFIG_ARG] = {}

azure-monitor-opentelemetry/samples/metrics/views.py

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
# Create a view matching the counter instrument `my.counter`
99
# and configure the new name `my.counter.total` for the result metrics stream
1010
change_metric_name_view = View(
11-
connection_string="<your-connection-string>",
1211
instrument_type=Counter,
1312
instrument_name="my.counter",
1413
name="my.counter.total",

0 commit comments

Comments
 (0)