Nginx - stream 模块中按时间记录日志 ngx_stream_log_module

2024-05-26 13:44:51 浏览数 (2)

官网

https://nginx.org/en/docs/stream/ngx_stream_log_module.html

ngx_stream_log_module 概述

ngx_stream_log_module 是 NGINX 中的一个模块,用于记录通过流式(TCP/UDP)代理的连接和数据传输。它允许配置日志格式和记录日志文件的位置,以便于监控和调试流式服务的请求和响应。

配置指令

ngx_stream_log_module 提供了几个主要指令,用于设置日志记录的各种参数:

log_format:

用于定义日志的格式。

语法: log_format <name> <format> [escape=default|json|none];

示例:

代码语言:javascript复制
log_format main '$remote_addr [$time_local] $protocol $status $bytes_sent $bytes_received $session_time';

access_log:

指定日志文件的位置和使用的日志格式。

语法: access_log <path> [format [buffer=size [flush=time]] [if=condition]];

示例:

代码语言:javascript复制
access_log /var/log/nginx/stream_access.log main;
配置示例

下面是一个完整的配置示例,展示了如何配置 ngx_stream_log_module 来记录流式服务的日志:

代码语言:javascript复制
stream {
    log_format main '$remote_addr [$time_local] $protocol $status $bytes_sent $bytes_received $session_time';

    access_log /var/log/nginx/stream_access.log main;

    server {
        listen 12345;
        proxy_pass backend_server;
    }
}

在这个配置中:

  • log_format 定义了一个名为 main 的日志格式,记录了客户端地址、时间、协议、状态、发送和接收的字节数以及会话时间。
  • access_log 指定了日志文件的位置 /var/log/nginx/stream_access.log,并使用 main 日志格式记录日志。
  • server 区块定义了一个监听在端口 12345 的服务器,将流量代理到 backend_server
定制日志格式

可以通过在 log_format 指令中使用内置变量来定制日志格式。常用的内置变量包括:

  • $remote_addr: 客户端地址。
  • $time_local: 本地时间。
  • $protocol: 使用的协议。
  • $status: 请求状态。
  • $bytes_sent: 发送的字节数。
  • $bytes_received: 接收的字节数。
  • $session_time: 会话持续时间。

例如,要添加更多的细节到日志中,可以这样做:

代码语言:javascript复制
log_format detailed '$remote_addr - [$time_local] "$protocol" $status '
                    'sent:$bytes_sent received:$bytes_received time:$session_time '
                    '"$upstream_addr" "$upstream_bytes_sent" "$upstream_bytes_received"';

这会记录更多关于上游服务器的信息以及发送和接收的数据量。


ngx_stream_log_module 高级功能

继续之前的基础配置介绍,ngx_stream_log_module 还支持一些高级功能,比如日志条件和缓冲区配置,这些功能可以帮助更精细地控制日志记录。

日志条件

日志条件允许根据特定条件记录日志。这通过 access_log 指令的 if 参数实现。条件可以使用 NGINX 变量来定义,只有在条件为真时才会记录日志。

语法: access_log <path> [format [buffer=size [flush=time]] [if=condition]];

示例:

代码语言:javascript复制
stream {
    log_format main '$remote_addr [$time_local] $protocol $status $bytes_sent $bytes_received $session_time';
    
    # 仅当客户端地址为特定 IP 时记录日志
    access_log /var/log/nginx/stream_access.log main if=$remote_addr ~ '192.168.1.1';

    server {
        listen 12345;
        proxy_pass backend_server;
    }
}

在上述配置中,只有当客户端地址是 192.168.1.1 时才会记录日志。

缓冲区配置

缓冲区配置可以提高日志记录性能,特别是在高负载的环境下。通过使用 bufferflush 参数,日志可以首先写入缓冲区,然后在适当的时候刷新到磁盘。

语法: access_log <path> [format [buffer=size [flush=time]] [if=condition]];

示例:

代码语言:javascript复制
stream {
    log_format main '$remote_addr [$time_local] $protocol $status $bytes_sent $bytes_received $session_time';

    # 配置缓冲区大小和刷新时间
    access_log /var/log/nginx/stream_access.log main buffer=32k flush=5s;

    server {
        listen 12345;
        proxy_pass backend_server;
    }
}

在这个配置中:

  • buffer=32k 设置缓冲区大小为 32KB。
  • flush=5s 设置每 5 秒刷新一次缓冲区。
综合配置示例

以下是一个结合日志条件和缓冲区配置的综合示例:

代码语言:javascript复制
stream {
    log_format main '$remote_addr [$time_local] $protocol $status $bytes_sent $bytes_received $session_time';
    
    # 仅记录成功的会话并使用缓冲区配置
    access_log /var/log/nginx/stream_access.log main buffer=16k flush=10s if=$status = 200;

    server {
        listen 12345;
        proxy_pass backend_server;
    }
}

