请求协助:编写Ruby日志解析脚本的正则表达式
解析Heroku Router日志的Ruby正则方案
我太懂你卡在Heroku日志正则这的感受了——这类日志看着复杂,但其实格式非常规整,咱们拆解开来写就能搞定。先看你给出的日志示例:
2014-01-09T06:16:53.766841+00:00 heroku[router]: at=info method=POST path=/logs/save_personal_data host=services.pocketplaylab.com fwd="5.13.87.91" dyno=web.10 connect=1ms service=42ms status=200 bytes=16
2014-01-09T06:16:53.772938+00:00 heroku[router]: at=info method=POST path=/api/users/1000028442...
它的核心结构就是时间戳 + 服务标识 + 一堆键值对,我们可以针对这个结构写正则,再用Ruby的正则分组轻松提取每个字段。
适配的正则表达式
这里给你一套能覆盖所有关键字段的正则,我逐段给你解释:
# 匹配日志整体结构的正则 LOG_PATTERN = /^(?<timestamp>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+[+-]\d{2}:\d{2}) (?<service>\w+\[\w+\]): (?<fields>.*)$/ # 匹配单个键值对的正则 FIELD_PATTERN = /(?<key>\w+)=("?(?<value>[^" ]+)"?)/
完整Ruby解析脚本示例
直接把下面的代码拿去用,替换成你自己的日志读取逻辑就行:
LOG_PATTERN = /^(?<timestamp>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+[+-]\d{2}:\d{2}) (?<service>\w+\[\w+\]): (?<fields>.*)$/ FIELD_PATTERN = /(?<key>\w+)=("?(?<value>[^" ]+)"?)/ # 这里可以替换成读取日志文件的逻辑,比如 File.readlines('your_log.log') log_lines = [ '2014-01-09T06:16:53.766841+00:00 heroku[router]: at=info method=POST path=/logs/save_personal_data host=services.pocketplaylab.com fwd="5.13.87.91" dyno=web.10 connect=1ms service=42ms status=200 bytes=16', '2014-01-09T06:16:53.772938+00:00 heroku[router]: at=info method=POST path=/api/users/1000028442...' ] log_lines.each do |line| # 先匹配日志的时间戳和服务标识 if match = line.match(LOG_PATTERN) log_data = { timestamp: match[:timestamp], service: match[:service], details: {} } # 逐个提取所有键值对字段 match[:fields].scan(FIELD_PATTERN) do |key, value| # 去掉字段值可能带的引号(比如fwd字段的双引号) clean_value = value.gsub(/^"|"$/, '') # 自动转换数字类型,方便后续统计 clean_value = case clean_value when /^\d+$/ then clean_value.to_i when /^\d+\.\d+$/ then clean_value.to_f else clean_value end log_data[:details][key.to_sym] = clean_value end # 这里可以换成写入数据库、生成统计报表等逻辑 puts "解析完成的日志:" p log_data puts "---" else puts "⚠️ 无法匹配的日志行: #{line}" end end
正则各部分细节解释
- 时间戳匹配:
(?<timestamp>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+[+-]\d{2}:\d{2})- 精准匹配Heroku用的ISO8601格式时间,包含毫秒和时区偏移,用命名分组
timestamp直接提取。
- 精准匹配Heroku用的ISO8601格式时间,包含毫秒和时区偏移,用命名分组
- 服务标识匹配:
(?<service>\w+\[\w+\])- 匹配
heroku[router]这类格式的服务名,命名分组service方便区分不同服务的日志。
- 匹配
- 键值对匹配:
(?<key>\w+)=("?(?<value>[^" ]+)"?)- 同时兼容
key=value和key="value"两种格式,处理带引号的字段(比如IP地址),用key和value分组直接提取内容。
- 同时兼容
小提示
如果你的日志里有特殊格式的字段(比如路径带特殊符号),可以把FIELD_PATTERN里的[^" ]改成[^"],允许值里包含空格——不过Heroku router日志的键值对一般不会有空格,当前版本足够用。
内容的提问来源于stack exchange,提问作者Максим
相关产品推荐
相关产品推荐

