Add log_manager concept docs (README.md, AGENTS.md) and update checklist
This commit is contained in:
@@ -18,8 +18,9 @@
|
|||||||
|
|
||||||
## Pending
|
## Pending
|
||||||
|
|
||||||
- [ ] Создать приложение `app/komAI.py` как точку входа
|
|
||||||
- [ ] Реализовать модуль логирования
|
- [ ] Реализовать модуль логирования
|
||||||
|
- [ ] stdout/stderr перехват при аварийном завершении (on crash)
|
||||||
|
- [ ] Создать приложение `app/komAI.py` как точку входа
|
||||||
- [ ] Реализовать систему модулей (`modules/`)
|
- [ ] Реализовать систему модулей (`modules/`)
|
||||||
- [ ] Настроить CI/CD
|
- [ ] Настроить CI/CD
|
||||||
- [ ] Написать интеграционные тесты
|
- [ ] Написать интеграционные тесты
|
||||||
299
src/utils/log_manager/AGENTS.md
Normal file
299
src/utils/log_manager/AGENTS.md
Normal file
@@ -0,0 +1,299 @@
|
|||||||
|
# LogManager Implementation Guide
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
LogManager wraps Python's `logging` to provide unified logging across all modules. All console output goes through `logger.print()` which handles console output and optional file duplication.
|
||||||
|
|
||||||
|
## Usage Pattern
|
||||||
|
|
||||||
|
```python
|
||||||
|
import src.utils.log_manager as log
|
||||||
|
|
||||||
|
# Register module
|
||||||
|
log.register(module="my_module", log_console=True, log_file="my_module.log")
|
||||||
|
|
||||||
|
# Get logger and use
|
||||||
|
logger = log.get_logger("my_module")
|
||||||
|
logger.print("message") # to console + file
|
||||||
|
logger.print("msg", level="warning") # with level for file
|
||||||
|
log.print("global message") # from root logger
|
||||||
|
```
|
||||||
|
|
||||||
|
## Config Constants
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Category
|
||||||
|
LOG_CATEGORY = "logger"
|
||||||
|
|
||||||
|
# Global config keys
|
||||||
|
LOG_CONSOLE = "log_console"
|
||||||
|
LOG_STDERR = "log_stderr"
|
||||||
|
LOG_FILE = "log_file"
|
||||||
|
LOG_PATH = "log_path"
|
||||||
|
LOG_LEVEL = "log_level"
|
||||||
|
LOG_FILE_LEVEL = "log_file_level"
|
||||||
|
LOG_ROTATION = "log_rotation"
|
||||||
|
LOG_ROTATION_SIZE = "log_rotation_size"
|
||||||
|
LOG_ROTATION_COUNT = "log_rotation_count"
|
||||||
|
LOG_TIMESTAMP = "log_timestamp"
|
||||||
|
LOG_BUFFERED = "log_buffered"
|
||||||
|
|
||||||
|
# Module config keys
|
||||||
|
MODULE_LOG_CONSOLE = "log_console"
|
||||||
|
MODULE_LOG_STDERR = "log_stderr"
|
||||||
|
MODULE_LOG_FILE = "log_file"
|
||||||
|
MODULE_LOG_LEVEL = "log_level"
|
||||||
|
|
||||||
|
# Defaults
|
||||||
|
DEFAULT_TIMESTAMP = "%Y-%m-%d %H:%M:%S"
|
||||||
|
DEFAULT_LOG_LEVEL = "INFO"
|
||||||
|
DEFAULT_FILE_LEVEL = "DEBUG"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Module Registration
|
||||||
|
|
||||||
|
### Global Registration (happens once)
|
||||||
|
|
||||||
|
Before using logging, global parameters must be registered in config:
|
||||||
|
|
||||||
|
```python
|
||||||
|
def register_global_params(config):
|
||||||
|
config.register(name=LOG_CONSOLE, val=True, cat=LOG_CATEGORY, desc="Enable console output")
|
||||||
|
config.register(name=LOG_STDERR, val=True, cat=LOG_CATEGORY, desc="Enable stderr for errors")
|
||||||
|
config.register(name=LOG_FILE, val="app.log", cat=LOG_CATEGORY, desc="Log file name")
|
||||||
|
config.register(name=LOG_PATH, val="./log", cat=LOG_CATEGORY, desc="Log directory path")
|
||||||
|
config.register(name=LOG_LEVEL, val="INFO", cat=LOG_CATEGORY, desc="Console log level")
|
||||||
|
config.register(name=LOG_FILE_LEVEL, val="DEBUG", cat=LOG_CATEGORY, desc="File log level")
|
||||||
|
config.register(name=LOG_ROTATION, val="size", cat=LOG_CATEGORY, desc="Rotation type: size|external")
|
||||||
|
config.register(name=LOG_ROTATION_SIZE, val="10MB", cat=LOG_CATEGORY, desc="Max file size for rotation")
|
||||||
|
config.register(name=LOG_ROTATION_COUNT, val=5, cat=LOG_CATEGORY, desc="Number of rotated files to keep")
|
||||||
|
config.register(name=LOG_TIMESTAMP, val=DEFAULT_TIMESTAMP, cat=LOG_CATEGORY, desc="Log timestamp format")
|
||||||
|
config.register(name=LOG_BUFFERED, val=False, cat=LOG_CATEGORY, desc="Buffer file writes")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Module Registration
|
||||||
|
|
||||||
|
Each module registers itself:
|
||||||
|
|
||||||
|
```python
|
||||||
|
def register(module, log_console=True, log_stderr=False, log_file=None, log_level=None):
|
||||||
|
"""
|
||||||
|
Register a module for logging.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
module: Module name (used as logger name suffix)
|
||||||
|
log_console: Enable console output (inherits from global if None)
|
||||||
|
log_stderr: Enable stderr for warnings/errors (inherits if None)
|
||||||
|
log_file: Log file name (inherits from global if None, None = no file logging)
|
||||||
|
log_level: Console/file level (inherits from global if None)
|
||||||
|
"""
|
||||||
|
```
|
||||||
|
|
||||||
|
## Config Hierarchy
|
||||||
|
|
||||||
|
```
|
||||||
|
# Global settings (category: "logger")
|
||||||
|
logger.log_console: true
|
||||||
|
logger.log_stderr: true
|
||||||
|
logger.log_file: "app.log"
|
||||||
|
logger.log_path: "./log"
|
||||||
|
logger.log_level: "INFO"
|
||||||
|
logger.log_file_level: "DEBUG"
|
||||||
|
logger.log_rotation: "size"
|
||||||
|
logger.log_rotation_size: "10MB"
|
||||||
|
logger.log_rotation_count: 5
|
||||||
|
logger.log_timestamp: "%Y-%m-%d %H:%M:%S"
|
||||||
|
logger.log_buffered: false
|
||||||
|
|
||||||
|
# Module-specific (category: "module_name")
|
||||||
|
module_name.log_console: false # override global
|
||||||
|
module_name.log_file: "custom.log" # override global
|
||||||
|
module_name.log_level: "DEBUG" # override global
|
||||||
|
```
|
||||||
|
|
||||||
|
**Inheritance rule:** If module-specific param is not set or None, inherits from global.
|
||||||
|
|
||||||
|
## Class Design
|
||||||
|
|
||||||
|
### LoggerPrint class
|
||||||
|
|
||||||
|
Wrapper around `logging.Logger` that provides `print()` method.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class LoggerPrint(logging.Logger):
|
||||||
|
def __init__(self, name, module_name):
|
||||||
|
super().__init__(name)
|
||||||
|
self.module_name = module_name
|
||||||
|
self.console_enabled = True
|
||||||
|
self.stderr_enabled = True
|
||||||
|
self.file_enabled = False
|
||||||
|
self.file_level = "DEBUG"
|
||||||
|
|
||||||
|
def print(self, msg, level="info"):
|
||||||
|
"""Print to console and optionally to file."""
|
||||||
|
# Determine if should output to console based on level
|
||||||
|
# Determine if should output to file based on level
|
||||||
|
# Handle stdout vs stderr based on level
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
### LogManager class
|
||||||
|
|
||||||
|
Factory and configuration holder.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class LogManager:
|
||||||
|
def __init__(self, config):
|
||||||
|
self.config = config
|
||||||
|
self._loggers = {} # module_name -> LoggerPrint
|
||||||
|
|
||||||
|
def register(self, module, log_console=None, log_stderr=None,
|
||||||
|
log_file=None, log_level=None):
|
||||||
|
"""Register a module with its logging settings."""
|
||||||
|
# Read global config
|
||||||
|
# Apply module overrides
|
||||||
|
# Create logger with appropriate handlers
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_logger(self, module):
|
||||||
|
"""Get existing logger or create new one."""
|
||||||
|
return self._loggers.get(module)
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
"""Initialize logging system."""
|
||||||
|
# Setup root logger
|
||||||
|
# Register all modules
|
||||||
|
pass
|
||||||
|
|
||||||
|
def print(self, msg, level="info"):
|
||||||
|
"""Print from root logger."""
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
### FileHandlerFactory
|
||||||
|
|
||||||
|
Creates appropriate file handler based on rotation settings.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class FileHandlerFactory:
|
||||||
|
@staticmethod
|
||||||
|
def create(path, filename, rotation="size",
|
||||||
|
max_bytes="10MB", backup_count=5):
|
||||||
|
"""Create file handler with rotation."""
|
||||||
|
if rotation == "size":
|
||||||
|
return RotatingFileHandler(
|
||||||
|
path / filename,
|
||||||
|
maxBytes=parse_size(max_bytes),
|
||||||
|
backupCount=backup_count
|
||||||
|
)
|
||||||
|
else: # external
|
||||||
|
return FileHandler(path / filename)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key Implementation Details
|
||||||
|
|
||||||
|
### Console Output
|
||||||
|
|
||||||
|
- stdout for levels: debug, info
|
||||||
|
- stderr for levels: warning, error, critical
|
||||||
|
|
||||||
|
### Level Mapping
|
||||||
|
|
||||||
|
```
|
||||||
|
level="debug" → console + file (DEBUG level)
|
||||||
|
level="info" → console + file (INFO level)
|
||||||
|
level="warning" → stderr + file (WARNING level)
|
||||||
|
level="error" → stderr + file (ERROR level)
|
||||||
|
```
|
||||||
|
|
||||||
|
### File Path Resolution
|
||||||
|
|
||||||
|
```python
|
||||||
|
def get_log_path():
|
||||||
|
log_path = config.get(LOG_PATH, cat=LOG_CATEGORY) or "./log"
|
||||||
|
base_path = Path(log_path)
|
||||||
|
base_path.mkdir(parents=True, exist_ok=True)
|
||||||
|
return base_path
|
||||||
|
```
|
||||||
|
|
||||||
|
### Size Parsing
|
||||||
|
|
||||||
|
```python
|
||||||
|
def parse_size(size_str):
|
||||||
|
"""Parse size string like '10MB' to bytes."""
|
||||||
|
units = {"B": 1, "KB": 1024, "MB": 1024*1024, "GB": 1024*1024*1024}
|
||||||
|
size_str = size_str.upper().strip()
|
||||||
|
for unit, multiplier in units.items():
|
||||||
|
if size_str.endswith(unit):
|
||||||
|
return int(size_str[:-len(unit)]) * multiplier
|
||||||
|
return int(size_str)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Module Config Reading
|
||||||
|
|
||||||
|
```python
|
||||||
|
def get_module_config(module):
|
||||||
|
"""Get effective config for module, merging global with module-specific."""
|
||||||
|
global_log_console = config.get(LOG_CONSOLE, cat=LOG_CATEGORY)
|
||||||
|
global_log_stderr = config.get(LOG_STDERR, cat=LOG_CATEGORY)
|
||||||
|
global_log_file = config.get(LOG_FILE, cat=LOG_CATEGORY)
|
||||||
|
global_log_level = config.get(LOG_LEVEL, cat=LOG_CATEGORY)
|
||||||
|
|
||||||
|
module_log_console = config.get(MODULE_LOG_CONSOLE, cat=module)
|
||||||
|
module_log_stderr = config.get(MODULE_LOG_STDERR, cat=module)
|
||||||
|
module_log_file = config.get(MODULE_LOG_FILE, cat=module)
|
||||||
|
module_log_level = config.get(MODULE_LOG_LEVEL, cat=module)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"log_console": module_log_console if module_log_console is not None else global_log_console,
|
||||||
|
"log_stderr": module_log_stderr if module_log_stderr is not None else global_log_stderr,
|
||||||
|
"log_file": module_log_file if module_log_file is not None else global_log_file,
|
||||||
|
"log_level": module_log_level if module_log_level is not None else global_log_level,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Module Requirements
|
||||||
|
|
||||||
|
1. **Never use `print()`** - always use `log.print()`
|
||||||
|
2. **Never use `logging` directly** - use LogManager wrapper
|
||||||
|
3. **Register module before use** - call `log.register(module="name", ...)`
|
||||||
|
4. **Use `log.setup()` at app startup** - after all module registrations
|
||||||
|
|
||||||
|
## Usage Flow
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 1. app/komAI.py
|
||||||
|
import src.utils.config_manager as config
|
||||||
|
import src.utils.log_manager as log
|
||||||
|
|
||||||
|
# Load config
|
||||||
|
config.load()
|
||||||
|
|
||||||
|
# Register global logging params (if not already registered)
|
||||||
|
log.register_global_params(config)
|
||||||
|
|
||||||
|
# Register modules
|
||||||
|
log.register(module="model", log_file="model.log")
|
||||||
|
log.register(module="ui", log_console=True)
|
||||||
|
|
||||||
|
# Setup logging
|
||||||
|
log.setup()
|
||||||
|
|
||||||
|
# Start application
|
||||||
|
log.print("Application started")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Files Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
src/utils/log_manager/
|
||||||
|
├── __init__.py # exports log, LogManager class
|
||||||
|
├── constants.py # LOG_CATEGORY, LOG_CONSOLE, etc.
|
||||||
|
├── logger.py # LoggerPrint class
|
||||||
|
├── factory.py # FileHandlerFactory, parse_size
|
||||||
|
└── manager.py # LogManager class implementation
|
||||||
|
```
|
||||||
|
|
||||||
|
## Open Questions
|
||||||
|
|
||||||
|
None - all details specified in this document.
|
||||||
249
src/utils/log_manager/README.md
Normal file
249
src/utils/log_manager/README.md
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
# LogManager
|
||||||
|
|
||||||
|
## Концепция
|
||||||
|
|
||||||
|
Логирование через `print()` вместо стандартного `logging`. Все сообщения через `logger.print()` выводятся в консоль, дублируются в файл если настроено.
|
||||||
|
|
||||||
|
## Использование в модулях
|
||||||
|
|
||||||
|
### Шаблон модуля с логированием
|
||||||
|
|
||||||
|
```python
|
||||||
|
# my_module/__init__.py
|
||||||
|
import src.utils.log_manager as log
|
||||||
|
|
||||||
|
def init():
|
||||||
|
log.register(
|
||||||
|
module="my_module", # имя модуля
|
||||||
|
log_console=True, # вывод в консоль
|
||||||
|
log_stderr=False, # вывод в stderr (для ошибок)
|
||||||
|
log_file="my_module.log" # имя файла (None = не писать в файл)
|
||||||
|
)
|
||||||
|
log.setup()
|
||||||
|
|
||||||
|
def do_something():
|
||||||
|
log.print("Starting process...") # вместо print()
|
||||||
|
log.print("Processing...", level="info") # уровень для лога (default: info)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Конфигурация в global.yaml
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Глобальные настройки
|
||||||
|
logger.log_console: true
|
||||||
|
logger.log_stderr: true
|
||||||
|
logger.log_file: "app.log"
|
||||||
|
logger.log_path: "./log"
|
||||||
|
logger.log_level: "INFO"
|
||||||
|
logger.log_file_level: "DEBUG"
|
||||||
|
logger.log_rotation: "size"
|
||||||
|
logger.log_rotation_size: "10MB"
|
||||||
|
logger.log_rotation_count: 5
|
||||||
|
logger.log_timestamp: "%Y-%m-%d %H:%M:%S"
|
||||||
|
logger.log_buffered: false
|
||||||
|
|
||||||
|
# Настройки для конкретного модуля (переопределяют глобальные)
|
||||||
|
my_module.log_console: false
|
||||||
|
my_module.log_file: "custom_module.log"
|
||||||
|
my_module.log_level: "DEBUG"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Правила наследования
|
||||||
|
|
||||||
|
1. Параметры модуля `module_name.*` переопределяют глобальные `logger.*`
|
||||||
|
2. Если параметр модуля не задан - берётся глобальный
|
||||||
|
3. `log_file: null` означает не писать в файл для этого модуля
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### Регистрация модуля
|
||||||
|
|
||||||
|
```python
|
||||||
|
log.register(
|
||||||
|
module="my_module",
|
||||||
|
log_console=True,
|
||||||
|
log_stderr=False,
|
||||||
|
log_file="my_module.log",
|
||||||
|
log_level="INFO",
|
||||||
|
log_file_level="DEBUG"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Получение логера
|
||||||
|
|
||||||
|
```python
|
||||||
|
logger = log.get_logger("my_module")
|
||||||
|
logger.print("message") # вывод в консоль
|
||||||
|
logger.print("message", level="debug") # с уровнем для лога (default: info)
|
||||||
|
logger.info("message") # стандартный logging (только в файл)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Глобальные функции
|
||||||
|
|
||||||
|
```python
|
||||||
|
log.print("message") # от root logger
|
||||||
|
log.setup() # инициализация (вызывается при старте)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Константы для конфига
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Категория логера
|
||||||
|
LOG_CATEGORY = "logger"
|
||||||
|
|
||||||
|
# Параметры глобальные
|
||||||
|
LOG_CONSOLE = "log_console"
|
||||||
|
LOG_STDERR = "log_stderr"
|
||||||
|
LOG_FILE = "log_file"
|
||||||
|
LOG_PATH = "log_path"
|
||||||
|
LOG_LEVEL = "log_level"
|
||||||
|
LOG_FILE_LEVEL = "log_file_level"
|
||||||
|
LOG_ROTATION = "log_rotation"
|
||||||
|
LOG_ROTATION_SIZE = "log_rotation_size"
|
||||||
|
LOG_ROTATION_COUNT = "log_rotation_count"
|
||||||
|
LOG_TIMESTAMP = "log_timestamp"
|
||||||
|
LOG_BUFFERED = "log_buffered"
|
||||||
|
|
||||||
|
# Параметры для модулей (внутри секции module_name)
|
||||||
|
MODULE_LOG_CONSOLE = "log_console"
|
||||||
|
MODULE_LOG_STDERR = "log_stderr"
|
||||||
|
MODULE_LOG_FILE = "log_file"
|
||||||
|
MODULE_LOG_LEVEL = "log_level"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Правила написания модулей
|
||||||
|
|
||||||
|
### Обязательно использовать `log.print()` вместо `print()`
|
||||||
|
|
||||||
|
```python
|
||||||
|
# НЕПРАВИЛЬНО
|
||||||
|
print("Message")
|
||||||
|
print(f"Value: {x}")
|
||||||
|
|
||||||
|
# ПРАВИЛЬНО
|
||||||
|
log.print("Message")
|
||||||
|
log.print(f"Value: {x}")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Уровни логирования
|
||||||
|
|
||||||
|
```python
|
||||||
|
log.print("debug message", level="debug")
|
||||||
|
log.print("info message", level="info") # default
|
||||||
|
log.print("warning message", level="warning")
|
||||||
|
log.print("error message", level="error")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Инициализация модуля
|
||||||
|
|
||||||
|
```python
|
||||||
|
# В __init__.py модуля
|
||||||
|
import src.utils.log_manager as log
|
||||||
|
|
||||||
|
def init():
|
||||||
|
log.register(
|
||||||
|
module="my_module",
|
||||||
|
log_console=True,
|
||||||
|
log_file="my_module.log"
|
||||||
|
)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
log.print("Module started")
|
||||||
|
# ... work ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Структура модуля с точки зрения логирования
|
||||||
|
|
||||||
|
```
|
||||||
|
my_module/
|
||||||
|
├── __init__.py # log.register(), init()
|
||||||
|
├── logger.py # опционально, если нужен свой logger
|
||||||
|
└── ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Регистрация параметров логирования в своём модуле
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Модуль может захотеть свои параметры логирования
|
||||||
|
import src.utils.config_manager as config
|
||||||
|
import src.utils.log_manager as log
|
||||||
|
|
||||||
|
def init():
|
||||||
|
# Регистрация параметров своего модуля
|
||||||
|
config.register(name="option1", val="value1", cat="my_module", ...)
|
||||||
|
config.register(name="option2", val="value2", cat="my_module", ...)
|
||||||
|
|
||||||
|
# Регистрация в log_manager для логирования
|
||||||
|
log.register(module="my_module", ...)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Вложенные модули
|
||||||
|
|
||||||
|
```python
|
||||||
|
# parent_module/__init__.py
|
||||||
|
import src.utils.log_manager as log
|
||||||
|
|
||||||
|
def init():
|
||||||
|
log.register(module="parent")
|
||||||
|
|
||||||
|
# parent_module/child/__init__.py
|
||||||
|
import src.utils.log_manager as log
|
||||||
|
|
||||||
|
def init():
|
||||||
|
log.register(module="parent.child")
|
||||||
|
log.print("Child module message")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Архитектура
|
||||||
|
|
||||||
|
### Обработчики
|
||||||
|
|
||||||
|
- **ConsoleWriter** - вывод в stdout/stderr
|
||||||
|
- **FileHandler** - запись в файл (с ротацией или без)
|
||||||
|
- **BufferedWriter** - буферизованный вывод в файл
|
||||||
|
|
||||||
|
### Поток сообщений
|
||||||
|
|
||||||
|
```
|
||||||
|
logger.print("msg")
|
||||||
|
│
|
||||||
|
├─→ ConsoleWriter (если log_console)
|
||||||
|
│ └─→ stdout (уровни info, debug)
|
||||||
|
│ └─→ stderr (уровни warning, error)
|
||||||
|
│
|
||||||
|
└─→ FileHandler (если log_file настроен)
|
||||||
|
└─→ BufferedWriter или direct write
|
||||||
|
```
|
||||||
|
|
||||||
|
### Структура логгеров
|
||||||
|
|
||||||
|
```
|
||||||
|
komAI # root logger
|
||||||
|
└── komAI.my_module # logger для модуля
|
||||||
|
├─ ConsoleWriter # управляется module.log_console
|
||||||
|
└─ FileHandler # управляется module.log_file, module.log_level
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ротация логов
|
||||||
|
|
||||||
|
### По размеру (`log_rotation=size`)
|
||||||
|
- `RotatingFileHandler`
|
||||||
|
- При достижении `log_rotation_size` происходит ротация
|
||||||
|
- Хранится `log_rotation_count` ротированных файлов
|
||||||
|
|
||||||
|
### Внешняя (`log_rotation=external`)
|
||||||
|
- Базовый `FileHandler` без ротации
|
||||||
|
- Внешняя система (logrotate) управляет ротацией
|
||||||
|
|
||||||
|
## Формат timestamp
|
||||||
|
|
||||||
|
По умолчанию: `DEFAULT_TIMESTAMP = "%Y-%m-%d %H:%M:%S"`
|
||||||
|
|
||||||
|
Настраивается через `logger.log_timestamp` в конфиге.
|
||||||
|
|
||||||
|
## Ограничения
|
||||||
|
|
||||||
|
1. **Никогда не использовать `print()`** - только `log.print()`
|
||||||
|
2. **Не использовать `logging` напрямую** - использовать обёртку
|
||||||
|
3. **Все модули должны регистрироваться** через `log.register()`
|
||||||
|
4. **Имя модуля уникально** в рамках проекта
|
||||||
Reference in New Issue
Block a user