Початок роботи

Отримайте телеметрію для вашого застосунку менш ніж за 5 хвилин!

Ця сторінка покаже вам, як почати роботу з OpenTelemetry у Python.

Ви дізнаєтесь, як можна автоматично інструментувати простий застосунок так, щоб трейси, метрики та логи виводилися в консоль.

Передумови

Переконайтеся, що у вас встановлено наступне:

Приклад застосунку

Наступний приклад використовує базовий застосунок Flask. Якщо ви не використовуєте Flask, це не проблема, ви можете використовувати OpenTelemetry Python з іншими веб-фреймворками, такими як Django та FastAPI. Для повного списку бібліотек для підтримуваних фреймворків дивіться реєстр.

Для складніших прикладів дивіться приклади.

Встановлення

Для початку створіть середовище в новій теці:

mkdir otel-getting-started cd otel-getting-started python3 -m venv venv source ./venv/bin/activate

Тепер встановіть Flask:

pip install flask

Створення та запуск HTTP сервера

Створіть файл app.py та додайте до нього наступний код:

from random import randint from flask import Flask, request import logging app = Flask(__name__) logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) @app.route("/rolldice") def roll_dice(): player = request.args.get('гравець', default=None, type=str) result = str(roll()) if player: logger.warning("%s кидає кубик: %s", player, result) else: logger.warning("Анонімний гравець кидає кубик: %s", result) return result def roll(): return randint(1, 6)

Запустіть застосунок за допомогою наступної команди та відкрийте http://localhost:8080/rolldice у вашому вебоглядачі, щоб переконатися, що він працює.

flask run -p 8080

Інструментування

Інструментування без коду буде генерувати телеметричні дані від вашого імені. Є кілька варіантів, які ви можете використовувати, детальніше описані в Інструментування без коду. Тут ми будемо використовувати агент opentelemetry-instrument.

Встановіть пакунок opentelemetry-distro, який містить API OpenTelemetry, SDK, а також інструменти opentelemetry-bootstrap та opentelemetry-instrument, які ви будете використовувати нижче.

pip install opentelemetry-distro

Запустіть команду opentelemetry-bootstrap:

opentelemetry-bootstrap -a install

Це встановить інструментування Flask.

Запуск інструментованого застосунку

Тепер ви можете запустити ваш інструментований застосунок за допомогою opentelemetry-instrument і вивести його в консоль:

export OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true opentelemetry-instrument \ --traces_exporter console \ --metrics_exporter console \ --logs_exporter console \ --service_name dice-server \ flask run -p 8080

Відкрийте http://localhost:8080/rolldice у вашому вебоглядачі та перезавантажте сторінку кілька разів. Через деякий час ви побачите, що відрізки виводяться в консоль, наприклад:

Переглянути приклад виводу
{ "name": "/rolldice", "context": { "trace_id": "0xdb1fc322141e64eb84f5bd8a8b1c6d1f", "span_id": "0x5c2b0f851030d17d", "trace_state": "[]" }, "kind": "SpanKind.SERVER", "parent_id": null, "start_time": "2023-10-10T08:14:32.630332Z", "end_time": "2023-10-10T08:14:32.631523Z", "status": { "status_code": "UNSET" }, "attributes": { "http.method": "GET", "http.server_name": "127.0.0.1", "http.scheme": "http", "net.host.port": 8080, "http.host": "localhost:8080", "http.target": "/rolldice?rolls=12", "net.peer.ip": "127.0.0.1", "http.user_agent": "curl/8.1.2", "net.peer.port": 58419, "http.flavor": "1.1", "http.route": "/rolldice", "http.status_code": 200 }, "events": [], "links": [], "resource": { "attributes": { "telemetry.sdk.language": "python", "telemetry.sdk.name": "opentelemetry", "telemetry.sdk.version": "1.17.0", "service.name": "dice-server", "telemetry.auto.version": "0.38b0" }, "schema_url": "" } } { "body": "Анонімний гравець кидає кубик: 3", "severity_number": "<SeverityNumber.WARN: 13>", "severity_text": "WARNING", "attributes": { "otelSpanID": "5c2b0f851030d17d", "otelTraceID": "db1fc322141e64eb84f5bd8a8b1c6d1f", "otelServiceName": "dice-server" }, "timestamp": "2023-10-10T08:14:32.631195Z", "trace_id": "0xdb1fc322141e64eb84f5bd8a8b1c6d1f", "span_id": "0x5c2b0f851030d17d", "trace_flags": 1, "resource": "BoundedAttributes({'telemetry.sdk.language': 'python', 'telemetry.sdk.name': 'opentelemetry', 'telemetry.sdk.version': '1.17.0', 'service.name': 'dice-server', 'telemetry.auto.version': '0.38b0'}, maxlen=None)" }

