Мониторинг Python приложений с помощью Proto Observability Platform

Подключение трейсинга и сбора метрик для Python приложений.

На этой странице:

Введение

Общий процесс подключения Python приложения на мониторинг:

  1. Установка ProtoOBP Агента.
  2. Установка трейсера.
  3. Конфигурация трейсера (опционально).

После подключения будут доступны все возможности модуля Application Performance Monitoring Proto Observability Platform.

Установка Python трейсера

  1. Установите библиотеку pobptrace выполнив:

    pip install pobptrace --user --index-url "https://<token_name>:<token_key>@git.proto.group/api/v4/projects/125/packages/pypi/simple"
    

    Пример для Dockerfile и .gitlab-ci.yml:

    • в настройках проекта в Gitlab добавьте две переменные окружения (Проект -> Settings -> CI/CD -> Variables):

      • имя: PROTOOBP_INSTALL_TOKEN_NAME, значение = ваши данные из лицензионного сертификата (token или логин)
      • имя: PROTOOBP_INSTALL_TOKEN_KEY, значение = ваши данные из лицензионного сертификата (пароль)

    Имя и значение токена находятся в вашем лицензионном сертификате Proto Observability Platform.

    • .gitlab-ci.yml – необходимо передать значения переменных от Gitlab CI к docker build через --build-arg:

        script:
          - docker build --build-arg PROTOOBP_INSTALL_TOKEN_NAME=${PROTOOBP_INSTALL_TOKEN_NAME} --build-arg PROTOOBP_INSTALL_TOKEN_KEY=${PROTOOBP_INSTALL_TOKEN_KEY} .
      
    • Dockerfile – необходимо добавить переменные окружения через ARG и передать их в pip install --index-url:

      FROM python:latest
      ARG PROTOOBP_INSTALL_TOKEN_NAME
      ARG PROTOOBP_INSTALL_TOKEN_KEY
      RUN pip install pobptrace --user --index-url "https://${PROTOOBP_INSTALL_TOKEN_NAME}:${PROTOOBP_INSTALL_TOKEN_KEY}@git.proto.group/api/v4/projects/125/packages/pypi/simple"
      
  2. Добавьте pobptrace-run команду как entrypoint вашего приложения. Например:

    pobptrace-run python app.py
    
    • Пример для типового Python приложения:

      CMD ["pobptrace-run", "python", "app.py"]
      
    • Пример для uwsgi и Dockerfile:

      CMD ["pobptrace-run", "uwsgi", "--ini", "app.ini"]
      
  3. Добавьте следующие переменные окружения:

    • POBP_AGENT_HOST – адрес Агента, на который будет отсылать данные трейсер
    • POBP_SERVICE=<service_name> – имя сервиса, как он будет отображаться в интерфейсе Proto Observability Platform
    • POBP_TRACE_TELEMETRY_ENABLED="false" – обязательно
  1. Установите библиотеку ddtrace выполнив:

    pip install ddtrace
    
  2. Добавьте ddtrace-run команду как entrypoint вашего приложения. Например:

    ddtrace-run python app.py
    
    • Пример для типового Python приложения:
      CMD ["ddtrace-run", "python", "app.py"]
      
  3. Добавьте следующие переменные окружения:

    • DD_AGENT_HOST – адрес Агента, на который будет отсылать данные трейсер
    • DD_SERVICE=<service_name> – имя сервиса, как он будет отображаться в интерфейсе Proto Observability Platform
    • DD_TRACE_TELEMETRY_ENABLED="false" – обязательно

Если вы используете uwsgi, то использовать ddtrace-run не нужно:

  • Dockerfile:

    FROM python:3.12.2
    ...
    RUN pip install ddtrace
    ...
    CMD ["uwsgi", "--ini", "app.ini"]
    
  • app.ini - добавьте следующее:

    ; ddtrace requirements:
    enable-threads = 1
    lazy-apps = 1
    import = ddtrace.bootstrap.sitecustomize
    

Скоро

  1. Выполните шаги, указанные на странице подключения инструментации OpenTelemetry для Python:

    https://opentelemetry.io/docs/languages/python/

  2. Выполните шаги, указанные на странице настройки OpenTelemetry в Proto Observability Platform.

