Nginx map 实现时间格式转换

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Nginx map 实现时间格式转换

哈喽大家好,我是咸鱼

最近我们需要把 Nginx 的日志接入到自研的日志采集平台上,但是这个平台只支持 JSON 格式,所以需要把 Nginx 日志格式改成 JSON 格式

例如下面这样的效果
image-20230912164014919.png
刚开始在主配置文件 nginx.conf 中定义了一个名叫 json 的日志格式字段
image-20230912164556449.png
验证的时候其他内容没啥问题,但是时间是2023-09-12T13:54:22+08:00 这样子的,不太符合预期
image-20230912142410045.png
咸鱼想着把 $time_iso8601 变量中的年月日时分秒分别提取出来然后用变量去接受它,如下所示:

我自定义了一个时间格式 $year-$month-$day $hour:$minutes:$seconds:000,然后接着用了一个 if 语句用于检查请求的时间是否匹配 ISO8601 时间格式(例如:2023-09-12T13:54:22+08:00

如果匹配,它将执行其中的代码块。在代码块中,使用正则表达式提取时间的年、月、日、小时、分钟和秒,并将它们赋值给变量 $year`、`$month$day`、`$hour$minutes` 和 `$seconds

    log_format json '{  "SYS_NO":"my_nginx",
                        "OS_TIME":"$year-$month-$day $hour:$minutes:$seconds",
                        "LOG_TYPE":"",
                        "RESULT":"$status",
                        "SPENT_TIME":"$request_time",
                        "CLIENT_IP":"$remote_addr",
                        "SERVER_IP":"$server_addr",
                        "O_CHANNEL":"$http_user_agent",
                        "UID":"$http_host",
                        "VALUE1":$body_bytes_sent,
                        "INFO1":"$http_referer",
                    }';
      if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})") {
                        set $year $1;
                        set $month $2;
                        set $day $3;
                        set $hour $4;
                        set $minutes $5;
                        set $seconds $6;
                        }

但是 nginx -t 检测的时候我发现 if 语句不能够放在 http 块内,否则会报错

在 Nginx 中,if 语句主要用于在 serverlocation 块内设置条件,以便根据请求的属性来执行不同的配置。if 语句通常应该包含在 serverlocation 块内,而不是直接放在 http 块中

如果将 if 语句放在一个一个 server 块中,这不得累死我(有很多个 server 块),而且后期维护也不方便

所以如何将自定义变量在全局配置中生效则成为了一个问题

map

map 指令是由 ngx_http_map_module 模块提供的,是 Nginx 配置文件中的一种用于创建变量映射的指令

模块链接:Module ngx_http_map_module (nginx.org)

它允许我们将一个或多个输入值映射到一个输出值,类似于字典或哈希表的概念。map 指令通常用于根据特定条件为请求设置自定义变量,或者执行基于请求属性的条件控制

比较常见的 map 用法是通过 map 来实现允许多个域名跨域访问的问题

语法如下:

map {
   mathJaxContainer[15]}new_variable {
   
    value1   result1;
    value2   result2;
    ...
    default  default_result;
}

其中:

  • $variable 输入变量,通常是 nginx 的内置变量。
  • $new_variable 输出变量,它将根据输入值的映射设置为特定的结果。
  • value1, value2, ... 输入值,可以列出多个值。
  • result1, result2, ... 与相应输入值相关联的输出结果。
  • default 一个可选项,表示如果没有匹配的输入值,将使用默认结果

需要注意的是,map 只能放在 http 块中

有了 map,我们就可以轻易的把 $time_iso8601` 变量中的 ISO 8601 格式的时间戳转换为指定的时间格式,然后存储到自定义变量 `$log_time

# nginx.conf
    map {
   mathJaxContainer[17]}log_time {
   
        default "";
        "~^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})T(?<hour>\d{2}):(?<minutes>\d{2}):(?<seconds>\d{2})" "${year}-${month}-${day} ${hour}:${minutes}:${seconds}";
    }