Згенерований відрізок відстежує тривалість запиту до маршруту /rolldice.

Рядок журналу, що виводиться під час запиту, містить той самий ідентифікатор трейсу та відрізка і експортується в консоль через експортер журналів.

Надішліть ще кілька запитів до точки доступу, а потім або зачекайте трохи, або завершіть роботу застосунку, і ви побачите метрики у виводі консолі, наприклад:

Переглянути приклад виводу
{ "resource_metrics": [ { "resource": { "attributes": { "service.name": "unknown_service", "telemetry.auto.version": "0.34b0", "telemetry.sdk.language": "python", "telemetry.sdk.name": "opentelemetry", "telemetry.sdk.version": "1.13.0" }, "schema_url": "" }, "schema_url": "", "scope_metrics": [ { "metrics": [ { "data": { "aggregation_temporality": 2, "data_points": [ { "attributes": { "http.flavor": "1.1", "http.host": "localhost:5000", "http.method": "GET", "http.scheme": "http", "http.server_name": "127.0.0.1" }, "start_time_unix_nano": 1666077040061693305, "time_unix_nano": 1666077098181107419, "value": 0 } ], "is_monotonic": false }, "description": "вимірює кількість одночасних HTTP-запитів, які зараз виконуються", "name": "http.server.active_requests", "unit": "requests" }, { "data": { "aggregation_temporality": 2, "data_points": [ { "attributes": { "http.flavor": "1.1", "http.host": "localhost:5000", "http.method": "GET", "http.scheme": "http", "http.server_name": "127.0.0.1", "http.status_code": 200, "net.host.port": 5000 }, "bucket_counts": [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], "count": 1, "explicit_bounds": [ 0, 5, 10, 25, 50, 75, 100, 250, 500, 1000 ], "max": 1, "min": 1, "start_time_unix_nano": 1666077040063027610, "sum": 1, "time_unix_nano": 1666077098181107419 } ] }, "description": "вимірює тривалість вхідного HTTP-запиту", "name": "http.server.duration", "unit": "ms" } ], "schema_url": "", "scope": { "name": "opentelemetry.instrumentation.flask", "schema_url": "", "version": "0.34b0" } } ] } ] }

Додайте ручне інструментування до автоматичного інструментування

Автоматичне інструментування захоплює телеметрію на краях ваших систем, таких як вхідні та вихідні HTTP-запити, але не захоплює те, що відбувається у вашому застосунку. Для цього вам потрібно написати деяке ручне інструментування. Ось як ви можете легко звʼязати ручне інструментування з автоматичним інструментуванням.

Трейси

Спочатку змініть app.py, щоб включити код, який ініціалізує трасувальник і використовує його для створення трейсу, який є дочірнім до автоматично згенерованого:

from random import randint from flask import Flask from opentelemetry import trace # Отримайте трасувальник tracer = trace.get_tracer("diceroller.tracer") app = Flask(__name__) @app.route("/rolldice") def roll_dice(): return str(roll()) def roll(): # Це створює новий відрізок, який є дочірнім до поточного with tracer.start_as_current_span("roll") as rollspan: res = randint(1, 6) rollspan.set_attribute("roll.value", res) return res

Тепер знову запустіть застосунок:

export OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true opentelemetry-instrument \ --traces_exporter console \ --metrics_exporter console \ --logs_exporter console \ --service_name dice-server \ flask run -p 8080

Коли ви надішлете запит до сервера, ви побачите два відрізки у трейсі, що виводиться в консоль, і той, що називається roll, реєструє свого батька як автоматично створеного:

