Open vislee opened 7 years ago
error log 记录了nginx系统日志,区别于业务日志。 封装成ngx_errlog_module模块,代码在文件core/ngx_log.h|c中。 ngx_errlog_module 属于核心模块NGX_CORE_MODULE,提供了error_log配置指令。
error_log
涉及到的结构体:
// 封装打开的文件结构体 定义在core/ngx_conf_file.h 文件中 struct ngx_open_file_s { ngx_fd_t fd; // 打开的文件描述符 ngx_str_t name; void (*flush)(ngx_open_file_t *file, ngx_log_t *log); void *data; }; struct ngx_log_s { ngx_uint_t log_level; // 错误日志等级 ngx_open_file_t *file; // 打开的文件描述结构体 // 链接的个数下标 ngx_atomic_uint_t connection; time_t disk_full_time; ngx_log_handler_pt handler; void *data; // 写回调ngx_syslog_writer ngx_log_writer_pt writer; // ngx_syslog_peer_t void *wdata; /* * we declare "action" as "char *" because the actions are usually * the static strings and in the "u_char *" case we have to override * their types all the time */ char *action; // 形成一个链表 ngx_log_t *next; };
ngx_log.c文件中定义了两个静态变量,static限制了变量的作用域和保存范围。
static ngx_log_t ngx_log; static ngx_open_file_t ngx_log_file;
通过ngx_error_log函数解析error_log配置指令。
涉及到的函数:
ngx_log_t *ngx_log_init(u_char *prefix); // 初始化定义的静态日志文件结构体 void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, const char *fmt, ...); // ngx_int_t ngx_log_open_default(ngx_cycle_t *cycle); // 没有配置error log,则打开默认error log
static char * ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_log_t *dummy; dummy = &cf->cycle->new_log; return ngx_log_set_log(cf, &dummy); } char * ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head) { ngx_log_t *new_log; ngx_str_t *value, name; ngx_syslog_peer_t *peer; if (*head != NULL && (*head)->log_level == 0) { new_log = *head; } else { new_log = ngx_pcalloc(cf->pool, sizeof(ngx_log_t)); if (new_log == NULL) { return NGX_CONF_ERROR; } if (*head == NULL) { *head = new_log; } } value = cf->args->elts; if (ngx_strcmp(value[1].data, "stderr") == 0) { ngx_str_null(&name); cf->cycle->log_use_stderr = 1; new_log->file = ngx_conf_open_file(cf->cycle, &name); if (new_log->file == NULL) { return NGX_CONF_ERROR; } } else if (ngx_strncmp(value[1].data, "memory:", 7) == 0) { #if (NGX_DEBUG) size_t size, needed; ngx_pool_cleanup_t *cln; ngx_log_memory_buf_t *buf; value[1].len -= 7; value[1].data += 7; needed = sizeof("MEMLOG :" NGX_LINEFEED) + cf->conf_file->file.name.len + NGX_SIZE_T_LEN + NGX_INT_T_LEN + NGX_MAX_ERROR_STR; size = ngx_parse_size(&value[1]); if (size == (size_t) NGX_ERROR || size < needed) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid buffer size \"%V\"", &value[1]); return NGX_CONF_ERROR; } buf = ngx_pcalloc(cf->pool, sizeof(ngx_log_memory_buf_t)); if (buf == NULL) { return NGX_CONF_ERROR; } buf->start = ngx_pnalloc(cf->pool, size); if (buf->start == NULL) { return NGX_CONF_ERROR; } buf->end = buf->start + size; buf->pos = ngx_slprintf(buf->start, buf->end, "MEMLOG %uz %V:%ui%N", size, &cf->conf_file->file.name, cf->conf_file->line); ngx_memset(buf->pos, ' ', buf->end - buf->pos); cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { return NGX_CONF_ERROR; } cln->data = new_log; cln->handler = ngx_log_memory_cleanup; new_log->writer = ngx_log_memory_writer; new_log->wdata = buf; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "nginx was built without debug support"); return NGX_CONF_ERROR; #endif } else if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) { peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t)); if (peer == NULL) { return NGX_CONF_ERROR; } if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) { return NGX_CONF_ERROR; } new_log->writer = ngx_syslog_writer; new_log->wdata = peer; } else { new_log->file = ngx_conf_open_file(cf->cycle, &value[1]); if (new_log->file == NULL) { return NGX_CONF_ERROR; } } if (ngx_log_set_levels(cf, new_log) != NGX_CONF_OK) { return NGX_CONF_ERROR; } if (*head != new_log) { ngx_log_insert(*head, new_log); } return NGX_CONF_OK; } void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, const char *fmt, va_list args) { u_char *p, *last, *msg; ssize_t n; ngx_uint_t wrote_stderr, debug_connection; u_char errstr[NGX_MAX_ERROR_STR]; // 2k的buffer 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; // 真正的错误消息的开始 // 错误消息 p = ngx_vslprintf(p, last, fmt, args); if (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) { 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; } // 需要向标准错误输出日志 // 用“nginx:[等级]”替换掉开始的“时间 [等级] tid#pid 等 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); }
概述
error log 记录了nginx系统日志,区别于业务日志。 封装成ngx_errlog_module模块,代码在文件core/ngx_log.h|c中。 ngx_errlog_module 属于核心模块NGX_CORE_MODULE,提供了
error_log
配置指令。代码分析
涉及到的结构体:
ngx_log.c文件中定义了两个静态变量,static限制了变量的作用域和保存范围。
通过ngx_error_log函数解析error_log配置指令。
涉及到的函数: