This commit is contained in:
zelong 2025-12-18 16:23:16 +08:00
parent 6e51a505bd
commit 9e959f58e0
7 changed files with 1708 additions and 154 deletions

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
[TAPD]
# TAPD项目ID
workspace_id = 58335167
workspace_id = 5833516 7
# Bug报告人
reporter = G41小助手

4
config/token_cache.json Normal file
View File

@ -0,0 +1,4 @@
{
"access_token": "NWdoeLm7usm42yi-6fXJ3KjEcY_JzON22cG5tH0Ezio1ytQyRbst9D52xjK01Ga0tXEI6q9U9zeCS1fjM51IfSPGRqo1By4yAgbbNQwIOJEsQr0fMXIRaMN3yi_DauifuRgqyv56h2sfInkuFB_3bhUNTMpe-xp0Vn1iSmg-D9Lo4gMAzvuqxXR1_WPyUZi9H9ZDg_KQtx4YsNMHxvxdl7jA6QvZckwveA96CRAb9fU",
"fetch_time": 1766040126.4893737
}

View File

@ -17,6 +17,7 @@ from src.smartsheet import SmartSheetAPI
from src.validator import RecordValidator
from src.tapd_api import TAPDApi
from src.mapper import FieldMapper, BugCreationResult
from src.token_manager import TokenManager
def parse_arguments():
@ -31,16 +32,23 @@ def parse_arguments():
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
示例用法:
# 手动提供access_token
python main.py --access-token YOUR_ACCESS_TOKEN
python main.py -t YOUR_ACCESS_TOKEN --config /path/to/config.ini
# 自动从环境变量获取access_token需要设置CORPID和CORPSECRET
python main.py
# 指定配置文件路径
python main.py --config /path/to/config.ini
"""
)
# 必需参数
# 可选参数access_token如果不提供将自动从环境变量获取
parser.add_argument(
'-t', '--access-token',
required=True,
help='企业微信access_token必填'
required=False,
default=None,
help='企业微信access_token可选如不提供则自动从环境变量获取'
)
# 可选参数
@ -65,22 +73,47 @@ def parse_arguments():
return parser.parse_args()
def validate_access_token(access_token):
def get_or_validate_access_token(access_token_arg):
"""
验证access_token是否有效
获取或验证access_token
如果命令行提供了token则验证并使用
如果未提供则通过TokenManager自动获取
Args:
access_token: 待验证的token
access_token_arg: 命令行传入的token可能为None
Returns:
str: 有效的access_token
Raises:
ValueError: token无效时抛出
ValueError: token无效或环境变量未设置时抛出
RuntimeError: 自动获取token失败时抛出
"""
if not access_token or not access_token.strip():
if access_token_arg:
# 命令行提供了token进行验证
print("使用命令行提供的access_token")
if not access_token_arg.strip():
raise ValueError("access_token不能为空")
# 基本格式检查企业微信的access_token通常较长
if len(access_token.strip()) < 20:
raise ValueError("access_token格式可能不正确长度过短")
return access_token_arg.strip()
else:
# 命令行未提供token使用TokenManager自动获取
print("命令行未提供access_token将自动从环境变量获取")
print()
try:
token_manager = TokenManager()
access_token = token_manager.get_token()
return access_token
except ValueError as e:
# 环境变量未设置
raise ValueError(f"自动获取access_token失败: {e}")
except RuntimeError as e:
# API调用失败
raise RuntimeError(f"自动获取access_token失败: {e}")
def scan_and_validate_records(access_token: str, docid: str, verbose: bool = False, test_mode: bool = False):
@ -437,7 +470,7 @@ def main():
"""主函数"""
print("=" * 60)
print("autoTAPD - Debug阶段自动开单工具")
print("版本: 0.2.0 (第二阶段)")
print("版本: 0.4.0 (第四阶段 - 支持自动获取access_token)")
print("=" * 60)
print()
@ -452,10 +485,11 @@ def main():
print(f" - verbose: {args.verbose}")
print(f" - test: {args.test}")
# 2. 验证access_token
print("[2/3] 验证access_token...")
validate_access_token(args.access_token)
print(" ✓ access_token格式验证通过")
# 2. 获取或验证access_token
print("[2/3] 获取access_token...")
access_token = get_or_validate_access_token(args.access_token)
print(" ✓ access_token准备就绪")
print()
# 3. 加载配置文件
print("[3/3] 加载配置文件...")
@ -472,14 +506,14 @@ def main():
print("-" * 60)
print(f"TAPD workspace_id: {all_config['tapd']['workspace_id']}")
print(f"SmartSheet docid: {all_config['smartsheet']['docid'][:20]}...")
print(f"Access Token: {args.access_token[:10]}...(已隐藏)")
print(f"Access Token: {access_token[:10]}...(已隐藏)")
if args.test:
print(f"测试模式: 已启用")
print("=" * 60)
# 4. 扫描智能表格并校验记录
result = scan_and_validate_records(
args.access_token,
access_token,
all_config['smartsheet']['docid'],
args.verbose,
args.test
@ -509,7 +543,7 @@ def main():
sheet_id = result.get('sheet_id')
if sheet_id:
writeback_result = write_back_results(
args.access_token,
access_token,
all_config['smartsheet']['docid'],
sheet_id,
creation_result['success_results'],

View File

@ -70,15 +70,7 @@ class SmartSheetAPI:
import json
print(f"\n响应状态码: {response.status_code}")
print(f"响应数据:")
# 对于records数据只显示摘要信息避免输出过多
if endpoint == "smartsheet/get_records" and 'records' in result:
display_result = result.copy()
records_count = len(result.get('records', []))
if records_count > 0:
display_result['records'] = f"[{records_count}条记录,已省略详情]"
display_result['_records_sample'] = result['records'][0] if records_count > 0 else None
print(json.dumps(display_result, ensure_ascii=False, indent=2))
else:
# 测试模式下显示完整的响应数据
print(json.dumps(result, ensure_ascii=False, indent=2))
print("=" * 80)
@ -219,11 +211,11 @@ class SmartSheetAPI:
# 构造过滤条件:开单状态字段为空
filter_spec = {
"conjunction": "and",
"conjunction": "CONJUNCTION_AND",
"conditions": [
{
"field_id": status_field_id,
"operator": "is_empty"
"operator": "OPERATOR_IS_EMPTY"
}
]
}

328
src/token_manager.py Normal file
View File

@ -0,0 +1,328 @@
"""
企业微信 Access Token 管理模块
负责自动获取缓存和刷新 access_token
该模块完全独立不依赖其他业务模块
"""
import os
import json
import time
import requests
from pathlib import Path
from typing import Optional, Dict
class TokenManager:
"""企业微信 Access Token 管理器"""
# 企业微信获取token的API地址
TOKEN_API_URL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken"
# Token有效期企业微信返回的是7200秒
TOKEN_EXPIRES_IN = 7200
# 提前刷新时间在token过期前5分钟就刷新
REFRESH_BEFORE_EXPIRE = 300
def __init__(self, cache_file_path: Optional[str] = None):
"""
初始化Token管理器
Args:
cache_file_path: token缓存文件路径如果为None则使用默认路径
"""
# 确定缓存文件路径
if cache_file_path is None:
# 默认路径:项目根目录/config/token_cache.json
project_root = Path(__file__).parent.parent
cache_file_path = project_root / "config" / "token_cache.json"
self.cache_file_path = Path(cache_file_path)
# 从环境变量读取企业微信配置
self.corpid = os.environ.get('CORPID')
self.corpsecret = os.environ.get('CORPSECRET')
def _validate_env_config(self):
"""
验证环境变量配置是否完整
Raises:
ValueError: 环境变量未设置时抛出
"""
if not self.corpid:
raise ValueError(
"环境变量 CORPID 未设置\n"
"请设置环境变量: export CORPID=your_corpid"
)
if not self.corpsecret:
raise ValueError(
"环境变量 CORPSECRET 未设置\n"
"请设置环境变量: export CORPSECRET=your_corpsecret"
)
def _fetch_token_from_api(self) -> Dict[str, any]:
"""
从企业微信API获取新的access_token
Returns:
Dict: 包含access_token和expires_in的字典
Raises:
RuntimeError: API调用失败时抛出
"""
print("正在从企业微信API获取新的access_token...")
try:
params = {
'corpid': self.corpid,
'corpsecret': self.corpsecret
}
response = requests.get(self.TOKEN_API_URL, params=params, timeout=10)
response.raise_for_status()
result = response.json()
# 检查返回的错误码
errcode = result.get('errcode', 0)
if errcode != 0:
errmsg = result.get('errmsg', '未知错误')
raise RuntimeError(f"获取access_token失败: errcode={errcode}, errmsg={errmsg}")
access_token = result.get('access_token')
expires_in = result.get('expires_in', self.TOKEN_EXPIRES_IN)
if not access_token:
raise RuntimeError("API返回的数据中未找到access_token")
print(f" ✓ 成功获取access_token (有效期: {expires_in}秒)")
return {
'access_token': access_token,
'expires_in': expires_in
}
except requests.exceptions.Timeout:
raise RuntimeError("获取access_token超时请检查网络连接")
except requests.exceptions.RequestException as e:
raise RuntimeError(f"获取access_token失败: {e}")
def _load_cache(self) -> Optional[Dict]:
"""
从缓存文件加载token
Returns:
Optional[Dict]: 缓存的token数据如果文件不存在或格式错误则返回None
"""
if not self.cache_file_path.exists():
return None
try:
with open(self.cache_file_path, 'r', encoding='utf-8') as f:
cache_data = json.load(f)
# 验证缓存数据格式
if 'access_token' not in cache_data or 'fetch_time' not in cache_data:
print(" ⚠ 缓存文件格式不正确将重新获取token")
return None
return cache_data
except json.JSONDecodeError:
print(" ⚠ 缓存文件JSON格式错误将重新获取token")
return None
except Exception as e:
print(f" ⚠ 读取缓存文件失败: {e}将重新获取token")
return None
def _save_cache(self, access_token: str, fetch_time: float):
"""
保存token到缓存文件
Args:
access_token: access_token值
fetch_time: 获取时间时间戳
Raises:
RuntimeError: 保存失败时抛出
"""
try:
# 确保缓存目录存在
self.cache_file_path.parent.mkdir(parents=True, exist_ok=True)
cache_data = {
'access_token': access_token,
'fetch_time': fetch_time
}
with open(self.cache_file_path, 'w', encoding='utf-8') as f:
json.dump(cache_data, f, ensure_ascii=False, indent=2)
print(f" ✓ Token已缓存到: {self.cache_file_path}")
except Exception as e:
raise RuntimeError(f"保存token缓存失败: {e}")
def _is_token_expired(self, fetch_time: float) -> bool:
"""
检查token是否已过期或即将过期
Args:
fetch_time: token获取时间时间戳
Returns:
bool: 如果已过期或即将过期返回True否则返回False
"""
current_time = time.time()
elapsed_time = current_time - fetch_time
# 如果已使用时间超过 (有效期 - 提前刷新时间),则认为需要刷新
return elapsed_time >= (self.TOKEN_EXPIRES_IN - self.REFRESH_BEFORE_EXPIRE)
def get_token(self) -> str:
"""
获取有效的access_token
优先从缓存读取如果缓存不存在或已过期则从API获取新token
Returns:
str: 有效的access_token
Raises:
ValueError: 环境变量未设置时抛出
RuntimeError: 获取token失败时抛出
"""
# 1. 验证环境变量配置
self._validate_env_config()
# 2. 尝试从缓存加载
print("检查token缓存...")
cache_data = self._load_cache()
if cache_data:
access_token = cache_data['access_token']
fetch_time = cache_data['fetch_time']
# 检查是否过期
if not self._is_token_expired(fetch_time):
elapsed_time = time.time() - fetch_time
remaining_time = self.TOKEN_EXPIRES_IN - elapsed_time
print(f" ✓ 使用缓存的token (剩余有效期: {int(remaining_time)}秒)")
return access_token
else:
print(" ⚠ 缓存的token已过期或即将过期将重新获取")
else:
print(" ⚠ 未找到有效的token缓存")
# 3. 从API获取新token
token_data = self._fetch_token_from_api()
access_token = token_data['access_token']
fetch_time = time.time()
# 4. 保存到缓存
self._save_cache(access_token, fetch_time)
return access_token
def refresh_token(self) -> str:
"""
强制刷新token无论是否过期
Returns:
str: 新的access_token
Raises:
ValueError: 环境变量未设置时抛出
RuntimeError: 获取token失败时抛出
"""
print("强制刷新access_token...")
# 验证环境变量配置
self._validate_env_config()
# 从API获取新token
token_data = self._fetch_token_from_api()
access_token = token_data['access_token']
fetch_time = time.time()
# 保存到缓存
self._save_cache(access_token, fetch_time)
return access_token
def clear_cache(self):
"""
清除token缓存文件
"""
if self.cache_file_path.exists():
try:
self.cache_file_path.unlink()
print(f" ✓ 已清除token缓存: {self.cache_file_path}")
except Exception as e:
print(f" ✗ 清除缓存失败: {e}")
else:
print(" 缓存文件不存在,无需清除")
def get_access_token(cache_file_path: Optional[str] = None) -> str:
"""
便捷函数获取有效的access_token
这是一个简化的接口用于快速获取token而不需要创建TokenManager实例
Args:
cache_file_path: token缓存文件路径如果为None则使用默认路径
Returns:
str: 有效的access_token
Raises:
ValueError: 环境变量未设置时抛出
RuntimeError: 获取token失败时抛出
"""
manager = TokenManager(cache_file_path)
return manager.get_token()
if __name__ == "__main__":
"""测试代码"""
print("=" * 60)
print("Token Manager 测试")
print("=" * 60)
print()
try:
# 测试获取token
manager = TokenManager()
token = manager.get_token()
print("\n" + "=" * 60)
print("测试结果")
print("=" * 60)
print(f"✓ 成功获取access_token")
print(f" Token (前20字符): {token[:20]}...")
print(f" Token长度: {len(token)}")
print("=" * 60)
# 测试再次获取(应该使用缓存)
print("\n再次获取token测试缓存...")
token2 = manager.get_token()
if token == token2:
print(" ✓ 成功使用缓存的token")
else:
print(" ⚠ 获取了新的token可能缓存失效")
except ValueError as e:
print(f"\n✗ 配置错误: {e}")
print("\n请设置以下环境变量:")
print(" export CORPID=your_corpid")
print(" export CORPSECRET=your_corpsecret")
except RuntimeError as e:
print(f"\n✗ 运行错误: {e}")
except Exception as e:
print(f"\n✗ 未预期的错误: {e}")
import traceback
traceback.print_exc()

View File

@ -7,14 +7,14 @@
## 二、开发说明
### 2.1 access_token管理策略
- **第阶段前:** 所有需要access_token的操作由开发者手动获取token并传入程序
- **第阶段:** 实现access_token的自动获取与缓存机制
- **第阶段后:** 程序自动管理access_token的获取、缓存和刷新
- **第阶段前:** 所有需要access_token的操作由开发者手动获取token并传入程序
- **第阶段:** 实现access_token的自动获取与缓存机制
- **第阶段后:** 程序自动管理access_token的获取、缓存和刷新
### 2.2 日志记录策略
- **所有api调用记录都要写入log文件夹下的api_log.json**
- **第阶段前:** 使用简单的print输出关键信息
- **第阶段:** 实现完整的日志记录系统
- **第阶段前:** 使用简单的print输出关键信息
- **第阶段:** 实现完整的日志记录系统
### 2.3 API频率限制
@ -269,9 +269,9 @@
- 重试机制
**验收标准:**
- [ ] 开单成功后能正确回写✅到"开单状态"字段
- [ ] 能正确回写TAPD单号并生成可点击的链接
- [ ] 能正确回写bug状态
- [x] 开单成功后能正确回写✅到"开单状态"字段
- [x] 能正确回写TAPD单号并生成可点击的链接
- [x] 能正确回写bug状态
- [ ] 开单失败后能正确回写❌到"开单状态"字段
- [ ] 回写失败时有重试机制
- [ ] 所有操作都有详细的日志记录
@ -288,102 +288,152 @@
---
### 第四阶段:定时任务与服务化
### 第四阶段:access_token自动获取与缓存
**目标:** 将工具部署为服务,实现定时扫描和状态同步
**目标:** 实现access_token的自动获取与缓存机制不再需要手动传入token该模块应该与其他功能独立
**任务清单:**
1. 实现企业微信认证模块
- 从环境变量读取CORPID和CORPSECRET
- 调用企业微信API获取access_token
- 处理认证失败的情况
2. 设计token缓存文件结构
- 在项目根目录创建token缓存文件token_cache.json
- 存储token值
- 存储获取时间(时间戳)
3. 实现token缓存逻辑
- 首次获取时写入缓存文件
- 每次使用前从文件读取并检查是否过期(当前时间 - 获取时间 >= 7200秒
- 过期则重新获取并更新缓存文件
4. 实现token失效处理
- 检测token失效API返回42001错误码
- 自动重新获取并更新缓存
5. 重构现有代码
- 保留命令行传入access_token的逻辑如无传入则自动从缓存获取
- 所有API调用自动使用缓存的token
- 修改wework_api.py添加token管理功能
**验收标准:**
- [x] 能从环境变量读取corpid和corpsecret
- [x] 能自动获取access_token并写入缓存文件
- [x] token能正确从文件读取和复用
- [x] token过期时能自动重新获取
- [ ] token失效时API返回42001能自动重新获取
- [x] 不再需要手动传入access_token命令行参数可选
- [ ] 减少了获取token的API调用次数
- [ ] 环境变量未设置时有清晰的错误提示
- [x] 缓存文件格式清晰易读
*修复了开单状态不为空的记录也被读取的问题filter_spec的conjunction应该为CONJUNCTION_AND而不是and
**技术要点:**
- token有效期为7200秒2小时
- 使用时间戳判断过期time.time()
- 使用os.environ读取环境变量
- JSON文件的读写操作
- 异常处理:网络错误、认证失败、文件读写错误等
**缓存文件格式示例:**
```json
{
"access_token": "xxx",
"fetch_time": 1702800000
}
```
**潜在问题记录:**
- 多实例部署时的token文件竞争问题本阶段暂不处理
- 时钟不同步导致的过期判断错误
- 环境变量的安全性问题
- 缓存文件的权限问题
---
### 第五阶段:定时任务与服务化
**目标:** 实现定时任务调度,让工具能够自动定期执行开单扫描
**任务清单:**
1. 实现定时任务调度
- 使用schedule库或APScheduler
- 配置开单扫描频率默认5分钟
- 配置状态同步频率默认15分钟
2. 实现bug状态同步功能
- 查询已开单的记录
- 调用TAPD API获取bug最新状态
- 更新智能表格的"bug状态"字段
3. 实现服务启动和停止
- 命令行参数解析
- 优雅退出机制
4. 实现配置文件扩展
- 添加轮询频率配置
- 添加状态同步频率配置
5. 完善日志和监控
- 添加运行统计信息
- 添加性能监控
- 创建调度脚本scheduler.py
2. 实现服务启动和停止
- 命令行参数解析(启动、停止)
- 优雅退出机制捕获SIGINT、SIGTERM信号
3. 实现配置文件扩展
- 在config.ini中添加轮询频率配置
4. 完善执行统计
- 每次执行后输出统计信息扫描X条成功Y条失败Z条
- 记录执行时间
**验收标准:**
- [ ] 服务能正常启动和停止
- [ ] 能按配置的频率执行开单扫描
- [ ] 能按配置的频率执行状态同步
- [ ] 状态同步功能正常工作
- [ ] 服务异常时能自动恢复
- [ ] 有完善的运行日志和统计信息
- [ ] 每次执行都调用main.py的核心逻辑
- [ ] 服务异常时能自动恢复(捕获异常后继续下次执行)
- [ ] 有清晰的执行统计信息
- [ ] Ctrl+C能优雅退出
**技术要点:**
- 定时任务的线程安全
- 信号处理SIGINT、SIGTERM
- schedule库的基本使用
- 信号处理(signal模块
- 异常捕获和恢复
- 配置热加载(可选)
- 循环执行的设计
**潜在问题记录:**
- 长时间运行的内存泄漏问题
- access_token过期的自动刷新
- 并发执行的冲突处理
- 并发执行的冲突处理(如果上次执行未完成)
---
### 第五阶段access_token自动获取与缓存
### 第六阶段bug状态同步功能
**目标:** 实现access_token的自动获取与缓存机制不再需要手动传入token
**目标:** 实现定期同步TAPD的bug状态到智能表格
**任务清单:**
1. 实现企业微信认证模块
- 从环境变量读取corpid和corpsecret
- 调用企业微信API获取access_token
- 处理认证失败的情况
2. 设计token缓存结构
- 存储token值
- 存储过期时间
- 存储获取时间
3. 实现token缓存逻辑
- 首次获取时缓存
- 使用前检查是否过期
- 过期前自动刷新建议提前5分钟
4. 实现持久化存储(可选)
- 使用文件存储token
- 服务重启后能恢复token
5. 实现token失效处理
- 检测token失效API返回42001错误码
- 自动重新获取
6. 重构现有代码
- 保留命令行传入access_token的逻辑如无传入则自动调用缓存的token
- 所有API调用自动使用缓存的token
1. 实现状态同步功能模块
- 查询智能表格中已开单的记录("开单状态"为✅且"TAPD单号"不为空)
- 过滤掉状态为"完成"或"取消"的记录
- 调用TAPD API获取bug最新状态
- 对比状态是否变化
2. 实现状态回写逻辑
- 只有状态发生变化时才更新智能表格
- 批量更新智能表格的"bug状态"字段
3. 集成到定时任务
- 在scheduler.py中添加状态同步任务
- 配置状态同步频率默认15分钟
4. 实现配置文件扩展
- 在config.ini中添加状态同步频率配置
5. 完善错误处理
- TAPD API调用失败的处理
- 智能表格更新失败的处理
**验收标准:**
- [ ] 能从环境变量读取corpid和corpsecret
- [ ] 能自动获取access_token
- [ ] token能正确缓存和复用
- [ ] token过期前能自动刷新
- [ ] token失效时能自动重新获取
- [ ] 不再需要手动传入access_token
- [ ] 减少了获取token的API调用次数
- [ ] 环境变量未设置时有清晰的错误提示
- [ ] 能正确查询已开单的记录
- [ ] 能正确过滤"完成"和"取消"状态的记录
- [ ] 能成功调用TAPD API获取bug状态
- [ ] 状态变化时能正确回写到智能表格
- [ ] 状态未变化时不进行更新减少API调用
- [ ] 能按配置的频率执行状态同步
- [ ] 有清晰的同步统计信息检查X条更新Y条
**技术要点:**
- token有效期为7200秒2小时
- 建议在过期前5分钟刷新
- 使用os.environ读取环境变量
- 线程安全的缓存实现
- 异常处理:网络错误、认证失败等
- TAPD获取bug详情API
- 状态对比逻辑
- 批量更新优化
- 定时任务的多任务调度
**潜在问题记录:**
- 多实例部署时的token共享问题
- 时钟不同步导致的过期判断错误
- 环境变量的安全性问题
- 大量bug的状态查询性能问题
- TAPD API频率限制
- 状态映射的准确性
---
### 第阶段:企业微信推送功能
### 第阶段:企业微信推送功能
**目标:** 实现开单失败时的企业微信推送通知
@ -425,48 +475,27 @@
---
### 第七阶段:字段合法性校验与优化
### 第八阶段:测试
**目标:** 完善字段值的合法性校验,提高数据质量
**目标:** 进行边界测试等,防止出现意外情况导致服务出错
**任务清单:**
1. 实现优先级字段校验
- 获取TAPD项目的优先级配置
- 校验智能表格中的值是否合法
2. 实现严重程度字段校验
- 校验可选值fatal、serious、normal、prompt、advice
3. 实现人员字段校验
- 校验userid格式
- 校验用户是否存在
4. 实现模块字段校验
- 获取TAPD项目的模块配置
- 校验模块是否存在
5. 实现版本字段校验
- 获取TAPD项目的版本配置
- 校验版本是否存在
6. 完善错误提示
- 明确指出不合法的字段和原因
- 提供修正建议
1.
**验收标准:**
- [ ] 能正确校验所有字段的合法性
- [ ] 不合法的值有明确的错误提示
- [ ] 校验失败时不创建TAPD单
- [ ] 校验结果能回写到智能表格(可选)
- [ ]
- [ ]
**技术要点:**
- TAPD API获取字段配置接口
- 智能表格单选字段的option_id
- 数据缓存:避免频繁查询配置
- 错误信息的友好展示
-
**潜在问题记录:**
- TAPD配置变更时的同步问题
- 自定义字段的校验规则
-
---
### 第阶段:日志系统与性能优化
### 第九阶段:日志系统与性能优化
**目标:** 实现完整的日志记录系统,优化系统性能,添加监控和告警
@ -534,8 +563,8 @@
- argparse命令行参数解析
- jsonJSON文件处理
- datetime时间处理
- logging日志记录阶段)
- schedule/APScheduler定时任务阶段)
- logging日志记录阶段)
- schedule/APScheduler定时任务阶段)
- **API**
- 企业微信文档API
- TAPD Open API
@ -551,14 +580,15 @@ workspace_id = 10158231
docid = your_doc_id
[Schedule]
# 第阶段添加
# 第阶段添加
scan_interval = 5
# 第六阶段添加
sync_interval = 15
```
### 环境变量(第阶段开始使用)
### 环境变量(第阶段开始使用)
```bash
# 企业微信(第阶段)
# 企业微信(第阶段)
WEWORK_CORPID=your_corpid
WEWORK_CORPSECRET=your_corpsecret
@ -577,18 +607,20 @@ autoTAPD/
│ ├── __init__.py
│ ├── api_test.py # 前期准备API测试工具
│ ├── config.py # 配置管理
│ ├── wework_api.py # 企业微信API阶段完善)
│ ├── wework_api.py # 企业微信API阶段完善)
│ ├── smartsheet.py # 智能表格操作
│ ├── tapd_api.py # TAPD API
│ ├── validator.py # 数据校验
│ ├── mapper.py # 字段映射
│ ├── token_cache.py # token缓存(第五阶段)
│ ├── scheduler.py # 定时任务(第四阶段)
│ ├── logger.py # 日志模块(第阶段)
│ ├── scheduler.py # 定时任务(第五阶段)
│ ├── sync_status.py # bug状态同步第六阶段)
│ ├── logger.py # 日志模块(第阶段)
│ └── main.py # 主程序
├── logs/ # 日志目录(第八阶段)
├── logs/ # 日志目录(第九阶段)
│ ├── api_log.json # API调用记录
│ └── api_test_log.json # API测试记录
├── tests/ # 测试代码
├── token_cache.json # token缓存文件第四阶段
├── requirements.txt # 依赖包
└── README.md # 项目说明
```
@ -609,8 +641,8 @@ autoTAPD/
3. **错误恢复:** 服务异常时要能自动恢复,不影响后续执行
4. **向后兼容:** 配置文件和数据结构的变更要考虑向后兼容
5. **文档更新:** 每个阶段完成后更新相关文档
6. **access_token管理**五阶段前手动传入,第五阶段后自动管理
7. **日志策略:**八阶段前使用print第八阶段后使用logging模块
6. **access_token管理**四阶段前手动传入,第四阶段后自动管理
7. **日志策略:**九阶段前使用print第九阶段后使用logging模块
## 十、阶段依赖关系
@ -623,15 +655,17 @@ autoTAPD/
第三阶段(回写结果)
第四阶段(定时任务
第四阶段(access_token自动化
第五阶段(access_token自动化)
第五阶段(定时任务与服务化)
第六阶段(企业微信推送
第六阶段(bug状态同步
第七阶段(字段合法性校验
第七阶段(企业微信推送
第八阶段(日志系统 + 性能优化)
第八阶段(测试)
第九阶段(日志系统 + 性能优化)
```
## 十一、后续优化方向