Переглянути приклад виводу
{ "name": "roll", "context": { "trace_id": "0x6f781c83394ed2f33120370a11fced47", "span_id": "0x623321c35b8fa837", "trace_state": "[]" }, "kind": "SpanKind.INTERNAL", "parent_id": "0x09abe52faf1d80d5", "start_time": "2023-10-10T08:18:28.679261Z", "end_time": "2023-10-10T08:18:28.679560Z", "status": { "status_code": "UNSET" }, "attributes": { "roll.value": "6" }, "events": [], "links": [], "resource": { "attributes": { "telemetry.sdk.language": "python", "telemetry.sdk.name": "opentelemetry", "telemetry.sdk.version": "1.17.0", "service.name": "dice-server", "telemetry.auto.version": "0.38b0" }, "schema_url": "" } } { "name": "/rolldice", "context": { "trace_id": "0x6f781c83394ed2f33120370a11fced47", "span_id": "0x09abe52faf1d80d5", "trace_state": "[]" }, "kind": "SpanKind.SERVER", "parent_id": null, "start_time": "2023-10-10T08:18:28.678348Z", "end_time": "2023-10-10T08:18:28.679677Z", "status": { "status_code": "UNSET" }, "attributes": { "http.method": "GET", "http.server_name": "127.0.0.1", "http.scheme": "http", "net.host.port": 8080, "http.host": "localhost:8080", "http.target": "/rolldice?rolls=12", "net.peer.ip": "127.0.0.1", "http.user_agent": "curl/8.1.2", "net.peer.port": 58485, "http.flavor": "1.1", "http.route": "/rolldice", "http.status_code": 200 }, "events": [], "links": [], "resource": { "attributes": { "telemetry.sdk.language": "python", "telemetry.sdk.name": "opentelemetry", "telemetry.sdk.version": "1.17.0", "service.name": "dice-server", "telemetry.auto.version": "0.38b0" }, "schema_url": "" } }

parent_id для roll збігається з span_id для /rolldice, що вказує на відношення пращур-нащадок!

Метрики

Тепер змініть app.py, щоб включити код, який ініціалізує вимірювач і використовує його для створення лічильника, який рахує кількість кидків для кожного можливого значення кидка:

# Це необхідні імпортні декларації from opentelemetry import trace from opentelemetry import metrics from random import randint from flask import Flask, request import logging # Отримайте трасувальник tracer = trace.get_tracer("diceroller.tracer") # Отримайте вимірювача meter = metrics.get_meter("diceroller.meter") # Тепер створіть лічильник для вимірювань roll_counter = meter.create_counter( "dice.rolls", description="Кількість кидків за значенням кидка", ) app = Flask(__name__) logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) @app.route("/rolldice") def roll_dice(): # Це створює новий відрізок, який є дочірнім до поточного with tracer.start_as_current_span("roll") as roll_span: player = request.args.get('гравець', default = None, type = str) result = str(roll()) roll_span.set_attribute("roll.value", result) # Це додає 1 до лічильника для даного значення кидка roll_counter.add(1, {"roll.value": result}) if player: logger.warn("%s кидає кубик: %s", player, result) else: logger.warn("Анонімний гравець кидає кубик: %s", result) return result def roll(): return randint(1, 6)

Тепер знову запустіть застосунок:

export OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true opentelemetry-instrument \ --traces_exporter console \ --metrics_exporter console \ --logs_exporter console \ --service_name dice-server \ flask run -p 8080

Коли ви надішлете запит до сервера, ви побачите лічильник метрик кидків, що виводиться в консоль, з окремими підрахунками для кожного значення кидка:

