2024-1-12 14:31
3.4 实现链路日志记录
目前可收集日志类型包括:当前的请求日志当前的响应日志自定义调试日志MySQL 操作日志Redis 操作信息Mongo 操作信息请求三方 API 接口的请求与响应日志日志收集,代码片段:// ./internal/pkg/core/core.go
// region 记录日志
var t *trace.Trace
if x := context.Trace(); x != nil {
t = x.(*trace.Trace)
} else {
return
}
decodedURL, _ := url.QueryUnescape(ctx.Request.URL.RequestURI())
// ctx.Request.Header,精简 Header 参数
traceHeader := map[string]string{
"Content-Type": ctx.GetHeader("Content-Type"),
}
t.WithRequest(&trace.Request{
TTL: "un-limit",
Method: ctx.Request.Method,
DecodedURL: decodedURL,
Header: traceHeader,
Body: string(context.RawData()),
})
var responseBody interface{}
if response != nil {
responseBody = response
}
t.WithResponse(&trace.Response{
Header: ctx.Writer.Header(),
HttpCode: ctx.Writer.Status(),
HttpCodeMsg: http.StatusText(ctx.Writer.Status()),
BusinessCode: businessCode,
BusinessCodeMsg: businessCodeMsg,
Body: responseBody,
CostSeconds: time.Since(ts).Seconds(),
})
t.Success = !ctx.IsAborted() && (ctx.Writer.Status() == http.StatusOK)
t.CostSeconds = time.Since(ts).Seconds()
logger.Info("trace-log",
zap.Any("method", ctx.Request.Method),
zap.Any("path", decodedURL),
zap.Any("http_code", ctx.Writer.Status()),
zap.Any("business_code", businessCode),
zap.Any("success", t.Success),
zap.Any("cost_seconds", t.CostSeconds),
zap.Any("trace_id", t.Identifier),
zap.Any("trace_info", t),
zap.Error(abortErr),
)
// endregion使用日志组件,代码片段:// main.go
import "gin-api-mono/internal/pkg/logger"
// 将日志输出到文件
accessLogger, err := logger.NewJSONLogger(
logger.WithField("domain", fmt.Sprintf("%s[%s]", configs.ProjectName, env.Active().Value())),
logger.WithTimeLayout(timeutil.CSTLayout),
logger.WithFileP(configs.ProjectAccessLogFile),
)
// 将日志输出到文件 + 控制台
accessLogger, err := logger.NewJSONLogger(
logger.WithOutputInConsole(),
logger.WithField("domain", fmt.Sprintf("%s[%s]", configs.ProjectName, env.Active().Value())),
logger.WithTimeLayout(timeutil.CSTLayout),
logger.WithFileP(configs.ProjectAccessLogFile),
)
// 如果需要日志分割,可以使用 WithFileRotationP() 方法。记录自定义调试日志,代码片段:import "gin-api-mono/internal/pkg/debug"
// 示例一,记录多个数据
debug.WithContext(ctx.RequestContext()).Logger("这是调试信息A1", "这是调试信息A2")
// 示例二,记录单个数据
debug.WithContext(ctx.RequestContext()).Logger("这是调试信息B")记录 MySQL 操作日志,代码片段:// 查询数据,核心是使用 .WithContext() 方法
h.db.GetDbR().WithContext(ctx.RequestContext()).Where(queryWhere).Find(&resultData)记录 Redis 操作日志,代码片段:import "gin-api-mono/internal/repository/redis"
// get,核心是使用 ctx.RequestContext() 参数
getResult, err := redis.GetRedisClient().Get(ctx.RequestContext(), "name").Result()记录 Mongo 操作日志,代码片段:import "gin-api-mono/internal/repository/mongo"
// 获取 Mongo Client
client := mongo.GetMongoClient()
// 获取 Collection,例如 Database 为 gin_api_mono,Collection 为 user
collection := client.Database("gin_api_mono").Collection("user")
// 查询数据,核心是使用 ctx.RequestContext() 参数
findResult, err := collection.Find(ctx.RequestContext(), bson.D{})记录请求三方 API 接口的日志,代码片段:import "gin-api-mono/internal/pkg/httpclient"
// 支持在上下文记录执行日志的 httpclient
client := httpclient.GetHttpClientWithContext(ctx.RequestContext())
// 普通的 httpclient
client := httpclient.GetHttpClient()
// GET
resp, err := client.R().
SetQueryParams(map[string]string{
"page_no": "1",
"limit": "20",
"sort":"name",
"order": "asc",
"random":strconv.FormatInt(time.Now().Unix(), 10),
}).
SetHeader("Accept", "application/json").
SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F").
Get("/search_result")日志结构,代码片段:// ./internal/pkg/trace/trace.go
// Trace 记录的参数
type Trace struct {
mux sync.Mutex
Identifier string `json:"trace_id"` // 链路ID
Request *Request `json:"request"` // 请求信息
Response *Response `json:"response"` // 返回信息
ThirdPartyRequests []*HttpLog `json:"third_party_requests"` // 调用第三方接口的信息
Debugs []*Debug `json:"debugs"` // 调试信息
SQLs []*SQL `json:"sqls"` // 执行的 SQL 信息
Redis []*Redis `json:"redis"` // 执行的 Redis 信息
Mongos []*Mongo `json:"mongos"` // 执行的 Mongo 信息
Success bool `json:"success"` // 请求结果 true or false
CostSeconds float64 `json:"cost_seconds"` // 执行时长(单位秒)
}不同组件能够将日志记录到上下文的核心是 拦截器,具体在第三方组件集成章节详细描述,此模块有些复杂,也可以微信找我沟通。有启发,左下角点击“启发”告诉我呀,点我即可直接跳转到小册目录合集 。