Конфигурация трейсера

Если приложение запускается в Docker контейнере

Выполните пункты указанные для установки трейсера и добавьте следующие дополнительную переменную окружения:

  • POBP_AGENT_HOST – адрес Агента, на который будет отсылать данные трейсер:
    • если Агент запущен в Docker контейнере, укажите имя Docker контейнера Агента:
      ENV POBP_AGENT_HOST="protoobp-agent"
      
      Убедитесь, что контейнер Агента и контейнер приложения находятся в одной Docker сети. Адрес агента должен быть доступен из Docker контейнера приложения.
    • если Агент запущен на хосте как сервис (не в контейнере):
      ENV POBP_AGENT_HOST="host.docker.internal"
      
      Убедитесь что в конфигурации Агента разрешен прием APM данных от контейнеров:
      apm_config:
        apm_non_local_traffic: true
      

Пример полного Dockerfile:

FROM python:latest

WORKDIR /
COPY requirements.txt .

ARG PROTOOBP_INSTALL_TOKEN_NAME
ARG PROTOOBP_INSTALL_TOKEN_KEY

RUN pip install pobptrace --user --index-url "https://${PROTOOBP_INSTALL_TOKEN_NAME}:${PROTOOBP_INSTALL_TOKEN_KEY}@git.proto.group/api/v4/projects/125/packages/pypi/simple"
RUN pip install -r requirements.txt --user

ENV POBP_SERVICE="hello-world"
ENV POBP_AGENT_HOST="protoobp-agent" 
ENV POBP_TRACE_TELEMETRY_ENABLED="false"

CMD ["pobptrace-run", "python", "app.py"]

Выполните пункты указанные для установки трейсера и добавьте следующие дополнительную переменную окружения:

  • DD_AGENT_HOST – адрес Агента, на который будет отсылать данные трейсер:
    • если Агент запущен в Docker контейнере, укажите имя Docker контейнера Агента:
      ENV POBP_AGENT_HOST="protoobp-agent"
      
      Убедитесь, что контейнер Агента и контейнер приложения находятся в одной Docker сети. Адрес агента должен быть доступен из Docker контейнера приложения.
    • если Агент запущен на хосте как сервис (не в контейнере):
      ENV POBP_AGENT_HOST="host.docker.internal"
      
      Убедитесь что в конфигурации Агента разрешен прием APM данных от контейнеров:
      apm_config:
        apm_non_local_traffic: true
      

Пример полного Dockerfile:

FROM python:latest

WORKDIR /
COPY requirements.txt .

RUN pip install ddtrace
RUN pip install -r requirements.txt --user

ENV DD_SERVICE="hello-world"
ENV DD_AGENT_HOST="protoobp-agent" 
ENV DD_TRACE_TELEMETRY_ENABLED="false"

CMD ["ddtrace-run", "python", "app.py"]

Скоро

  1. Выполните шаги, указанные на странице подключения инструментации OpenTelemetry для Python:

    https://opentelemetry.io/docs/languages/python/

  2. Выполните шаги, указанные на странице настройки OpenTelemetry в Proto Observability Platform.

Если приложение работает в Kubernetes

Убедитесь, что у вас успешно установлен и настроен ProtoOBP Агент для Kubernetes.

При использовании стандартного подключения трейсера (см. выше) Дополнительно необходимо передать поду c Python приложением переменную окружения POBP_AGENT_HOST со значением IP адреса воркер-ноды, а также переменные окружения для связи трейсов с инфраструктурой (имя k8s кластера нужно задать вручную).

apiVersion: apps/v1
kind: Deployment
#(...)
    spec:
      containers:
      - name: "<CONTAINER_NAME>"
        image: "<CONTAINER_IMAGE>/<TAG>"
        env:
          - name: POBP_SERVICE
            value: dispatch			
          - name: POBP_AGENT_HOST
            valueFrom:
              fieldRef:
                fieldPath: status.hostIP
          - name: NODE_NAME
            valueFrom:
              fieldRef:
                fieldPath: spec.nodeName
          - name: POD_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
          - name: POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
          - name: POBP_TAGS
            value: "pod_name:$(POD_NAME),node:$(NODE_NAME),kube_namespace:$(POD_NAMESPACE),kube_cluster_name:<my_cluster_name>"            
            

