您的位置:首页 > 财经 > 金融 > 易搭应用快速开发平台_网站模板库免费_成都seo培训班_开通网站需要多少钱

易搭应用快速开发平台_网站模板库免费_成都seo培训班_开通网站需要多少钱

2025/2/27 9:15:27 来源:https://blog.csdn.net/weixin_41812346/article/details/145655726  浏览:    关键词:易搭应用快速开发平台_网站模板库免费_成都seo培训班_开通网站需要多少钱
易搭应用快速开发平台_网站模板库免费_成都seo培训班_开通网站需要多少钱

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

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

实现在 src\core\ngx_log.c

#if (NGX_HAVE_VARIADIC_MACROS)void
ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,const char *fmt, ...)#elsevoid
ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,const char *fmt, va_list args)#endif
{
#if (NGX_HAVE_VARIADIC_MACROS)va_list      args;
#endifu_char      *p, *last, *msg;ssize_t      n;ngx_uint_t   wrote_stderr, debug_connection;u_char       errstr[NGX_MAX_ERROR_STR];last = errstr + NGX_MAX_ERROR_STR;p = ngx_cpymem(errstr, ngx_cached_err_log_time.data,ngx_cached_err_log_time.len);p = ngx_slprintf(p, last, " [%V] ", &err_levels[level]);/* pid#tid */p = ngx_slprintf(p, last, "%P#" NGX_TID_T_FMT ": ",ngx_log_pid, ngx_log_tid);if (log->connection) {p = ngx_slprintf(p, last, "*%uA ", log->connection);}msg = p;#if (NGX_HAVE_VARIADIC_MACROS)va_start(args, fmt);p = ngx_vslprintf(p, last, fmt, args);va_end(args);#elsep = ngx_vslprintf(p, last, fmt, args);#endifif (err) {p = ngx_log_errno(p, last, err);}if (level != NGX_LOG_DEBUG && log->handler) {p = log->handler(log, p, last - p);}if (p > last - NGX_LINEFEED_SIZE) {p = last - NGX_LINEFEED_SIZE;}ngx_linefeed(p);wrote_stderr = 0;debug_connection = (log->log_level & NGX_LOG_DEBUG_CONNECTION) != 0;while (log) {if (log->log_level < level && !debug_connection) {break;}if (log->writer) {log->writer(log, level, errstr, p - errstr);goto next;}if (ngx_time() == log->disk_full_time) {/** on FreeBSD writing to a full filesystem with enabled softupdates* may block process for much longer time than writing to non-full* filesystem, so we skip writing to a log for one second*/goto next;}n = ngx_write_fd(log->file->fd, errstr, p - errstr);if (n == -1 && ngx_errno == NGX_ENOSPC) {log->disk_full_time = ngx_time();}if (log->file->fd == ngx_stderr) {wrote_stderr = 1;}next:log = log->next;}if (!ngx_use_stderr|| level > NGX_LOG_WARN|| wrote_stderr){return;}msg -= (7 + err_levels[level].len + 3);(void) ngx_sprintf(msg, "nginx: [%V] ", &err_levels[level]);(void) ngx_write_console(ngx_stderr, msg, p - msg);
}

NGX_HAVE_VARIADIC_MACROS 宏在

src\core\ngx_log.h 中被定义为1


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

也可以通过 gcc -E 看一下预编译指令处理后的样子

