Перейти к содержанию

Мониторинг

Настройка журналирования

Настройка библиотеки производится через переменные окружения. Переменные окружения имеют префикс LOG_. Переменные окружения для включения-выключения функций имеют значение 1 или 0. На данный момент доступны следующие настройки:

Переменная окружения Назначение Значение по умолчанию
LOG_MESSAGE_FORMAT Формат логирования пользовательских записей {time} {level} {message}
LOG_RESPONSE_FORMAT Формат логирования http ответа {time} {http_code} {local_request_id} {level} {url} {data} {message}
LOG_REQUEST_FORMAT Формат логирования http запроса {time} {local_request_id} {level} {user_uuid} {method} {url} {data} {message}
LOG_REMOVE_COOKIES Удаление куки из лога 1
LOG_SKIP_LOGGING_ENDPOINTS Список эндпоинтов, которые не нужно логировать, через запятую []
LOG_SKIP_LOGGING_CONTENT_TYPES Список типов контента, которые не нужно логировать, через запятую []
LOG_RESPONSE_BODY Логирование тела ответа 0
LOG_REQUEST_BODY Логирование тела запроса 1
LOG_REQUEST_USER Логирование пользователя (только Django) 1
LOG_REQUEST_METHOD Логирование метода запроса 1
LOG_RESPONSE_STATUS_CODE Логирование кода ответа 1
LOG_RESPONSE_HEADERS Логирование заголовков ответа 1
LOG_REQUEST_HEADERS Логирование заголовков запроса 1
LOG_REQUEST_URL_PATH Логирование URL-адреса запроса (PATH) 1
LOG_SQL_LOGGING Логирование SQL-запросов. Работает только совместно с DEBUG=True 0
LOG_JSON_LOGGING JSON-формат логов 0

Формат журналирования запроса и ответа

Форма сообщений HTTP-запроса и ответа задается переменными окружения LOG_REQUEST_FORMAT и LOG_RESPONSE_FORMAT соответственно.

Пример:

LOG_REQUEST_FORMAT='{time} {local_request_id} {level} {user_uuid} {method} {url} {data} {message}' LOG_RESPONSE_FORMAT='{time} {http_code} {local_request_id} {level} {url} {data} {message}'

Общие для LOG_REQUEST_FORMAT и LOG_RESPONSE_FORMAT

Ключ Описание
elapsed Примерное время выполнения запроса
file Имя файла, из которого пишется сообщение
function Имя функции, из которой пишется сообщение
level Уровень логирования
line Номер строки, из которой пишется сообщение
message Сообщение
module Модуль, из которого пишется сообщение
name Ключ name модуля, из которого пишется сообщение
process Процесс
thread Поток
time Временная метка
local_request_id Локальный идентификатор запроса и ответа
headers Заголовки HTTP-пакета
url URL-ардес запроса
data Полезная нагрузка HTTP-пакета

Специфичные для LOG_REQUEST_FORMAT

Ключ Описание
user_uuid Идентификатор пользователя
method HTTP-метод (GET/POST/PUT/и т.д.)

Специфичные для LOG_RESPONSE_FORMAT

Ключ Описание
http_code HTTP-код ответа

Примеры логов

Стандартный, при значениях переменных окружения

LOG_REQUEST_FORMAT='{time} {local_request_id} {level} {user_uuid} {method} {url} {data} {message}'

LOG_RESPONSE_FORMAT='{time} {http_code} {local_request_id} {level} {url} {data} {message}'

Пример:

2023-10-11 12:11:34.557 2023-10-11T09:11:34.556661+0000 200 4b5d1c29-6fb0-495b-a8e3-7e92440f4752 INFO /api/comments/internal/comment/count/newsentry/ RESPONSE

2023-10-11 12:11:34.548|2023-10-11T09:11:34.547514+0000 4b5d1c29-6fb0-495b-a8e3-7e92440f4752 INFO None GET /api/comments/internal/comment/count/newsentry/ REQUEST

2023-10-11 12:11:34.218|2023-10-11T09:11:34.218558+0000 200 f9577935-2e3c-46d1-b5b1-f585efa2562e INFO /api/comments/internal/comment/count/entry/ RESPONSE

2023-10-11 12:11:34.206|2023-10-11T09:11:34.205082+0000 f9577935-2e3c-46d1-b5b1-f585efa2562e INFO None GET /api/comments/internal/comment/count/entry/ REQUEST

JSON-формата при установленной переменной окружения LOG_JSON_LOGGING=1

