195 lines
5.7 KiB
Markdown
195 lines
5.7 KiB
Markdown
|
|
|||
|
# Настройки логирования в модулях
|
|||
|
|
|||
|
## ML-компонент
|
|||
|
|
|||
|
Для единообразия логов самого модуля и логов библиотеки unip-mlcmp рекомендуется использовать один из двух форматов логирования:
|
|||
|
|
|||
|
1. Простой формат.
|
|||
|
2. Формат с добавлением request_id.
|
|||
|
|
|||
|
### Простой формат
|
|||
|
|
|||
|
Для соответствия простому формату, ваше сообщение должно форматироваться строкой:
|
|||
|
|
|||
|
```
|
|||
|
"[%(asctime)s] %(name)-15.15s [%(levelname)-8.8s] %(message)s"
|
|||
|
```
|
|||
|
|
|||
|
Примеры настроек приведены ниже.
|
|||
|
|
|||
|
#### Настройка с помощью `dictConfig`:
|
|||
|
|
|||
|
```python
|
|||
|
from logging.config import dictConfig
|
|||
|
dictConfig({
|
|||
|
'version': 1,
|
|||
|
'formatters': {
|
|||
|
'default_formatter': {
|
|||
|
'format': '[%(asctime)s] %(name)-15.15s [%(levelname)-8.8s] %(message)s'
|
|||
|
}
|
|||
|
},
|
|||
|
'handlers': {
|
|||
|
'default_handler': {
|
|||
|
'class': 'logging.StreamHandler',
|
|||
|
'stream': 'ext://sys.stdout',
|
|||
|
'formatter': 'default_formatter'
|
|||
|
}
|
|||
|
},
|
|||
|
'loggers': {
|
|||
|
'my_project': {
|
|||
|
'level': 'INFO',
|
|||
|
'handlers': ['default_handler']
|
|||
|
},
|
|||
|
}
|
|||
|
'disable_existing_loggers': False
|
|||
|
})
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
#### Настройка с помощью `fileConfig`:
|
|||
|
|
|||
|
Файл `logging.conf`
|
|||
|
|
|||
|
```toml
|
|||
|
[loggers]
|
|||
|
keys=root,my_project
|
|||
|
|
|||
|
[handlers]
|
|||
|
keys=default_handler
|
|||
|
|
|||
|
[formatters]
|
|||
|
keys=default_formatter
|
|||
|
|
|||
|
[logger_root]
|
|||
|
level=INFO
|
|||
|
handlers=
|
|||
|
|
|||
|
[logger_my_project]
|
|||
|
level=INFO
|
|||
|
handlers=default_handler
|
|||
|
propagate=1
|
|||
|
qualname=my_project
|
|||
|
|
|||
|
[handler_default_handler]
|
|||
|
class=StreamHandler
|
|||
|
level=NOTSET
|
|||
|
formatter=default_formatter
|
|||
|
args=(sys.stdout,)
|
|||
|
|
|||
|
[formatter_default_formatter]
|
|||
|
format=[%(asctime)s] %(name)-15.15s [%(levelname)-8.8s] %(message)s
|
|||
|
datefmt=
|
|||
|
style=%
|
|||
|
validate=True
|
|||
|
class=logging.Formatter
|
|||
|
```
|
|||
|
|
|||
|
Настройка в коде:
|
|||
|
|
|||
|
```python
|
|||
|
from logging.config import fileConfig
|
|||
|
fileConfig("logging.conf")
|
|||
|
```
|
|||
|
|
|||
|
### Формат с добавлением request_id
|
|||
|
|
|||
|
Для добавления `request_id` в логи достаточно изменить формат на следующий:
|
|||
|
|
|||
|
```
|
|||
|
"[%(asctime)s] %(name)-15.15s [%(levelname)-8.8s] [%(request_id)s] %(message)s"
|
|||
|
```
|
|||
|
|
|||
|
Но в таком случае при локальном выполнении кода возникнет ошибка - значение `request_id` устанавливается при обработке запроса в модуле, чего локально не происходит.
|
|||
|
|
|||
|
Чтобы эта ошибка не возникала, рекомендуется использовать функцию-фильтр, добавляющую поле `request_id` в объект `LogRecord`, полями которого заполняется строка логов.
|
|||
|
|
|||
|
#### Фильтр напрямую в коде
|
|||
|
|
|||
|
Пример добавления фильтр-функции через `logger.addFilter()`. Предполагается, что обработчик (hanlder) добавлен только к логгеру `"my_project"` как корневому логгеру проекта. Метод `addFilter` нужно вызвать для всех логгеров, к которым добавлены обработчики, либо к самому обработчику.
|
|||
|
|
|||
|
```python
|
|||
|
logger = logging.getLogger("my_project")
|
|||
|
|
|||
|
def filter_request_id(record):
|
|||
|
if not hasattr(record, "request_id"):
|
|||
|
record.request_id = "-"
|
|||
|
return True
|
|||
|
|
|||
|
logger.addFilter(filter_request_id)
|
|||
|
```
|
|||
|
|
|||
|
#### Фильтр в `dictConfig`
|
|||
|
|
|||
|
При настройке фильтров в `dictConfig` нужно передавать не саму фильтр-функцию, а функцию, которая возвращает фильтр-функцию.
|
|||
|
|
|||
|
Пример:
|
|||
|
|
|||
|
```python
|
|||
|
def filter_record_factory():
|
|||
|
def filter_record(record):
|
|||
|
if not hasattr(record, "request_id"):
|
|||
|
record.request_id = "-"
|
|||
|
return True
|
|||
|
return filter_record
|
|||
|
|
|||
|
dictConfig({
|
|||
|
'version': 1,
|
|||
|
'formatters': {
|
|||
|
'default_formatter': {
|
|||
|
'format': '[%(asctime)s] %(name)-15.15s [%(levelname)-8.8s] %(message)s'
|
|||
|
}
|
|||
|
},
|
|||
|
'filters': {
|
|||
|
'request_id': {
|
|||
|
'()': filter_record_factory
|
|||
|
},
|
|||
|
}
|
|||
|
'handlers': {
|
|||
|
'default_handler': {
|
|||
|
'class': 'logging.StreamHandler',
|
|||
|
'stream': 'ext://sys.stdout',
|
|||
|
'filters': ['request_id']
|
|||
|
'formatter': 'default_formatter',
|
|||
|
}
|
|||
|
},
|
|||
|
'loggers': {
|
|||
|
'my_project': {
|
|||
|
'level': 'INFO',
|
|||
|
'handlers': ['default_handler']
|
|||
|
},
|
|||
|
}
|
|||
|
'disable_existing_loggers': False
|
|||
|
})
|
|||
|
```
|
|||
|
|
|||
|
## Пайплайн
|
|||
|
|
|||
|
В пайплайнах рекомендуется использовать следующий формат логирования: `[%(asctime)s] %(name)s [%(levelname)s] %(message)s`.
|
|||
|
|
|||
|
Пример конфигурации:
|
|||
|
|
|||
|
```python
|
|||
|
from logging.config import dictConfig
|
|||
|
dictConfig({
|
|||
|
'version': 1,
|
|||
|
'formatters': {
|
|||
|
'validation': {
|
|||
|
'format': '[%(asctime)s] %(name)s [%(levelname)s] %(message)s',
|
|||
|
}
|
|||
|
},
|
|||
|
'handlers': {
|
|||
|
'default': {
|
|||
|
'class': 'logging.StreamHandler',
|
|||
|
'stream': 'ext://sys.stdout',
|
|||
|
'formatter': 'validation',
|
|||
|
}
|
|||
|
},
|
|||
|
'loggers': {
|
|||
|
'my_project': {
|
|||
|
'level': 'INFO',
|
|||
|
'handlers': ['default_handler']
|
|||
|
},
|
|||
|
}
|
|||
|
})
|
|||
|
```
|