用 bufio.Scanner 流式读取大日志文件可避免内存溢出;默认按行切分,每次仅加载一行,需设置 scanner.Buffer 防止超长行报错。

直接上手做日志分析,不需要先搭整套可观测体系——用 os.Open + bufio.Scanner 读文件、strings.Contains 或 regexp 匹配关键信息、再用 map 统计,三步就能跑通一个真实可用的分析脚本。
怎么读大日志文件不卡死?
新手常把整个日志文件 os.ReadFile 读进内存,一碰几百 MB 的 /var/log/syslog 就 panic:out of memory。Go 原生没“流式读取”封装,但 bufio.Scanner 就是干这个的。
- 它默认按行切分,每次只加载一行到内存,适合处理任意大小的日志文件
- 注意设置缓冲区上限,避免超长日志行触发
scanner.Err() == bufio.ErrTooLong,可加scanner.Buffer(make([]byte, 4096), 1 - 别用
for line := range scanner.Lines(那是tail库的写法),标准库 Scanner 没这个字段
匹配关键字该用 strings 还是 regexp?
看场景:查 "ERROR" 或 "timeout" 这种固定字符串,strings.Contains 快 5–10 倍,且无编译开销;要抽 ID=12345 或解析 Nginx 时间戳,必须用 regexp。
-
strings.ToLower(line)再搜,比正则忽略大小写更轻量,适合简单 case - 正则别在循环里反复
regexp.Compile,提成全局变量或用sync.Once初始化 - 容器 JSON 日志里
"log":"panic: connection refused"这种嵌套内容,得先json.Unmarshal解一层,再对log字段做字符串处理
统计结果不准?大概率是时间/编码/换行踩了坑
分析结果和 grep -c 对不上?常见三个隐形雷:
立即学习“go语言免费学习笔记(深入)”;
- 日志含中文或特殊符号时,文件可能是
GBK编码,而 Go 默认按 UTF-8 解析——scanner.Text()返回乱码,匹配必然失败(Linux 系统日志一般为 UTF-8,但某些嵌入式设备或旧服务可能不是) - 用
time.Parse解析[05/Feb/2024:10:23:45 +0000]这类格式,Layout 必须严格匹配:对应的是"02/Jan/2006:15:04:05 -0700",错一位就返回零值时间 -
scanner.Scan()遇到 CR/LF 不一致(Windows vs Linux)可能跳行,建议统一用strings.TrimRight(line, "\r\n")清理
package main
import (
"bufio"
"fmt"
"os"
"regexp"
"strings"
)
func main() {
file, _ := os.Open("/var/log/syslog")
defer file.Close()
scanner := bufio.NewScanner(file)
scanner.Buffer(make([]byte, 4096), 1<<20) // 防超长行
// 预编译正则:提取 "kernel:" 开头的内核消息
kernelRe := regexp.MustCompile(`^kernel: \[.*?\] (.+)`)
errorCount := 0
kernelMsgs := []string{}
for scanner.Scan() {
line := strings.TrimRight(scanner.Text(), "\r\n")
if strings.Contains(strings.ToLower(line), "error") {
errorCount++
}
if matches := kernelRe.FindStringSubmatch([]byte(line)); matches != nil {
kernelMsgs = append(kernelMsgs, string(matches[1]))
}
}
fmt.Printf("Error count: %d\n", errorCount)
fmt.Printf("Kernel messages: %d\n", len(kernelMsgs))
}
真正难的从来不是写代码,而是确认你读的那行日志,确实是原始日志里“那一行”——比如 Docker 容器日志是 JSON 行,tail -f 看着是纯文本,实际每行开头有时间戳和容器 ID 字段,直接字符串匹配会漏掉真实错误内容。










