forked from aegis/pyserveX
feat: Enhance logging configuration with support for multiple log files and formats; improve CLI help output
This commit is contained in:
+167
-12
@@ -1,6 +1,6 @@
|
||||
import yaml
|
||||
import os
|
||||
from typing import Dict, Any, List
|
||||
from typing import Dict, Any, List, cast
|
||||
from dataclasses import dataclass, field
|
||||
import logging
|
||||
from .logging_utils import setup_logging
|
||||
@@ -28,11 +28,37 @@ class SSLConfig:
|
||||
key_file: str = "./ssl/key.pem"
|
||||
|
||||
|
||||
@dataclass
|
||||
class LogFormatConfig:
|
||||
type: str = "standard"
|
||||
use_colors: bool = True
|
||||
show_module: bool = True
|
||||
timestamp_format: str = "%Y-%m-%d %H:%M:%S"
|
||||
|
||||
|
||||
@dataclass
|
||||
class LogFileConfig:
|
||||
path: str
|
||||
level: str = "INFO"
|
||||
format: LogFormatConfig = field(default_factory=LogFormatConfig)
|
||||
loggers: List[str] = field(default_factory=list) # Список logger'ов для этого файла
|
||||
max_bytes: int = 10 * 1024 * 1024 # 10MB
|
||||
backup_count: int = 5
|
||||
|
||||
|
||||
@dataclass
|
||||
class LogHandlerConfig:
|
||||
level: str = "INFO"
|
||||
format: LogFormatConfig = field(default_factory=LogFormatConfig)
|
||||
|
||||
|
||||
@dataclass
|
||||
class LoggingConfig:
|
||||
level: str = "INFO"
|
||||
console_output: bool = True
|
||||
log_file: str = "./logs/pyserve.log"
|
||||
format: LogFormatConfig = field(default_factory=LogFormatConfig)
|
||||
console: LogHandlerConfig = field(default_factory=LogHandlerConfig)
|
||||
files: List[LogFileConfig] = field(default_factory=list)
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -99,10 +125,85 @@ class Config:
|
||||
|
||||
if 'logging' in data:
|
||||
log_data = data['logging']
|
||||
format_data = log_data.get('format', {})
|
||||
global_format = LogFormatConfig(
|
||||
type=format_data.get('type', 'standard'),
|
||||
use_colors=format_data.get('use_colors', True),
|
||||
show_module=format_data.get('show_module', True),
|
||||
timestamp_format=format_data.get('timestamp_format', '%Y-%m-%d %H:%M:%S')
|
||||
)
|
||||
console_data = log_data.get('console', {})
|
||||
console_format_data = console_data.get('format', {})
|
||||
console_format = LogFormatConfig(
|
||||
type=console_format_data.get('type', global_format.type),
|
||||
use_colors=console_format_data.get('use_colors', global_format.use_colors),
|
||||
show_module=console_format_data.get('show_module', global_format.show_module),
|
||||
timestamp_format=console_format_data.get('timestamp_format', global_format.timestamp_format)
|
||||
)
|
||||
console_config = LogHandlerConfig(
|
||||
level=console_data.get('level', log_data.get('level', 'INFO')),
|
||||
format=console_format
|
||||
)
|
||||
files_config = []
|
||||
if 'log_file' in log_data:
|
||||
default_file_format = LogFormatConfig(
|
||||
type=global_format.type,
|
||||
use_colors=False,
|
||||
show_module=global_format.show_module,
|
||||
timestamp_format=global_format.timestamp_format
|
||||
)
|
||||
default_file = LogFileConfig(
|
||||
path=log_data['log_file'],
|
||||
level=log_data.get('level', 'INFO'),
|
||||
format=default_file_format,
|
||||
loggers=[], # Empty list means including all loggers
|
||||
max_bytes=10 * 1024 * 1024,
|
||||
backup_count=5
|
||||
)
|
||||
files_config.append(default_file)
|
||||
|
||||
if 'files' in log_data:
|
||||
for file_data in log_data['files']:
|
||||
file_format_data = file_data.get('format', {})
|
||||
file_format = LogFormatConfig(
|
||||
type=file_format_data.get('type', global_format.type),
|
||||
use_colors=file_format_data.get('use_colors', False),
|
||||
show_module=file_format_data.get('show_module', global_format.show_module),
|
||||
timestamp_format=file_format_data.get('timestamp_format', global_format.timestamp_format)
|
||||
)
|
||||
file_config = LogFileConfig(
|
||||
path=file_data.get('path', './logs/pyserve.log'),
|
||||
level=file_data.get('level', log_data.get('level', 'INFO')),
|
||||
format=file_format,
|
||||
loggers=file_data.get('loggers', []),
|
||||
max_bytes=file_data.get('max_bytes', 10 * 1024 * 1024),
|
||||
backup_count=file_data.get('backup_count', 5)
|
||||
)
|
||||
files_config.append(file_config)
|
||||
|
||||
if not files_config:
|
||||
default_file_format = LogFormatConfig(
|
||||
type=global_format.type,
|
||||
use_colors=False,
|
||||
show_module=global_format.show_module,
|
||||
timestamp_format=global_format.timestamp_format
|
||||
)
|
||||
default_file = LogFileConfig(
|
||||
path='./logs/pyserve.log',
|
||||
level=log_data.get('level', 'INFO'),
|
||||
format=default_file_format,
|
||||
loggers=[],
|
||||
max_bytes=10 * 1024 * 1024,
|
||||
backup_count=5
|
||||
)
|
||||
files_config.append(default_file)
|
||||
|
||||
config.logging = LoggingConfig(
|
||||
level=log_data.get('level', config.logging.level),
|
||||
console_output=log_data.get('console_output', config.logging.console_output),
|
||||
log_file=log_data.get('log_file', config.logging.log_file)
|
||||
level=log_data.get('level', 'INFO'),
|
||||
console_output=log_data.get('console_output', True),
|
||||
format=global_format,
|
||||
console=console_config,
|
||||
files=files_config
|
||||
)
|
||||
|
||||
if 'extensions' in data:
|
||||
@@ -130,12 +231,34 @@ class Config:
|
||||
if not (1 <= self.server.port <= 65535):
|
||||
errors.append(f"Invalid port: {self.server.port}")
|
||||
|
||||
log_dir = os.path.dirname(self.logging.log_file)
|
||||
if log_dir and not os.path.exists(log_dir):
|
||||
try:
|
||||
os.makedirs(log_dir, exist_ok=True)
|
||||
except OSError as e:
|
||||
errors.append(f"Unable to create log directory: {e}")
|
||||
valid_log_levels = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
|
||||
if self.logging.level.upper() not in valid_log_levels:
|
||||
errors.append(f"Invalid logging level: {self.logging.level}")
|
||||
|
||||
if self.logging.console.level.upper() not in valid_log_levels:
|
||||
errors.append(f"Invalid console logging level: {self.logging.console.level}")
|
||||
|
||||
valid_format_types = ['standard', 'json']
|
||||
|
||||
if self.logging.format.type not in valid_format_types:
|
||||
errors.append(f"Invalid logging format type: {self.logging.format.type}")
|
||||
|
||||
if self.logging.console.format.type not in valid_format_types:
|
||||
errors.append(f"Invalid console format type: {self.logging.console.format.type}")
|
||||
|
||||
for i, file_config in enumerate(self.logging.files):
|
||||
if file_config.level.upper() not in valid_log_levels:
|
||||
errors.append(f"Invalid file[{i}] logging level: {file_config.level}")
|
||||
|
||||
if file_config.format.type not in valid_format_types:
|
||||
errors.append(f"Invalid file[{i}] format type: {file_config.format.type}")
|
||||
|
||||
log_dir = os.path.dirname(file_config.path)
|
||||
if log_dir and not os.path.exists(log_dir):
|
||||
try:
|
||||
os.makedirs(log_dir, exist_ok=True)
|
||||
except OSError as e:
|
||||
errors.append(f"Unable to create log directory for {file_config.path}: {e}")
|
||||
|
||||
if errors:
|
||||
for error in errors:
|
||||
@@ -148,6 +271,38 @@ class Config:
|
||||
config_dict = {
|
||||
'level': self.logging.level,
|
||||
'console_output': self.logging.console_output,
|
||||
'log_file': self.logging.log_file
|
||||
'format': {
|
||||
'type': self.logging.format.type,
|
||||
'use_colors': self.logging.format.use_colors,
|
||||
'show_module': self.logging.format.show_module,
|
||||
'timestamp_format': self.logging.format.timestamp_format
|
||||
},
|
||||
'console': {
|
||||
'level': self.logging.console.level,
|
||||
'format': {
|
||||
'type': self.logging.console.format.type,
|
||||
'use_colors': self.logging.console.format.use_colors,
|
||||
'show_module': self.logging.console.format.show_module,
|
||||
'timestamp_format': self.logging.console.format.timestamp_format
|
||||
}
|
||||
},
|
||||
'files': []
|
||||
}
|
||||
|
||||
for file_config in self.logging.files:
|
||||
file_dict = {
|
||||
'path': file_config.path,
|
||||
'level': file_config.level,
|
||||
'loggers': file_config.loggers,
|
||||
'max_bytes': file_config.max_bytes,
|
||||
'backup_count': file_config.backup_count,
|
||||
'format': {
|
||||
'type': file_config.format.type,
|
||||
'use_colors': file_config.format.use_colors,
|
||||
'show_module': file_config.format.show_module,
|
||||
'timestamp_format': file_config.format.timestamp_format
|
||||
}
|
||||
}
|
||||
cast(List[Dict[str, Any]], config_dict['files']).append(file_dict)
|
||||
|
||||
setup_logging(config_dict)
|
||||
|
||||
Reference in New Issue
Block a user