Merge branch 'main' into exec-publish

This commit is contained in:
Jeremy Voss 2023-01-25 14:02:57 -08:00 коммит произвёл GitHub
Родитель d796347e79 578dfdb952
Коммит 1a2beedcbf
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
23 изменённых файлов: 775 добавлений и 409 удалений

Просмотреть файл

@ -21,6 +21,7 @@ exclude =
CVS
.venv*/
venv*/
*/samples/*
target
__pycache__
*/build/lib/*

Просмотреть файл

@ -20,6 +20,8 @@
([#217](https://github.com/microsoft/ApplicationInsights-Python/pull/217))
- Add Logging configuration to Distro API
([#218](https://github.com/microsoft/ApplicationInsights-Python/pull/218))
- Add instrumentation selection config
([#228](https://github.com/microsoft/ApplicationInsights-Python/pull/228))
## [1.0.0b8](https://github.com/microsoft/ApplicationInsights-Python/releases/tag/v1.0.0b8) - 2022-09-26

Просмотреть файл

@ -33,7 +33,8 @@ pip install azure-monitor-opentelemetry-distro --pre
You can use `configure_azure_monitor` to set up instrumentation for your app to Azure Monitor. `configure_azure_monitor` supports the following optional arguments:
* 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.
* service_name = Specifies the [service][service_semantic_convention_doc] name.
* instrumentations = Specifies the libraries with [instrumentations][ot_instrumentations] that you would like to use. Accepts a comma separated list. e.g. `["requests", "flask"]`
* service_name = Specifies the [service][service_semantic_convention_doc] name.
* service_namespace = Specifies the [service][service_semantic_convention_doc] namespace.
* service_instance_id = Specifies the [service][service_semantic_convention_doc] instance id.
* disable_logging = If set to `True`, disables collection and export of logging telemetry.
@ -66,6 +67,7 @@ To use this package, you must have:
[connection_string_doc]: https://learn.microsoft.com/en-us/azure/azure-monitor/app/sdk-connection-string
[exporter_configuration_docs]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/monitor/azure-monitor-opentelemetry-exporter#configuration
[logging_level]: https://docs.python.org/3/library/logging.html#levels
[ot_instrumentations]: https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation
[ot_python_docs]: https://opentelemetry.io/docs/instrumentation/python/
[ot_sdk_python]: https://github.com/open-telemetry/opentelemetry-python
[opentelemetry_instrumentation_requests]: https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation/opentelemetry-instrumentation-requests

Просмотреть файл

@ -3,7 +3,9 @@
# Licensed under the MIT License. See License in the project root for
# license information.
# --------------------------------------------------------------------------
import importlib
from logging import NOTSET, getLogger
from typing import Any, Dict
from azure.monitor.opentelemetry.distro.util import get_configurations
from azure.monitor.opentelemetry.exporter import (
@ -24,6 +26,16 @@ from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.semconv.resource import ResourceAttributes
from opentelemetry.trace import get_tracer_provider, set_tracer_provider
_logger = getLogger(__name__)
_SUPPORTED_INSTRUMENTED_LIBRARIES = {
"django",
"flask",
"psycopg2",
"requests",
}
def configure_azure_monitor(**kwargs):
"""
@ -33,51 +45,110 @@ def configure_azure_monitor(**kwargs):
"""
configurations = get_configurations(**kwargs)
disable_tracing = configurations.get("disable_tracing", False)
disable_logging = configurations.get("disable_logging", False)
resource = None
if not disable_logging or not disable_tracing:
resource = _get_resource(configurations)
# Setup tracing pipeline
if not disable_tracing:
_setup_tracing(resource, configurations)
# Setup logging pipeline
if not disable_logging:
_setup_logging(resource, 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 _get_resource(configurations: Dict[str, Any]) -> Resource:
service_name = configurations.get("service_name", "")
service_namespace = configurations.get("service_namespace", "")
service_instance_id = configurations.get("service_instance_id", "")
disable_logging = configurations.get("disable_logging", False)
logging_level = configurations.get("logging_level", NOTSET)
logging_export_interval_millis = configurations.get(
"logging_export_interval_millis", 30000
return Resource.create(
{
ResourceAttributes.SERVICE_NAME: service_name,
ResourceAttributes.SERVICE_NAMESPACE: service_namespace,
ResourceAttributes.SERVICE_INSTANCE_ID: service_instance_id,
}
)
disable_tracing = configurations.get("disable_tracing", False)
def _setup_tracing(resource: Resource, configurations: Dict[str, Any]):
sampling_ratio = configurations.get("sampling_ratio", 1.0)
tracing_export_interval_millis = configurations.get(
"tracing_export_interval_millis", 30000
)
tracer_provider = TracerProvider(
sampler=ApplicationInsightsSampler(sampling_ratio=sampling_ratio),
resource=resource,
)
set_tracer_provider(tracer_provider)
trace_exporter = AzureMonitorTraceExporter(**configurations)
span_processor = BatchSpanProcessor(
trace_exporter,
export_timeout_millis=tracing_export_interval_millis,
)
get_tracer_provider().add_span_processor(span_processor)
resource = None
if not disable_logging or not disable_tracing:
resource = Resource.create(
{
ResourceAttributes.SERVICE_NAME: service_name,
ResourceAttributes.SERVICE_NAMESPACE: service_namespace,
ResourceAttributes.SERVICE_INSTANCE_ID: service_instance_id,
}
)
if not disable_logging:
logger_provider = LoggerProvider(resource=resource)
set_logger_provider(logger_provider)
log_exporter = AzureMonitorLogExporter(**kwargs)
log_record_processor = BatchLogRecordProcessor(
log_exporter,
export_timeout_millis=logging_export_interval_millis,
)
get_logger_provider().add_log_record_processor(log_record_processor)
handler = LoggingHandler(
level=logging_level, logger_provider=get_logger_provider()
)
getLogger().addHandler(handler)
if not disable_tracing:
tracer_provider = TracerProvider(
sampler=ApplicationInsightsSampler(sampling_ratio=sampling_ratio),
resource=resource,
)
set_tracer_provider(tracer_provider)
trace_exporter = AzureMonitorTraceExporter(**kwargs)
span_processor = BatchSpanProcessor(
trace_exporter,
export_timeout_millis=tracing_export_interval_millis,
)
get_tracer_provider().add_span_processor(span_processor)
def _setup_logging(resource: Resource, configurations: Dict[str, Any]):
logging_level = configurations.get("logging_level", NOTSET)
logging_export_interval_millis = configurations.get(
"logging_export_interval_millis", 30000
)
logger_provider = LoggerProvider(resource=resource)
set_logger_provider(logger_provider)
log_exporter = AzureMonitorLogExporter(**configurations)
log_record_processor = BatchLogRecordProcessor(
log_exporter,
export_timeout_millis=logging_export_interval_millis,
)
get_logger_provider().add_log_record_processor(log_record_processor)
handler = LoggingHandler(
level=logging_level, logger_provider=get_logger_provider()
)
getLogger().addHandler(handler)
def _setup_instrumentations(configurations: Dict[str, Any]):
instrumentations = configurations.get("instrumentations", [])
for lib_name in instrumentations:
if lib_name in _SUPPORTED_INSTRUMENTED_LIBRARIES:
try:
importlib.import_module(lib_name)
except ImportError:
_logger.warning(
"Unable to import %s. Please make sure it is installed.",
lib_name,
)
continue
instr_lib_name = "opentelemetry.instrumentation." + lib_name
try:
module = importlib.import_module(instr_lib_name)
instrumentor_name = "{}Instrumentor".format(
lib_name.capitalize()
)
class_ = getattr(module, instrumentor_name)
class_().instrument()
except ImportError:
_logger.warning(
"Unable to import %s. Please make sure it is installed.",
instr_lib_name,
)
except Exception as ex:
_logger.warning(
"Exception occured when instrumenting: %s.",
lib_name,
exc_info=ex,
)
else:
_logger.warning(
"Instrumentation not supported for library: %s.", lib_name
)

Просмотреть файл

@ -1,3 +1,9 @@
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for
# license information.
# --------------------------------------------------------------------------
import logging
import platform
from os import environ
@ -7,11 +13,7 @@ from azure.monitor.opentelemetry.exporter._connection_string_parser import (
ConnectionStringParser,
)
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for
# license information.
# --------------------------------------------------------------------------
# --------------------Diagnostic/status logging------------------------------
_LOG_PATH_LINUX = "/var/log/applicationinsights"
_LOG_PATH_WINDOWS = "\\LogFiles\\ApplicationInsights"

Просмотреть файл

@ -0,0 +1,34 @@
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for
# license information.
# --------------------------------------------------------------------------
import logging
import requests
from azure.monitor.opentelemetry.distro import configure_azure_monitor
from opentelemetry import trace
logger = logging.getLogger(__name__)
# Configure Azure monitor collection telemetry pipeline
configure_azure_monitor(
connection_string="<your-connection-string>",
service_name="client_service_name",
disable_logging=True,
instrumentations=["requests"],
tracing_export_interval_millis=15000,
)
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("Request parent span") as span:
try:
# Requests made using the requests library will be automatically captured
response = requests.get("https://azure.microsoft.com/", timeout=5)
logger.warning("Request sent")
except Exception as ex:
# If an exception occurs, this can be manually recorded on the parent span
span.set_attribute("status", "exception")
span.record_exception(ex)
input()

Просмотреть файл

@ -0,0 +1,22 @@
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for
# license information.
# --------------------------------------------------------------------------
import psycopg2
from azure.monitor.opentelemetry.distro import configure_azure_monitor
# Configure Azure monitor collection telemetry pipeline
configure_azure_monitor(
connection_string="<your-connection-string>",
service_name="psycopg2_service_name",
disable_logging=True,
instrumentations=["psycopg2"],
tracing_export_interval_millis=15000,
)
cnx = psycopg2.connect(database="test", user="<user>", password="<password>")
cursor = cnx.cursor()
cursor.execute("INSERT INTO test_tables (test_field) VALUES (123)")
cursor.close()
cnx.close()

Просмотреть файл

@ -0,0 +1,2 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

Просмотреть файл

@ -0,0 +1,5 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
from django.contrib import admin
# Register your models here.

Просмотреть файл

@ -0,0 +1,8 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
from django.apps import AppConfig
class ExampleConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "example"

Просмотреть файл

@ -0,0 +1,2 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

Просмотреть файл

@ -0,0 +1,5 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
from django.db import models
# Create your models here.

Просмотреть файл

@ -0,0 +1,5 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
from django.test import TestCase
# Create your tests here.

Просмотреть файл

@ -0,0 +1,10 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
path("exception", views.exception, name="exception"),
]

Просмотреть файл

@ -0,0 +1,26 @@
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for
# license information.
# --------------------------------------------------------------------------
from azure.monitor.opentelemetry.distro import configure_azure_monitor
from django.http import HttpResponse
# Configure Azure monitor collection telemetry pipeline
configure_azure_monitor(
# connection_string="<your-connection-string>",
service_name="django_service_name",
instrumentations=["django"],
disable_logging=True,
tracing_export_interval_millis=15000,
)
# Requests sent to the django application will be automatically captured
def index(request):
return HttpResponse("Hello, world.")
# Exceptions that are raised within the request are automatically captured
def exception(request):
raise Exception("Exception was raised.")

Просмотреть файл

@ -0,0 +1,25 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sample.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == "__main__":
main()

Просмотреть файл

@ -0,0 +1,2 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

Просмотреть файл

@ -0,0 +1,21 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
# cSpell:disable
"""
ASGI config for sample project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sample.settings")
application = get_asgi_application()
# cSpell:enable

Просмотреть файл

@ -0,0 +1,133 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
"""
Django settings for sample project.
Generated by 'django-admin startproject' using Django 3.2.7.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/
"""
# cSpell:disable
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = (
"django-insecure--9p!az#-flphjtvtl#c_ep6x#1lo+0@nzci#-(!-3c$!o0lyjk"
)
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "sample.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "sample.wsgi.application"
# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = "/static/"
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
# cSpell:enable

Просмотреть файл

@ -0,0 +1,22 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
"""sample URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.urls import include, path
urlpatterns = [
path("", include("example.urls")),
]

Просмотреть файл

@ -0,0 +1,18 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
"""
WSGI config for sample project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sample.settings")
application = get_wsgi_application()

Просмотреть файл

@ -0,0 +1,33 @@
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for
# license information.
# --------------------------------------------------------------------------
import flask
from azure.monitor.opentelemetry.distro import configure_azure_monitor
# Configure Azure monitor collection telemetry pipeline
configure_azure_monitor(
connection_string="<your-connection-string>",
service_name="flask_service_name",
disable_logging=True,
instrumentations=["flask"],
tracing_export_interval_millis=15000,
)
app = flask.Flask(__name__)
# Requests sent to the flask application will be automatically captured
@app.route("/")
def test():
return "Test flask request"
# Exceptions that are raised within the request are automatically captured
@app.route("/exception")
def exception():
raise Exception("Hit an exception")
if __name__ == "__main__":
app.run(host="localhost", port=8080)

Просмотреть файл

@ -13,321 +13,147 @@
# limitations under the License.
import unittest
from unittest.mock import Mock, patch
from unittest.mock import Mock, call, patch
from azure.monitor.opentelemetry.distro import configure_azure_monitor
from azure.monitor.opentelemetry.distro import (
_SUPPORTED_INSTRUMENTED_LIBRARIES,
_get_resource,
_setup_instrumentations,
_setup_logging,
_setup_tracing,
configure_azure_monitor,
)
from opentelemetry.semconv.resource import ResourceAttributes
class TestConfigure(unittest.TestCase):
@patch(
"azure.monitor.opentelemetry.distro.BatchSpanProcessor",
"azure.monitor.opentelemetry.distro._setup_instrumentations",
)
@patch(
"azure.monitor.opentelemetry.distro.AzureMonitorTraceExporter",
"azure.monitor.opentelemetry.distro._setup_logging",
)
@patch(
"azure.monitor.opentelemetry.distro.get_tracer_provider",
"azure.monitor.opentelemetry.distro._setup_tracing",
)
@patch(
"azure.monitor.opentelemetry.distro.set_tracer_provider",
)
@patch(
"azure.monitor.opentelemetry.distro.TracerProvider",
autospec=True,
)
@patch(
"azure.monitor.opentelemetry.distro.ApplicationInsightsSampler",
)
@patch(
"azure.monitor.opentelemetry.distro.getLogger",
)
@patch(
"azure.monitor.opentelemetry.distro.LoggingHandler",
)
@patch(
"azure.monitor.opentelemetry.distro.BatchLogRecordProcessor",
)
@patch(
"azure.monitor.opentelemetry.distro.AzureMonitorLogExporter",
)
@patch(
"azure.monitor.opentelemetry.distro.get_logger_provider",
)
@patch(
"azure.monitor.opentelemetry.distro.set_logger_provider",
)
@patch(
"azure.monitor.opentelemetry.distro.LoggerProvider",
autospec=True,
)
@patch(
"azure.monitor.opentelemetry.distro.Resource",
"azure.monitor.opentelemetry.distro._get_resource",
)
def test_configure_azure_monitor(
self,
resource_mock,
lp_mock,
set_logger_provider_mock,
get_logger_provider_mock,
log_exporter_mock,
blrp_mock,
logging_handler_mock,
get_logger_mock,
sampler_mock,
tp_mock,
set_tracer_provider_mock,
get_tracer_provider_mock,
trace_exporter_mock,
bsp_mock,
tracing_mock,
logging_mock,
instrumentation_mock,
):
kwargs = {
"connection_string": "test_cs",
"disable_logging": False,
"disable_tracing": False,
"logging_export_interval_millis": 10000,
"logging_level": "test_logging_level",
"service_name": "test_service_name",
"service_namespace": "test_namespace",
"service_instance_id": "test_id",
"sampling_ratio": 0.5,
"tracing_export_interval_millis": 15000,
}
resource_init_mock = Mock()
resource_mock.create.return_value = resource_init_mock
lp_init_mock = Mock()
lp_mock.return_value = lp_init_mock
get_logger_provider_mock.return_value = lp_init_mock
log_exp_init_mock = Mock()
log_exporter_mock.return_value = log_exp_init_mock
blrp_init_mock = Mock()
blrp_mock.return_value = blrp_init_mock
logging_handler_init_mock = Mock()
logging_handler_mock.return_value = logging_handler_init_mock
logger_mock = Mock()
get_logger_mock.return_value = logger_mock
sampler_init_mock = Mock()
sampler_mock.return_value = sampler_init_mock
tp_init_mock = Mock()
tp_mock.return_value = tp_init_mock
get_tracer_provider_mock.return_value = tp_init_mock
trace_exp_init_mock = Mock()
trace_exporter_mock.return_value = trace_exp_init_mock
bsp_init_mock = Mock()
bsp_mock.return_value = bsp_init_mock
configure_azure_monitor(
connection_string="test_cs",
console_exporting=False,
disable_logging=False,
disable_tracing=False,
logging_export_interval_millis=10000,
logging_level="test_logging_level",
service_name="test_service_name",
service_namespace="test_namespace",
service_instance_id="test_id",
sampling_ratio=0.5,
tracing_export_interval_millis=15000,
)
resource_mock.create.assert_called_once_with(
{
ResourceAttributes.SERVICE_NAME: "test_service_name",
ResourceAttributes.SERVICE_NAMESPACE: "test_namespace",
ResourceAttributes.SERVICE_INSTANCE_ID: "test_id",
}
)
lp_mock.assert_called_once_with(resource=resource_init_mock)
set_logger_provider_mock.assert_called_once_with(lp_init_mock)
get_logger_provider_mock.assert_called()
log_exporter_mock.assert_called_once()
blrp_mock.assert_called_once_with(
log_exp_init_mock, export_timeout_millis=10000
)
lp_init_mock.add_log_record_processor.assert_called_once_with(
blrp_init_mock
)
logging_handler_mock.assert_called_once_with(
level="test_logging_level", logger_provider=lp_init_mock
)
get_logger_mock.assert_called_once_with()
logger_mock.addHandler.assert_called_once_with(
logging_handler_init_mock
)
sampler_mock.assert_called_once_with(sampling_ratio=0.5)
tp_mock.assert_called_once_with(
resource=resource_init_mock,
sampler=sampler_init_mock,
)
set_tracer_provider_mock.assert_called_once_with(tp_init_mock)
get_tracer_provider_mock.assert_called()
trace_exporter_mock.assert_called_once()
bsp_mock.assert_called_once_with(
trace_exp_init_mock, export_timeout_millis=15000
)
tp_init_mock.add_span_processor(bsp_init_mock)
resource_mock.return_value = resource_init_mock
configure_azure_monitor(**kwargs)
resource_mock.assert_called_once_with(kwargs)
tracing_mock.assert_called_once_with(resource_init_mock, kwargs)
logging_mock.assert_called_once_with(resource_init_mock, kwargs)
instrumentation_mock.assert_called_once_with(kwargs)
@patch(
"azure.monitor.opentelemetry.distro.BatchSpanProcessor",
"azure.monitor.opentelemetry.distro._setup_instrumentations",
)
@patch(
"azure.monitor.opentelemetry.distro.AzureMonitorTraceExporter",
"azure.monitor.opentelemetry.distro._setup_logging",
)
@patch(
"azure.monitor.opentelemetry.distro.get_tracer_provider",
"azure.monitor.opentelemetry.distro._setup_tracing",
)
@patch(
"azure.monitor.opentelemetry.distro.set_tracer_provider",
)
@patch(
"azure.monitor.opentelemetry.distro.TracerProvider",
autospec=True,
)
@patch(
"azure.monitor.opentelemetry.distro.ApplicationInsightsSampler",
)
@patch(
"azure.monitor.opentelemetry.distro.getLogger",
)
@patch(
"azure.monitor.opentelemetry.distro.LoggingHandler",
)
@patch(
"azure.monitor.opentelemetry.distro.BatchLogRecordProcessor",
)
@patch(
"azure.monitor.opentelemetry.distro.AzureMonitorLogExporter",
)
@patch(
"azure.monitor.opentelemetry.distro.get_logger_provider",
)
@patch(
"azure.monitor.opentelemetry.distro.set_logger_provider",
)
@patch(
"azure.monitor.opentelemetry.distro.LoggerProvider",
autospec=True,
)
@patch(
"azure.monitor.opentelemetry.distro.Resource",
)
def test_configure_azure_monitor_disable_tracing_and_logging(
self,
resource_mock,
lp_mock,
set_logger_provider_mock,
get_logger_provider_mock,
log_exporter_mock,
blrp_mock,
logging_handler_mock,
get_logger_mock,
sampler_mock,
tp_mock,
set_tracer_provider_mock,
get_tracer_provider_mock,
trace_exporter_mock,
bsp_mock,
):
configure_azure_monitor(
connection_string="test_cs",
disable_logging=True,
disable_tracing=True,
)
resource_mock.assert_not_called()
lp_mock.assert_not_called()
set_logger_provider_mock.assert_not_called()
get_logger_provider_mock.assert_not_called()
log_exporter_mock.assert_not_called()
blrp_mock.assert_not_called()
logging_handler_mock.assert_not_called()
get_logger_mock.assert_not_called()
sampler_mock.assert_not_called()
tp_mock.assert_not_called()
set_tracer_provider_mock.assert_not_called()
get_tracer_provider_mock.assert_not_called()
trace_exporter_mock.assert_not_called()
bsp_mock.assert_not_called()
@patch(
"azure.monitor.opentelemetry.distro.BatchSpanProcessor",
)
@patch(
"azure.monitor.opentelemetry.distro.AzureMonitorTraceExporter",
)
@patch(
"azure.monitor.opentelemetry.distro.get_tracer_provider",
)
@patch(
"azure.monitor.opentelemetry.distro.set_tracer_provider",
)
@patch(
"azure.monitor.opentelemetry.distro.TracerProvider",
autospec=True,
)
@patch(
"azure.monitor.opentelemetry.distro.ApplicationInsightsSampler",
)
@patch(
"azure.monitor.opentelemetry.distro.getLogger",
)
@patch(
"azure.monitor.opentelemetry.distro.LoggingHandler",
)
@patch(
"azure.monitor.opentelemetry.distro.BatchLogRecordProcessor",
)
@patch(
"azure.monitor.opentelemetry.distro.AzureMonitorLogExporter",
)
@patch(
"azure.monitor.opentelemetry.distro.get_logger_provider",
)
@patch(
"azure.monitor.opentelemetry.distro.set_logger_provider",
)
@patch(
"azure.monitor.opentelemetry.distro.LoggerProvider",
autospec=True,
)
@patch(
"azure.monitor.opentelemetry.distro.Resource",
"azure.monitor.opentelemetry.distro._get_resource",
)
def test_configure_azure_monitor_disable_tracing(
self,
resource_mock,
lp_mock,
set_logger_provider_mock,
get_logger_provider_mock,
log_exporter_mock,
blrp_mock,
logging_handler_mock,
get_logger_mock,
sampler_mock,
tp_mock,
set_tracer_provider_mock,
get_tracer_provider_mock,
trace_exporter_mock,
bsp_mock,
tracing_mock,
logging_mock,
instrumentation_mock,
):
kwargs = {
"connection_string": "test_cs",
"disable_logging": False,
"disable_tracing": True,
"logging_export_interval_millis": 10000,
"logging_level": "test_logging_level",
"service_name": "test_service_name",
"service_namespace": "test_namespace",
"service_instance_id": "test_id",
"sampling_ratio": 0.5,
"tracing_export_interval_millis": 15000,
}
resource_init_mock = Mock()
resource_mock.create.return_value = resource_init_mock
resource_mock.return_value = resource_init_mock
configure_azure_monitor(**kwargs)
resource_mock.assert_called_once_with(kwargs)
tracing_mock.assert_not_called()
logging_mock.assert_called_once_with(resource_init_mock, kwargs)
instrumentation_mock.assert_called_once_with(kwargs)
lp_init_mock = Mock()
lp_mock.return_value = lp_init_mock
get_logger_provider_mock.return_value = lp_init_mock
log_exp_init_mock = Mock()
log_exporter_mock.return_value = log_exp_init_mock
blrp_init_mock = Mock()
blrp_mock.return_value = blrp_init_mock
logging_handler_init_mock = Mock()
logging_handler_mock.return_value = logging_handler_init_mock
logger_mock = Mock()
get_logger_mock.return_value = logger_mock
@patch(
"azure.monitor.opentelemetry.distro._setup_instrumentations",
)
@patch(
"azure.monitor.opentelemetry.distro._setup_logging",
)
@patch(
"azure.monitor.opentelemetry.distro._setup_tracing",
)
@patch(
"azure.monitor.opentelemetry.distro._get_resource",
)
def test_configure_azure_monitor_disable_logging(
self,
resource_mock,
tracing_mock,
logging_mock,
instrumentation_mock,
):
kwargs = {
"connection_string": "test_cs",
"disable_logging": True,
"disable_tracing": False,
"logging_export_interval_millis": 10000,
"logging_level": "test_logging_level",
"service_name": "test_service_name",
"service_namespace": "test_namespace",
"service_instance_id": "test_id",
"sampling_ratio": 0.5,
"tracing_export_interval_millis": 15000,
}
resource_init_mock = Mock()
resource_mock.return_value = resource_init_mock
configure_azure_monitor(**kwargs)
resource_mock.assert_called_once_with(kwargs)
tracing_mock.assert_called_once_with(resource_init_mock, kwargs)
logging_mock.assert_not_called()
instrumentation_mock.assert_called_once_with(kwargs)
configure_azure_monitor(
connection_string="test_cs",
console_exporting=False,
disable_logging=False,
disable_tracing=True,
logging_export_interval_millis=10000,
logging_level="test_logging_level",
service_name="test_service_name",
service_namespace="test_namespace",
service_instance_id="test_id",
)
@patch(
"azure.monitor.opentelemetry.distro.Resource",
)
def test_get_resource(self, resource_mock):
configuration = {
"service_name": "test_service_name",
"service_namespace": "test_namespace",
"service_instance_id": "test_id",
}
_get_resource(configuration)
resource_mock.create.assert_called_once_with(
{
ResourceAttributes.SERVICE_NAME: "test_service_name",
@ -336,31 +162,6 @@ class TestConfigure(unittest.TestCase):
}
)
lp_mock.assert_called_once_with(resource=resource_init_mock)
set_logger_provider_mock.assert_called_once_with(lp_init_mock)
get_logger_provider_mock.assert_called()
log_exporter_mock.assert_called_once()
blrp_mock.assert_called_once_with(
log_exp_init_mock, export_timeout_millis=10000
)
lp_init_mock.add_log_record_processor.assert_called_once_with(
blrp_init_mock
)
logging_handler_mock.assert_called_once_with(
level="test_logging_level", logger_provider=lp_init_mock
)
get_logger_mock.assert_called_once_with()
logger_mock.addHandler.assert_called_once_with(
logging_handler_init_mock
)
sampler_mock.assert_not_called()
tp_mock.assert_not_called()
set_tracer_provider_mock.assert_not_called()
get_tracer_provider_mock.assert_not_called()
trace_exporter_mock.assert_not_called()
bsp_mock.assert_not_called()
@patch(
"azure.monitor.opentelemetry.distro.BatchSpanProcessor",
)
@ -380,6 +181,46 @@ class TestConfigure(unittest.TestCase):
@patch(
"azure.monitor.opentelemetry.distro.ApplicationInsightsSampler",
)
def test_setup_tracing(
self,
sampler_mock,
tp_mock,
set_tracer_provider_mock,
get_tracer_provider_mock,
trace_exporter_mock,
bsp_mock,
):
resource_mock = Mock()
sampler_init_mock = Mock()
sampler_mock.return_value = sampler_init_mock
tp_init_mock = Mock()
tp_mock.return_value = tp_init_mock
get_tracer_provider_mock.return_value = tp_init_mock
trace_exp_init_mock = Mock()
trace_exporter_mock.return_value = trace_exp_init_mock
bsp_init_mock = Mock()
bsp_mock.return_value = bsp_init_mock
configurations = {
"connection_string": "test_cs",
"disable_tracing": False,
"sampling_ratio": 0.5,
"tracing_export_interval_millis": 15000,
}
_setup_tracing(resource_mock, configurations)
sampler_mock.assert_called_once_with(sampling_ratio=0.5)
tp_mock.assert_called_once_with(
resource=resource_mock,
sampler=sampler_init_mock,
)
set_tracer_provider_mock.assert_called_once_with(tp_init_mock)
get_tracer_provider_mock.assert_called()
trace_exporter_mock.assert_called_once()
bsp_mock.assert_called_once_with(
trace_exp_init_mock, export_timeout_millis=15000
)
tp_init_mock.add_span_processor(bsp_init_mock)
@patch(
"azure.monitor.opentelemetry.distro.getLogger",
)
@ -402,12 +243,8 @@ class TestConfigure(unittest.TestCase):
"azure.monitor.opentelemetry.distro.LoggerProvider",
autospec=True,
)
@patch(
"azure.monitor.opentelemetry.distro.Resource",
)
def test_configure_azure_monitor_disable_logging(
def test_setup_logging(
self,
resource_mock,
lp_mock,
set_logger_provider_mock,
get_logger_provider_mock,
@ -415,63 +252,141 @@ class TestConfigure(unittest.TestCase):
blrp_mock,
logging_handler_mock,
get_logger_mock,
sampler_mock,
tp_mock,
set_tracer_provider_mock,
get_tracer_provider_mock,
trace_exporter_mock,
bsp_mock,
):
resource_init_mock = Mock()
resource_mock.create.return_value = resource_init_mock
resource_mock = Mock()
sampler_init_mock = Mock()
sampler_mock.return_value = sampler_init_mock
tp_init_mock = Mock()
tp_mock.return_value = tp_init_mock
get_tracer_provider_mock.return_value = tp_init_mock
trace_exp_init_mock = Mock()
trace_exporter_mock.return_value = trace_exp_init_mock
bsp_init_mock = Mock()
bsp_mock.return_value = bsp_init_mock
lp_init_mock = Mock()
lp_mock.return_value = lp_init_mock
get_logger_provider_mock.return_value = lp_init_mock
log_exp_init_mock = Mock()
log_exporter_mock.return_value = log_exp_init_mock
blrp_init_mock = Mock()
blrp_mock.return_value = blrp_init_mock
logging_handler_init_mock = Mock()
logging_handler_mock.return_value = logging_handler_init_mock
logger_mock = Mock()
get_logger_mock.return_value = logger_mock
configure_azure_monitor(
connection_string="test_cs",
console_exporting=False,
disable_logging=True,
disable_tracing=False,
logging_level="test_logging_level",
service_name="test_service_name",
service_namespace="test_namespace",
service_instance_id="test_id",
sampling_ratio=0.5,
tracing_export_interval_millis=15000,
configurations = {
"connection_string": "test_cs",
"disable_logging": False,
"logging_export_interval_millis": 10000,
"logging_level": "test_logging_level",
}
_setup_logging(resource_mock, configurations)
lp_mock.assert_called_once_with(resource=resource_mock)
set_logger_provider_mock.assert_called_once_with(lp_init_mock)
get_logger_provider_mock.assert_called()
log_exporter_mock.assert_called_once()
blrp_mock.assert_called_once_with(
log_exp_init_mock, export_timeout_millis=10000
)
resource_mock.create.assert_called_once_with(
{
ResourceAttributes.SERVICE_NAME: "test_service_name",
ResourceAttributes.SERVICE_NAMESPACE: "test_namespace",
ResourceAttributes.SERVICE_INSTANCE_ID: "test_id",
}
lp_init_mock.add_log_record_processor.assert_called_once_with(
blrp_init_mock
)
logging_handler_mock.assert_called_once_with(
level="test_logging_level", logger_provider=lp_init_mock
)
get_logger_mock.assert_called_once_with()
logger_mock.addHandler.assert_called_once_with(
logging_handler_init_mock
)
lp_mock.assert_not_called()
set_logger_provider_mock.assert_not_called()
get_logger_provider_mock.assert_not_called()
log_exporter_mock.assert_not_called()
blrp_mock.assert_not_called()
logging_handler_mock.assert_not_called()
get_logger_mock.assert_not_called()
@patch("azure.monitor.opentelemetry.distro.getattr")
def test_setup_instrumentations(
self,
getattr_mock,
):
for lib_name in _SUPPORTED_INSTRUMENTED_LIBRARIES:
with patch("importlib.import_module") as import_module_mock:
configurations = {"instrumentations": [lib_name]}
instrument_mock = Mock()
instrumentor_mock = Mock()
instrumentor_mock.return_value = instrument_mock
getattr_mock.return_value = instrumentor_mock
_setup_instrumentations(configurations)
self.assertEqual(import_module_mock.call_count, 2)
instr_lib_name = "opentelemetry.instrumentation." + lib_name
import_module_mock.assert_has_calls(
[call(lib_name), call(instr_lib_name)]
)
instrumentor_mock.assert_called_once()
instrument_mock.instrument.assert_called_once()
sampler_mock.assert_called_once_with(sampling_ratio=0.5)
tp_mock.assert_called_once_with(
resource=resource_init_mock,
sampler=sampler_init_mock,
)
set_tracer_provider_mock.assert_called_once_with(tp_init_mock)
get_tracer_provider_mock.assert_called()
trace_exporter_mock.assert_called_once()
bsp_mock.assert_called_once_with(
trace_exp_init_mock, export_timeout_millis=15000
)
tp_init_mock.add_span_processor(bsp_init_mock)
@patch("azure.monitor.opentelemetry.distro.getattr")
def test_setup_instrumentations_lib_not_found(
self,
getattr_mock,
):
with patch("importlib.import_module") as import_module_mock:
configurations = {"instrumentations": ["non_supported_lib"]}
instrument_mock = Mock()
instrumentor_mock = Mock()
instrumentor_mock.return_value = instrument_mock
getattr_mock.return_value = instrumentor_mock
_setup_instrumentations(configurations)
import_module_mock.assert_not_called()
instrumentor_mock.assert_not_called()
instrument_mock.instrument.assert_not_called()
@patch("azure.monitor.opentelemetry.distro.getattr")
def test_setup_instrumentations_import_lib_failed(
self,
getattr_mock,
):
for lib_name in _SUPPORTED_INSTRUMENTED_LIBRARIES:
with patch(
"importlib.import_module", side_effect=ImportError()
) as import_module_mock:
configurations = {"instrumentations": [lib_name]}
instrument_mock = Mock()
instrumentor_mock = Mock()
instrumentor_mock.return_value = instrument_mock
getattr_mock.return_value = instrumentor_mock
_setup_instrumentations(configurations)
import_module_mock.assert_called_once()
instrumentor_mock.assert_not_called()
instrument_mock.instrument.assert_not_called()
@patch("azure.monitor.opentelemetry.distro.getattr")
def test_setup_instrumentations_import_instr_failed(
self,
getattr_mock,
):
for lib_name in _SUPPORTED_INSTRUMENTED_LIBRARIES:
with patch("importlib.import_module") as import_module_mock:
configurations = {"instrumentations": [lib_name]}
instrument_mock = Mock()
instrumentor_mock = Mock()
instrumentor_mock.return_value = instrument_mock
getattr_mock.return_value = instrumentor_mock
import_module_mock.side_effect = [None, ImportError()]
_setup_instrumentations(configurations)
instr_lib_name = "opentelemetry.instrumentation." + lib_name
import_module_mock.assert_has_calls(
[call(lib_name), call(instr_lib_name)]
)
instrumentor_mock.assert_not_called()
instrument_mock.instrument.assert_not_called()
@patch("azure.monitor.opentelemetry.distro.getattr")
def test_setup_instrumentations_failed_general(
self,
getattr_mock,
):
for lib_name in _SUPPORTED_INSTRUMENTED_LIBRARIES:
with patch("importlib.import_module") as import_module_mock:
configurations = {"instrumentations": [lib_name]}
instrument_mock = Mock()
instrumentor_mock = Mock()
instrumentor_mock.return_value = instrument_mock
getattr_mock.side_effect = Exception()
_setup_instrumentations(configurations)
self.assertEqual(import_module_mock.call_count, 2)
instr_lib_name = "opentelemetry.instrumentation." + lib_name
import_module_mock.assert_has_calls(
[call(lib_name), call(instr_lib_name)]
)
instrumentor_mock.assert_not_called()
instrument_mock.instrument.assert_not_called()