crit级别日志用于捕获阻断服务的致命错误,涵盖crit、alert、emerg三级,包括worker崩溃前兆、上游全不可达、严重SSL错误、rewrite无限循环及resolver失效等;应仅在核心location中启用并配合request_id等上下文字段精确定位。

用 crit 级别过滤错误日志,不是为了“少记点”,而是让真正阻断服务、导致请求完全失败的致命问题浮出水面。在高并发场景下,warn 或 error 会混入大量可恢复或非关键异常(比如临时 upstream 超时、客户端主动断连),反而掩盖真正要命的问题。
crit 级别实际覆盖哪些错误
crit 不是“最严重的一个”,而是从 crit 开始往上的所有级别都会记录:crit、alert、emerg。它对应的是 Nginx 内部无法继续安全运行、必须中断当前请求甚至影响 worker 稳定性的错误。典型包括:
- worker 进程因内存分配失败、文件描述符耗尽而崩溃前的最后日志
- upstream 服务器全部不可达且重试策略彻底失效(如所有 backend 均 connection refused + timeout)
- SSL 握手阶段证书严重错误(如签名不匹配、过期超过 30 天)
- rewrite 指令触发无限循环,Nginx 主动终止并标记为 crit
- 配置中引用了不存在的 resolver 或 shared memory zone,导致模块初始化失败
仅对核心业务路径启用 crit 日志
全局设成 crit 容易漏掉上游服务返回 500 的线索——那属于应用层错误,Nginx 默认只记为 error。更有效的方式是在关键 location 块中单独定义:
location /api/v2/order/submit {
proxy_pass http://backend_order;
error_log /var/log/nginx/error_order_crit.log crit;
}
这样只有下单接口出致命问题(比如连接池全满、TLS 握手卡死)才会写入该文件,和其他接口日志物理隔离,排查时不用 grep 筛选。
配合 log_format 提取上下文关键字段
默认 error_log 不带请求 ID 或 upstream 地址,单看 crit 日志很难定位是哪个实例挂了。建议自定义格式并绑定到 crit 日志:
log_format crit_detail '$time_iso8601 $pid#$tid: [$level] $request_id "$request" '
'upstream: "$upstream_addr" "$upstream_status" '
'client: $remote_addr';
error_log /var/log/nginx/crit.log crit;
其中 $request_id 需在 server 块中提前生成:map $request_id $request_id { default $request_id; "" $request_id; },再用 proxy_set_header X-Request-ID $request_id; 透传给后端。这样每条 crit 日志都自带唯一追踪线索和真实后端地址。
避免误判:注意 crit 不记录 PHP 或应用层 5xx
PHP-FPM 崩溃、脚本 fatal error、数据库连接超时等,Nginx 默认只记为 error(除非进程真的 segfault)。如果想捕获这类问题,不能只靠 error_log crit,而应:
- 确保 php-fpm.conf 中
log_level = warning或更高,并开启catch_workers_output = yes - 在 Nginx 的 proxy_intercept_errors on; 配置下,把 500/502/503 显式映射为 error_log warn,再用 log_format 补充 $upstream_http_x_error_code 等自定义头
不复杂但容易忽略


















