首页
学习
活动
专区
圈层
工具
发布

我试了试用 SQL查 Linux日志,好用到飞起

前两天我在公司机房里加班,凌晨一点多,咖啡喝到胃烧得慌,日志还一大片在那滚动。结果我们组的小李突然冒出来一句:“哥们你用 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 查日志,太好用了。结果人家一脸懵逼…算了,这种快乐可能只有程序员懂。

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OO7buTbRbFa9QSlOs7oUxMhQ0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。
领券