在这个配置中:

  • 只有会话状态为 200(成功)的日志才会被记录。
  • 日志记录使用 16KB 的缓冲区,并每 10 秒刷新一次。

实操

要在 Nginx 的 stream 模块中增加日志记录,以记录请求 IP 和请求时间等详细信息,可以按照以下最佳实践进行配置:

配置步骤

打开 Nginx 配置文件: 通常,Nginx 的主配置文件位于 /etc/nginx/nginx.conf。你也可以在特定的 stream 配置文件中进行设置。

定义日志格式: 使用 log_format 指令定义日志格式。可以包括请求 IP、请求时间、协议、状态、发送和接收的字节数等信息。例如:

代码语言:javascript复制
stream {
    log_format detailed '$remote_addr [$time_local] '
                       '$protocol $status $bytes_sent $bytes_received '
                       '$session_time $upstream_addr '
                       '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';
}

设置访问日志: 使用 access_log 指令指定日志文件的位置和使用的日志格式。例如:

代码语言:javascript复制
stream {
    access_log /var/log/nginx/stream-access.log detailed buffer=32k flush=5s;
}

启用日志缓冲: 为了优化日志记录性能,可以启用日志缓冲。使用 buffer 参数指定缓冲区大小,使用 flush 参数指定刷新间隔。例如:

代码语言:javascript复制
stream {
    access_log /var/log/nginx/stream-access.log detailed buffer=32k flush=5s;
}

重启 Nginx: 修改配置文件后,重启 Nginx 以使更改生效:

代码语言:javascript复制
sudo systemctl restart nginx

示例配置

以下是一个完整的示例配置,展示了如何在 Nginx 的 stream 模块中记录详细的请求信息:

代码语言:javascript复制
stream {
  upstream socket_proxy  {
       hash $remote_addr consistent;
       # 转发的目的地址和端口
       server 127.0.0.1:5002;
      }
  server {
        listen 5001;
        proxy_connect_timeout 600s;
        proxy_timeout 600s;
        proxy_pass socket_proxy;
       }

 log_format detailed '$remote_addr [$time_local] '
                        '$protocol $status $bytes_sent $bytes_received '
                        '$session_time $upstream_addr '
                        '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';
  
  #  logs目录下
 access_log logs/stream-access.log detailed buffer=32k flush=5s;


}

Nginx 的 stream 模块可以用于记录 TCP 和 UDP 流量。日志格式由各种变量组成,每个变量代表请求处理过程中的一个特定信息。

代码语言:javascript复制
log_format detailed '$remote_addr [$time_local] '
                    '$protocol $status $bytes_sent $bytes_received '
                    '$session_time $upstream_addr '
                    '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';
  1. $remote_addr:
    • 远程客户端的 IP 地址。
  2. [$time_local]:
    • 处理请求的本地时间,格式类似于 [10/May/2024:15:05:06 0000]
  3. $protocol:
    • 使用的协议,例如 TCP 或 UDP。
  4. $status:
    • 连接的状态。一般来说,这个状态码显示连接是否成功。例如,成功的连接状态码为 0。
  5. $bytes_sent:
    • 发送给客户端的字节数。
  6. $bytes_received:
    • 从客户端接收的字节数。
  7. $session_time:
    • 会话时间,单位是秒。表示连接的持续时间。
  8. $upstream_addr:
    • 上游服务器的地址。如果有多个上游服务器,这里会列出选择的上游服务器的 IP 和端口。
  9. "$upstream_bytes_sent":
    • 发送到上游服务器的字节数。双引号用于处理变量值中可能包含的空格。
  10. "$upstream_bytes_received":
    • 从上游服务器接收的字节数。双引号用于处理变量值中可能包含的空格。
  11. "$upstream_connect_time":
    • 连接到上游服务器所用的时间,单位是秒。双引号用于处理变量值中可能包含的空格。

Nginx 的 access_log 指令用于配置访问日志的记录方式及相关选项。在 stream 模块中,这条指令可以记录 TCP 和 UDP 连接的日志信息。

代码语言:javascript复制
access_log logs/stream-access.log detailed buffer=32k flush=5s;
  1. access_log:
    • 指定访问日志的存储位置和格式。
  2. logs/stream-access.log:
    • 日志文件路径
    • 表示访问日志将记录到 logs/stream-access.log 文件中。
  3. detailed:
    • 日志格式名称
    • 指定使用之前定义的 log_format 格式,这里使用的是名为 detailed 的日志格式。在 log_format detailed ... 中定义了具体格式。
  4. buffer=32k:
    • 日志缓冲区大小
    • 设置日志缓冲区的大小为 32 KB。日志信息首先会写入这个缓冲区,而不是立即写入磁盘文件,这样可以提高性能。
  5. flush=5s:
    • 日志刷新间隔
    • 指定日志缓冲区每 5 秒刷新一次,即将缓冲区中的日志信息写入到磁盘文件。这种设置有助于在提高性能的同时确保日志信息不会长时间滞留在内存中。
  • 日志文件路径 (logs/stream-access.log):
    • 日志文件路径可以是相对路径(如示例中的 logs/stream-access.log)或者绝对路径,取决于你配置文件的具体位置和服务器的目录结构。
  • 日志格式 (detailed):
    • log_format 指令中预先定义的格式名 detailed,该格式包含了具体的日志记录变量和格式。
  • 缓冲区大小 (buffer=32k):
    • 当 Nginx 记录日志时,它会先将日志信息写入一个 32 KB 的缓冲区。只有当缓冲区满了或者刷新间隔到达时,日志才会被写入到磁盘文件中。这样可以减少磁盘 I/O 操作,提升服务器性能。
  • 刷新间隔 (flush=5s):
    • 即使缓冲区未满,日志信息也会每隔 5 秒写入一次磁盘。这可以确保日志不会因缓冲区的存在而长时间滞留在内存中,保证日志的实时性。

