Nginx日志加工分析

本文涉及的产品
对象存储 OSS,20GB 3个月
日志服务 SLS,月写入数据量 50GB 1个月
对象存储 OSS,恶意文件检测 1000次 1年
简介: 介绍如何使用阿里云日志服务-数据加工处理Nginx日志,帮助后续分析、可视化以及报警。

数据加工服务简介

数据加工服务是阿里云SLS推出的面向日志ETL处理的服务,主要解决数据加工过程中转换、过滤、分发、富化等场景。

img1.png
接下来,我们以nginx日志解析为例, 帮助大家快速入门阿里云日志服务的数据加工。

用于实验的Nginx日志

假设我们通过极简模式采集了Nginx默认日志。默认的nginx 日志format如下

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                     '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

通过使用极简模式采集Nginx日志,样例如下:
img2.png

数据加工交互界面

点击 准备数据加工的Logstore,在查询栏的上方,有一个“数据加工”的开关,打开
img3.png

数据加工的代码编辑、预览、发布相关界面如下图:
img4.png

一般情况下,我们都可以使用快速预览模式,如果我们的数据加工涉及到使用mysql、oss等维表,可以使用高级预览做实际预览测试。

对Nginx日志进行数据加工 (Step by Step)

Step1. 使用正则抽取基础字段

对于极简模式采集的日志,内容都在一个字段叫content的字段里,不利于我们做分析。可以通过数据加工正则函数,抽取nginx日志里的字段,使用到的加工函数如下:

# 用于将源字段里的内容,通过正则捕获组抽取出对应的字段
e_regex("源字段", "正则或有命名捕获正则", "目标字段名或数组(可选)")

针对Nginx日志,使用以下语句进行正则抽取

# 通用字段抽取
e_regex("content",'(?<remote_addr>[0-9:\.]*) - (?<remote_user>[a-zA-Z0-9\-_]*) \[(?<local_time>[a-zA-Z0-9\/ :\-\+]*)\] "(?<request>[^"]*)" (?<status>[0-9]*) (?<body_bytes_sent>[0-9\-]*) "(?<refer>[^"]*)" "(?<http_user_agent>[^"]*)"')

通过正则抽取以后,可以看到日志的字段增加了refer、remote_addr、remote_user、request等字段。

img5.png

Step2. 处理时间字段

当前提取到的localtime不易读,我们把它解析成易读的格式,会用到的以下数据加工函数:

# 用于设置字段值
e_set("字段名", "固定值或表达式函数")

# 将时间字符串解析为日期时间对象
dt_strptime('值如v("字段名")', "格式化字符串")

# 将日期时间对象按照指定格式转换为字符串
dt_strftime(日期时间表达式, "格式化字符串")

实现思路,先通过 dt_strptime 将local_time的时间转化为日期时间对象,然后再通过dt_strftime将日期时间对象转化为标准的日期时间字符串。 针对Nginx local_time的转化,使用如下数据加工语句:

e_set("local_time", dt_strftime(dt_strptime(v("local_time"),"%d/%b/%Y:%H:%M:%S %z"),"%Y-%m-%d %H:%M:%S"))

实现效果如下:
img6.png

Step3. 解析request uri

可以看到request字段由 METHOD URI VERSION组成,我们希望对 requst字段进行抽取,获取到请求的METHOD、URI以及VERSION,并且将请求URI中的请求的参数变成字段,方便后续进行查询。可以用以下函数来做实现

# 使用正则将request uri抽取
e_regex("源字段名", "正则或有命名捕获正则", "目标字段名或数组(可选)", mode="fill-auto")

