1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
| import structlog
from typing import Any
class LogContext:
"""日志上下文"""
def __init__(self):
self.context = {}
def set(self, key: str, value: Any):
"""设置上下文"""
self.context[key] = value
def get(self, key: str, default=None):
"""获取上下文"""
return self.context.get(key, default)
def clear(self):
"""清空上下文"""
self.context.clear()
# 全局日志上下文
log_context = LogContext()
# 配置structlog
structlog.configure(
processors=[
structlog.stdlib.filter_by_level,
structlog.stdlib.add_logger_name,
structlog.stdlib.add_log_level,
structlog.stdlib.PositionalArgumentsFormatter(),
structlog.processors.TimeStamper(fmt="iso"),
structlog.processors.StackInfoRenderer(),
structlog.processors.format_exc_info,
structlog.processors.UnicodeDecoder(),
# 添加上下文
lambda logger, method_name, event_dict: {
**event_dict,
**log_context.context
},
# 格式化输出
structlog.processors.JSONRenderer()
],
context_class=dict,
logger_factory=structlog.stdlib.LoggerFactory(),
cache_logger_on_first_use=True,
)
class ServiceLogger:
"""服务日志记录器"""
def __init__(self, service_name: str):
self.service_name = service_name
self.logger = structlog.get_logger()
def log_request(self, request_id: str, method: str, path: str, **kwargs):
"""记录请求"""
self.logger.info(
"incoming_request",
request_id=request_id,
service=self.service_name,
method=method,
path=path,
**kwargs
)
def log_response(
self,
request_id: str,
status_code: int,
duration_ms: float,
**kwargs
):
"""记录响应"""
self.logger.info(
"outgoing_response",
request_id=request_id,
service=self.service_name,
status_code=status_code,
duration_ms=duration_ms,
**kwargs
)
def log_error(self, error: Exception, **kwargs):
"""记录错误"""
self.logger.error(
"error_occurred",
service=self.service_name,
error_type=type(error).__name__,
error_message=str(error),
**kwargs
)
def log_service_call(
self,
service_name: str,
method: str,
duration_ms: float,
success: bool,
**kwargs
):
"""记录服务调用"""
self.logger.info(
"service_call",
caller=self.service_name,
service=service_name,
method=method,
duration_ms=duration_ms,
success=success,
**kwargs
)
# 中间件示例
class LoggingMiddleware:
"""日志中间件"""
def __init__(self, logger: ServiceLogger):
self.logger = logger
async def process_request(self, request, call_next):
"""处理请求"""
request_id = generate_request_id()
start_time = time.time()
# 设置日志上下文
log_context.set('request_id', request_id)
log_context.set('user_id', request.user_id)
# 记录请求
self.logger.log_request(
request_id=request_id,
method=request.method,
path=request.path
)
try:
# 处理请求
response = await call_next(request)
# 记录响应
duration_ms = (time.time() - start_time) * 1000
self.logger.log_response(
request_id=request_id,
status_code=response.status_code,
duration_ms=duration_ms
)
return response
except Exception as e:
duration_ms = (time.time() - start_time) * 1000
self.logger.log_error(
error=e,
request_id=request_id,
duration_ms=duration_ms
)
raise
finally:
log_context.clear()
|