go轻量日志收集工具核心是fsnotify监听文件写入、偏移量断点续读、正则解析时间/级别/消息、chan解耦采集与多目标输出(控制台/文件/http),需妥善处理logrotate轮转与offset持久化。

用 Go 实现一个轻量级日志收集工具,核心在于:监听文件变化、实时读取新增内容、结构化解析、统一发送到目标(如控制台、文件或网络端点)。不依赖重型框架,靠标准库就能搭出稳定可用的基础版本。
监听日志文件增量(使用 fsnotify)
日志通常是追加写入的,不能每次全量读取。推荐用 fsnotify 监听文件修改事件,只在收到 Write 或 Create 事件时触发读取逻辑。
- 初始化 watcher,添加待监控的日志路径(支持通配符需自行 glob 展开)
- 忽略
Chmod等无关事件,专注OpWrite - 注意:linux 下轮转日志(logrotate)可能触发
Rename,需配合检查 inode 变更或监听整个目录
按行流式读取 + 断点续读(避免重复/丢失)
文件可能持续增长,进程重启后要从上次位置继续读。关键是在读取器中维护偏移量(offset),并持久化到本地小文件(如 .offset.json)。
- 打开文件后,先
Seek(offset, io.SeekStart)跳转到上次位置 - 用
bufio.Scanner按行读取,每成功处理一行就更新 offset(建议每 N 行或每秒刷盘一次) - 遇到文件截断(size
简单结构化解析(适配常见格式)
不必一开始就支持复杂 DSL。先覆盖最常用场景:时间戳 + 级别 + 消息(如 [2024-05-10 14:22:08] INFO hello world)。
立即学习“go语言免费学习笔记(深入)”;
- 用正则提取字段:
^[(d{4}-d{2}-d{2} d{2}:d{2}:d{2})]s+(w+)s+(.*)$ - 解析失败的行保留原始字符串,打上
parse_error: true标记 - 后续可扩展 json 行日志直通(检测首字符是否为
{)
输出到多种目标(channel 驱动 + 插件化)
用 Go 的 channel 做内部管道,解耦采集与发送。定义统一日志结构体,下游按需实现 Writer 接口:
-
ConsoleWriter:格式化后输出到 stdout -
FileWriter:写入本地归档文件,按天分片 -
HttpWriter:POST 到日志服务 API(带重试、批量打包、超时控制) - 所有 Writer 启动独立 goroutine,通过
chan *LogEntry接收数据
基本上就这些。不复杂但容易忽略的是 offset 持久化时机和轮转兼容性——这两点调好,基础版就稳了。