首先通过Docker API或文件监听采集容器日志,再用正则匹配或关键词检测解析异常,最后通过钉钉Webhook发送告警,结合channel与goroutine实现高并发处理,并加入去重与频率控制避免告警风暴。

在现代微服务架构中,容器化应用产生的日志是系统可观测性的核心部分。通过 Golang 实现容器日志的告警与通知,可以帮助开发者及时发现异常行为,比如错误频繁出现、服务崩溃或请求超时等。下面是一个实用的操作指南,教你如何用 Golang 构建一个轻量级的日志告警系统。
收集容器日志
要实现告警,首先要获取容器的日志数据。常见方式包括:
- Docker API:使用官方 docker/docker 客户端库直接读取容器日志流。
- Kubernetes 日志:通过 kubernetes/client-go 获取 Pod 的标准输出日志。
- 文件监听:若日志已落盘(如 /var/log/containers),可用 fsnotify 监听文件变化。
示例:使用 Docker SDK 读取日志
package main
import (
"context"
"io"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
)
func readContainerLogs(containerID string) {
cli, _ := client.NewClientWithOpts(client.FromEnv)
ctx := context.Background()
options := types.ContainerLogsOptions{
ShowStdout: true,
ShowStderr: true,
Follow: true,
Tail: "10",
}
reader, _ := cli.ContainerLogs(ctx, containerID, options)
defer reader.Close()
io.Copy(defaultWriter, reader) // 可替换为自定义处理器
}
解析与规则匹配
原始日志通常是文本流,需解析结构化内容并判断是否触发告警。你可以基于关键词、正则表达式或结构化解码(如 JSON 日志)来识别异常。
立即学习“go语言免费学习笔记(深入)”;
- 将日志行解析为结构体,提取时间、级别、消息等字段。
- 定义告警规则,例如:“ERROR 出现超过 5 次/分钟” 或 “包含 'panic' 关键词”。
- 使用 regexp 包进行模式匹配。
示例:简单关键字检测
func shouldAlert(logLine string) bool {
errorPatterns := []string{"panic", "fatal", "connection refused", "timeout"}
for _, pattern := range errorPatterns {
if strings.Contains(strings.ToLower(logLine), pattern) {
return true
}
}
return false
}
实现告警通知机制
当检测到异常日志时,系统应通过可靠渠道发送通知。常用方式包括:
- 邮件通知:使用 net/smtp 发送 SMTP 邮件。
- Webhook 推送:向钉钉、企业微信或 Slack 的机器人接口 POST 消息。
- 集成 Prometheus Alertmanager:将事件转为 Alert 字段推送。
示例:发送钉钉告警
func sendDingTalkAlert(message string) {
payload := map[string]interface{}{
"msgtype": "text",
"text": map[string]string{"content": "[LOG ALERT] " + message},
}
jsonBody, _ := json.Marshal(payload)
resp, _ := http.Post(
"https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN",
"application/json",
bytes.NewBuffer(jsonBody),
)
resp.Body.Close()
}
整合与运行
将上述模块组合成一个常驻服务:
- 启动日志采集协程(goroutine)。
- 使用缓冲 channel 将日志传递给处理管道。
- 维护滑动窗口计数器或限流机制避免重复告警。
- 记录已触发事件的指纹(如 hash(message[:10]) + timestamp),防止风暴。
基本流程:
logs := make(chan string, 100)
go readContainerLogsToChan(containerID, logs)
for log := range logs {
if shouldAlert(log) {
sendDingTalkAlert(trimLog(log))
}
}
基本上就这些。Golang 凭借其高并发和简洁的网络支持,非常适合构建这类监控小工具。关键是稳定采集、精准识别、及时通知。不复杂但容易忽略的是去重和误报控制,建议加入简单的频率限制和环境标记(如 dev/staging/prod)。










