feat: unified logging module and remove redundant first_run logic

- Add logger.py with TimedRotatingFileHandler (daily rotation, 30-day retention)
- Replace all print() in migrate.py with logging calls
- Add logging to sync.py for sync status tracking
- Refactor watch.py to use logger.py, remove duplicate first_run branch
- All logs now go to logs/app.log consistently
- Add logging config section to config.yaml, add logs/ to .gitignore

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Misaka_Company
2026-06-01 13:56:23 +08:00
parent 7edbd987f0
commit d224b98893
5 changed files with 124 additions and 113 deletions

108
watch.py
View File

@@ -5,41 +5,16 @@ Watch daemon - periodically syncs LAN Excel files and migrates changed tables to
import argparse
import logging
import os
import sys
import time
import yaml
from logger import setup_logger
from migrate import load_config, get_connection, create_schema, migrate_table
from sync import sync_all_files, determine_tables_to_migrate
def setup_logging(log_file):
"""Configure logging to both console and file."""
logger = logging.getLogger()
logger.setLevel(logging.INFO)
fmt = logging.Formatter(
'%(asctime)s [%(levelname)s] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
# Console handler
ch = logging.StreamHandler(sys.stdout)
ch.setLevel(logging.INFO)
ch.setFormatter(fmt)
logger.addHandler(ch)
# File handler
fh = logging.FileHandler(log_file, encoding='utf-8')
fh.setLevel(logging.INFO)
fh.setFormatter(fmt)
logger.addHandler(fh)
return logger
logger = logging.getLogger('app')
def run_once(cfg, logger):
def run_once(cfg):
"""Execute one sync + migrate cycle."""
excel_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Excel')
@@ -47,14 +22,6 @@ def run_once(cfg, logger):
logger.info("开始同步 LAN 文件...")
sync_results = sync_all_files(cfg, excel_dir)
for rel_path, (status, error_msg) in sync_results.items():
if status == 'error':
logger.error(f" 同步失败: {rel_path} - {error_msg}")
elif status in ('copied', 'updated'):
logger.info(f" {status}: {rel_path}")
else:
logger.debug(f" 跳过: {rel_path}")
# 2. Determine which tables need migration
tables_to_migrate = determine_tables_to_migrate(cfg, sync_results)
@@ -78,9 +45,9 @@ def run_once(cfg, logger):
try:
rows = migrate_table(cursor, table_cfg, cfg, use_truncate=True)
logger.info(f" 迁移完成: {table_name} ({rows:,} 行)")
logger.info(f"迁移完成: {table_name} ({rows:,} 行)")
except Exception as e:
logger.error(f" 迁移失败: {table_name} - {e}", exc_info=True)
logger.error(f"迁移失败: {table_name} - {e}", exc_info=True)
# Rollback any uncommitted transaction for this table
try:
conn.rollback()
@@ -106,12 +73,18 @@ def main():
help='覆盖配置文件中的 check_interval_minutes')
args = parser.parse_args()
# Setup logging
log_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'watch.log')
logger = setup_logging(log_file)
# Load config
cfg = load_config(args.config)
# Setup logging
log_cfg = cfg.get('logging', {})
setup_logger(
'app',
log_dir=log_cfg.get('log_dir'),
level=log_cfg.get('level', 'INFO'),
max_keep_days=log_cfg.get('max_keep_days', 30),
)
interval = args.interval or cfg.get('check_interval_minutes', 30)
logger.info("=" * 50)
@@ -119,58 +92,9 @@ def main():
logger.info(f" 同步间隔: {interval} 分钟")
logger.info("=" * 50)
first_run = True
while True:
try:
if first_run:
logger.info("首次运行,强制同步并迁移所有表...")
# On first run, force all tables to migrate by marking all files as 'updated'
excel_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Excel')
sync_results = sync_all_files(cfg, excel_dir)
# Log sync results
for rel_path, (status, error_msg) in sync_results.items():
if status == 'error':
logger.error(f" 同步失败: {rel_path} - {error_msg}")
else:
logger.info(f" {status}: {rel_path}")
# Force all tables to migrate on first run
all_tables = {t['table'] for t in cfg['tables']}
conn = None
try:
conn = get_connection(cfg)
cursor = conn.cursor()
create_schema(cursor, cfg['schema'])
for table_cfg in cfg['tables']:
table_name = table_cfg['table']
try:
rows = migrate_table(cursor, table_cfg, cfg, use_truncate=True)
logger.info(f" 迁移完成: {table_name} ({rows:,} 行)")
except Exception as e:
logger.error(f" 迁移失败: {table_name} - {e}", exc_info=True)
try:
conn.rollback()
except Exception:
pass
cursor.close()
except Exception as e:
logger.error(f"数据库连接失败: {e}", exc_info=True)
finally:
if conn:
try:
conn.close()
except Exception:
pass
first_run = False
else:
run_once(cfg, logger)
run_once(cfg)
except Exception as e:
logger.error(f"运行周期异常: {e}", exc_info=True)