我们可以看到:

  • 输入变量为 $time_iso8601`,输出变量为 `$log_time
  • default "":如果没有匹配任何条件,将使用空字符串作为 $log_time 的值
  • "~^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})T(?<hour>\d{2}):(?<minutes>\d{2}):(?<seconds>\d{2})":这是一个正则表达式条件,它用于匹配 ISO 8601 格式的时间戳。该正则表达式包含了多个捕获组(使用 ?<name> 语法),用于从时间戳中提取年、月、日、小时、分钟和秒的值
  • "${year}-${month}-${day} ${hour}:${minutes}:${seconds}":这是与正则表达式条件匹配时设置的输出值。当正则表达式条件匹配时,它会将捕获组中提取的年、月、日、小时、分钟和秒的值组合成一个自定义的时间格式,然后将该值设置为 $log_time 变量的值

例如,如果 $time_iso8601` 的值是 "2023-09-09T14:30:00",则 `$log_time 将被设置为 "2023-09-09 14:30:00"

然后我们再把 $log_time 放进我们自定义的日志格式里面,完整配置如下

    log_format json '{  "SYS_NO":"my_nginx",
                        "OS_TIME":"$log_time",
                        "LOG_TYPE":"",
                        "RESULT":"$status",
                        "SPENT_TIME":"$request_time",
                        "CLIENT_IP":"$remote_addr",
                        "SERVER_IP":"$server_addr",
                        "O_CHANNEL":"$http_user_agent",
                        "UID":"$http_host",
                        "VALUE1":$body_bytes_sent,
                        "INFO1":"$http_referer",
                    }';

    map {
   mathJaxContainer[26]}log_time {
   
        default "";
        "~^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})T(?<hour>\d{2}):(?<minutes>\d{2}):(?<seconds>\d{2})" "${year}-${month}-${day} ${hour}:${minutes}:${seconds}";
    }

最后我们验证一下

image-20230912164314568.png

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
6月前
|
应用服务中间件 nginx
nginx $request_uri map 白名单
nginx $request_uri map 白名单
122 0
|
监控 应用服务中间件 nginx
nginx map ip黑名单
nginx map ip黑名单
4316 0
|
应用服务中间件 nginx 数据安全/隐私保护
nginx访问控制:如何通过map来控制http_x_forwarded_for访问限制
通过map修改访问限制 请求从lb过来,host已经变化,所以需要用http_x_forwarded_for来做限制。
4236 0
|
应用服务中间件 nginx
|
30天前
|
应用服务中间件 BI nginx
Nginx的location配置详解
【10月更文挑战第16天】Nginx的location配置详解
|
1月前
|
缓存 负载均衡 安全
Nginx常用基本配置总结:从入门到实战的全方位指南
Nginx常用基本配置总结:从入门到实战的全方位指南
262 0
|
1月前
|
应用服务中间件 Linux nginx
Jetson 环境安装(四):jetson nano配置ffmpeg和nginx(亲测)之编译错误汇总
这篇文章是关于在Jetson Nano上配置FFmpeg和Nginx时遇到的编译错误及其解决方案的汇总。
93 4
|
10天前
|
存储 负载均衡 中间件
Nginx反向代理配置详解,图文全面总结,建议收藏
Nginx 是大型架构必备中间件,也是大厂喜欢考察的内容,必知必会。本篇全面详解 Nginx 反向代理及配置,建议收藏。
Nginx反向代理配置详解,图文全面总结,建议收藏
|
23天前
|
应用服务中间件 API nginx
nginx配置反向代理404问题
【10月更文挑战第18天】本文介绍了使用Nginx进行反向代理的配置方法,解决了404错误、跨域问题和302重定向问题。关键配置包括代理路径、请求头设置、跨域头添加以及端口转发设置。通过调整`proxy_set_header`和添加必要的HTTP头,实现了稳定的服务代理和跨域访问。
116 1
nginx配置反向代理404问题
|
7天前
|
应用服务中间件 网络安全 nginx
轻松上手Nginx Proxy Manager:安装、配置与实战
Nginx Proxy Manager (NPM) 是一款基于 Nginx 的反向代理管理工具,提供直观的 Web 界面,方便用户配置和管理反向代理、SSL 证书等。本文档介绍了 NPM 的安装步骤,包括 Docker 和 Docker Compose 的安装、Docker Compose 文件的创建与配置、启动服务、访问 Web 管理界面、基本使用方法以及如何申请和配置 SSL 证书,帮助用户快速上手 NPM。
38 1