前两天我在公司机房里加班,凌晨一点多,咖啡喝到胃烧得慌,日志还一大片在那滚动。结果我们组的小李突然冒出来一句:“哥们你用 SQL 查过 Linux 日志没?比你 grep awk 那套快多了。”我当时愣了一下,心说日志不是一堆文本文件嘛,用 SQL?这不扯呢嘛。结果一试…真香。
我们线上有几十台机器,Nginx、Tomcat、系统内核,各种日志一堆,每个文件都几百 MB 往上。正常用cat | grep | awk能搞,但一旦要做复杂统计,比如“过去半小时 500 错误里哪个 IP 最多”,就特别难受。命令拼半天还容易打错。小李说他在用log2sql的思路,把日志导进 SQLite 或 MySQL,然后用 SQL 直接分析,瞬间理解了。SQL 本来就是干这种事的。
把日志导进数据库
我最开始试的是 Nginx 的 access.log,格式大概这样:
192.168.0.12 - - [24/Aug/2025:11:43:21 +0800] "GET /api/order?id=123 HTTP/1.1" 200 532 "-" "Mozilla/5.0"
随手写了个 Java 程序,用正则解析,然后写进 MySQL。核心代码差不多长这样:
import java.sql.*;
import java.util.regex.*;
publicclass LogImporter {
privatestaticfinal String regex = "^(\\S+) - - \\[(.+?)\\] \"(\\S+) (.*?) (\\S+)\" (\\d{3}) (\\d+)";
privatestaticfinal Pattern pattern = Pattern.compile(regex);
public static void main(String[] args) throws Exception {
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/logs", "root", "123456");
PreparedStatement ps = conn.prepareStatement(
"INSERT INTO access_log(ip, time, method, url, protocol, status, size) VALUES (?,?,?,?,?,?,?)");
String line = "192.168.0.12 - - [24/Aug/2025:11:43:21 +0800] \"GET /api/order?id=123 HTTP/1.1\" 200 532";
Matcher m = pattern.matcher(line);
if (m.find()) {
ps.setString(1, m.group(1));
ps.setString(2, m.group(2));
ps.setString(3, m.group(3));
ps.setString(4, m.group(4));
ps.setString(5, m.group(5));
ps.setInt(6, Integer.parseInt(m.group(6)));
ps.setInt(7, Integer.parseInt(m.group(7)));
ps.executeUpdate();
}
ps.close();
conn.close();
}
}
简单跑一下,一行日志就进库了。再配个批量处理,把整个 access.log 全倒进来。
查询的快乐
导进去以后,SQL 就能随便玩了,比如:
查最常见的请求:
SELECT url, COUNT(*) as cnt
FROM access_log
GROUP BY url
ORDER BY cnt DESC
LIMIT 10;
半小时内 500 错误最多的 IP:
SELECT ip, COUNT(*)
FROM access_log
WHERE status = 500
AND time > NOW() - INTERVAL 30 MINUTE
GROUP BY ip
ORDER BY COUNT(*) DESC;
以前要写 awk,现在三行 SQL,结果清清楚楚。
一些坑
当然也不是没坑。比如日志时间格式带[24/Aug/2025:11:43:21 +0800],要先转成标准时间,插库时就得写个转换函数。还有就是日志量太大时 MySQL 撑不住,后来我换了 SQLite 本地快速实验,效果也不错,再大就得考虑 ELK 或 ClickHouse 这种专业玩意儿了。
用 SQL 和 Java 搭配的妙处
为什么不用 Python?主要是我们后端项目都在 Java 上,直接写个小工具挂到 Spring Boot 里,顺便还能做个接口,比如:
@RestController
public class LogQueryController {
@Autowired
JdbcTemplate jdbcTemplate;
@GetMapping("/top-errors")
public List<Map<String,Object>> topErrors() {
return jdbcTemplate.queryForList(
"SELECT ip, COUNT(*) as cnt FROM access_log WHERE status=500 GROUP BY ip ORDER BY cnt DESC LIMIT 5"
);
}
}
这样运维同事一打开浏览器就能看到,完全不需要懂 SQL。
说实话,这种玩法挺取巧的。日志其实就是半结构化数据,你要是硬用 grep,效率就低。换成 SQL,就像突然有了个分析平台,写点查询就能出报告。特别是晚上排查线上问题的时候,一句SELECT出来,心情比咖啡还提神。
不过话说回来,这玩意儿不适合长期大规模用,真要日志分析,还是 ELK、ClickHouse、Druid 那些专业系统更靠谱。但对个人开发者或者小团队,搞个 Java + SQL 方案足够轻便,能救命。
我那天折腾完都快三点了,下楼还碰见值夜班的保安,他看我一脸兴奋,以为我中大奖了。我说没,就是 SQL 查日志,太好用了。结果人家一脸懵逼…算了,这种快乐可能只有程序员懂。