void
ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,const char *fmt, ...)
# 106 "src/core/ngx_log.c"
{va_list args;u_char *p, *last, *msg;ssize_t n;ngx_uint_t wrote_stderr, debug_connection;u_char errstr[2048];last = errstr + 2048;p = (((u_char *) memcpy(errstr, ngx_cached_err_log_time.data, ngx_cached_err_log_time.len)) + (ngx_cached_err_log_time.len));p = ngx_slprintf(p, last, " [%V] ", &err_levels[level]);p = ngx_slprintf(p, last, "%P#" "%d" ": ",ngx_pid, 0);if (log->connection) {p = ngx_slprintf(p, last, "*%uA ", log->connection);}msg = p;# 134 "src/core/ngx_log.c" 3 4__builtin_va_start(
# 134 "src/core/ngx_log.c"args
# 134 "src/core/ngx_log.c" 3 4,
# 134 "src/core/ngx_log.c"fmt
# 134 "src/core/ngx_log.c" 3 4)
# 134 "src/core/ngx_log.c";p = ngx_vslprintf(p, last, fmt, args);# 136 "src/core/ngx_log.c" 3 4__builtin_va_end(
# 136 "src/core/ngx_log.c"args
# 136 "src/core/ngx_log.c" 3 4)
# 136 "src/core/ngx_log.c";if (err) {p = ngx_log_errno(p, last, err);}if (level != 8 && log->handler) {p = log->handler(log, p, last - p);}if (p > last - 1) {p = last - 1;}*p++ = (u_char) '\n';;wrote_stderr = 0;debug_connection = (log->log_level & 0x80000000) != 0;while (log) {if (log->log_level < level && !debug_connection) {break;}if (log->writer) {log->writer(log, level, errstr, p - errstr);goto next;}if (ngx_cached_time->sec == log->disk_full_time) {goto next;}n = ngx_write_fd(log->file->fd, errstr, p - errstr);if (n == -1 && 
# 185 "src/core/ngx_log.c" 3 4(*__errno_location ()) 
# 185 "src/core/ngx_log.c"== 
# 185 "src/core/ngx_log.c" 3 428
# 185 "src/core/ngx_log.c") {log->disk_full_time = ngx_cached_time->sec;}if (log->file->fd == 
# 189 "src/core/ngx_log.c" 3 42
# 189 "src/core/ngx_log.c") {wrote_stderr = 1;}next:log = log->next;}if (!ngx_use_stderr|| level > 5|| wrote_stderr){return;}msg -= (7 + err_levels[level].len + 3);(void) ngx_sprintf(msg, "nginx: [%V] ", &err_levels[level]);(void) ngx_write_fd(
# 209 "src/core/ngx_log.c" 3 42
# 209 "src/core/ngx_log.c", msg, p - msg);
}

函数的作用是负责将错误信息格式化并输出到日志文件或控制台。

函数声明 

#if (NGX_HAVE_VARIADIC_MACROS)
void
ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,const char *fmt, ...)
#else
void
ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,const char *fmt, va_list args)
#endif

 

  • NGX_HAVE_VARIADIC_MACROS 是一个预定义宏,用于判断编译器是否支持可变参数宏(variadic macros)。
    • 如果支持,则使用标准的可变参数函数形式(...),并通过 va_list 处理可变参数。
    • 如果不支持,则直接通过 va_list 参数传递可变参数列表。
  • 函数签名:
    • level: 日志级别(如 NGX_LOG_ERRNGX_LOG_WARN 等)。
    • log: 指向日志对象的指针,包含日志文件描述符、连接信息等。
    • err: 错误码(通常为系统错误码,如 errno)。
    • fmt: 格式化字符串,用于生成日志消息。
    • ...args: 可变参数列表。

局部变量声明 

#if (NGX_HAVE_VARIADIC_MACROS)va_list      args;
#endifu_char      *p, *last, *msg;ssize_t      n;ngx_uint_t   wrote_stderr, debug_connection;u_char       errstr[NGX_MAX_ERROR_STR];
  • va_list args : 仅在支持可变参数宏时声明,用于存储可变参数列表。
  • u_char *p, *last, *msg :
    • p: 当前写入位置指针,指向日志缓冲区。
    • last: 缓冲区末尾指针,防止越界。
    • msg: 记录日志消息起始位置,用于后续处理。
  • ssize_t n : 用于存储写入操作的返回值(字节数)。
  • ngx_uint_t wrote_stderr, debug_connection :
    • wrote_stderr: 标记是否已将日志写入标准错误流。
    • debug_connection: 判断当前日志是否为调试连接日志。
  • u_char errstr[NGX_MAX_ERROR_STR] : 固定大小的日志缓冲区,用于存储格式化后的日志消息。

NGX_MAX_ERROR_STR 定义在 

src/core/ngx_log.h 中

#define NGX_MAX_ERROR_STR   2048

NGX_MAX_ERROR_STR 的主要作用是限制日志消息的长度 ,以防止缓冲区溢出、控制内存使用并提高日志系统的可靠性


初始化缓冲区

    last = errstr + NGX_MAX_ERROR_STR;p = ngx_cpymem(errstr, ngx_cached_err_log_time.data,ngx_cached_err_log_time.len);

 

  • last = errstr + NGX_MAX_ERROR_STR : 设置缓冲区末尾指针,确保后续写入不会越界。
  • ngx_cpymem :
    • 将缓存的时间戳(ngx_cached_err_log_time)复制到缓冲区开头。
    • 返回值 p 指向时间戳之后的位置,准备写入其他内容。