{
  "time": "2023-10-11 12:14:57.788005+03:00",
  "elapsed": "0:00:10.732528",
  "level": "INFO",
  "message": {
    "request_id": "0263e10e-2a7e-4392-a7f7-819a93eea353",
    "request_url": "\/",
    "http_headers": {
      "host": "127.0.0.1:8000",
      "sec-fetch-site": "none",
      "connection": "keep-alive",
      "upgrade-insecure-requests": "1",
      "sec-fetch-mode": "navigate",
      "accept": "text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8",
      "user-agent": "Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/17.0 Safari\/605.1.15",
      "accept-language": "ru",
      "sec-fetch-dest": "document",
      "accept-encoding": "gzip, deflate",
      "x_request_id": "0263e10e-2a7e-4392-a7f7-819a93eea353"
    },
    "http_body": "",
    "method": "GET",
    "user": {
      "id": "41757af9-2c40-4e26-90fb-03a40d90ce3b",
      "is_superuser": true,
      "username": "None"
    }
  },
  "file": "ph_logging.models:97"
}{
  "time": "2023-10-11 12:14:57.788982+03:00",
  "elapsed": "0:00:10.733505",
  "level": "INFO",
  "message": {
    "request_id": "0263e10e-2a7e-4392-a7f7-819a93eea353",
    "request_url": "\/",
    "http_headers": {
      "content-length": "22",
      "content-type": "application\/json"
    },
    "http_body": "{\"detail\":\"Not Found\"}",
    "http_code": 404
  },
  "file": "ph_logging.models:138"
}
{
  "time": "2023-10-11 12:14:57.837834+03:00",
  "elapsed": "0:00:10.782357",
  "level": "INFO",
  "message": {
    "request_id": "e455f0c3-2d44-4dc6-8f96-e850f25dfc75",
    "request_url": "\/favicon.ico",
    "http_headers": {
      "host": "127.0.0.1:8000",
      "sec-fetch-site": "same-origin",
      "accept-encoding": "gzip, deflate",
      "connection": "keep-alive",
      "sec-fetch-mode": "no-cors",
      "accept": "*\/*",
      "user-agent": "Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/17.0 Safari\/605.1.15",
      "referer": "http:\/\/127.0.0.1:8000\/",
      "sec-fetch-dest": "image",
      "accept-language": "ru",
      "x_request_id": "e455f0c3-2d44-4dc6-8f96-e850f25dfc75"
    },
    "http_body": "",
    "method": "GET",
    "user": {
      "id": "88c7c226-3d05-4b93-a878-87c3c61d081e",
      "is_superuser": true,
      "username": "None"
    }
  },
  "file": "ph_logging.models:97"
}{
  "time": "2023-10-11 12:14:57.838680+03:00",
  "elapsed": "0:00:10.783203",
  "level": "INFO",
  "message": {
    "request_id": "e455f0c3-2d44-4dc6-8f96-e850f25dfc75",
    "request_url": "\/favicon.ico",
    "http_headers": {
      "content-length": "22",
      "content-type": "application\/json"
    },
    "http_body": "{\"detail\":\"Not Found\"}",
    "http_code": 404
  },
  "file": "ph_logging.models:138"
}

Установка

Django

Добаьте middleware:

MIDDLEWARE = [
    ...
    'ph_logging.middlewares.django_middleware.DjangoLoggingMiddleware',
    ...
]
Настройте библиотеку:
from ph_logging import logging_config
LOGGING = None
logging_config.configure_loguru_logger(echo_settings=True)  # для вывода текущих настроек
logging_config.add_skip_endpoints([
    STATIC_URL,
    f"/{API_BASE_URL}swagger/",
    f"/{API_BASE_URL}admin/",
    f"/{API_BASE_URL}media/",
    f"/{API_BASE_URL}redoc/",
    f"/{API_BASE_URL}internal/prometheus/metrics",
    f"/{API_BASE_URL}diagnostic/",
])

Для логирования SQL-запросов добавьте в настройки:

DATABASES = {
    'default': {
        'ENGINE': 'ph_logging.django_db_engine.postgres',
        ...
    }
}

FastAPI

Добавьте middleware:

from ph_logging.middlewares.fastapi_middleware import FastApiLoggingMiddleware
app.add_middleware(FastApiLoggingMiddleware)

Настройте логирование SQL-запросов:

from ph_logging.logging_config import LoguruHandler, LOG_SQL_LOGGING
import logging

logging.getLogger('sqlalchemy.engine').addHandler(LoguruHandler())
engine = create_async_engine(
    ...
    echo=LOG_SQL_LOGGING,
)

Информация для разработчика

Свойство headers для Django response добавили только в версии Django 3.2. Для совместимости с более ранними версиями пришлось сооружать такую конструкцию.

Запуск тестов

  1. Установите переменные окружения:
    export DJANGO_SETTINGS_MODULE=tests.django_settings;
    export LOG_SKIP_LOGGING_CONTENT_TYPES=application/xml,image/jpeg;
    export LOG_SKIP_LOGGING_ENDPOINTS=/skip_url/,/skip_url2/;
    export LOG_RESPONSE_BODY=1
    
  2. Выполните команду:
    python3 -m pytest -v -s tests/
    

Наблюдение за состоянием сервисов

Наблюдение за состоянием сервисов доступно на портале пользователю с правами Администратор системы (superuser).

Список зависимостей (dependencies) каждого сервиса может меняться в зависимости от инфраструктуры компании. У каждого сервиса обязательно будут указаны следующие параметры — URL, host, name и is available.

Параметр is available показывает доступен ли данный сервис в данный момент времени. При недоступности сервиса — он помечен соответствующей пометкой в разделе Панель администратора → Состояние портала.

Если при наблюдении за состоянием сервиса какой-либо из них оказывается недоступным, необходимо обращаться в техподдержку или инженеру по внедрению продукта.

Ниже указан список сервисов продукта, наблюдение за состоянием которых доступно пользователю с правами Администратор системы (superuser):

  • Сервис asyncblogs.
  • Сервис blogs.
  • Сервис calendar.
  • Сервис CMS.
  • Сервис comments.
  • Сервис events.
  • Сервис gamifications.
  • Сервис groups.
  • Сервис meetings.
  • Сервис news.
  • Сервис polls.
  • Сервис profile.
  • Сервис settings.
  • Сервис tasks.
  • Сервис pages.
  • Сервис notifications.
  • Сервис filestorage.
  • Сервис dictionaries.