Files
hotime/docs/Seq_日志集成.md

6.3 KiB
Raw Permalink Blame History

Seq 日志集成

HoTime 框架内置 Seq 日志推送支持。通过在 config.json 填写 seqUrl 即可激活。
目标:用 Seq 集中检索替代翻 logs/*.txt;本地 logFile 可并行保留。


配置项

config.json 中添加:

"seqUrl":    "http://127.0.0.1:5341",
"seqApiKey": ""
字段 默认值 说明
seqUrl 空(不激活) Seq 服务地址,空值时功能静默不生效
seqApiKey API Key,免费单用户版留空

instance 字段由框架自动拼接为 ip:port(如 192.168.1.10:8085),无需手动填写。

激活后每个 HTTP 请求会自动:

  • 生成 request_id12 位 hex),回写响应头 X-Request-Id
  • sessionId 前 12 位作为 sid 写入请求级日志(脱敏,避免把登录凭据写进 Seq)
  • 业务日志、SQL 日志、访问日志均携带 sid / request_id
  • 控制台自动降噪(零额外配置):业务日志(that.Log)控制台放宽到 Info+(Debug/SQL 不上控制台),访问日志(that.WebConnectLog)控制台保持 Warn+(量大不上控制台);Debug/SQL/访问日志(Info 级)仍全量进 Seq 与文件

会话追踪与 LogBind

框架在 handler 入口派生请求级 Logger,并浅拷贝 Db 将其 Log 指向同一 Logger,因此 SQL 日志自动带会话字段。字段会出现在同条日志的控制台/文件/Seq 出口上。

业务在 SetConnectListener 中按需绑定自定义字段(建议放在鉴权/守卫之前,这样未登录被拒的 Warning 也能带上维度字段):

appIns.SetConnectListener(func(context *Context) bool {
	if v := context.Session("user_id").ToCeilInt64(); v > 0 {
		context.LogBind("user_id", v)
	}
	// 其他 session / 请求参数字段同理:有值再绑
	return false
})

LogBind 后,本请求后续业务日志与 SQL 日志都会带上该字段。session 在 context 内有缓存,多次 Session() 只查一次库。字段名与取值由业务自行约定。

不带会话字段的边界:

  • fmt.Println / stdout 捕获、panic、MySQL driver、定时任务等无请求上下文的日志
  • 直接写 that.Application.Log 的旧代码(应改用 that.Loggerthat.LogBind 后的请求级 Logger

控制台降噪(配了 seqUrl

Logger 控制台行为
业务日志(that.Log Info+Info / Warn / Error,含 Display 非 0 的 WarnDebug/SQL 不上控制台)
访问日志(that.WebConnectLog Warn+(访问日志量大,Info 级不上控制台)
出口 行为
Seq logLevel 全量(Info/Debug/SQL/访问日志等)
本地文件 与原先一致,不受控制台过滤影响

未配置 seqUrl 时控制台仍按 logLevel 全打。

框架不新增配置项;如需自定义某个 Logger 的控制台门槛,可在挂 Seq 后调用 Logger.SetConsoleMinLevel(level zerolog.Level)(仅影响该 Logger 的控制台出口,不影响 Seq/文件)。


客户端 IP 与地域

零配置。ip 选取优先级(跳过空值与回环 127.0.0.1 / ::1):

  1. EO-Connecting-IPEdgeOne 真实建连 IP
  2. X-Forwarded-For 从左到右第一个非回环(反代误把 CDN 写入 X-Real-IP 时仍能落到客户端)
  3. X-Real-IP(非回环)
  4. RemoteAddr

访问日志另附 ip_chain:上述源头出现过的 IP 按首次出现顺序逗号拼接,同一 IP 不重复;若与 ip 相同则省略该字段。

请求头有 EO-Client-IPCountry 时,访问日志追加 ip_country(两位国家码);没有则不记。


架构原理

业务代码
  │  that.Logger.Info().Msg("...")  ← 请求级(含 sid/request_id
  │  Db.Query → SQL 日志            ← 同一请求级 Logger
  │  fmt.Println("...")             ← 捕获后无 sid
  ↓
multiWriterhotimev1.5/log/logger.go
  ├─ Console(挂 Seq 后:业务 Info+ / 访问日志 Warn+)→ 终端
  ├─ FileWriter                 → 本地文件(按需,全量)
  └─ SeqWriter                  → Seq(全量)
        │  Write() 只做 channel <- bytesO(1) 非阻塞
        ↓
     channel(容量 10000
        ↓  后台 goroutine
     批量打包(100 条 或 500ms
        ↓  HTTP POST(失败重试 1 次)
     Seq 服务(CLEF 格式)

优雅停机时调用 CloseSeq() 冲刷残留批次,避免停机前后日志丢失。


字段映射(zerolog → CLEF

zerolog 字段 Seq CLEF 字段 说明
time @t 毫秒精度 ISO 8601
level @l Debug/Information/Warning/Error/Fatal
message / msg @m 消息正文(不用 @mt,避免 {xxx} 被当模板)
caller caller 调用位置
sid sid sessionId 前 12 位
request_id request_id 单次请求 id
ip ip 客户端最佳 IP
ip_chain ip_chain 多源去重链路(与 ip 不同时才有)
ip_country ip_country EO-Client-IPCountry
ua ua 访问日志携带,User-Agent 原文截断 200 字符(按 rune 安全截断)
其余自定义字段 原字段名 LogBind 追加的字段原样保留
instance ip:port
source stdout / stderr / panic 等

搜索语法速查

目标 查询语句
按会话追踪 sid = 'abc123def456'
按单次请求 request_id = 'fedcba987654'
关键词 直接输入,如 支付失败
日志级别 @l = 'Error'
特定实例 instance = '192.168.1.10:8085'
地域 ip_country = 'CN'
stdout source = 'stdout'
panic source = 'panic'
组合 @l = 'Error' and sid = 'abc123def456'
关键字组合其他条件 @Message like '%支付失败%' and @l = 'Warning' and instance = '192.168.1.10:8085'

Seq 安装

  • Windowshttps://datalust.co/download/seq
  • Dockerdocker run -d --restart always --name seq -p 5341:80 -e ACCEPT_EULA=Y datalust/seq
  • 访问 http://localhost:5341

相关文档