45 lines
3.5 KiB
Markdown
45 lines
3.5 KiB
Markdown
# WebSocket 可选观测
|
||
|
||
`ws/observe` 为 `ws.Client`、`ws.Server` 的会话提供连接日志和聚合快照。核心 `ws` 不依赖全局 Logger;观测器不启动后台 goroutine,不给每条消息增加日志、锁或 span。
|
||
|
||
```go
|
||
logger, err := logx.New(logx.Default())
|
||
if err != nil { return err }
|
||
defer logger.Close() // 必须晚于 Client/Server 的 Shutdown 完成
|
||
|
||
observer := observe.New(logger) // nil 表示只统计,不记日志
|
||
handlers := observer.Wrap(ws.Handlers{
|
||
OnMessage: func(ctx context.Context, session *ws.Session, message ws.Message) error {
|
||
return session.Send(ctx, message)
|
||
},
|
||
})
|
||
server, err := ws.NewServer(ws.ServerConfig{})
|
||
if err != nil { return err }
|
||
mux.Handle("/ws", server.Handler(handlers))
|
||
|
||
// 由项目按自己的采样周期读取,接入 metrics、Prometheus 或 OTel。
|
||
snapshot := observer.Snapshot()
|
||
```
|
||
|
||
导入路径为 `git.yuntuo.hk/k2safe/go-omni/ws/observe`。同一个 Observer 和同一组包装后的 Handlers 可供多个连接并发复用;每个会话有独立的开始时间。每个会话仅包装一次。使用客户端重连和 `ClientConfig.Prepare` 时,在每次 Prepare 返回前调用 `observer.Wrap(handlers)`。
|
||
|
||
快照包含:
|
||
|
||
- `Opened / Closed / Active`:已观察到的连接总数、关闭回调结束数、当前处于受观察生命周期中的连接数。连接可能在 OnOpen 执行前断开,此时仍在 OnClose 计入 Opened 和 Closed,日志时长为 0。
|
||
- `MessagesSent / MessagesReceived / BytesSent / BytesReceived`:已关闭会话的最终统计,加上当前会话的即时统计。发送成功表示写入完成;不是对端收到消息或业务处理成功的确认。统计口径与 `Session.Stats()` 一致。
|
||
- `WriteQueuedMessages / WriteQueuedBytes / ReadQueuedMessages / ReadQueuedBytes`:调用快照时,各活跃连接队列水位之和。接收侧包括仍在处理、尚未释放的消息。
|
||
- `SampledPeak*`:历次 Snapshot 观察到的聚合峰值;不是精确的历史峰值,采样间隔内的突增可能未被记录。
|
||
- `CloseCallbackPanics`:下游 OnClose 回调发生 panic 的次数。
|
||
|
||
Snapshot 为 O(活跃会话数),只在采样时读取 `Session.Stats()`,不会替换消息回调。避免在每条消息上采样;采样周期由项目根据连接规模决定。快照不会保存已关闭连接的 ID,也不引入高基数指标标签。自行导出 OTel 时,建议记录握手、连接时长、消息数与字节数;业务消息追踪应显式传递上下文,不自动延长握手 span 到整条连接的寿命。
|
||
|
||
日志只由适配器写入固定事件名、Session ID、时长、关闭码和固定阶段。不会展开错误文本、Cause、URL、请求头、消息体或对端关闭原因;业务自定义 `OpError.Op` 也通过固定白名单筛选。用户传入 Logger 自身已经附加的属性仍由用户负责。默认日志级别为 Info。
|
||
|
||
OnClose 的收尾使用 defer,即使业务回调 panic,也会归档消息统计、移除活跃记录、记录固定的 `on_close_panic` 阶段,再把 panic 交还核心处理。此处“关闭”表示 I/O 已停止且下游 OnClose 已返回或 panic;核心随后才关闭 `Session.Done()`。因此 `Snapshot.Active == 0` 不是生命周期完成屏障,停机必须等待 `Client/Server.Shutdown` 或 `Session.Done`,再关闭 Logger。观测器不会在 OnClose 中等待自身 Done,也不会在 Done 后继续写日志。
|
||
|
||
运行真实 TCP 与并发测试:
|
||
|
||
```sh
|
||
go test -race ./ws/observe
|
||
```
|