写入日志级别

    p = ngx_slprintf(p, last, " [%V] ", &err_levels[level]);

 

  • 使用 ngx_slprintf 格式化日志级别(如 [error][warn])并写入缓冲区。
  • err_levels[level] 是一个全局数组,存储了不同日志级别的字符串表示。

err_levels 定义在

src\core\ngx_log.c 中

static ngx_str_t err_levels[] = {ngx_null_string,ngx_string("emerg"),ngx_string("alert"),ngx_string("crit"),ngx_string("error"),ngx_string("warn"),ngx_string("notice"),ngx_string("info"),ngx_string("debug")
};

写入进程 ID 和线程 ID

    p = ngx_slprintf(p, last, "%P#" NGX_TID_T_FMT ": ",ngx_log_pid, ngx_log_tid);

 

  • 格式化并写入当前进程 ID(ngx_log_pid)和线程 ID(ngx_log_tid)。
  • NGX_TID_T_FMT 是线程 ID 的格式化宏,具体实现依赖于平台。

src/os/unix/ngx_thread.h

#define NGX_TID_T_FMT         "%P"

格式化并写入当前进程 ID(ngx_log_pid)和线程 ID(ngx_log_tid


src/os/unix/ngx_process.h 中

#ifndef ngx_log_pid
#define ngx_log_pid  ngx_pid
#endif

ngx_log_pid 就是之前处理过的 ngx_pid


src/os/unix/ngx_thread.h 中

ngx_log_tid 的定义有2个

#if (NGX_THREADS)
...#define ngx_log_tid           ngx_thread_tid()#else#define ngx_log_tid           0

这主要取决于 是否定义了 NGX_THREADS

NGX_THREADS 通常通过编译时的配置选项(如 --with-threads)来启用或禁用


 

ngx_tid_t ngx_thread_tid(void);

定义在 src\os\unix\ngx_thread_id.c 

ngx_tid_t
ngx_thread_tid(void)
{return syscall(SYS_gettid);
}

syscall(SYS_gettid) 是一个系统调用,用于获取当前线程的线程 ID(Thread ID)

  • SYS_gettid 是 Linux 内核提供的一个系统调用编号,用于获取当前线程的 TID。
  • 它是通过 syscall 函数调用的,因为标准 C 库(如 glibc)没有直接提供封装该系统调用的函数

<sys/syscall.h>: 提供了 syscall 函数的声明。

<unistd.h>: 定义了 SYS_gettid 的宏。

返回值 :

  • 返回当前线程的线程 ID(TID),类型为 pid_t
  • 如果调用失败(理论上几乎不可能),返回值为 -1,并设置 errno

写入连接数

    if (log->connection) {p = ngx_slprintf(p, last, "*%uA ", log->connection);}

格式化日志消息

    msg = p;
#if (NGX_HAVE_VARIADIC_MACROS)va_start(args, fmt);p = ngx_vslprintf(p, last, fmt, args);va_end(args);
#elsep = ngx_vslprintf(p, last, fmt, args);
#endif

 

  • msg = p : 保存日志消息的起始位置。
  • ngx_vslprintf :
    • 根据格式化字符串 fmt 和可变参数列表 args,将日志消息写入缓冲区。
    • 在支持可变参数宏的情况下,使用 va_startva_end 初始化和清理 args

处理错误码

    if (err) {p = ngx_log_errno(p, last, err);}

 如果存在错误码(err),调用 ngx_log_errno 将其转换为可读的错误信息并追加到日志中

调用自定义日志处理器

    if (level != NGX_LOG_DEBUG && log->handler) {p = log->handler(log, p, last - p);}

 

  • 如果日志级别不是调试级别且日志对象中定义了自定义处理器(log->handler),则调用该处理器对日志进行进一步处理。

限制日志长度

    if (p > last - NGX_LINEFEED_SIZE) {p = last - NGX_LINEFEED_SIZE;}ngx_linefeed(p);

 确保日志消息不超过缓冲区大小,并在末尾添加换行符(ngx_linefeed

wrote_stderr = 0;
debug_connection = (log->log_level & NGX_LOG_DEBUG_CONNECTION) != 0;

 初始化两个变量 wrote_stderrdebug_connection,并为后续的日志处理逻辑提供必要的状态信息

(1) wrote_stderr
  • 作用 : 标记是否已将日志消息写入标准错误流(stderr)。
  • 类型 : ngx_uint_t(无符号整数)。
  • 初始值 : 设置为 0,表示尚未写入标准错误流。
(2) debug_connection
  • 作用 : 标记当前日志是否为调试连接日志(NGX_LOG_DEBUG_CONNECTION)。
  • 类型 : ngx_uint_t(无符号整数)。
  • 计算方式 : 检查日志对象的 log_level 是否包含 NGX_LOG_DEBUG_CONNECTION 标志

写入日志

    while (log) {if (log->log_level < level && !debug_connection) {break;}if (log->writer) {log->writer(log, level, errstr, p - errstr);goto next;}if (ngx_time() == log->disk_full_time) {goto next;}n = ngx_write_fd(log->file->fd, errstr, p - errstr);if (n == -1 && ngx_errno == NGX_ENOSPC) {log->disk_full_time = ngx_time();}if (log->file->fd == ngx_stderr) {wrote_stderr = 1;}next:log = log->next;}

 

  • 遍历日志链表(log),根据日志级别和条件决定是否写入。
  • 自定义写入器 :
    • 如果日志对象定义了自定义写入器(log->writer),则调用它。
  • 磁盘空间检查 :
    • 如果磁盘已满(NGX_ENOSPC),记录当前时间为 disk_full_time,避免频繁尝试写入。
  • 写入文件或标准错误流 :
    • 调用 ngx_write_fd 将日志写入文件描述符。
    • 如果目标是标准错误流(ngx_stderr),标记 wrote_stderr

ngx_time() 定义在

src\core\ngx_times.h 中

#define ngx_time()           ngx_cached_time->sec

本质就是当前时间缓存的 秒数 部分


ngx_write_fd 定义在

src\os\unix\ngx_files.h 中

static ngx_inline ssize_t
ngx_write_fd(ngx_fd_t fd, void *buf, size_t n)
{return write(fd, buf, n);
}

本质就是 调用 write 函数


NGX_ENOSPC

定义在 src/os/unix/ngx_errno.h

#define NGX_ENOSPC        ENOSPC

ENOSPC 是一个标准的 POSIX 错误码,表示 "No space left on device" (设备上没有剩余空间)。当尝试写入数据时,如果目标存储设备(如磁盘、文件系统)已满,无法容纳更多数据,操作系统会返回此错误。

写入控制台

    if (!ngx_use_stderr|| level > NGX_LOG_WARN|| wrote_stderr){return;}msg -= (7 + err_levels[level].len + 3);(void) ngx_sprintf(msg, "nginx: [%V] ", &err_levels[level]);(void) ngx_write_console(ngx_stderr, msg, p - msg);

 

如果未启用标准错误流、日志级别低于警告级别或已写入标准错误流,则直接返回。

否则,将日志消息写入控制台(ngx_write_console

  • 如果 ngx_use_stderr0,跳过标准错误流输出。
  • 如果日志级别高于警告级别(NGX_LOG_WARN),也跳过标准错误流输出。
  • 如果已经写入标准错误流(wrote_stderr 为真),避免重复写入

ngx_use_stderr 

 定义在 src\core\ngx_log.c

ngx_uint_t              ngx_use_stderr = 1;

默认值是1

ngx_use_stderr 用于控制是否将日志消息输出到标准错误流(stderr

  • 0: 禁用标准错误流输出。
  • 非零(通常是 1): 启用标准错误流输出

在 Nginx 中,日志消息通常会被写入文件或通过其他方式处理(如发送到远程服务器)。

如果启用了 ngx_use_stderr,则某些日志消息(如错误或警告级别日志)会同时写入标准错误流(stderr),以便用户可以直接在终端中看到这些消息


msg -= (7 + err_levels[level].len + 3);

这行代码的作用是调整日志消息缓冲区的起始位置指针 msg,以便在日志消息前插入额外的内容(如日志前缀)

变量说明
  • msg : 当前日志消息缓冲区的起始位置指针。
  • err_levels[level] : 日志级别字符串数组,表示不同日志级别的名称(如 [error], [warn] 等)。
    • err_levels[level].len: 当前日志级别字符串的长度。
  • 常量值 :
    • 7: 表示固定的字符串 "nginx: " 的长度。
    • 3: 方括号和日志级别(如 [error]),其长度为 err_levels[level].len + 3(包括方括号和空格)

为了在日志消息前插入这些内容,需要将 msg 指针向前移动(即减去所需的空间大小)。这样可以确保后续的格式化操作不会覆盖现有的日志消息。


ngx_write_console

定义在 src\os\unix\ngx_files.h 中:

#define ngx_write_console        ngx_write_fd

本质就是调用 write 函数 ,文件描述符指向 标准错误流

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com