Ubuntu 下 nginx-1.24.0 源码分析 - ngx_log_error 函数

时间:2025-02-19 08:43:01

ngx_log_error 

声明在 src\core\ngx_log.h 中:

但是通过检索找到了 3 个结果

#if (NGX_HAVE_C99_VARIADIC_MACROS)

#define NGX_HAVE_VARIADIC_MACROS  1

#define ngx_log_error(level, log, ...)                                        \
    if ((log)->log_level >= level) ngx_log_error_core(level, log, __VA_ARGS__)

void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
    const char *fmt, ...);

#define ngx_log_debug(level, log, ...)                                        \
    if ((log)->log_level & level)                                             \
        ngx_log_error_core(NGX_LOG_DEBUG, log, __VA_ARGS__)

/*********************************/

#elif (NGX_HAVE_GCC_VARIADIC_MACROS)

#define NGX_HAVE_VARIADIC_MACROS  1

#define ngx_log_error(level, log, args...)                                    \
    if ((log)->log_level >= level) ngx_log_error_core(level, log, args)

void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
    const char *fmt, ...);

#define ngx_log_debug(level, log, args...)                                    \
    if ((log)->log_level & level)                                             \
        ngx_log_error_core(NGX_LOG_DEBUG, log, args)

/*********************************/

#else /* no variadic macros */

#define NGX_HAVE_VARIADIC_MACROS  0

void ngx_cdecl ngx_log_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
    const char *fmt, ...);
void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
    const char *fmt, va_list args);
void ngx_cdecl ngx_log_debug_core(ngx_log_t *log, ngx_err_t err,
    const char *fmt, ...);


#endif /* variadic macros */

 

 通过 gcc -E 先来看一下结果:

gcc -E src/event/ngx_event_openssl.c \
	-I src/core \
	-I src/event \
	-I src/event/modules \
	-I src/os/unix \
	-I objs \
	> ngx_event_openssl_preprocessed.c

在输出文件 ngx_event_openssl_preprocessed.c 中查找 ngx_ssl_error

void
ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...)
{
    int flags;
    u_long n;
    va_list args;
    u_char *p, *last;
    u_char errstr[1024];
    const char *data;

    last = errstr + 1024;

    
# 3623 "src/event/ngx_event_openssl.c" 3 4
   __builtin_va_start(
# 3623 "src/event/ngx_event_openssl.c"
   args
# 3623 "src/event/ngx_event_openssl.c" 3 4
   ,
# 3623 "src/event/ngx_event_openssl.c"
   fmt
# 3623 "src/event/ngx_event_openssl.c" 3 4
   )
# 3623 "src/event/ngx_event_openssl.c"
                      ;
    p = ngx_vslprintf(errstr, last - 1, fmt, args);
    
# 3625 "src/event/ngx_event_openssl.c" 3 4
   __builtin_va_end(
# 3625 "src/event/ngx_event_openssl.c"
   args
# 3625 "src/event/ngx_event_openssl.c" 3 4
   )
# 3625 "src/event/ngx_event_openssl.c"
               ;

    if (ERR_peek_error()) {
        p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p);

        for ( ;; ) {

            n = ERR_peek_error_data(&data, &flags);

            if (n == 0) {
                break;
            }



            if (p >= last - 1) {
                goto next;
            }

            *p++ = ' ';

            ERR_error_string_n(n, (char *) p, last - p);

            while (p < last && *p) {
                p++;
            }

            if (p < last && *data && (flags & 
# 3652 "src/event/ngx_event_openssl.c" 3 4
                                             0x02
# 3652 "src/event/ngx_event_openssl.c"
                                                           )) {
                *p++ = ':';
                p = ngx_cpystrn(p, (u_char *) data, last - p);
            }

        next:

            (void) ERR_get_error();
        }

        if (p < last) {
            *p++ = ')';
        }
    }

    if ((log)->log_level >= level) ngx_log_error_core(level, log, err, "%*s", p - errstr, errstr);
}

原本

ngx_log_error(level, log, err, "%*s", p - errstr, errstr);

对应的地方现在是:

