From aa4ec47cd8a1a91f0e92a27a9d5f1c8701e11e34 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Thu, 19 Jan 2023 15:57:33 -0800 Subject: [PATCH 1/6] instr --- CHANGELOG.md | 2 + .../monitor/opentelemetry/distro/__init__.py | 72 +++++++++- .../opentelemetry/distro/_constants.py | 12 +- .../samples/tracing/client.py | 29 ++++ .../tracing/{simple.py => db_psycopg2.py} | 17 +-- .../tracing/django/sample/example/__init__.py | 2 + .../tracing/django/sample/example/admin.py | 5 + .../tracing/django/sample/example/apps.py | 8 ++ .../sample/example/migrations/__init__.py | 2 + .../tracing/django/sample/example/models.py | 5 + .../tracing/django/sample/example/tests.py | 5 + .../tracing/django/sample/example/urls.py | 10 ++ .../tracing/django/sample/example/views.py | 25 ++++ .../samples/tracing/django/sample/manage.py | 27 ++++ .../tracing/django/sample/sample/__init__.py | 2 + .../tracing/django/sample/sample/asgi.py | 22 +++ .../tracing/django/sample/sample/settings.py | 131 ++++++++++++++++++ .../tracing/django/sample/sample/urls.py | 22 +++ .../tracing/django/sample/sample/wsgi.py | 18 +++ .../samples/tracing/server_flask.py | 32 +++++ .../tests/configuration/test_configure.py | 103 +++++++++++++- 21 files changed, 529 insertions(+), 22 deletions(-) create mode 100644 azure-monitor-opentelemetry-distro/samples/tracing/client.py rename azure-monitor-opentelemetry-distro/samples/tracing/{simple.py => db_psycopg2.py} (59%) create mode 100644 azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/__init__.py create mode 100644 azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/admin.py create mode 100644 azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/apps.py create mode 100644 azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/migrations/__init__.py create mode 100644 azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/models.py create mode 100644 azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/tests.py create mode 100644 azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/urls.py create mode 100644 azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/views.py create mode 100644 azure-monitor-opentelemetry-distro/samples/tracing/django/sample/manage.py create mode 100644 azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/__init__.py create mode 100644 azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/asgi.py create mode 100644 azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/settings.py create mode 100644 azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/urls.py create mode 100644 azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/wsgi.py create mode 100644 azure-monitor-opentelemetry-distro/samples/tracing/server_flask.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a9a994a..e6fb73fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ ([#215](https://github.com/microsoft/ApplicationInsights-Python/pull/215)) - Rename to `configure_azure_monitor`, add sampler to config ([#216](https://github.com/microsoft/ApplicationInsights-Python/pull/216)) +- Add instrumentation selection config + ([#216](https://github.com/microsoft/ApplicationInsights-Python/pull/216)) ## [1.0.0b8](https://github.com/microsoft/ApplicationInsights-Python/releases/tag/v1.0.0b8) - 2022-09-26 diff --git a/azure-monitor-opentelemetry-distro/azure/monitor/opentelemetry/distro/__init__.py b/azure-monitor-opentelemetry-distro/azure/monitor/opentelemetry/distro/__init__.py index 32c6259d..e328f5b9 100644 --- a/azure-monitor-opentelemetry-distro/azure/monitor/opentelemetry/distro/__init__.py +++ b/azure-monitor-opentelemetry-distro/azure/monitor/opentelemetry/distro/__init__.py @@ -3,6 +3,10 @@ # Licensed under the MIT License. See License in the project root for # license information. # -------------------------------------------------------------------------- +import importlib +import logging + +from typing import Any, Dict from azure.monitor.opentelemetry.distro.util import get_configurations from azure.monitor.opentelemetry.exporter import ( ApplicationInsightsSampler, @@ -14,6 +18,16 @@ from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.semconv.resource import ResourceAttributes +_logger = logging.getLogger(__name__) + + +_SUPPORTED_INSTRUMENTED_LIBRARIES = { + "django", + "flask", + "psycopg2", + "requests", +} + def configure_azure_monitor(**kwargs): """ @@ -23,16 +37,60 @@ def configure_azure_monitor(**kwargs): """ configurations = get_configurations(**kwargs) + + # Setup tracing pipeline + _setup_tracing(configurations, **kwargs) + + # Setup instrumentations + # Instrumentations need to be setup last so to use the global providers + # instanstiated in the other setup steps + _setup_instrumentations(configurations.get("instrumentations", [])) + + +def _setup_instrumentations(instrumentations: Dict[str, str]): + for lib_name in instrumentations: + if lib_name in _SUPPORTED_INSTRUMENTED_LIBRARIES: + try: + importlib.import_module(lib_name) + except ImportError as ex: + _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) + finally: + continue + else: + _logger.warning("Instrumentation not supported for library: %s.", lib_name) + + +def _setup_tracing(configurations: Dict[str, Any], **kwargs: Dict[Any, Any]): disable_tracing = configurations.get("disable_tracing", False) - service_name = configurations.get("service_name", "") - service_namespace = configurations.get("service_namespace", "") - service_instance_id = configurations.get("service_instance_id", "") - sampling_ratio = configurations.get("sampling_ratio", 1.0) - tracing_export_interval_millis = configurations.get( - "tracing_export_interval_millis", 30000 - ) if not disable_tracing: + service_name = configurations.get("service_name", "") + service_namespace = configurations.get("service_namespace", "") + service_instance_id = configurations.get("service_instance_id", "") + sampling_ratio = configurations.get("sampling_ratio", 1.0) + tracing_export_interval_millis = configurations.get( + "tracing_export_interval_millis", 30000 + ) resource = Resource.create( { ResourceAttributes.SERVICE_NAME: service_name, diff --git a/azure-monitor-opentelemetry-distro/azure/monitor/opentelemetry/distro/_constants.py b/azure-monitor-opentelemetry-distro/azure/monitor/opentelemetry/distro/_constants.py index 810c500c..51c4f558 100644 --- a/azure-monitor-opentelemetry-distro/azure/monitor/opentelemetry/distro/_constants.py +++ b/azure-monitor-opentelemetry-distro/azure/monitor/opentelemetry/distro/_constants.py @@ -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 @@ 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" diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/client.py b/azure-monitor-opentelemetry-distro/samples/tracing/client.py new file mode 100644 index 00000000..7b07a05c --- /dev/null +++ b/azure-monitor-opentelemetry-distro/samples/tracing/client.py @@ -0,0 +1,29 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License in the project root for +# license information. +# -------------------------------------------------------------------------- +import requests + +from azure.monitor.opentelemetry.distro import configure_azure_monitor +from opentelemetry import trace + +# Configure Azure monitor collection telemetry pipeline +configure_azure_monitor( + connection_string="", + service_name="client_service_name", + 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) + 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() diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/simple.py b/azure-monitor-opentelemetry-distro/samples/tracing/db_psycopg2.py similarity index 59% rename from azure-monitor-opentelemetry-distro/samples/tracing/simple.py rename to azure-monitor-opentelemetry-distro/samples/tracing/db_psycopg2.py index c2de31ea..8d7be1e4 100644 --- a/azure-monitor-opentelemetry-distro/samples/tracing/simple.py +++ b/azure-monitor-opentelemetry-distro/samples/tracing/db_psycopg2.py @@ -3,19 +3,20 @@ # 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 -from opentelemetry import trace +# Configure Azure monitor collection telemetry pipeline configure_azure_monitor( connection_string="", - service_name="foo_service", + service_name="psycopg2_service_name", + instrumentations=["psycopg2"], tracing_export_interval_millis=15000, ) -tracer = trace.get_tracer(__name__) - -with tracer.start_as_current_span("hello"): - print("Hello, World!") - -input() +cnx = psycopg2.connect(database='test', user="", password="") +cursor = cnx.cursor() +cursor.execute("INSERT INTO test_tables (test_field) VALUES (123)") +cursor.close() +cnx.close() diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/__init__.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/__init__.py new file mode 100644 index 00000000..6fcf0de4 --- /dev/null +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/__init__.py @@ -0,0 +1,2 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. \ No newline at end of file diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/admin.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/admin.py new file mode 100644 index 00000000..3f8b9caa --- /dev/null +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/admin.py @@ -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. diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/apps.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/apps.py new file mode 100644 index 00000000..79d02ec3 --- /dev/null +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/apps.py @@ -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' diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/migrations/__init__.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/migrations/__init__.py new file mode 100644 index 00000000..6fcf0de4 --- /dev/null +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/migrations/__init__.py @@ -0,0 +1,2 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. \ No newline at end of file diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/models.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/models.py new file mode 100644 index 00000000..526ea7fd --- /dev/null +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/models.py @@ -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. diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/tests.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/tests.py new file mode 100644 index 00000000..7705f147 --- /dev/null +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/tests.py @@ -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. diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/urls.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/urls.py new file mode 100644 index 00000000..443b11cb --- /dev/null +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/urls.py @@ -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'), +] diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/views.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/views.py new file mode 100644 index 00000000..9b1989b4 --- /dev/null +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/views.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License in the project root for +# license information. +# -------------------------------------------------------------------------- + +from django.http import HttpResponse + +from azure.monitor.opentelemetry.distro import configure_azure_monitor + +# Configure Azure monitor collection telemetry pipeline +configure_azure_monitor( + connection_string="", + service_name="django_service_name", + instrumentations=["django"], + 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.") diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/manage.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/manage.py new file mode 100644 index 00000000..334904f4 --- /dev/null +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/manage.py @@ -0,0 +1,27 @@ +# 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 + +from opentelemetry.instrumentation.django import DjangoInstrumentor + + +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() diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/__init__.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/__init__.py new file mode 100644 index 00000000..6fcf0de4 --- /dev/null +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/__init__.py @@ -0,0 +1,2 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. \ No newline at end of file diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/asgi.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/asgi.py new file mode 100644 index 00000000..7caf941a --- /dev/null +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/asgi.py @@ -0,0 +1,22 @@ +# 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 + diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/settings.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/settings.py new file mode 100644 index 00000000..177e83d3 --- /dev/null +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/settings.py @@ -0,0 +1,131 @@ +# 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 \ No newline at end of file diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/urls.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/urls.py new file mode 100644 index 00000000..5714ebcf --- /dev/null +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/urls.py @@ -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')), +] diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/wsgi.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/wsgi.py new file mode 100644 index 00000000..34f760be --- /dev/null +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/wsgi.py @@ -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() diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/server_flask.py b/azure-monitor-opentelemetry-distro/samples/tracing/server_flask.py new file mode 100644 index 00000000..018c7075 --- /dev/null +++ b/azure-monitor-opentelemetry-distro/samples/tracing/server_flask.py @@ -0,0 +1,32 @@ +# ------------------------------------------------------------------------- +# 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="", + service_name="flask_service_name", + 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) diff --git a/azure-monitor-opentelemetry-distro/tests/configuration/test_configure.py b/azure-monitor-opentelemetry-distro/tests/configuration/test_configure.py index b41ae37f..f6f7057f 100644 --- a/azure-monitor-opentelemetry-distro/tests/configuration/test_configure.py +++ b/azure-monitor-opentelemetry-distro/tests/configuration/test_configure.py @@ -13,9 +13,14 @@ # limitations under the License. import unittest -from unittest.mock import Mock, patch +from unittest.mock import Mock, patch, call -from azure.monitor.opentelemetry.distro import configure_azure_monitor +from azure.monitor.opentelemetry.distro import ( + configure_azure_monitor, + _setup_instrumentations, + _setup_tracing, + _SUPPORTED_INSTRUMENTED_LIBRARIES, +) from opentelemetry.semconv.resource import ResourceAttributes @@ -179,3 +184,97 @@ def test_configure_azure_monitor_exporter( exporter_mock.assert_called_once_with(**kwargs) sampler_mock.assert_called_once() bsp_mock.assert_called_once() + + + @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: + instrumentations = [lib_name] + instrument_mock = Mock() + instrumentor_mock = Mock() + instrumentor_mock.return_value = instrument_mock + getattr_mock.return_value = instrumentor_mock + _setup_instrumentations(instrumentations) + 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() + + @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: + instrumentations = ["non_supported_lib"] + instrument_mock = Mock() + instrumentor_mock = Mock() + instrumentor_mock.return_value = instrument_mock + getattr_mock.return_value = instrumentor_mock + _setup_instrumentations(instrumentations) + 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: + instrumentations = [lib_name] + instrument_mock = Mock() + instrumentor_mock = Mock() + instrumentor_mock.return_value = instrument_mock + getattr_mock.return_value = instrumentor_mock + _setup_instrumentations(instrumentations) + 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: + 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(instrumentations) + 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: + instrumentations = [lib_name] + instrument_mock = Mock() + instrumentor_mock = Mock() + instrumentor_mock.return_value = instrument_mock + getattr_mock.side_effect = Exception() + _setup_instrumentations(instrumentations) + 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() From 0596c0984503161f93d5c8b9f68fed219f5e95f2 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Tue, 24 Jan 2023 11:33:03 -0800 Subject: [PATCH 2/6] instr --- azure-monitor-opentelemetry-distro/README.md | 4 +- .../monitor/opentelemetry/distro/__init__.py | 17 +- .../samples/tracing/client.py | 5 + .../tracing/django/sample/example/views.py | 3 +- .../samples/tracing/django/sample/manage.py | 2 - .../samples/tracing/server_flask.py | 1 + .../samples/tracing/simple.py | 22 + .../tests/configuration/test_configure.py | 499 ++++++------------ 8 files changed, 198 insertions(+), 355 deletions(-) create mode 100644 azure-monitor-opentelemetry-distro/samples/tracing/simple.py diff --git a/azure-monitor-opentelemetry-distro/README.md b/azure-monitor-opentelemetry-distro/README.md index 2e47ae79..e70037e3 100644 --- a/azure-monitor-opentelemetry-distro/README.md +++ b/azure-monitor-opentelemetry-distro/README.md @@ -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 diff --git a/azure-monitor-opentelemetry-distro/azure/monitor/opentelemetry/distro/__init__.py b/azure-monitor-opentelemetry-distro/azure/monitor/opentelemetry/distro/__init__.py index 7dc01a85..b1f786d6 100644 --- a/azure-monitor-opentelemetry-distro/azure/monitor/opentelemetry/distro/__init__.py +++ b/azure-monitor-opentelemetry-distro/azure/monitor/opentelemetry/distro/__init__.py @@ -56,16 +56,16 @@ def configure_azure_monitor(**kwargs): # Setup tracing pipeline if not disable_tracing: - _setup_tracing(resource, configurations, **kwargs) + _setup_tracing(resource, configurations) # Setup logging pipeline if not disable_logging: - _setup_logging(resource, configurations, **kwargs) + _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.get("instrumentations", [])) + _setup_instrumentations(configurations) def _get_resource(configurations: Dict[str, Any]) -> Resource: @@ -81,7 +81,7 @@ def _get_resource(configurations: Dict[str, Any]) -> Resource: ) -def _setup_tracing(resource: Resource, configurations: Dict[str, Any], **kwargs: Dict[Any, Any]): +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 @@ -91,7 +91,7 @@ def _setup_tracing(resource: Resource, configurations: Dict[str, Any], **kwargs: resource=resource, ) set_tracer_provider(tracer_provider) - trace_exporter = AzureMonitorTraceExporter(**kwargs) + trace_exporter = AzureMonitorTraceExporter(**configurations) span_processor = BatchSpanProcessor( trace_exporter, export_timeout_millis=tracing_export_interval_millis, @@ -99,14 +99,14 @@ def _setup_tracing(resource: Resource, configurations: Dict[str, Any], **kwargs: get_tracer_provider().add_span_processor(span_processor) -def _setup_logging(resource: Resource, configurations: Dict[str, Any], **kwargs: Dict[Any, Any]): +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(**kwargs) + log_exporter = AzureMonitorLogExporter(**configurations) log_record_processor = BatchLogRecordProcessor( log_exporter, export_timeout_millis=logging_export_interval_millis, @@ -118,7 +118,8 @@ def _setup_logging(resource: Resource, configurations: Dict[str, Any], **kwargs: getLogger().addHandler(handler) -def _setup_instrumentations(instrumentations: Dict[str, str]): +def _setup_instrumentations(configurations: Dict[str, Any]): + instrumentations = configurations.get("instrumentations", []) for lib_name in instrumentations: if lib_name in _SUPPORTED_INSTRUMENTED_LIBRARIES: try: diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/client.py b/azure-monitor-opentelemetry-distro/samples/tracing/client.py index 7b07a05c..4529b973 100644 --- a/azure-monitor-opentelemetry-distro/samples/tracing/client.py +++ b/azure-monitor-opentelemetry-distro/samples/tracing/client.py @@ -3,15 +3,19 @@ # 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="", service_name="client_service_name", + disable_logging=True, instrumentations=["requests"], tracing_export_interval_millis=15000, ) @@ -21,6 +25,7 @@ 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") diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/views.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/views.py index 9b1989b4..7c23e3cd 100644 --- a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/views.py +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/views.py @@ -10,9 +10,10 @@ # Configure Azure monitor collection telemetry pipeline configure_azure_monitor( - connection_string="", + # connection_string="", service_name="django_service_name", instrumentations=["django"], + disable_logging=True, tracing_export_interval_millis=15000, ) diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/manage.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/manage.py index 334904f4..7f20d97d 100644 --- a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/manage.py +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/manage.py @@ -5,8 +5,6 @@ import os import sys -from opentelemetry.instrumentation.django import DjangoInstrumentor - def main(): """Run administrative tasks.""" diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/server_flask.py b/azure-monitor-opentelemetry-distro/samples/tracing/server_flask.py index 018c7075..2ba12246 100644 --- a/azure-monitor-opentelemetry-distro/samples/tracing/server_flask.py +++ b/azure-monitor-opentelemetry-distro/samples/tracing/server_flask.py @@ -11,6 +11,7 @@ configure_azure_monitor( connection_string="", service_name="flask_service_name", + disable_logging=True, instrumentations=["flask"], tracing_export_interval_millis=15000, ) diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/simple.py b/azure-monitor-opentelemetry-distro/samples/tracing/simple.py new file mode 100644 index 00000000..fbca7f1f --- /dev/null +++ b/azure-monitor-opentelemetry-distro/samples/tracing/simple.py @@ -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. +# -------------------------------------------------------------------------- + +from azure.monitor.opentelemetry.distro import configure_azure_monitor +from opentelemetry import trace + +configure_azure_monitor( + connection_string="", + service_name="foo_service", + tracing_export_interval_millis=15000, + disable_logging=True, +) + +tracer = trace.get_tracer(__name__) + +with tracer.start_as_current_span("hello"): + print("Hello, World!") + +input() diff --git a/azure-monitor-opentelemetry-distro/tests/configuration/test_configure.py b/azure-monitor-opentelemetry-distro/tests/configuration/test_configure.py index 721b2f16..5cb3f8b3 100644 --- a/azure-monitor-opentelemetry-distro/tests/configuration/test_configure.py +++ b/azure-monitor-opentelemetry-distro/tests/configuration/test_configure.py @@ -17,7 +17,9 @@ from azure.monitor.opentelemetry.distro import ( configure_azure_monitor, + _get_resource, _setup_instrumentations, + _setup_logging, _setup_tracing, _SUPPORTED_INSTRUMENTED_LIBRARIES, ) @@ -26,142 +28,139 @@ 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, + "azure.monitor.opentelemetry.distro._get_resource", ) + def test_configure_azure_monitor( + self, + resource_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.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.ApplicationInsightsSampler", + "azure.monitor.opentelemetry.distro._setup_instrumentations", ) @patch( - "azure.monitor.opentelemetry.distro.getLogger", + "azure.monitor.opentelemetry.distro._setup_logging", ) @patch( - "azure.monitor.opentelemetry.distro.LoggingHandler", + "azure.monitor.opentelemetry.distro._setup_tracing", ) @patch( - "azure.monitor.opentelemetry.distro.BatchLogRecordProcessor", - ) - @patch( - "azure.monitor.opentelemetry.distro.AzureMonitorLogExporter", + "azure.monitor.opentelemetry.distro._get_resource", ) + def test_configure_azure_monitor_disable_tracing( + self, + resource_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.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) + + @patch( - "azure.monitor.opentelemetry.distro.get_logger_provider", + "azure.monitor.opentelemetry.distro._setup_instrumentations", ) @patch( - "azure.monitor.opentelemetry.distro.set_logger_provider", + "azure.monitor.opentelemetry.distro._setup_logging", ) @patch( - "azure.monitor.opentelemetry.distro.LoggerProvider", - autospec=True, + "azure.monitor.opentelemetry.distro._setup_tracing", ) @patch( - "azure.monitor.opentelemetry.distro.Resource", + "azure.monitor.opentelemetry.distro._get_resource", ) - def test_configure_azure_monitor( + def test_configure_azure_monitor_disable_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, + 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.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 + 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=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) + @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", + } + resource = _get_resource(configuration) + resource_mock.create.assert_called_once_with({ + ResourceAttributes.SERVICE_NAME: "test_service_name", + ResourceAttributes.SERVICE_NAMESPACE: "test_namespace", + ResourceAttributes.SERVICE_INSTANCE_ID: "test_id", + }) @patch( "azure.monitor.opentelemetry.distro.BatchSpanProcessor", @@ -182,41 +181,8 @@ def test_configure_azure_monitor( @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( + def test_setup_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, @@ -224,47 +190,38 @@ def test_configure_azure_monitor_disable_tracing_and_logging( trace_exporter_mock, bsp_mock, ): - configure_azure_monitor( - connection_string="test_cs", - disable_logging=True, - disable_tracing=True, - ) - resource_mock.assert_not_called() + 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_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() + 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) - 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", ) @@ -287,12 +244,8 @@ def test_configure_azure_monitor_disable_tracing_and_logging( "azure.monitor.opentelemetry.distro.LoggerProvider", autospec=True, ) - @patch( - "azure.monitor.opentelemetry.distro.Resource", - ) - def test_configure_azure_monitor_disable_tracing( + def test_setup_logging( self, - resource_mock, lp_mock, set_logger_provider_mock, get_logger_provider_mock, @@ -300,15 +253,8 @@ def test_configure_azure_monitor_disable_tracing( 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() lp_init_mock = Mock() lp_mock.return_value = lp_init_mock @@ -322,26 +268,15 @@ def test_configure_azure_monitor_disable_tracing( logger_mock = Mock() get_logger_mock.return_value = logger_mock - 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", - ) - resource_mock.create.assert_called_once_with( - { - ResourceAttributes.SERVICE_NAME: "test_service_name", - ResourceAttributes.SERVICE_NAMESPACE: "test_namespace", - ResourceAttributes.SERVICE_INSTANCE_ID: "test_id", - } - ) + 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_init_mock) + 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() @@ -359,128 +294,6 @@ def test_configure_azure_monitor_disable_tracing( 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", - ) - @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", - ) - def test_configure_azure_monitor_disable_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, - ): - resource_init_mock = Mock() - resource_mock.create.return_value = resource_init_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=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, - ) - 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_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_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( @@ -489,12 +302,12 @@ def test_setup_instrumentations( ): for lib_name in _SUPPORTED_INSTRUMENTED_LIBRARIES: with patch("importlib.import_module") as import_module_mock: - instrumentations = [lib_name] + configurations = {"instrumentations": [lib_name]} instrument_mock = Mock() instrumentor_mock = Mock() instrumentor_mock.return_value = instrument_mock getattr_mock.return_value = instrumentor_mock - _setup_instrumentations(instrumentations) + _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)]) @@ -507,12 +320,12 @@ def test_setup_instrumentations_lib_not_found( getattr_mock, ): with patch("importlib.import_module") as import_module_mock: - instrumentations = ["non_supported_lib"] + 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(instrumentations) + _setup_instrumentations(configurations) import_module_mock.assert_not_called() instrumentor_mock.assert_not_called() instrument_mock.instrument.assert_not_called() @@ -527,12 +340,12 @@ def test_setup_instrumentations_import_lib_failed( "importlib.import_module", side_effect=ImportError() ) as import_module_mock: - instrumentations = [lib_name] + configurations = {"instrumentations": [lib_name]} instrument_mock = Mock() instrumentor_mock = Mock() instrumentor_mock.return_value = instrument_mock getattr_mock.return_value = instrumentor_mock - _setup_instrumentations(instrumentations) + _setup_instrumentations(configurations) import_module_mock.assert_called_once() instrumentor_mock.assert_not_called() instrument_mock.instrument.assert_not_called() @@ -544,13 +357,13 @@ def test_setup_instrumentations_import_instr_failed( ): for lib_name in _SUPPORTED_INSTRUMENTED_LIBRARIES: with patch("importlib.import_module") as import_module_mock: - instrumentations = [lib_name] + 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(instrumentations) + _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() @@ -563,12 +376,12 @@ def test_setup_instrumentations_failed_general( ): for lib_name in _SUPPORTED_INSTRUMENTED_LIBRARIES: with patch("importlib.import_module") as import_module_mock: - instrumentations = [lib_name] + configurations = {"instrumentations": [lib_name]} instrument_mock = Mock() instrumentor_mock = Mock() instrumentor_mock.return_value = instrument_mock getattr_mock.side_effect = Exception() - _setup_instrumentations(instrumentations) + _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)]) From 241ba2df3845940c5ae52113d1fe51fa94b2ec1a Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Tue, 24 Jan 2023 11:54:29 -0800 Subject: [PATCH 3/6] lint --- CHANGELOG.md | 2 +- .../monitor/opentelemetry/distro/__init__.py | 80 ++++++++++--------- .../samples/tracing/client.py | 2 +- .../samples/tracing/db_psycopg2.py | 3 +- .../tracing/django/sample/example/__init__.py | 2 +- .../tracing/django/sample/example/apps.py | 4 +- .../sample/example/migrations/__init__.py | 2 +- .../tracing/django/sample/example/urls.py | 4 +- .../tracing/django/sample/example/views.py | 4 +- .../samples/tracing/django/sample/manage.py | 4 +- .../tracing/django/sample/sample/__init__.py | 2 +- .../tracing/django/sample/sample/asgi.py | 3 +- .../tracing/django/sample/sample/settings.py | 76 +++++++++--------- .../tracing/django/sample/sample/urls.py | 2 +- .../tracing/django/sample/sample/wsgi.py | 2 +- .../samples/tracing/server_flask.py | 2 +- .../tests/configuration/test_configure.py | 50 ++++++------ 17 files changed, 124 insertions(+), 120 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5507aeb..c62bb239 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ - Add Logging configuration to Distro API ([#218](https://github.com/microsoft/ApplicationInsights-Python/pull/218)) - Add instrumentation selection config - ([#220](https://github.com/microsoft/ApplicationInsights-Python/pull/220)) + ([#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 diff --git a/azure-monitor-opentelemetry-distro/azure/monitor/opentelemetry/distro/__init__.py b/azure-monitor-opentelemetry-distro/azure/monitor/opentelemetry/distro/__init__.py index b1f786d6..dccff7be 100644 --- a/azure-monitor-opentelemetry-distro/azure/monitor/opentelemetry/distro/__init__.py +++ b/azure-monitor-opentelemetry-distro/azure/monitor/opentelemetry/distro/__init__.py @@ -4,9 +4,8 @@ # license information. # -------------------------------------------------------------------------- import importlib - -from typing import Any, Dict 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 ( @@ -52,7 +51,7 @@ def configure_azure_monitor(**kwargs): resource = None if not disable_logging or not disable_tracing: - resource = _get_resource(configurations) + resource = _get_resource(configurations) # Setup tracing pipeline if not disable_tracing: @@ -73,12 +72,12 @@ def _get_resource(configurations: Dict[str, Any]) -> Resource: service_namespace = configurations.get("service_namespace", "") service_instance_id = configurations.get("service_instance_id", "") return Resource.create( - { - ResourceAttributes.SERVICE_NAME: service_name, - ResourceAttributes.SERVICE_NAMESPACE: service_namespace, - ResourceAttributes.SERVICE_INSTANCE_ID: service_instance_id, - } - ) + { + ResourceAttributes.SERVICE_NAME: service_name, + ResourceAttributes.SERVICE_NAMESPACE: service_namespace, + ResourceAttributes.SERVICE_INSTANCE_ID: service_instance_id, + } + ) def _setup_tracing(resource: Resource, configurations: Dict[str, Any]): @@ -87,9 +86,9 @@ def _setup_tracing(resource: Resource, configurations: Dict[str, Any]): "tracing_export_interval_millis", 30000 ) tracer_provider = TracerProvider( - sampler=ApplicationInsightsSampler(sampling_ratio=sampling_ratio), - resource=resource, - ) + sampler=ApplicationInsightsSampler(sampling_ratio=sampling_ratio), + resource=resource, + ) set_tracer_provider(tracer_provider) trace_exporter = AzureMonitorTraceExporter(**configurations) span_processor = BatchSpanProcessor( @@ -122,31 +121,34 @@ 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 as ex: - _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) - finally: - continue + 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) + _logger.warning( + "Instrumentation not supported for library: %s.", lib_name + ) diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/client.py b/azure-monitor-opentelemetry-distro/samples/tracing/client.py index 4529b973..5c6730ef 100644 --- a/azure-monitor-opentelemetry-distro/samples/tracing/client.py +++ b/azure-monitor-opentelemetry-distro/samples/tracing/client.py @@ -4,8 +4,8 @@ # license information. # -------------------------------------------------------------------------- import logging -import requests +import requests from azure.monitor.opentelemetry.distro import configure_azure_monitor from opentelemetry import trace diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/db_psycopg2.py b/azure-monitor-opentelemetry-distro/samples/tracing/db_psycopg2.py index a2837750..909a1ae4 100644 --- a/azure-monitor-opentelemetry-distro/samples/tracing/db_psycopg2.py +++ b/azure-monitor-opentelemetry-distro/samples/tracing/db_psycopg2.py @@ -4,7 +4,6 @@ # license information. # -------------------------------------------------------------------------- import psycopg2 - from azure.monitor.opentelemetry.distro import configure_azure_monitor # Configure Azure monitor collection telemetry pipeline @@ -16,7 +15,7 @@ disable_logging=True, ) -cnx = psycopg2.connect(database='test', user="", password="") +cnx = psycopg2.connect(database="test", user="", password="") cursor = cnx.cursor() cursor.execute("INSERT INTO test_tables (test_field) VALUES (123)") cursor.close() diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/__init__.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/__init__.py index 6fcf0de4..5b7f7a92 100644 --- a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/__init__.py +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/__init__.py @@ -1,2 +1,2 @@ # Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. \ No newline at end of file +# Licensed under the MIT License. diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/apps.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/apps.py index 79d02ec3..cfad6058 100644 --- a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/apps.py +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/apps.py @@ -4,5 +4,5 @@ class ExampleConfig(AppConfig): - default_auto_field = 'django.db.models.BigAutoField' - name = 'example' + default_auto_field = "django.db.models.BigAutoField" + name = "example" diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/migrations/__init__.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/migrations/__init__.py index 6fcf0de4..5b7f7a92 100644 --- a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/migrations/__init__.py +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/migrations/__init__.py @@ -1,2 +1,2 @@ # Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. \ No newline at end of file +# Licensed under the MIT License. diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/urls.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/urls.py index 443b11cb..27499cbf 100644 --- a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/urls.py +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/urls.py @@ -5,6 +5,6 @@ from . import views urlpatterns = [ - path('', views.index, name='index'), - path('exception', views.exception, name='exception'), + path("", views.index, name="index"), + path("exception", views.exception, name="exception"), ] diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/views.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/views.py index 7c23e3cd..05da83b4 100644 --- a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/views.py +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/example/views.py @@ -4,9 +4,8 @@ # license information. # -------------------------------------------------------------------------- -from django.http import HttpResponse - from azure.monitor.opentelemetry.distro import configure_azure_monitor +from django.http import HttpResponse # Configure Azure monitor collection telemetry pipeline configure_azure_monitor( @@ -21,6 +20,7 @@ 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.") diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/manage.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/manage.py index 7f20d97d..5d854eb0 100644 --- a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/manage.py +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/manage.py @@ -8,7 +8,7 @@ def main(): """Run administrative tasks.""" - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sample.settings') + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sample.settings") try: from django.core.management import execute_from_command_line @@ -21,5 +21,5 @@ def main(): execute_from_command_line(sys.argv) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/__init__.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/__init__.py index 6fcf0de4..5b7f7a92 100644 --- a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/__init__.py +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/__init__.py @@ -1,2 +1,2 @@ # Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. \ No newline at end of file +# Licensed under the MIT License. diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/asgi.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/asgi.py index 7caf941a..90020111 100644 --- a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/asgi.py +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/asgi.py @@ -14,9 +14,8 @@ from django.core.asgi import get_asgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sample.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sample.settings") application = get_asgi_application() # cSpell:enable - diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/settings.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/settings.py index 177e83d3..27456feb 100644 --- a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/settings.py +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/settings.py @@ -24,7 +24,9 @@ # 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' +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 @@ -35,52 +37,52 @@ # Application definition INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', + "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', + "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' +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', + "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' +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', + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", } } @@ -90,16 +92,16 @@ AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, ] @@ -107,9 +109,9 @@ # Internationalization # https://docs.djangoproject.com/en/3.2/topics/i18n/ -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = "en-us" -TIME_ZONE = 'UTC' +TIME_ZONE = "UTC" USE_I18N = True @@ -121,11 +123,11 @@ # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.2/howto/static-files/ -STATIC_URL = '/static/' +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' +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" -# cSpell:enable \ No newline at end of file +# cSpell:enable diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/urls.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/urls.py index 5714ebcf..851a91e5 100644 --- a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/urls.py +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/urls.py @@ -18,5 +18,5 @@ from django.urls import include, path urlpatterns = [ - path('', include('example.urls')), + path("", include("example.urls")), ] diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/wsgi.py b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/wsgi.py index 34f760be..1d473397 100644 --- a/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/wsgi.py +++ b/azure-monitor-opentelemetry-distro/samples/tracing/django/sample/sample/wsgi.py @@ -13,6 +13,6 @@ from django.core.wsgi import get_wsgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sample.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sample.settings") application = get_wsgi_application() diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/server_flask.py b/azure-monitor-opentelemetry-distro/samples/tracing/server_flask.py index 2ba12246..5ff0c5da 100644 --- a/azure-monitor-opentelemetry-distro/samples/tracing/server_flask.py +++ b/azure-monitor-opentelemetry-distro/samples/tracing/server_flask.py @@ -4,7 +4,6 @@ # license information. # -------------------------------------------------------------------------- import flask - from azure.monitor.opentelemetry.distro import configure_azure_monitor # Configure Azure monitor collection telemetry pipeline @@ -23,6 +22,7 @@ def test(): return "Test flask request" + # Exceptions that are raised within the request are automatically captured @app.route("/exception") def exception(): diff --git a/azure-monitor-opentelemetry-distro/tests/configuration/test_configure.py b/azure-monitor-opentelemetry-distro/tests/configuration/test_configure.py index 5cb3f8b3..ec7c3016 100644 --- a/azure-monitor-opentelemetry-distro/tests/configuration/test_configure.py +++ b/azure-monitor-opentelemetry-distro/tests/configuration/test_configure.py @@ -13,15 +13,15 @@ # limitations under the License. import unittest -from unittest.mock import Mock, patch, call +from unittest.mock import Mock, call, patch from azure.monitor.opentelemetry.distro import ( - configure_azure_monitor, + _SUPPORTED_INSTRUMENTED_LIBRARIES, _get_resource, _setup_instrumentations, _setup_logging, _setup_tracing, - _SUPPORTED_INSTRUMENTED_LIBRARIES, + configure_azure_monitor, ) from opentelemetry.semconv.resource import ResourceAttributes @@ -105,7 +105,6 @@ def test_configure_azure_monitor_disable_tracing( logging_mock.assert_called_once_with(resource_init_mock, kwargs) instrumentation_mock.assert_called_once_with(kwargs) - @patch( "azure.monitor.opentelemetry.distro._setup_instrumentations", ) @@ -145,7 +144,6 @@ def test_configure_azure_monitor_disable_logging( logging_mock.assert_not_called() instrumentation_mock.assert_called_once_with(kwargs) - @patch( "azure.monitor.opentelemetry.distro.Resource", ) @@ -155,12 +153,14 @@ def test_get_resource(self, resource_mock): "service_namespace": "test_namespace", "service_instance_id": "test_id", } - resource = _get_resource(configuration) - resource_mock.create.assert_called_once_with({ - ResourceAttributes.SERVICE_NAME: "test_service_name", - ResourceAttributes.SERVICE_NAMESPACE: "test_namespace", - ResourceAttributes.SERVICE_INSTANCE_ID: "test_id", - }) + _get_resource(configuration) + resource_mock.create.assert_called_once_with( + { + ResourceAttributes.SERVICE_NAME: "test_service_name", + ResourceAttributes.SERVICE_NAMESPACE: "test_namespace", + ResourceAttributes.SERVICE_INSTANCE_ID: "test_id", + } + ) @patch( "azure.monitor.opentelemetry.distro.BatchSpanProcessor", @@ -221,7 +221,6 @@ def test_setup_tracing( ) tp_init_mock.add_span_processor(bsp_init_mock) - @patch( "azure.monitor.opentelemetry.distro.getLogger", ) @@ -294,10 +293,9 @@ def test_setup_logging( logging_handler_init_mock ) - @patch("azure.monitor.opentelemetry.distro.getattr") def test_setup_instrumentations( - self, + self, getattr_mock, ): for lib_name in _SUPPORTED_INSTRUMENTED_LIBRARIES: @@ -310,13 +308,15 @@ def test_setup_instrumentations( _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)]) + import_module_mock.assert_has_calls( + [call(lib_name), call(instr_lib_name)] + ) instrumentor_mock.assert_called_once() instrument_mock.instrument.assert_called_once() @patch("azure.monitor.opentelemetry.distro.getattr") def test_setup_instrumentations_lib_not_found( - self, + self, getattr_mock, ): with patch("importlib.import_module") as import_module_mock: @@ -332,13 +332,12 @@ def test_setup_instrumentations_lib_not_found( @patch("azure.monitor.opentelemetry.distro.getattr") def test_setup_instrumentations_import_lib_failed( - self, + self, getattr_mock, ): for lib_name in _SUPPORTED_INSTRUMENTED_LIBRARIES: with patch( - "importlib.import_module", - side_effect=ImportError() + "importlib.import_module", side_effect=ImportError() ) as import_module_mock: configurations = {"instrumentations": [lib_name]} instrument_mock = Mock() @@ -352,7 +351,7 @@ def test_setup_instrumentations_import_lib_failed( @patch("azure.monitor.opentelemetry.distro.getattr") def test_setup_instrumentations_import_instr_failed( - self, + self, getattr_mock, ): for lib_name in _SUPPORTED_INSTRUMENTED_LIBRARIES: @@ -365,13 +364,15 @@ def test_setup_instrumentations_import_instr_failed( 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)]) + 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, + self, getattr_mock, ): for lib_name in _SUPPORTED_INSTRUMENTED_LIBRARIES: @@ -384,7 +385,8 @@ def test_setup_instrumentations_failed_general( _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)]) + import_module_mock.assert_has_calls( + [call(lib_name), call(instr_lib_name)] + ) instrumentor_mock.assert_not_called() instrument_mock.instrument.assert_not_called() - From 2f4de3ee67da96e73e07c73ee02c99008661df2c Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Tue, 24 Jan 2023 12:00:00 -0800 Subject: [PATCH 4/6] Update .flake8 --- .flake8 | 1 + 1 file changed, 1 insertion(+) diff --git a/.flake8 b/.flake8 index 6180ee0a..a3e2e7a3 100644 --- a/.flake8 +++ b/.flake8 @@ -21,6 +21,7 @@ exclude = CVS .venv*/ venv*/ + samples/* target __pycache__ */build/lib/* From 5e498cfbb427512897373d01891fa757ed6d9d51 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Tue, 24 Jan 2023 12:18:33 -0800 Subject: [PATCH 5/6] Update .flake8 --- .flake8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.flake8 b/.flake8 index a3e2e7a3..9ec8d18b 100644 --- a/.flake8 +++ b/.flake8 @@ -21,7 +21,7 @@ exclude = CVS .venv*/ venv*/ - samples/* + */samples/* target __pycache__ */build/lib/* From 5c32d631dbe0a7336d5b662ef684308071dcc8e6 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Wed, 25 Jan 2023 12:55:37 -0800 Subject: [PATCH 6/6] Update db_psycopg2.py --- .../samples/tracing/db_psycopg2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-monitor-opentelemetry-distro/samples/tracing/db_psycopg2.py b/azure-monitor-opentelemetry-distro/samples/tracing/db_psycopg2.py index 909a1ae4..79a3c5b7 100644 --- a/azure-monitor-opentelemetry-distro/samples/tracing/db_psycopg2.py +++ b/azure-monitor-opentelemetry-distro/samples/tracing/db_psycopg2.py @@ -10,9 +10,9 @@ configure_azure_monitor( connection_string="", service_name="psycopg2_service_name", + disable_logging=True, instrumentations=["psycopg2"], tracing_export_interval_millis=15000, - disable_logging=True, ) cnx = psycopg2.connect(database="test", user="", password="")