С использованием автоматического подключения трейсера ProtoOBP

Агент ProtoOBP в K8s кластере по умолчанию инструментирует Python приложения с лейблом: admission.proto.group/enabled: "true"

  1. В спецификации пода приложения добавьте анотацию и лейбл с версией Python трейсинг агента:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
     labels:
     ...
    ...
    template:
       metadata:
         annotations:
           admission.proto.group/python-lib.version: "2.3.0" #Если Версия Python < 3.7, тогда необходимо указать версию "v1"
         creationTimestamp: null
         labels:
           admission.proto.group/enabled: "true" # Включение автоматической инструментации
           tags.proto.group/service: "my_service" #Укажите имя сервиса
           service: my_service
    
  2. В спецификации пода добавьте imagePullSecrets для доступа к Docker репозиторию ProtoOBP. Подробнее о добавление Secret указано в документации Установка агента в Kubernetes

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
      ...
    ...
     template:
        metadata:
          annotations:
            admission.proto.group/python-lib.version: "2.3.0" #Если Версия Python < 3.7, тогда необходимо указать версию "v1"
          creationTimestamp: null
          labels:
            admission.proto.group/enabled: "true" # Включение автоматической инструментации
           service: my_service
       spec:
          containers:
             ...
          ...
          imagePullSecrets:
          - name: protoobp-registry
    

Автоматическое подключение трейсера ProtoOBP без использования лейблов

В конфигурации агента вы можете включить автоматическую инструментацию без использования лейблов.

Дополнительно необходимо передать поду c Python приложением переменную окружения DD_AGENT_HOST со значением IP адреса воркер-ноды, а также переменные окружения для связи трейсов с инфраструктурой (имя k8s кластера нужно задать вручную).

apiVersion: apps/v1
kind: Deployment
#(...)
    spec:
      containers:
      - name: "<CONTAINER_NAME>"
        image: "<CONTAINER_IMAGE>/<TAG>"
        env:
          - name: DD_SERVICE
            value: dispatch			
          - name: DD_AGENT_HOST
            valueFrom:
              fieldRef:
                fieldPath: status.hostIP
          - name: NODE_NAME
            valueFrom:
              fieldRef:
                fieldPath: spec.nodeName
          - name: POD_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
          - name: POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
          - name: DD_TAGS
            value: "pod_name:$(POD_NAME),node:$(NODE_NAME),kube_namespace:$(POD_NAMESPACE),kube_cluster_name:<my_cluster_name>"
      

Скоро

  1. Выполните шаги, указанные на странице подключения инструментации OpenTelemetry для Python:

    https://opentelemetry.io/docs/languages/python/

  2. Выполните шаги, указанные на странице настройки OpenTelemetry в Proto Observability Platform.

Поддерживаемые технологии трейсером

Версии Python

Поддерживает CPython версий 2.7, 3.5-3.10.

ОС CPU архитектура Runtime Версии Python
Linux x86-64 CPython 2.7, 3.5-3.10
ОС CPU архитектура Runtime Версии Python версии пакета ddtrace
Linux x86-64, i686, AArch64 CPython 3.8+ >=3, <4
MacOS Intel, Apple Silicon CPython 3.8+ >=3, <4
Windows 64bit, 32bit CPython 3.8+ >=3, <4
Linux x86-64, i686, AArch64 CPython 3.7–3.13 >=2, <3
MacOS Intel, Apple Silicon CPython 3.7–3.13 >=2, <3
Windows 64bit, 32bit CPython 3.7–3.13 >=2, <3
Linux x86-64, i686, AArch64 CPython 2.7, 3.5–3.11 <2
MacOS Intel, Apple Silicon CPython 2.7, 3.5–3.11 <2
Windows 64bit, 32bit CPython 2.7, 3.5–3.11 <2

Скоро

  1. Выполните шаги, указанные на странице подключения инструментации OpenTelemetry для Python:

    https://opentelemetry.io/docs/languages/python/

  2. Выполните шаги, указанные на странице настройки OpenTelemetry в Proto Observability Platform.

