分享个有意思的access.log解析的工具

242 阅读3分钟

前言

一直以来很想找个轻量级的关于项目相应时间的监控工具

通常如果只是单独某个功能慢的话我们可以通过arths排查然后去进行优化。

或者客户有IT的会给我们一份慢SQL进行处理优化。

但是客户只是说用系统慢运维反馈给开发也只是说客户反馈慢,对这种情况我一直没有找到好的突破口,skwalking感觉有点重,还有些老项目,最重要的是为客户搭建一套监控超出了我的工作范畴。最后思来思去还是冲access日志作为突破口。

goaccess功能挺强大的,但是win下的环境安装感觉有点复杂。最近找了一个简单的java版解析和过滤工具自己也可以改造处理,但他写的链式过滤感觉挺有意思的和单表SQL查询媲美了(有sql转化的部分但是我还没深入了解),先忍不住在这里分享下。

项目地址:我不知道gitee和github是不是同一个作者

GITEE:gitee.com/aacsgaa/log…

GITHUB:github.com/at0x7c00/lo…

我拉的分支搞了些小优化:gitee.com/0X00000000/…

基本用法

用法很简单自带的测试demo里面写了很多例子。这里简单的说一点。

access日志

127.0.0.1 - - [18/Nov/2024:14:42:16 +0800] "GET /t2/static/images/index/bg4.png HTTP/1.1" 200 55912

数据过滤的一个例子

//文件读取
public void init(){
    scaner = new FileScaner(
          "D:\log_idea\localhost_access_log.2024-11-1*.txt");
}
@Test
public void testOrderByMax()throws Exception{
//查询显示的列默认数组索引从0开始 默认的分割时空格 有点问题 例如上面的时间有[]也有空格
// max min avg total这些分组都是支持的
    scaner.select("5,max(8)") 
          .processor(3, processor)//这个是对应的列转换函数
          .processor(8, processor_time)
          //可以用where条件进行过滤 作者居然还实现了一个and or的多条件过滤
          //照猫画虎我这里添加了一个正则非的过滤
          .where(Conditions.and(Conditions.noRegexMatch("5", ".*\.(js|css|png).*$")))
          //分组查询
          .groupBy("5")
          //对应的查询排序的是select那里分割的也是从0开始的
          .orderBy(OrderBy.desc(1))
          .list();
    scaner.print();
}

上面的逻辑处理看了下流程大概

  • 读取文件支持多个批量,文件名支持正则搜索
  • 切割数据 access日志天然的一行一行的。查询都是根据分割的数组索引来的(demo里面的数字)
  • where条件过滤
  • 从group开始分组保存map<groupkey,List<String[]>)
  • 不分组的话key是null
  • 然后条件带分组函数的处理:max min avg total 过滤
  • 排序输出

修复关于日志行分割的一个问题

原有时通过空格,这里处理了下 类似上面日期的问题[ ]可以单独做为一个内容。这个代码是问的AI哈哈

public static List<String> split(String input) {
    List<String> result = new ArrayList<>();
    StringBuilder token = new StringBuilder();
    int bracketLevel = 0;
    for (char c : input.toCharArray()) {
       if (c == '[') {
          bracketLevel++;
       } else if (c == ']') {
          bracketLevel--;
       }
       if (bracketLevel == 0 && c == ' ') {
          if (token.length() > 0) {
             result.add(token.toString());
             token = new StringBuilder();
          }
       } else {
          token.append(c);
       }
    }
    if (token.length() > 0) {
       result.add(token.toString());
    }
    return result;
}

最后SQL转化部分有时间了看了在分享下了