# 进行urldecode
url_decoding('值如v("字段名")’)

# 设置字段值
e_set("字段名", "固定值或表达式函数", ..., mode="overwrite")

# 将request_uri中的key=value的组合抽取成字段 值的模式
e_kv("源字段正则或列表", sep="=", prefix="")

实现语句

e_regex("request", "(?<request_method>[^\s]*) (?<request_uri>[^\s]*) (?<http_version>[^\s]*)")
e_set("request_uri", url_decoding(v("request_uri")))
e_kv("request_uri", prefix="uri_")

实现效果
img7.png

Step4. http code状态码映射

每一个http状态码都代表了不同的含义,下面是一份http状态码的映射表, 我们可以通过e_table_map 函数来将状态码的信息扩展到我们的日志字段中,方便后续做统计分析。
img8.png

涉及到的数据加工函数如下:

# 用来做字段富化,类似sql里join的功能
e_table_map("表格如通过tab_parse_csv(...)解析得到的",
            "源字段列表或映射列表如[('f1', 'f1_new'), ('f2', 'f2_new')]", 
            "目标字段列表")

# 用来把csv文件解析成table对象
tab_parse_csv(CSV文本数据, sep=',', quote='"')

# code的映射关系维度表是一个csv文件,存在oss上,使用res_oss_file
res_oss_file(endpoint="OSS的endpoint", ak_id="OSS的AK_ID", 
             ak_key="OSS的AK_KEY", bucket="OSS的bucket", file="在OSS中存的文件地址", 
             change_detect_interval="定时更新时间,默认为0")

实际使用到的DSL语句如下

# http状态码映射
e_table_map(
      tab_parse_csv(
           res_oss_file(endpoint="oss-cn-shanghai.aliyuncs.com",
              ak_id='',ak_key='',
              bucket="etl-test", 
              file="http_code.csv", format='text')),
              [("status","code")],
              [("alias","http_code_alias"),
               ("description","http_code_desc"),
               ("category","http_code_category")])

看一下映射后的效果
img9.png

Step5. 通过UserAgent判断客户端操作系统

我们想了解客户用的是什么os版本,可以通过user agent里的字段用正则匹配来判断,用到dsl语句

# 取某个字段的值
v("字段名")

# 获取ua相关信息
ua_parse_all("带useragent信息的内容")

# 展开json字段, 因为ua_parse_all得到的是一个json对象,为了展开到一级字段使用e_json做展开
# 模式有 simple、full、parent、root 参考https://help.aliyun.com/document_detail/125488.html#section-o7x-7rl-2qh
e_json("源字段名", fmt="模式", sep="字段分隔符")

# 丢弃临时产生的字段
e_drop_fields("字段1", "字段2")

用到的dsl语句

# 通过User Agent解析获得客户端信息
e_set("ua",ua_parse_all(v("http_user_agent")))
e_json("ua", fmt='full',sep='_')
e_drop_fields("ua",regex=False)

加工效果
img10.png

Step6. 非200的日志投递到指定logstore

可以使用e_output函数来做日志投递,用regex_match做字段匹配

# 条件判断if
e_if("条件1如e_match(...)", "操作1如e_regex(...)", "条件2", "操作2", ....)

# 判断是否相等
op_ne(v("字段名1"), v("字段名2"))

# output发送到目标名称,目标名称在数据加工保存任务的时候配置对应的logstore信息
e_output(name="指定的目标名称")

实际的dsl语句

# 分发非200的日志
e_if(op_ne(v("http_code_alias"),"2xx"), e_output(name="nginx-log-bad"))

在预览里看到这个效果。(保存加工的时候,需要设置好对应project、logstore的ak信息)
img11.png

完整的DSL代码以及上线流程

好了,通过一步一步的开发调试,现得到完整的DSL代码如下

# 通用字段抽取
e_regex("content",'(?<remote_addr>[0-9:\.]*) - (?<remote_user>[a-zA-Z0-9\-_]*) \[(?<local_time>[a-zA-Z0-9\/ :\-]*)\] "(?<request>[^"]*)" (?<status>[0-9]*) (?<body_bytes_sent>[0-9\-]*) "(?<refer>[^"]*)" "(?<http_user_agent>[^"]*)"')

# 设置localttime
e_set("local_time", dt_strftime(dt_strptime(v("local_time"),"%d/%b/%Y:%H:%M:%S"),"%Y-%m-%d %H:%M:%S"))

# uri字段抽取
e_regex("request", "(?<request_method>[^\s]*) (?<request_uri>[^\s]*) (?<http_version>[^\s]*)")
e_set("request_uri", url_decoding(v("request_uri")))
e_kv("request_uri", prefix="uri_")

# http状态码映射
e_table_map(
      tab_parse_csv(
           res_oss_file(endpoint="oss-cn-shanghai.aliyuncs.com",
              ak_id='',ak_key='',
              bucket="etl-test", 
              file="http_code.csv", format='text')),
              [("status","code")],
              [("alias","http_code_alias"),
               ("description","http_code_desc"),
               ("category","http_code_category")])

# 通过User Agent解析获得客户端信息
e_set("ua",ua_parse_all(v("http_user_agent")))
e_json("ua", fmt='full',sep='_')
e_drop_fields("ua",regex=False)

# 分发非200的日志
e_if(op_ne(v("http_code_alias"),"2xx"), e_coutput(name="nginx-log-bad"))

在页面提交代码以后,保存数据加工

配置目标logstore信息,默认走完加工逻辑的日志都会发送到第一个目标logstore,我们在代码里指定了e_output到指定logstore,因此还需要第二个目标,并且目标的名字和e_output里指定的目标名称一致。

img12.png

保存完即完成上线,可以在数据处理-加工下看到该任务,点击进去可以看到加工延迟等信息。

img13.png

Nginx日志查询、可视化、报警

查询

假设,我们想对nginx异常的日志进行查询,以便做问题定位。我们可以针对需要查询的字段开启索引
img14.png

开启索引可以使用“自动生成索引”来自动帮助生成字段索引列表(否则需要手工填写字段)
img15.png

点击确定后,即完成索引配置。比如我们要查询 uri_item_name参数值为“测试商品_89”的错误情况,可以使用这样的query

* and uri_item_name : 测试商品_89

img16.png

可视化

我们关心每个请求的http请求是否成功,对于异常状态码,想做相应的统计,以方便我们做问题发现。 可以使用如下query统计 nginx-log-bad(非2xx类请求的logstore)状态码分布

* | select http_code_alias,count(*) as c 
         from log where http_code_alias is not null 
             group by http_code_alias order by c

使用饼图做可视化
img17.png

点击,“添加到仪表盘”,即可完成仪表盘的创建
img18.png

添加完成后,在左侧仪表盘就
img19.png

报警

针对非2xx的状态码,我们不仅要做可视化,还需要对它进行报警。 可以在刚才创建的仪表盘里,点击“告警->创建”,根据提示创建相应的告警规则。
img20.png

img21.png
img30.jpg

总结

本次训练营,以最常见的Nginx日志作为例,介绍数据加工在日志的转化、处理、富化、转发等场景下相关的算子使用,帮助大家入门SLS的数据加工。除了文中提到的算子,数据加工还有200+的算子以支持更多的日志处理的场景,相关内容可以参考如下:
a) SLS数据加工整体简介:https://help.aliyun.com/document_detail/125384.html
b) SLS数据加工函数总览:https://help.aliyun.com/document_detail/159702.html
在数据加工之后,针对相关字段建立索引,可以方便地对日志内容进行各种场景的分析,并且针对有需要的场景设置对应的报警,提升系统的稳定性。