Автоматическая инструментация библиотек и фреймворков

Фреймворк Версии Автоматически подключается
asgi >= 2.0 нет
aiohttp (клиент) >= 2.0 да
aiohttp (сервер) >= 2.0 нет
Bottle >= 0.11 нет
CherryPy >= 11.2.0 нет
Django >= 1.8 да
djangorestframework >= 3.4 да
Falcon >= 1.0 нет
Flask >= 0.10 да
FastAPI >= 0.51 да
Molten >= 0.7.0 да
Pylons >= 0.9.6 нет
Pyramid >= 1.7 нет
pytest >= 3.0 нет
Sanic >= 19.6.0 да
Starlette >= 0.13.0 да
Tornado >= 4.0 нет
Фреймворк Версии Автоматически подключается
asgi >= 2.0 нет
aiohttp (client) >= 2.0 да
aiohttp (server) >= 2.0 нет
Bottle >= 0.11 нет
CherryPy >= 11.2.0 нет
Django >= 1.8 да
djangorestframework >= 3.4 да
Falcon >= 1.0 нет
Flask >= 0.10 да
FastAPI >= 0.51 да
Gunicorn >= 20.0.04 нет
Molten >= 0.7.0 да
Pylons >= 0.9.6 (dd-trace-py 1.x only) нет
Pyramid >= 1.7 нет
Sanic >= 19.6.0 да
Starlette >= 0.13.0 да
Tornado >= 4.0 нет

Скоро

  1. Выполните шаги, указанные на странице подключения инструментации OpenTelemetry для Python:

    https://opentelemetry.io/docs/languages/python/

  2. Выполните шаги, указанные на странице настройки OpenTelemetry в Proto Observability Platform.

Хранилища данных

Хранилище Версии Автоматически подключается
algoliasearch >= 1.20.0 да
asyncpg >= 0.18.0 да
Cassandra >= 3.5 да
Elasticsearch >= 1.6 да
Flask Cache >= 0.12 нет
Mariadb >= 1.0.0 да
Memcached pylibmc >= 1.4 да
Memcached pymemcache >= 1.3 да
MongoDB Mongoengine >= 0.11 да
MongoDB Pymongo >= 3.0 да
MySQL MySQL-Python >= 1.2.3 да
MySQL mysqlclient >= 1.3 да
MySQL mysql-connector >= 2.1 да
Postgres aiopg >= 0.12.0, <= 0.16 да
Postgres psycopg >= 2.4 да
PyMySQL >= 0.7 да
PynamoDB >= 4.0 да
PyODBC >= 4.0 да
Redis >= 2.6 да
Redis redis-py-cluster >= 1.3.5 да
SQLAlchemy >= 1.0 нет
SQLite3 все да
Vertica >= 0.6 да
Хранилище Версии Автоматически подключается
algoliasearch >= 1.20.0 да
asyncpg >= 0.18.0 да
Cassandra >= 3.5 да
Elasticsearch >= 1.6 да
Flask Cache >= 0.12 нет
Mariadb >= 1.0.0 да
Memcached pylibmc >= 1.4 да
Memcached pymemcache >= 1.3 да
MongoDB Mongoengine >= 0.11 да
MongoDB Pymongo >= 3.0 да
MySQL MySQL-python >= 1.2.3 да
MySQL mysqlclient >= 1.3 да
MySQL mysql-connector >= 2.1 да
Opensearch >= 1.0 да
Postgres aiopg >= 0.12.0, < 0.16 да
Postgres psycopg >= 2.4 да
PyMySQL >= 0.7 да
PyODBC >= 4.0 да
Redis >= 2.6 да
Redis redis-py-cluster >= 1.3.5 да
snowflake-connector-python >= 2.1 нет
SQLAlchemy >= 1.0 нет
SQLite3 все да
Vertica >= 0.6 да

Скоро

  1. Выполните шаги, указанные на странице подключения инструментации OpenTelemetry для Python:

    https://opentelemetry.io/docs/languages/python/

  2. Выполните шаги, указанные на странице настройки OpenTelemetry в Proto Observability Platform.

Прочие библиотеки