Переглянути приклад виводу
{ "resource_metrics": [ { "resource": { "attributes": { "telemetry.sdk.language": "python", "telemetry.sdk.name": "opentelemetry", "telemetry.sdk.version": "1.17.0", "service.name": "dice-server", "telemetry.auto.version": "0.38b0" }, "schema_url": "" }, "scope_metrics": [ { "scope": { "name": "opentelemetry.instrumentation.flask", "version": "0.38b0", "schema_url": "" }, "metrics": [ { "name": "http.server.active_requests", "description": "вимірює кількість одночасних HTTP-запитів, які зараз виконуються", "unit": "requests", "data": { "data_points": [ { "attributes": { "http.method": "GET", "http.host": "localhost:8080", "http.scheme": "http", "http.flavor": "1.1", "http.server_name": "127.0.0.1" }, "start_time_unix_nano": 1696926005694857000, "time_unix_nano": 1696926063549782000, "value": 0 } ], "aggregation_temporality": 2, "is_monotonic": false } }, { "name": "http.server.duration", "description": "вимірює тривалість вхідного HTTP-запиту", "unit": "ms", "data": { "data_points": [ { "attributes": { "http.method": "GET", "http.host": "localhost:8080", "http.scheme": "http", "http.flavor": "1.1", "http.server_name": "127.0.0.1", "net.host.port": 8080, "http.status_code": 200 }, "start_time_unix_nano": 1696926005695798000, "time_unix_nano": 1696926063549782000, "count": 7, "sum": 6, "bucket_counts": [ 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], "explicit_bounds": [ 0.0, 5.0, 10.0, 25.0, 50.0, 75.0, 100.0, 250.0, 500.0, 750.0, 1000.0, 2500.0, 5000.0, 7500.0, 10000.0 ], "min": 0, "max": 1 } ], "aggregation_temporality": 2 } } ], "schema_url": "" }, { "scope": { "name": "diceroller.meter", "version": "", "schema_url": "" }, "metrics": [ { "name": "dice.rolls", "description": "Кількість кидків за значенням кидка", "unit": "", "data": { "data_points": [ { "attributes": { "roll.value": "5" }, "start_time_unix_nano": 1696926005695491000, "time_unix_nano": 1696926063549782000, "value": 3 }, { "attributes": { "roll.value": "6" }, "start_time_unix_nano": 1696926005695491000, "time_unix_nano": 1696926063549782000, "value": 1 }, { "attributes": { "roll.value": "1" }, "start_time_unix_nano": 1696926005695491000, "time_unix_nano": 1696926063549782000, "value": 1 }, { "attributes": { "roll.value": "3" }, "start_time_unix_nano": 1696926005695491000, "time_unix_nano": 1696926063549782000, "value": 1 }, { "attributes": { "roll.value": "4" }, "start_time_unix_nano": 1696926005695491000, "time_unix_nano": 1696926063549782000, "value": 1 } ], "aggregation_temporality": 2, "is_monotonic": true } } ], "schema_url": "" } ], "schema_url": "" } ] }

Надсилання телеметрії до OpenTelemetry Collector

OpenTelemetry Collector є критичним компонентом більшості промислових розгортань. Ось деякі приклади, коли корисно використовувати колектор:

  • Єдиний приймач телеметрії, який використовується кількома сервісами, щоб зменшити накладні витрати на перемикання експортерів
  • Агрегація трейсів між кількома сервісами, що працюють на кількох хостах
  • Центральне місце для обробки трейсів перед їх експортом до бекенду

Якщо у вас є лише один сервіс або ви експериментуєте, вам знадобиться колектор у промислових розгортаннях.

Налаштування та запуск локального колектора

Спочатку збережіть наступний конфігураційний код колектора у файл у теку /tmp/:

# /tmp/otel-collector-config.yaml receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 exporters: # NOTE: Prior to v0.86.0 use `logging` instead of `debug`. debug: verbosity: detailed service: pipelines: traces: receivers: [otlp] exporters: [debug] metrics: receivers: [otlp] exporters: [debug] logs: receivers: [otlp] exporters: [debug]

Потім запустіть команду docker, щоб отримати та запустити колектор на основі цієї конфігурації:

docker run -p 4317:4317 \ -v /tmp/otel-collector-config.yaml:/etc/otel-collector-config.yaml \ otel/opentelemetry-collector:latest \ --config=/etc/otel-collector-config.yaml

Тепер у вас буде запущено локальний екземпляр колектора, який слухає на порту 4317.

Змініть команду для експорту відрізків та метрик через OTLP

Наступний крок — змінити команду для надсилання відрізків та метрик до колектора через OTLP замість консолі.

Для цього встановіть пакунок експортера OTLP:

pip install opentelemetry-exporter-otlp

Агент opentelemetry-instrument виявить пакунок, який ви щойно встановили, і використовуватиме OTLP експортер при наступному запуску.

Запуск застосунку

Запустіть застосунок, як раніше, але не експортуйте до консолі:

export OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true opentelemetry-instrument --logs_exporter otlp flask run -p 8080

