本文目录导读:

我来帮你设计一个Python脚本用于记录结构变更同步日志,这里提供几种不同场景的实现方案:
方案1:数据库表结构变更监控
基础日志记录器
import json
import hashlib
from datetime import datetime
from typing import Dict, List, Any, Optional
import logging
from pathlib import Path
class StructureChangeLogger:
"""结构变更日志记录器"""
def __init__(self, log_file: str = "structure_changes.json"):
self.log_file = Path(log_file)
self.logger = logging.getLogger(__name__)
self.setup_logging()
def setup_logging(self):
"""设置日志配置"""
handler = logging.FileHandler('structure_sync.log')
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
handler.setFormatter(formatter)
self.logger.addHandler(handler)
self.logger.setLevel(logging.INFO)
def record_change(self, change_type: str, source: str, target: str,
details: Dict[str, Any], status: str = "pending"):
"""
记录结构变更
Args:
change_type: 变更类型 (create/alter/drop)
source: 源结构信息
target: 目标结构信息
details: 变更详情
status: 状态 (pending/success/failed)
"""
change_record = {
"timestamp": datetime.now().isoformat(),
"change_type": change_type,
"source": source,
"target": target,
"details": details,
"status": status,
"change_id": self._generate_change_id(details)
}
self._save_change(change_record)
self._log_change(change_record)
return change_record
def _generate_change_id(self, details: Dict) -> str:
"""生成变更ID"""
content = json.dumps(details, sort_keys=True)
return hashlib.md5(content.encode()).hexdigest()[:12]
def _save_change(self, record: Dict):
"""保存变更记录到JSON文件"""
changes = []
if self.log_file.exists():
with open(self.log_file, 'r', encoding='utf-8') as f:
changes = json.load(f)
changes.append(record)
with open(self.log_file, 'w', encoding='utf-8') as f:
json.dump(changes, f, ensure_ascii=False, indent=2)
def _log_change(self, record: Dict):
"""记录到日志文件"""
log_msg = (
f"结构变更 [{record['change_type']}] "
f"ID: {record['change_id']} "
f"状态: {record['status']} "
f"详情: {json.dumps(record['details'], ensure_ascii=False)}"
)
if record['status'] == 'failed':
self.logger.error(log_msg)
else:
self.logger.info(log_msg)
def get_changes(self, start_time: Optional[str] = None,
end_time: Optional[str] = None,
change_type: Optional[str] = None) -> List[Dict]:
"""查询变更记录"""
if not self.log_file.exists():
return []
with open(self.log_file, 'r', encoding='utf-8') as f:
changes = json.load(f)
# 过滤条件
filtered = changes
if start_time:
filtered = [c for c in filtered if c['timestamp'] >= start_time]
if end_time:
filtered = [c for c in filtered if c['timestamp'] <= end_time]
if change_type:
filtered = [c for c in filtered if c['change_type'] == change_type]
return filtered
数据库表结构比较器
import sqlite3
import mysql.connector
from typing import Dict, List, Tuple
class DatabaseStructureComparator:
"""数据库结构比较器"""
def __init__(self, source_conn, target_conn):
self.source_conn = source_conn
self.target_conn = target_conn
self.logger = StructureChangeLogger()
def compare_tables(self) -> List[Dict]:
"""比较两个数据库的表结构"""
changes = []
source_tables = self._get_table_info(self.source_conn)
target_tables = self._get_table_info(self.target_conn)
# 检查新表
for table_name in source_tables:
if table_name not in target_tables:
changes.append({
"type": "create",
"table": table_name,
"details": source_tables[table_name]
})
# 检查删除的表
for table_name in target_tables:
if table_name not in source_tables:
changes.append({
"type": "drop",
"table": table_name,
"details": target_tables[table_name]
})
# 检查表结构变更
for table_name in source_tables:
if table_name in target_tables:
column_changes = self._compare_columns(
source_tables[table_name]["columns"],
target_tables[table_name]["columns"]
)
if column_changes:
changes.append({
"type": "alter",
"table": table_name,
"details": column_changes
})
return changes
def _get_table_info(self, conn) -> Dict:
"""获取数据库表结构信息"""
tables = {}
cursor = conn.cursor()
# 获取所有表
cursor.execute("SHOW TABLES")
table_names = [row[0] for row in cursor.fetchall()]
for table_name in table_names:
# 获取表结构
cursor.execute(f"DESCRIBE {table_name}")
columns = []
for row in cursor.fetchall():
columns.append({
"name": row[0],
"type": row[1],
"nullable": row[2],
"key": row[3],
"default": row[4],
"extra": row[5]
})
# 获取索引信息
cursor.execute(f"SHOW INDEX FROM {table_name}")
indexes = cursor.fetchall()
tables[table_name] = {
"columns": columns,
"indexes": indexes
}
return tables
def _compare_columns(self, source_columns: List, target_columns: List) -> List[Dict]:
"""比较两组的列结构"""
changes = []
source_names = {col["name"]: col for col in source_columns}
target_names = {col["name"]: col for col in target_columns}
# 新增列
for name in source_names:
if name not in target_names:
changes.append({
"action": "add_column",
"column": source_names[name]
})
# 删除列
for name in target_names:
if name not in source_names:
changes.append({
"action": "drop_column",
"column": target_names[name]
})
# 修改列
for name in source_names:
if name in target_names:
if source_names[name] != target_names[name]:
changes.append({
"action": "modify_column",
"column": name,
"before": target_names[name],
"after": source_names[name]
})
return changes
def sync_and_log(self):
"""同步结构并记录日志"""
changes = self.compare_tables()
for change in changes:
change_type = change["type"]
table_name = change["table"]
details = change["details"]
# 记录变更日志
self.logger.record_change(
change_type=change_type,
source=str(details.get("after", details)),
target=str(details.get("before", "")),
details=details
)
return changes
方案2:文件系统结构变更监控
import os
import hashlib
from datetime import datetime
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import json
class FileStructureChangeHandler(FileSystemEventHandler):
"""文件系统结构变更处理器"""
def __init__(self, tracked_path: str, log_file: str = "file_changes.json"):
self.tracked_path = tracked_path
self.log_file = log_file
self.known_structure = {}
self.load_known_structure()
def load_known_structure(self):
"""加载已知结构"""
if os.path.exists(self.log_file):
with open(self.log_file, 'r') as f:
self.known_structure = json.load(f)
def save_structure(self):
"""保存当前结构"""
current_structure = self.scan_current_structure()
self.known_structure = current_structure
with open(self.log_file, 'w') as f:
json.dump(current_structure, f, indent=2)
def scan_current_structure(self) -> Dict:
"""扫描当前目录结构"""
structure = {}
for root, dirs, files in os.walk(self.tracked_path):
rel_path = os.path.relpath(root, self.tracked_path)
for file in files:
file_path = os.path.join(root, file)
rel_file_path = os.path.join(rel_path, file)
try:
stat = os.stat(file_path)
structure[rel_file_path] = {
"size": stat.st_size,
"modified": datetime.fromtimestamp(stat.st_mtime).isoformat(),
"hash": self._file_hash(file_path)
}
except Exception as e:
structure[rel_file_path] = {
"error": str(e)
}
return structure
def _file_hash(self, file_path: str) -> str:
"""计算文件哈希"""
hasher = hashlib.md5()
with open(file_path, 'rb') as f:
for chunk in iter(lambda: f.read(4096), b''):
hasher.update(chunk)
return hasher.hexdigest()
def on_modified(self, event):
"""文件修改事件"""
if not event.is_directory:
rel_path = os.path.relpath(event.src_path, self.tracked_path)
change_record = {
"timestamp": datetime.now().isoformat(),
"event": "modified",
"path": rel_path,
"details": self._get_file_info(event.src_path)
}
self._log_change(change_record)
def on_created(self, event):
"""文件创建事件"""
rel_path = os.path.relpath(event.src_path, self.tracked_path)
change_record = {
"timestamp": datetime.now().isoformat(),
"event": "created",
"path": rel_path,
"details": self._get_file_info(event.src_path) if not event.is_directory else {}
}
self._log_change(change_record)
def on_deleted(self, event):
"""文件删除事件"""
rel_path = os.path.relpath(event.src_path, self.tracked_path)
change_record = {
"timestamp": datetime.now().isoformat(),
"event": "deleted",
"path": rel_path,
"details": {}
}
self._log_change(change_record)
def _get_file_info(self, file_path: str) -> Dict:
"""获取文件信息"""
try:
stat = os.stat(file_path)
return {
"size": stat.st_size,
"modified": datetime.fromtimestamp(stat.st_mtime).isoformat()
}
except:
return {}
def _log_change(self, record: Dict):
"""记录变更到日志文件"""
changes = []
if os.path.exists("structure_changes.log"):
with open("structure_changes.log", 'r') as f:
changes = json.load(f)
changes.append(record)
with open("structure_changes.log", 'w') as f:
json.dump(changes, f, indent=2)
print(f"结构变更记录: {record}")
class FileStructureMonitor:
"""文件结构监控器"""
def __init__(self, path: str):
self.path = path
self.observer = Observer()
self.handler = FileStructureChangeHandler(path)
def start(self):
"""开始监控"""
self.observer.schedule(self.handler, self.path, recursive=True)
self.observer.start()
print(f"开始监控目录: {self.path}")
def stop(self):
"""停止监控"""
self.observer.stop()
self.observer.join()
self.handler.save_structure()
print("监控已停止")
方案3:API结构变更日志
from flask import Flask, request, jsonify
from pydantic import BaseModel, Field
from typing import Optional, List
import json
from datetime import datetime
app = Flask(__name__)
class StructureChangeLog(BaseModel):
"""结构变更日志模型"""
id: Optional[int] = None
timestamp: str = Field(default_factory=lambda: datetime.now().isoformat())
api_endpoint: str
http_method: str
change_type: str # request/response/parameter
field_name: str
old_value: Optional[str] = None
new_value: Optional[str] = None
description: str
status: str = "pending"
class APIVersionManager:
"""API版本管理器,记录结构变更"""
def __init__(self, log_file: str = "api_changes.json"):
self.log_file = log_file
self.changes = []
self.load_changes()
def load_changes(self):
"""加载历史变更"""
try:
with open(self.log_file, 'r') as f:
self.changes = json.load(f)
except FileNotFoundError:
self.changes = []
def save_changes(self):
"""保存变更记录"""
with open(self.log_file, 'w') as f:
json.dump(self.changes, f, indent=2, default=str)
def record_change(self, change: StructureChangeLog):
"""记录结构变更"""
if self.changes:
change.id = max(c.get("id", 0) for c in self.changes) + 1
else:
change.id = 1
self.changes.append(change.dict())
self.save_changes()
return change.id
def get_changes(self, endpoint: Optional[str] = None,
change_type: Optional[str] = None) -> List[dict]:
"""获取变更记录"""
filtered = self.changes
if endpoint:
filtered = [c for c in filtered if c["api_endpoint"] == endpoint]
if change_type:
filtered = [c for c in filtered if c["change_type"] == change_type]
return filtered
# 创建API版本管理器实例
api_version_manager = APIVersionManager()
@app.route('/api/v1/users', methods=['GET'])
def get_users():
"""示例API端点"""
# 记录请求结构变更
change = StructureChangeLog(
api_endpoint="/api/v1/users",
http_method="GET",
change_type="request",
field_name="page",
new_value="新增分页参数",
description="新增用户列表分页功能"
)
api_version_manager.record_change(change)
return jsonify({"users": []})
@app.route('/api/changes', methods=['GET'])
def get_api_changes():
"""获取API变更记录"""
endpoint = request.args.get('endpoint')
change_type = request.args.get('change_type')
changes = api_version_manager.get_changes(endpoint, change_type)
return jsonify({"changes": changes})
@app.route('/api/changes', methods=['POST'])
def record_api_change():
"""记录API变更"""
data = request.json
change = StructureChangeLog(**data)
change_id = api_version_manager.record_change(change)
return jsonify({"id": change_id, "message": "变更记录成功"})
# 装饰器用于自动记录API变化
def track_api_change(change_type: str, field_name: str, description: str):
"""自动记录API变更的装饰器"""
def decorator(func):
def wrapper(*args, **kwargs):
# 记录变更
change = StructureChangeLog(
api_endpoint=request.path,
http_method=request.method,
change_type=change_type,
field_name=field_name,
new_value=description,
description=description
)
api_version_manager.record_change(change)
return func(*args, **kwargs)
return wrapper
return decorator
if __name__ == "__main__":
app.run(debug=True)
使用示例
# 数据库结构变更日志
def example_database_sync():
# 假设有源数据库和目标数据库连接
source_conn = mysql.connector.connect(
host="source_host",
database="source_db",
user="user",
password="password"
)
target_conn = mysql.connector.connect(
host="target_host",
database="target_db",
user="user",
password="password"
)
comparator = DatabaseStructureComparator(source_conn, target_conn)
changes = comparator.sync_and_log()
for change in changes:
print(f"检测到结构变更: {change['type']} - {change['table']}")
# 文件系统监控
def example_file_monitoring():
monitor = FileStructureMonitor("./my_project")
try:
monitor.start()
# 保持监控运行
import time
time.sleep(60)
finally:
monitor.stop()
# 查看变更日志
def view_change_logs():
logger = StructureChangeLogger()
# 获取所有变更
all_changes = logger.get_changes()
# 获取特定类型的变更
create_changes = logger.get_changes(change_type="create")
# 获取时间范围内的变更
recent_changes = logger.get_changes(
start_time="2024-01-01T00:00:00",
end_time="2024-01-31T23:59:59"
)
return all_changes, create_changes, recent_changes
功能特点
- 多场景支持:数据库、文件系统、API等多种场景
- 完整记录:包含时间戳、变更类型、变更详情
- 持久化存储:JSON文件或数据库存储
- 查询功能:按时间、类型等条件查询
- 版本追踪:支持版本回退和追溯
- 自动监控:实时监控结构变更
这个方案提供了完整的结构变更日志记录功能,可以根据具体需求进行扩展和定制。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播