示例日志条目

  • 客户端 172.168.20.20 在 2024 年 5 月 16 日 21:09:19(UTC 8)发起了一个 TCP 请求。
  • 请求成功,状态码为 200
  • 在这次连接中,服务器发送给客户端 154764 字节,并从客户端接收 1518 字节。
  • 整个会话持续了 23.700 秒。
  • 请求被转发到上游服务器 10.11.211.35:15002
  • 发送到上游服务器 1518 字节,并从上游服务器接收 154764 字节。
  • 连接到上游服务器的时间仅为 0.001 秒。

将 stream-access.log 按天存储

stream 块中使用 map 指令定义一个变量来存储当前日期,用于构建日志文件名。

代码语言:javascript复制
stream {
  upstream socket_proxy  {
       hash $remote_addr consistent;
       # 转发的目的地址和端口
       server 127.0.0.1:5002;
      }
  server {
        listen 5001;
        proxy_connect_timeout 600s;
        proxy_timeout 600s;
        proxy_pass socket_proxy;
       }


  log_format detailed '$remote_addr [$time_local] '
                        '$protocol $status $bytes_sent $bytes_received '
                        '$session_time $upstream_addr '
                        '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';
  map $time_iso8601 $logdate {
    default 'date-not-found';
    '~^(?<ymd>d{4}-d{2}-d{2})' $ymd;
  }
 access_log logs/stream-access-$logdate.log detailed;
}

按天记录日志,就无法使用bufferd 选项了。

对于 buffered logs(缓冲日志),确实存在一些限制:

  1. 缓冲日志不支持变量作为日志文件名

Nginx 官方文档明确指出,对于缓冲日志(使用 buffer 参数),日志文件名不能包含变量。这是因为缓冲日志在写入磁盘之前会先缓存在内存中,如果文件名包含变量,可能会导致多个日志写入同一个文件,从而造成日志混乱。[4]

  1. 非缓冲日志可以使用变量作为日志文件名

对于非缓冲日志(没有使用 buffer 参数),Nginx 允许在日志文件名中使用变量,比如您之前提到的 $logdate 变量。这样可以实现按天自动创建新的日志文件。

因此,如果想要按天存储访问日志,并且使用 $logdate 变量作为日志文件名,需要将访问日志配置为非缓冲日志,即不使用 buffer 参数。示例配置:

代码语言:javascript复制
http {
    # 定义日期变量
    map $time_iso8601 $logdate { ... }

    # 非缓冲访问日志
    access_log /var/log/nginx/access-$logdate.log main;
    
    # ...
}

这样就可以避免使用变量作为缓冲日志文件名的错误,并实现按天存储访问日志的目的。


参考资料

[1] http://nginx.org/en/docs/stream/ngx_stream_log_module.html [2] https://serverfault.com/questions/916653/what-is-the-default-log-format-on-nginx [3] https://docs.nginx.com/nginx/admin-guide/monitoring/logging/ [4] https://www.nginx.com/blog/diagnostic-logging-nginx-javascript-module/ [5] https://webdock.io/en/docs/mastering-web-fundamentals/web-server-setup-management/nginx-logs-step-step-configuration-guide [6] https://stackoverflow.com/questions/42083611/how-to-make-nginx-print-full-log-for-tcp-stream [7] https://signoz.io/blog/nginx-logging/ [8] https://www.digitalocean.com/community/tutorials/how-to-add-the-log-module-to-nginx-on-ubuntu-16-04 [9] https://sematext.com/blog/nginx-logs/ [10] https://www.nginx.com/blog/rate-limiting-nginx/ [11] https://betterstack.com/community/guides/logging/how-to-view-and-configure-nginx-access-and-error-logs/ [12] https://www.digitalocean.com/community/tutorials/nginx-access-logs-error-logs [13] https://gist.github.com/tuxity/bf52447fa393c40114210d7f6d623015 [14] http://nginx.org/en/docs/http/ngx_http_log_module.html [15] https://wenvpn.com/devops/web/nginx/how-to-record-full-url-in-nginx-log-a-guide-for-improved-tracking/

0 人点赞