相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
目录
相关文章
|
5月前
|
存储 运维 监控
SelectDB 实现日志高效存储与实时分析,完成任务可领取积分、餐具套装/水杯/帆布包!
SelectDB 实现日志高效存储与实时分析,完成任务可领取积分、餐具套装/水杯/帆布包!
|
5月前
|
SQL 监控 数据挖掘
SLS 重磅升级:超大规模数据实现完全精确分析
SLS 全新推出的「SQL 完全精确」模式,通过“限”与“换”的策略切换,在快速分析与精确计算之间实现平衡,满足用户对于超大数据规模分析结果精确的刚性需求。标志着其在超大规模日志数据分析领域再次迈出了重要的一步。
468 117
|
6月前
|
数据可视化 关系型数据库 MySQL
ELK实现nginx、mysql、http的日志可视化实验
通过本文的步骤,你可以成功配置ELK(Elasticsearch, Logstash, Kibana)来实现nginx、mysql和http日志的可视化。通过Kibana,你可以直观地查看和分析日志数据,从而更好地监控和管理系统。希望这些步骤能帮助你在实际项目中有效地利用ELK来处理日志数据。
469 90
|
4月前
|
自然语言处理 监控 安全
阿里云发布可观测MCP!支持自然语言查询和分析多模态日志
阿里云可观测官方发布了Observable MCP Server,提供了一系列访问阿里云可观测各产品的工具能力,包含阿里云日志服务SLS、阿里云应用实时监控服务ARMS等,支持用户通过自然语言形式查询
464 0
阿里云发布可观测MCP!支持自然语言查询和分析多模态日志
|
3月前
|
人工智能 运维 监控
Aipy实战:分析apache2日志中的网站攻击痕迹
Apache2日志系统灵活且信息全面,但安全分析、实时分析和合规性审计存在较高技术门槛。为降低难度,可借助AI工具如aipy高效分析日志,快速发现攻击痕迹并提供反制措施。通过结合AI与学习技术知识,新手运维人员能更轻松掌握复杂日志分析任务,提升工作效率与技能水平。
|
6月前
|
存储 消息中间件 缓存
MiniMax GenAI 可观测性分析 :基于阿里云 SelectDB 构建 PB 级别日志系统
基于阿里云SelectDB,MiniMax构建了覆盖国内及海外业务的日志可观测中台,总体数据规模超过数PB,日均新增日志写入量达数百TB。系统在P95分位查询场景下的响应时间小于3秒,峰值时刻实现了超过10GB/s的读写吞吐。通过存算分离、高压缩比算法和单副本热缓存等技术手段,MiniMax在优化性能的同时显著降低了建设成本,计算资源用量降低40%,热数据存储用量降低50%,为未来业务的高速发展和技术演进奠定了坚实基础。
253 1
MiniMax GenAI 可观测性分析 :基于阿里云 SelectDB 构建 PB 级别日志系统
|
6月前
|
SQL 存储 自然语言处理
让跨 project 联查更轻松,SLS StoreView 查询和分析实践
让跨 project 联查更轻松,SLS StoreView 查询和分析实践
114 1
|
8月前
|
机器学习/深度学习 人工智能 运维
智能日志分析:用AI点亮运维的未来
智能日志分析:用AI点亮运维的未来
2405 15
|
8月前
|
SQL 关系型数据库 MySQL
MySQL事务日志-Undo Log工作原理分析
事务的持久性是交由Redo Log来保证,原子性则是交由Undo Log来保证。如果事务中的SQL执行到一半出现错误,需要把前面已经执行过的SQL撤销以达到原子性的目的,这个过程也叫做"回滚",所以Undo Log也叫回滚日志。
302 7
MySQL事务日志-Undo Log工作原理分析
|
7月前
|
SQL 分布式计算 Serverless
基于阿里云 EMR Serverless Spark 版快速搭建OSS日志分析应用
基于阿里云 EMR Serverless Spark 版快速搭建OSS日志分析应用
130 0