Стандартно opentelemetry-instrument експортує трейси та метрики через OTLP/gRPC і надсилатиме їх на localhost:4317, саме туди де слухає колектор.

Коли ви зараз звертаєтесь до маршруту /rolldice, ви побачите вивід у процесі колектора замість процесу flask, який виглядатиме приблизно так:

Переглянути приклад виводу
2022-06-09T20:43:39.915Z DEBUG debugexporter/debug_exporter.go:51 ResourceSpans #0 Resource labels: -> telemetry.sdk.language: STRING(python) -> telemetry.sdk.name: STRING(opentelemetry) -> telemetry.sdk.version: STRING(1.12.0rc1) -> telemetry.auto.version: STRING(0.31b0) -> service.name: STRING(unknown_service) InstrumentationLibrarySpans #0 InstrumentationLibrary app Span #0 Trace ID : 7d4047189ac3d5f96d590f974bbec20a Parent ID : 0b21630539446c31 ID : 4d18cee9463a79ba Name : roll Kind : SPAN_KIND_INTERNAL Start time : 2022-06-09 20:43:37.390134089 +0000 UTC End time : 2022-06-09 20:43:37.390327687 +0000 UTC Status code : STATUS_CODE_UNSET Status message : Attributes: -> roll.value: INT(5) InstrumentationLibrarySpans #1 InstrumentationLibrary opentelemetry.instrumentation.flask 0.31b0 Span #0 Trace ID : 7d4047189ac3d5f96d590f974bbec20a Parent ID : ID : 0b21630539446c31 Name : /rolldice Kind : SPAN_KIND_SERVER Start time : 2022-06-09 20:43:37.388733595 +0000 UTC End time : 2022-06-09 20:43:37.390723792 +0000 UTC Status code : STATUS_CODE_UNSET Status message : Attributes: -> http.method: STRING(GET) -> http.server_name: STRING(127.0.0.1) -> http.scheme: STRING(http) -> net.host.port: INT(5000) -> http.host: STRING(localhost:5000) -> http.target: STRING(/rolldice) -> net.peer.ip: STRING(127.0.0.1) -> http.user_agent: STRING(curl/7.82.0) -> net.peer.port: INT(53878) -> http.flavor: STRING(1.1) -> http.route: STRING(/rolldice) -> http.status_code: INT(200) 2022-06-09T20:43:40.025Z INFO debugexporter/debug_exporter.go:56 MetricsExporter {"#metrics": 1} 2022-06-09T20:43:40.025Z DEBUG debugexporter/debug_exporter.go:66 ResourceMetrics #0 Resource labels: -> telemetry.sdk.language: STRING(python) -> telemetry.sdk.name: STRING(opentelemetry) -> telemetry.sdk.version: STRING(1.12.0rc1) -> telemetry.auto.version: STRING(0.31b0) -> service.name: STRING(unknown_service) InstrumentationLibraryMetrics #0 InstrumentationLibrary app Metric #0 Descriptor: -> Name: roll_counter -> Description: The number of rolls by roll value -> Unit: -> DataType: Sum -> IsMonotonic: true -> AggregationTemporality: AGGREGATION_TEMPORALITY_CUMULATIVE NumberDataPoints #0 Data point attributes: -> roll.value: INT(5) StartTimestamp: 2022-06-09 20:43:37.390226915 +0000 UTC Timestamp: 2022-06-09 20:43:39.848587966 +0000 UTC Value: 1

Наступні кроки

Є кілька варіантів для автоматичного інструментування та Python. Дивіться Інструментування без коду, щоб дізнатися про них та як їх налаштувати.

Є багато більше до ручного інструментування, ніж просто створення дочірнього відрізку. Щоб дізнатися деталі про ініціалізацію ручного інструментування та багато інших частин API OpenTelemetry, які ви можете використовувати, дивіться Ручне інструментування.

Є кілька варіантів для експорту ваших телеметричних даних з OpenTelemetry. Щоб дізнатися, як експортувати ваші дані до бажаного бекенду, дивіться Експортери.

Якщо ви хочете дослідити складніший приклад, подивіться на Демо OpenTelemetry, яке включає основані на Python Сервіс рекомендацій та Генератор навантаження.


Востаннє змінено December 26, 2024: [uk] Ukrainian documentation for OpenTelemetry (bd70b52d)