Nginx输出JSON格式日志

为了配合nginx日志分析,需要将Nginx的日志转为json格式,这个本身并不是很难,配置一个log_format即可,但在具体操作中却遇到了很多意想不到的问题。

根据实际需求,将记录的字段以json格式创建一个命名的日志,下面是我创建的一个示例:

log_format json '{"@timestamp":"$time_iso8601",'
            '"@version":"1",'
            '"server_addr":"$server_addr",'
            '"remote_addr":"$remote_addr",'
            '"host":"$host",'
            '"uri":"$uri",'
            '"body_bytes_sent":$body_bytes_sent,'
            '"bytes_sent":$body_bytes_sent,'
            '"upstream_response_time":$upstream_response_time,'
            '"request":"$request",'
            '"request_length":$request_length,'
            '"request_time":$request_time,'
            '"status":"$status",'
            '"http_referer":"$http_referer",'
            '"http_x_forwarded_for":"$http_x_forwarded_for",'
            '"http_user_agent":"$http_user_agent"'
            '}';

发布到线上之后发现部分json字符串不能正常解析,主要体现在非法json值未转义字符串的问题

0x01 非法json值处理

非法json值

json中key为upstream_response_time的value为-,这很明显不是一个json字符串,而且这种情况大多出现在301的响应中。通过排查发现是在Nginx中配置了301跳转,也就是说Nginx自己处理了这个请求,不再将请求向后端转发,这直接导致upstream_response_time的值为空,写入日志后,Nginx将空值替换为了-,从而导致了惨案的发生。

那如何处理呢?Google之后发现Nginx有个map的指令,该指令的作用是创建一个变量,而这个变量由其它变量通过一个映射表置换得来,跟Python中的map很像,但是Nginx的map值支持正则等。

根据描述,我们在配置文件中添加一个入下的map,在$upstream_response_time为空的时候返回为0,将该值赋值给新变量$upstream_response_timer,添加之后该问题得到了处理,但是接着出现了另外一个问题。

map $upstream_response_time $upstream_response_timer {
    default $upstream_response_time;
    ""        0;
}

0x02 未转义字符串问题

运行一段时间后,发现依然后很多请求未解析,查找发现日志中充斥了大量如下图的字符:

特殊字符

很显然这是“恶意”扫描的请求,这类请求的特点是可能会包含如双引号(“)、反斜杠等在json字符串中被认为非法的字符,处理这类问题的最直接手段就是转义,那Nginx下如何处理呢?

通过查询nginx日志,发现log\_format本身就可以对字符串进行转义,这个参数的名称是escape,这个参数本身也需要指定一个值,可以是defaultjsonnone,很明显,我们需要指定为json

log_format json escape=json '{"@timestamp":"$time_iso8601",'
...

配置之后,所有json字符串格式的非法字符都会被转义处理。

0x03 结论

总结起来,对于Nginx输出json格式日志需要添加如下配置来保证json格式的正确性:

map $upstream_response_time $upstream_response_timer {
    default $upstream_response_time;
    ""        0;
}
log_format json escape=json '{"@timestamp":"$time_iso8601",'
            '"@version":"1",'
            '"server_addr":"$server_addr",'
            '"remote_addr":"$remote_addr",'
            '"host":"$host",'
            '"uri":"$uri",'
            '"body_bytes_sent":$body_bytes_sent,'
            '"bytes_sent":$body_bytes_sent,'
            '"upstream_response_time":$upstream_response_timer,'
            '"request":"$request",'
            '"request_length":$request_length,'
            '"request_time":$request_time,'
            '"status":"$status",'
            '"http_referer":"$http_referer",'
            '"http_x_forwarded_for":"$http_x_forwarded_for",'
            '"http_user_agent":"$http_user_agent"'
            '}';
            
server {
    ...
    access_log /path/to/access.log json;
}

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏javathings

WebClient 实践

Spring 发展很快,Spring 5 已经出来很久了,但有些新的特性却还没怎么研究过, 比如 WebClient。

1.3K20
来自专栏bamboo前端学习记录

mock数据

本文主要是记录如何mock数据操作,防止我这条金鱼过几天又忘了如何操作。不涉及原理(当然写原理目前的我也写不出来,哈哈哈),只是写了操作步骤。如果有误欢迎大佬指...

77020
来自专栏钱塘小甲子的博客

sjtuLib爬虫(二)----sjtuLib爬虫之建立Scrapy框架

还是爬交大图书馆的数据,不过这次我们用Scrapy的开源爬虫框架。上次我们在Anaconda平台下安装了Scrapy,这回就可以开始用啦。

8820
来自专栏TheOneGIS空间站

Struts2中的Ajax请求

1. 使用Stream result的方式以流的形式写出到客户端。(这种方式我没有亲自做实验,下面的例子参考的是Struts2的官方文档)

46330
来自专栏Java进阶之路

Logstash解析嵌套Json

由于我们的埋点日志是嵌套json类型,要想最终所有字段展开来统计分析就必须把嵌套json展开。

45420
来自专栏编程微刊

小程序读取几种不同格式json数据(小程序json解析)

1:解析这个json:http://www.intmote.com/myproject/test/new_file.json

3.1K30
来自专栏钱塘小甲子的博客

绕过JS写爬虫

      最近要把很多数据抓下来先存起来,现有历史数据再说。其中,东方财富网有许多数据,其中有一个是机构调研的数据。

21820
来自专栏bamboo前端学习记录

JSON 格式

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。 易于人阅读和编写。同时也易于机器解析和生成。2001年由 Dou...

54340
来自专栏学习

linux 使用jq对json数据进行操作

背景: 通过jmeter生成的resultReport报告,在linux上需要获取到报告结果数据。

74650
来自专栏Java架构师进阶

深入学习SpringMVC以及学习总结

如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135...

8310

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励