Библиотека Версии Автоматически подключается
aiobotocore >= 0.2.3 нет
asyncio все > Python 3.7 да
Botocore >= 1.4.51 да
Boto2 >= 2.29.0 да
Celery >= 3.1 да
Consul >= 0.7 да
Futures все да
gevent >= 1.0 нет
Grpc >= 1.8.0 да
httplib все нет
Jinja2 >= 2.7 да
Kombu >= 4.0 нет
Mako >= 0.1.0 да
Requests >= 2.08 да
urllib3 >= 1.22 нет
graphql-core >= 2.0 да
Библиотека Версии Автоматически подключается
aiobotocore >= 0.2.3 нет
asyncio все > Python 3.7 — да
Botocore >= 1.4.51 да
Boto2 >= 2.29.0 да
Celery >= 4.4.0 да
Consul >= 0.7 да
Futures все да
gevent >= 20.12 да
Grpc >= 1.8.0 да
httplib все нет
Logbook >= 1.0.0 нет
Loguru >= 0.4.0 нет
Jinja2 >= 2.7 да
Kombu >= 4.0 нет
Mako >= 0.1.0 да
Requests >= 2.08 да
structlog >= 20.2.0 нет
urllib3 >= 1.22 нет
graphql-core >= 2.0 да
pytest >= 3.0 нет

Скоро

  1. Выполните шаги, указанные на странице подключения инструментации OpenTelemetry для Python:

    https://opentelemetry.io/docs/languages/python/

  2. Выполните шаги, указанные на странице настройки OpenTelemetry в Proto Observability Platform.

Дополнительная инструментация вызовов

Дополнительную инструментацию можно использовать, если в перечене автоматически инструментированных библиотек и фреймворков нет необходимых.

Для примера будет использоваться следующий код приложения:

def make_sandwich_request(request):
    ingredients = get_ingredients()
    sandwich = assemble_sandwich(ingredients)
@tracer.wrap(service="my-sandwich-making-svc", resource="resource_name")
def get_ingredients():
    # сходить в кладовку
    # сходить к холодильнику
    # может быть сходить в магазин
    return

# можно добавить больше данных для кастомизации спана
@tracer.wrap("assemble_sandwich", service="my-sandwich-making-svc", resource="resource_name")
def assemble_sandwich(ingredients):
    return
from pobptrace import tracer

def make_sandwich_request(request):
    # запишем обе операции в спаны
    with tracer.trace("sandwich.make"):
        ingredients = get_ingredients()
        sandwich = assemble_sandwich(ingredients)

def make_sandwich_request(request):
    # запишем обе операции в спаны
    with tracer.trace("sandwich.create", resource="resource_name") as outer_span:

        with tracer.trace("get_ingredients", resource="resource_name") as span:
            ingredients = get_ingredients()

        with tracer.trace("assemble_sandwich", resource="resource_name") as span:
            sandwich = assemble_sandwich(ingredients)
from pobptrace import tracer
def make_sandwich_request(request):
    span = tracer.trace("sandwich.create", resource="resource_name")
    ingredients = get_ingredients()
    sandwich = assemble_sandwich(ingredients)
    span.finish()  # не забудьте закрыть спан

Кастомные метрики Python приложений

