Java如何从访问日志字符串中提取datetime、requestType等指定字段
日志字段正则提取需求实现
需求说明
需要从标准Apache/Nginx格式的访问日志中,提取datetime、requestType、resourceUrl、status四个字段,适配的日志样例如下:
127.0.0.1 - - [03/Dec/2020:05:48:05 +0000] "GET /web/test/explorer HTTP/1.1" 200 175842
对应字段提取要求:
datetime:取值为方括号内的时间部分,无需时区后缀,样例取值03/Dec/2020:05:48:05requestType:取值为双引号开头的HTTP请求方法,样例取值GETresourceUrl:取值为请求方法后的完整请求路径+协议,样例取值/web/test/explorer HTTP/1.1status:取值为双引号结束后的第一个3位数字状态码,样例取值200
前置修正提示
你现有代码存在bug:getRequestObject方法中第二次调用setUrl是错误的,应该改为setResourceUrl,否则会覆盖之前设置的IP字段值。
各字段提取方法实现
1. extractDateTime 方法
匹配逻辑:匹配行中[和+之间的内容,正则规则为\[(.*?) \+
private String extractDateTime(String line) { String dateTime = ""; Pattern pattern = Pattern.compile("\\[(.*?) \\+"); Matcher matcher = pattern.matcher(line); if (matcher.find()) { dateTime = matcher.group(1); } return dateTime; }
2. extractRequestType 方法
匹配逻辑:匹配双引号后到第一个空格之间的请求方法,正则规则为"([A-Z]+)
private String extractRequestType(String line) { String requestType = ""; Pattern pattern = Pattern.compile("\"([A-Z]+) "); Matcher matcher = pattern.matcher(line); if (matcher.find()) { requestType = matcher.group(1); } return requestType; }
3. extractResourceUrl 方法
匹配逻辑:匹配请求方法后到双引号之前的内容,正则规则为"[A-Z]+ (.*?)"
private String extractResourceUrl(String line) { String resourceUrl = ""; Pattern pattern = Pattern.compile("\"[A-Z]+ (.*?)\""); Matcher matcher = pattern.matcher(line); if (matcher.find()) { resourceUrl = matcher.group(1); } return resourceUrl; }
4. extractStatus 方法
匹配逻辑:匹配双引号结束后第一个3位数字,正则规则为" (\d{3})
private int extractStatus(String line) { int status = 0; Pattern pattern = Pattern.compile("\" (\\d{3}) "); Matcher matcher = pattern.matcher(line); if (matcher.find()) { status = Integer.parseInt(matcher.group(1)); } return status; }
性能优化建议
- 所有正则的Pattern实例可以提前声明为类静态常量,避免每次调用方法重复编译,大幅提升大体积日志文件的解析性能
- 可以使用全量匹配正则一次性提取所有5个字段,减少多次匹配的开销,全量正则参考:
^(\\S+) - - \\[(.*?) \\+\\d+\\] "(\\S+) (.*?)" (\\d{3}) \\d+$,仅需一次匹配即可拿到所有字段值
内容的提问来源于stack exchange,提问作者Abdul Basit
相关产品推荐
相关产品推荐

