求助:无法为Sophos UTM的特定syslog日志编写grok表达式
我完全懂这种感受——Sophos UTM的日志格式混合了系统日志头和自定义键值对,有时候还有截断内容,写grok确实容易卡壳。咱们一步步拆解你的日志,搞定这个表达式。
首先先把你的原始日志再贴一遍方便对照:
Apr 28 16:57:49 utm-vap-xx.domain.local 2018: 04:28-17:02:05 s-utm-01 httpproxy[52816]: id="0001" severity="info" sys="SecureWeb" sub="http" name="http access" action="pass" method="POST" srcip="10.11.110.5" dstip="216.163.176.36" user="" group="" ad_domain="" statuscode="200" cached="0" profile="REF_DefaultHTTPProfile (Default Web Filter Profile)" filteraction="REF_Defaul...
第一步:匹配系统日志头部
日志开头是标准的syslog格式部分,我们可以用预定义的grok模式来匹配:
%{MONTH:log_month} %{MONTHDAY:log_day} %{TIME:log_time} %{HOSTNAME:utm_hostname}
这部分会提取出:
log_month: Aprlog_day: 28log_time: 16:57:49utm_hostname: utm-vap-xx.domain.local
第二步:匹配Sophos内部时间和设备标识
接下来是UTM自己的时间戳和设备名:
%{YEAR:utm_year}: %{MONTHDAY:utm_day}-%{TIME:utm_time} %{HOSTNAME:utm_device}
提取内容:
utm_year: 2018utm_day: 28utm_time: 17:02:05utm_device: s-utm-01
第三步:匹配进程信息
然后是httpproxy的进程ID:
%{DATA:process_name}\[%{NUMBER:process_id:int}\]:
这里int是把进程ID转换成整数类型,提取结果:
process_name: httpproxyprocess_id: 52816
第四步:匹配键值对部分
最麻烦的就是后面的key="value"格式内容,因为有些值是空字符串(比如user=""),还有带空格的(比如profile="REF_DefaultHTTPProfile (Default Web Filter Profile)"),另外你的日志最后有截断的...,所以我们用GREEDYDATA来处理剩余内容,同时逐个匹配关键字段保证准确性:
id="%{DATA:log_id}" severity="%{DATA:severity}" sys="%{DATA:system}" sub="%{DATA:subsystem}" name="%{DATA:event_name}" action="%{DATA:action}" method="%{DATA:http_method}" srcip="%{IP:src_ip}" dstip="%{IP:dst_ip}" user="%{DATA:user}" group="%{DATA:group}" ad_domain="%{DATA:ad_domain}" statuscode="%{NUMBER:http_status:int}" cached="%{NUMBER:cached:int}" profile="%{DATA:web_filter_profile}" filteraction="%{GREEDYDATA:filter_action}"
这里用IP模式匹配IP地址更精准,int转换数字类型方便后续统计。GREEDYDATA会把filteraction的值(包括截断的...)全部捕获。
完整的Grok表达式
把所有部分组合起来,注意空格和分隔符:
%{MONTH:log_month} %{MONTHDAY:log_day} %{TIME:log_time} %{HOSTNAME:utm_hostname} %{YEAR:utm_year}: %{MONTHDAY:utm_day}-%{TIME:utm_time} %{HOSTNAME:utm_device} %{DATA:process_name}\[%{NUMBER:process_id:int}\]: id="%{DATA:log_id}" severity="%{DATA:severity}" sys="%{DATA:system}" sub="%{DATA:subsystem}" name="%{DATA:event_name}" action="%{DATA:action}" method="%{DATA:http_method}" srcip="%{IP:src_ip}" dstip="%{IP:dst_ip}" user="%{DATA:user}" group="%{DATA:group}" ad_domain="%{DATA:ad_domain}" statuscode="%{NUMBER:http_status:int}" cached="%{NUMBER:cached:int}" profile="%{DATA:web_filter_profile}" filteraction="%{GREEDYDATA:filter_action}"
测试建议
你可以用Grok Debugger(比如Elastic自带的或者本地调试工具)来测试这个表达式,把你的日志粘贴进去验证每个字段是否正确提取。如果遇到其他变体日志(比如不同的action或者profile名称),只需要调整对应的DATA部分即可——比如如果profile里的内容有特殊字符,DATA模式依然能处理,因为它匹配除了换行之外的所有字符。
内容的提问来源于stack exchange,提问作者Sean Jose