Кастомные, например, бизнес-метрики, можно генерировать напрямую из приложения и отсылать на Агента.

  1. Подключите библиотеку protoobp выполнив:

    pip install protoobp --user --index-url "https://<token_name>:<token_key>@git.proto.group/api/v4/projects/125/packages/pypi/simple"
    

    имя и значение токена находятся в вашем лицензионном сертификате Proto Observability Platform.

    Пример для Dockerfile и .gitlab-ci.yml:

    • в настройках проекта в Gitlab добавьте две переменные окружения (Проект -> Settings -> CI/CD -> Variables):

      • имя: PROTOOBP_INSTALL_TOKEN_NAME, значение = ваши данные из лицензионного сертификата (token или логин)
      • имя: PROTOOBP_INSTALL_TOKEN_KEY, значение = ваши данные из лицензионного сертификата (пароль)
    • .gitlab-ci.yml – необходимо передать значения переменных от Gitlab CI к docker build через --build-arg:

        script:
          - docker build --build-arg PROTOOBP_INSTALL_TOKEN_NAME=${PROTOOBP_INSTALL_TOKEN_NAME} --build-arg PROTOOBP_INSTALL_TOKEN_KEY=${PROTOOBP_INSTALL_TOKEN_KEY} .
      
    • Dockerrfile – необходимо добавить переменные окружения через ARG и передать их в pip install --index-url:

      FROM python:latest
      ARG PROTOOBP_INSTALL_TOKEN_NAME
      ARG PROTOOBP_INSTALL_TOKEN_KEY
      RUN pip install protoobp --user --index-url "https://${PROTOOBP_INSTALL_TOKEN_NAME}:${PROTOOBP_INSTALL_TOKEN_KEY}@git.proto.group/api/v4/projects/125/packages/pypi/simple"
      
  2. Инициализируйте StatsD клиента, используя UDP в коде приложения:

    from protoobp import initialize, statsd
    
    options = {
        "statsd_host": "127.0.0.1",
        "statsd_port": 8125,
    }
    
    initialize(**options)
    
  3. Теперь можно добавлять собственные метрики, пример использования:

    from protoobp import initialize, statsd
    import time
    
    options = {
        'statsd_host':'127.0.0.1',
        'statsd_port':8125
    }
    
    initialize(**options)
    
    while(1):
      statsd.increment('example_metric.increment', tags=["environment:dev"])
      statsd.decrement('example_metric.decrement', tags=["environment:dev"])
      time.sleep(10)
    

Типы кастомных метрик

После установки библиотеки для отправки метрик в Protoobp будут доступны следующие функции в зависимости от типа метрик. Функции имеют следующие общие параметры:

Параметр Тип Обязательно
<METRIC_NAME> String Да Имя метрики
<METRIC_VALUE> Double Да Значение метрики
<SAMPLE_RATE> Double Нет Рейт сэмплирования. Значение между 0 (все сэмплируется, то есть ничего не отправляется) и 1 (нет сэмплирования).
<TAGS> List of strings Нет Список тегов для метрики
  1. COUNT

    • increment(<METRIC_NAME>, <SAMPLE_RATE>, <TAGS>)
      Используется для увеличения значения метрики типа COUNT.

    • decrement(<METRIC_NAME>, <SAMPLE_RATE>, <TAGS>)
      Используется для уменьшения значения метрики типа COUNT.

    Пример:

    from protoobp import initialize, statsd
    import time
    
    options = {
        'statsd_host':'127.0.0.1',
        'statsd_port':8125
    }
    
    initialize(**options)
    
    while(1):
      statsd.increment('example_metric.increment', tags=["environment:dev"])
      statsd.decrement('example_metric.decrement', tags=["environment:dev"])
      time.sleep(10)
    
  2. GAUGE

    • gauge(<METRIC_NAME>, <METRIC_VALUE>, <SAMPLE_RATE>, <TAGS>)

    Пример:

    from protoobp import initialize, statsd
    import time
    
    options = {
        'statsd_host':'127.0.0.1',
        'statsd_port':8125
    }
    
    initialize(**options)
    
    i = 0
    
    while(1):
      i += 1
      statsd.gauge('example_metric.gauge', i, tags=["environment:dev"])
      time.sleep(10)
    
  3. HISTOGRAM

    • histogram(<METRIC_NAME>, <METRIC_VALUE>, <SAMPLE_RATE>, <TAGS>)
      Отправляются агрегаты max, median, avg и count.
      Отправляется 95-й перцентиль.

    Пример:

    from protoobp import initialize, statsd
    import time
    import random
    
    options = {
        'statsd_host':'127.0.0.1',
        'statsd_port':8125
    }
    
    initialize(**options)
    
    while(1):
      statsd.histogram('example_metric.histogram', random.randint(0, 20), tags=["environment:dev"])
      time.sleep(2)   
    

    Пример выше создаст следующие метрики:

    Метрика Описание
    example_metric_histogram_count Количество раз сбора метрики
    example_metric_histogram_avg Среднее из собранных значений
    example_metric_histogram_median Медианное значение собранных значений
    example_metric_histogram_max Максимум среди собранных значений
    example_metric_histogram_95percentile 95-й перцентиль собранных значений