if ((log)->log_level >= level) ngx_log_error_core(level, log, err, "%*s", p - errstr, errstr);

 

再回到 src\core\ngx_log.h 中

成立的是这部分

#define ngx_log_error(level, log, ...)                                        \
    if ((log)->log_level >= level) ngx_log_error_core(level, log, __VA_ARGS__)


NGX_HAVE_C99_VARIADIC_MACROS 

NGX_HAVE_GCC_VARIADIC_MACROS

定义在 objs/ngx_auto_config.h 中:

#ifndef NGX_HAVE_C99_VARIADIC_MACROS
#define NGX_HAVE_C99_VARIADIC_MACROS  1
#endif


#ifndef NGX_HAVE_GCC_VARIADIC_MACROS
#define NGX_HAVE_GCC_VARIADIC_MACROS  1
#endif

NGX_HAVE_C99_VARIADIC_MACROSNGX_HAVE_GCC_VARIADIC_MACROS 是 Nginx 源码中用于检测编译器是否支持 可变参数宏(Variadic Macros) 的两个宏。

它们的作用是帮助 Nginx 在不同编译器和标准下选择合适的实现方式,以确保代码的兼容性和正确性。


什么是可变参数宏?

在 C 语言中,可变参数宏 是一种允许宏定义接受可变数量参数的功能。它的语法类似于函数的可变参数(...),但用于预处理器宏。


C99 标准中的可变参数宏

C99 标准引入了对可变参数宏的支持,语法如下:

#define LOG_ERROR(fmt, ...) printf(fmt, ##__VA_ARGS__)

__VA_ARGS__: 表示宏调用时传递的所有额外参数

##__VA_ARGS__: 在某些编译器中(如 GCC),可以用来处理空参数的情况,避免多余的逗号


GCC 扩展中的可变参数宏

在 C99 标准之前,GCC 编译器已经通过扩展支持了可变参数宏,语法与 C99 类似,但在某些细节上可能有所不同。

GCC 风格的可变参数宏使用 args... 来表示可变参数部分,而不是 C99 标准中的 __VA_ARGS__

其基本语法如下:

#define MACRO_NAME(fixed_args, args...) implementation_using_args
  • fixed_args : 宏的固定参数。
  • args... : 表示可变参数部分,类似于函数中的 ...
  • ##args : 在 GCC 扩展中,可以使用 ## 来处理空参数的情况,避免多余的逗号。

NGX_HAVE_C99_VARIADIC_MACROS
  • 含义 : 表示当前编译环境是否支持 C99 标准的可变参数宏
  • 检测方式 : 通常通过检查编译器是否支持 C99 标准来定义该宏。
  • 用途 : 如果定义了该宏,Nginx 可以使用 C99 风格的可变参数宏。
NGX_HAVE_GCC_VARIADIC_MACROS
  • 含义 : 表示当前编译环境是否支持 GCC 扩展的可变参数宏
  • 检测方式 : 通常通过检查编译器是否为 GCC 或兼容 GCC 的编译器来定义该宏。
  • 用途 : 如果定义了该宏,Nginx 可以使用 GCC 风格的可变参数宏。

  • 如果支持 C99 标准,则使用 __VA_ARGS__
  • 如果仅支持 GCC 扩展,则使用 args...

回到  ngx_log_error 的定义中来:

#define ngx_log_error(level, log, ...)                                        \
    if ((log)->log_level >= level) ngx_log_error_core(level, log, __VA_ARGS__)
(log)->log_level

表示当前日志对象允许记录的最低日志级别


level

指定当前日志消息的级别


(log)->log_level >= level

比较当前日志对象的配置级别和日志消息的级别

  • 如果 log->log_level 大于或等于 level,表示当前日志消息的严重程度足够高,应该被记录。
  • 否则,跳过日志记录,避免不必要的性能开销

ngx_log_error_core(level, log, __VA_ARGS__)

调用核心日志函数,实际执行日志记录操作

  • level: 当前日志消息的级别。
  • log: 日志对象,包含日志的输出目标(如文件、标准错误等)。
  • __VA_ARGS__: 可变参数,表示格式化字符串及其参数(类似于 printf 的参数)