Annotation of embedaddon/nginx/src/http/modules/ngx_http_log_module.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * Copyright (C) Igor Sysoev
! 4: * Copyright (C) Nginx, Inc.
! 5: */
! 6:
! 7:
! 8: #include <ngx_config.h>
! 9: #include <ngx_core.h>
! 10: #include <ngx_http.h>
! 11:
! 12: #if (NGX_ZLIB)
! 13: #include <zlib.h>
! 14: #endif
! 15:
! 16:
! 17: typedef struct ngx_http_log_op_s ngx_http_log_op_t;
! 18:
! 19: typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf,
! 20: ngx_http_log_op_t *op);
! 21:
! 22: typedef size_t (*ngx_http_log_op_getlen_pt) (ngx_http_request_t *r,
! 23: uintptr_t data);
! 24:
! 25:
! 26: struct ngx_http_log_op_s {
! 27: size_t len;
! 28: ngx_http_log_op_getlen_pt getlen;
! 29: ngx_http_log_op_run_pt run;
! 30: uintptr_t data;
! 31: };
! 32:
! 33:
! 34: typedef struct {
! 35: ngx_str_t name;
! 36: ngx_array_t *flushes;
! 37: ngx_array_t *ops; /* array of ngx_http_log_op_t */
! 38: } ngx_http_log_fmt_t;
! 39:
! 40:
! 41: typedef struct {
! 42: ngx_array_t formats; /* array of ngx_http_log_fmt_t */
! 43: ngx_uint_t combined_used; /* unsigned combined_used:1 */
! 44: } ngx_http_log_main_conf_t;
! 45:
! 46:
! 47: typedef struct {
! 48: u_char *start;
! 49: u_char *pos;
! 50: u_char *last;
! 51:
! 52: ngx_event_t *event;
! 53: ngx_msec_t flush;
! 54: ngx_int_t gzip;
! 55: } ngx_http_log_buf_t;
! 56:
! 57:
! 58: typedef struct {
! 59: ngx_array_t *lengths;
! 60: ngx_array_t *values;
! 61: } ngx_http_log_script_t;
! 62:
! 63:
! 64: typedef struct {
! 65: ngx_open_file_t *file;
! 66: ngx_http_log_script_t *script;
! 67: time_t disk_full_time;
! 68: time_t error_log_time;
! 69: ngx_http_log_fmt_t *format;
! 70: } ngx_http_log_t;
! 71:
! 72:
! 73: typedef struct {
! 74: ngx_array_t *logs; /* array of ngx_http_log_t */
! 75:
! 76: ngx_open_file_cache_t *open_file_cache;
! 77: time_t open_file_cache_valid;
! 78: ngx_uint_t open_file_cache_min_uses;
! 79:
! 80: ngx_uint_t off; /* unsigned off:1 */
! 81: } ngx_http_log_loc_conf_t;
! 82:
! 83:
! 84: typedef struct {
! 85: ngx_str_t name;
! 86: size_t len;
! 87: ngx_http_log_op_run_pt run;
! 88: } ngx_http_log_var_t;
! 89:
! 90:
! 91: static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log,
! 92: u_char *buf, size_t len);
! 93: static ssize_t ngx_http_log_script_write(ngx_http_request_t *r,
! 94: ngx_http_log_script_t *script, u_char **name, u_char *buf, size_t len);
! 95:
! 96: #if (NGX_ZLIB)
! 97: static ssize_t ngx_http_log_gzip(ngx_fd_t fd, u_char *buf, size_t len,
! 98: ngx_int_t level, ngx_log_t *log);
! 99:
! 100: static void *ngx_http_log_gzip_alloc(void *opaque, u_int items, u_int size);
! 101: static void ngx_http_log_gzip_free(void *opaque, void *address);
! 102: #endif
! 103:
! 104: static void ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log);
! 105: static void ngx_http_log_flush_handler(ngx_event_t *ev);
! 106:
! 107: static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf,
! 108: ngx_http_log_op_t *op);
! 109: static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf,
! 110: ngx_http_log_op_t *op);
! 111: static u_char *ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf,
! 112: ngx_http_log_op_t *op);
! 113: static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf,
! 114: ngx_http_log_op_t *op);
! 115: static u_char *ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
! 116: ngx_http_log_op_t *op);
! 117: static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf,
! 118: ngx_http_log_op_t *op);
! 119: static u_char *ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
! 120: ngx_http_log_op_t *op);
! 121: static u_char *ngx_http_log_body_bytes_sent(ngx_http_request_t *r,
! 122: u_char *buf, ngx_http_log_op_t *op);
! 123: static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
! 124: ngx_http_log_op_t *op);
! 125:
! 126: static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf,
! 127: ngx_http_log_op_t *op, ngx_str_t *value);
! 128: static size_t ngx_http_log_variable_getlen(ngx_http_request_t *r,
! 129: uintptr_t data);
! 130: static u_char *ngx_http_log_variable(ngx_http_request_t *r, u_char *buf,
! 131: ngx_http_log_op_t *op);
! 132: static uintptr_t ngx_http_log_escape(u_char *dst, u_char *src, size_t size);
! 133:
! 134:
! 135: static void *ngx_http_log_create_main_conf(ngx_conf_t *cf);
! 136: static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf);
! 137: static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent,
! 138: void *child);
! 139: static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
! 140: void *conf);
! 141: static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
! 142: void *conf);
! 143: static char *ngx_http_log_compile_format(ngx_conf_t *cf,
! 144: ngx_array_t *flushes, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s);
! 145: static char *ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd,
! 146: void *conf);
! 147: static ngx_int_t ngx_http_log_init(ngx_conf_t *cf);
! 148:
! 149:
! 150: static ngx_command_t ngx_http_log_commands[] = {
! 151:
! 152: { ngx_string("log_format"),
! 153: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE,
! 154: ngx_http_log_set_format,
! 155: NGX_HTTP_MAIN_CONF_OFFSET,
! 156: 0,
! 157: NULL },
! 158:
! 159: { ngx_string("access_log"),
! 160: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
! 161: |NGX_HTTP_LMT_CONF|NGX_CONF_1MORE,
! 162: ngx_http_log_set_log,
! 163: NGX_HTTP_LOC_CONF_OFFSET,
! 164: 0,
! 165: NULL },
! 166:
! 167: { ngx_string("open_log_file_cache"),
! 168: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
! 169: ngx_http_log_open_file_cache,
! 170: NGX_HTTP_LOC_CONF_OFFSET,
! 171: 0,
! 172: NULL },
! 173:
! 174: ngx_null_command
! 175: };
! 176:
! 177:
! 178: static ngx_http_module_t ngx_http_log_module_ctx = {
! 179: NULL, /* preconfiguration */
! 180: ngx_http_log_init, /* postconfiguration */
! 181:
! 182: ngx_http_log_create_main_conf, /* create main configuration */
! 183: NULL, /* init main configuration */
! 184:
! 185: NULL, /* create server configuration */
! 186: NULL, /* merge server configuration */
! 187:
! 188: ngx_http_log_create_loc_conf, /* create location configuration */
! 189: ngx_http_log_merge_loc_conf /* merge location configuration */
! 190: };
! 191:
! 192:
! 193: ngx_module_t ngx_http_log_module = {
! 194: NGX_MODULE_V1,
! 195: &ngx_http_log_module_ctx, /* module context */
! 196: ngx_http_log_commands, /* module directives */
! 197: NGX_HTTP_MODULE, /* module type */
! 198: NULL, /* init master */
! 199: NULL, /* init module */
! 200: NULL, /* init process */
! 201: NULL, /* init thread */
! 202: NULL, /* exit thread */
! 203: NULL, /* exit process */
! 204: NULL, /* exit master */
! 205: NGX_MODULE_V1_PADDING
! 206: };
! 207:
! 208:
! 209: static ngx_str_t ngx_http_access_log = ngx_string(NGX_HTTP_LOG_PATH);
! 210:
! 211:
! 212: static ngx_str_t ngx_http_combined_fmt =
! 213: ngx_string("$remote_addr - $remote_user [$time_local] "
! 214: "\"$request\" $status $body_bytes_sent "
! 215: "\"$http_referer\" \"$http_user_agent\"");
! 216:
! 217:
! 218: static ngx_http_log_var_t ngx_http_log_vars[] = {
! 219: { ngx_string("pipe"), 1, ngx_http_log_pipe },
! 220: { ngx_string("time_local"), sizeof("28/Sep/1970:12:00:00 +0600") - 1,
! 221: ngx_http_log_time },
! 222: { ngx_string("time_iso8601"), sizeof("1970-09-28T12:00:00+06:00") - 1,
! 223: ngx_http_log_iso8601 },
! 224: { ngx_string("msec"), NGX_TIME_T_LEN + 4, ngx_http_log_msec },
! 225: { ngx_string("request_time"), NGX_TIME_T_LEN + 4,
! 226: ngx_http_log_request_time },
! 227: { ngx_string("status"), NGX_INT_T_LEN, ngx_http_log_status },
! 228: { ngx_string("bytes_sent"), NGX_OFF_T_LEN, ngx_http_log_bytes_sent },
! 229: { ngx_string("body_bytes_sent"), NGX_OFF_T_LEN,
! 230: ngx_http_log_body_bytes_sent },
! 231: { ngx_string("request_length"), NGX_SIZE_T_LEN,
! 232: ngx_http_log_request_length },
! 233:
! 234: { ngx_null_string, 0, NULL }
! 235: };
! 236:
! 237:
! 238: static ngx_int_t
! 239: ngx_http_log_handler(ngx_http_request_t *r)
! 240: {
! 241: u_char *line, *p;
! 242: size_t len;
! 243: ngx_uint_t i, l;
! 244: ngx_http_log_t *log;
! 245: ngx_http_log_op_t *op;
! 246: ngx_http_log_buf_t *buffer;
! 247: ngx_http_log_loc_conf_t *lcf;
! 248:
! 249: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 250: "http log handler");
! 251:
! 252: lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
! 253:
! 254: if (lcf->off) {
! 255: return NGX_OK;
! 256: }
! 257:
! 258: log = lcf->logs->elts;
! 259: for (l = 0; l < lcf->logs->nelts; l++) {
! 260:
! 261: if (ngx_time() == log[l].disk_full_time) {
! 262:
! 263: /*
! 264: * on FreeBSD writing to a full filesystem with enabled softupdates
! 265: * may block process for much longer time than writing to non-full
! 266: * filesystem, so we skip writing to a log for one second
! 267: */
! 268:
! 269: continue;
! 270: }
! 271:
! 272: ngx_http_script_flush_no_cacheable_variables(r, log[l].format->flushes);
! 273:
! 274: len = 0;
! 275: op = log[l].format->ops->elts;
! 276: for (i = 0; i < log[l].format->ops->nelts; i++) {
! 277: if (op[i].len == 0) {
! 278: len += op[i].getlen(r, op[i].data);
! 279:
! 280: } else {
! 281: len += op[i].len;
! 282: }
! 283: }
! 284:
! 285: len += NGX_LINEFEED_SIZE;
! 286:
! 287: buffer = log[l].file ? log[l].file->data : NULL;
! 288:
! 289: if (buffer) {
! 290:
! 291: if (len > (size_t) (buffer->last - buffer->pos)) {
! 292:
! 293: ngx_http_log_write(r, &log[l], buffer->start,
! 294: buffer->pos - buffer->start);
! 295:
! 296: buffer->pos = buffer->start;
! 297: }
! 298:
! 299: if (len <= (size_t) (buffer->last - buffer->pos)) {
! 300:
! 301: p = buffer->pos;
! 302:
! 303: if (buffer->event && p == buffer->start) {
! 304: ngx_add_timer(buffer->event, buffer->flush);
! 305: }
! 306:
! 307: for (i = 0; i < log[l].format->ops->nelts; i++) {
! 308: p = op[i].run(r, p, &op[i]);
! 309: }
! 310:
! 311: ngx_linefeed(p);
! 312:
! 313: buffer->pos = p;
! 314:
! 315: continue;
! 316: }
! 317:
! 318: if (buffer->event && buffer->event->timer_set) {
! 319: ngx_del_timer(buffer->event);
! 320: }
! 321: }
! 322:
! 323: line = ngx_pnalloc(r->pool, len);
! 324: if (line == NULL) {
! 325: return NGX_ERROR;
! 326: }
! 327:
! 328: p = line;
! 329:
! 330: for (i = 0; i < log[l].format->ops->nelts; i++) {
! 331: p = op[i].run(r, p, &op[i]);
! 332: }
! 333:
! 334: ngx_linefeed(p);
! 335:
! 336: ngx_http_log_write(r, &log[l], line, p - line);
! 337: }
! 338:
! 339: return NGX_OK;
! 340: }
! 341:
! 342:
! 343: static void
! 344: ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf,
! 345: size_t len)
! 346: {
! 347: u_char *name;
! 348: time_t now;
! 349: ssize_t n;
! 350: ngx_err_t err;
! 351: #if (NGX_ZLIB)
! 352: ngx_http_log_buf_t *buffer;
! 353: #endif
! 354:
! 355: if (log->script == NULL) {
! 356: name = log->file->name.data;
! 357:
! 358: #if (NGX_ZLIB)
! 359: buffer = log->file->data;
! 360:
! 361: if (buffer && buffer->gzip) {
! 362: n = ngx_http_log_gzip(log->file->fd, buf, len, buffer->gzip,
! 363: r->connection->log);
! 364: } else {
! 365: n = ngx_write_fd(log->file->fd, buf, len);
! 366: }
! 367: #else
! 368: n = ngx_write_fd(log->file->fd, buf, len);
! 369: #endif
! 370:
! 371: } else {
! 372: name = NULL;
! 373: n = ngx_http_log_script_write(r, log->script, &name, buf, len);
! 374: }
! 375:
! 376: if (n == (ssize_t) len) {
! 377: return;
! 378: }
! 379:
! 380: now = ngx_time();
! 381:
! 382: if (n == -1) {
! 383: err = ngx_errno;
! 384:
! 385: if (err == NGX_ENOSPC) {
! 386: log->disk_full_time = now;
! 387: }
! 388:
! 389: if (now - log->error_log_time > 59) {
! 390: ngx_log_error(NGX_LOG_ALERT, r->connection->log, err,
! 391: ngx_write_fd_n " to \"%s\" failed", name);
! 392:
! 393: log->error_log_time = now;
! 394: }
! 395:
! 396: return;
! 397: }
! 398:
! 399: if (now - log->error_log_time > 59) {
! 400: ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
! 401: ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
! 402: name, n, len);
! 403:
! 404: log->error_log_time = now;
! 405: }
! 406: }
! 407:
! 408:
! 409: static ssize_t
! 410: ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script,
! 411: u_char **name, u_char *buf, size_t len)
! 412: {
! 413: size_t root;
! 414: ssize_t n;
! 415: ngx_str_t log, path;
! 416: ngx_open_file_info_t of;
! 417: ngx_http_log_loc_conf_t *llcf;
! 418: ngx_http_core_loc_conf_t *clcf;
! 419:
! 420: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
! 421:
! 422: if (!r->root_tested) {
! 423:
! 424: /* test root directory existence */
! 425:
! 426: if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
! 427: /* simulate successful logging */
! 428: return len;
! 429: }
! 430:
! 431: path.data[root] = '\0';
! 432:
! 433: ngx_memzero(&of, sizeof(ngx_open_file_info_t));
! 434:
! 435: of.valid = clcf->open_file_cache_valid;
! 436: of.min_uses = clcf->open_file_cache_min_uses;
! 437: of.test_dir = 1;
! 438: of.test_only = 1;
! 439: of.errors = clcf->open_file_cache_errors;
! 440: of.events = clcf->open_file_cache_events;
! 441:
! 442: if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
! 443: /* simulate successful logging */
! 444: return len;
! 445: }
! 446:
! 447: if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
! 448: != NGX_OK)
! 449: {
! 450: if (of.err == 0) {
! 451: /* simulate successful logging */
! 452: return len;
! 453: }
! 454:
! 455: ngx_log_error(NGX_LOG_ERR, r->connection->log, of.err,
! 456: "testing \"%s\" existence failed", path.data);
! 457:
! 458: /* simulate successful logging */
! 459: return len;
! 460: }
! 461:
! 462: if (!of.is_dir) {
! 463: ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ENOTDIR,
! 464: "testing \"%s\" existence failed", path.data);
! 465:
! 466: /* simulate successful logging */
! 467: return len;
! 468: }
! 469: }
! 470:
! 471: if (ngx_http_script_run(r, &log, script->lengths->elts, 1,
! 472: script->values->elts)
! 473: == NULL)
! 474: {
! 475: /* simulate successful logging */
! 476: return len;
! 477: }
! 478:
! 479: log.data[log.len - 1] = '\0';
! 480: *name = log.data;
! 481:
! 482: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 483: "http log \"%s\"", log.data);
! 484:
! 485: llcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
! 486:
! 487: ngx_memzero(&of, sizeof(ngx_open_file_info_t));
! 488:
! 489: of.log = 1;
! 490: of.valid = llcf->open_file_cache_valid;
! 491: of.min_uses = llcf->open_file_cache_min_uses;
! 492: of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;
! 493:
! 494: if (ngx_http_set_disable_symlinks(r, clcf, &log, &of) != NGX_OK) {
! 495: /* simulate successful logging */
! 496: return len;
! 497: }
! 498:
! 499: if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool)
! 500: != NGX_OK)
! 501: {
! 502: ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
! 503: "%s \"%s\" failed", of.failed, log.data);
! 504: /* simulate successful logging */
! 505: return len;
! 506: }
! 507:
! 508: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 509: "http log #%d", of.fd);
! 510:
! 511: n = ngx_write_fd(of.fd, buf, len);
! 512:
! 513: return n;
! 514: }
! 515:
! 516:
! 517: #if (NGX_ZLIB)
! 518:
! 519: static ssize_t
! 520: ngx_http_log_gzip(ngx_fd_t fd, u_char *buf, size_t len, ngx_int_t level,
! 521: ngx_log_t *log)
! 522: {
! 523: int rc, wbits, memlevel;
! 524: u_char *out;
! 525: size_t size;
! 526: ssize_t n;
! 527: z_stream zstream;
! 528: ngx_err_t err;
! 529: ngx_pool_t *pool;
! 530:
! 531: wbits = MAX_WBITS;
! 532: memlevel = MAX_MEM_LEVEL - 1;
! 533:
! 534: while ((ssize_t) len < ((1 << (wbits - 1)) - 262)) {
! 535: wbits--;
! 536: memlevel--;
! 537: }
! 538:
! 539: /*
! 540: * This is a formula from deflateBound() for conservative upper bound of
! 541: * compressed data plus 18 bytes of gzip wrapper.
! 542: */
! 543:
! 544: size = len + ((len + 7) >> 3) + ((len + 63) >> 6) + 5 + 18;
! 545:
! 546: ngx_memzero(&zstream, sizeof(z_stream));
! 547:
! 548: pool = ngx_create_pool(256, log);
! 549: if (pool == NULL) {
! 550: /* simulate successful logging */
! 551: return len;
! 552: }
! 553:
! 554: pool->log = log;
! 555:
! 556: zstream.zalloc = ngx_http_log_gzip_alloc;
! 557: zstream.zfree = ngx_http_log_gzip_free;
! 558: zstream.opaque = pool;
! 559:
! 560: out = ngx_pnalloc(pool, size);
! 561: if (out == NULL) {
! 562: goto done;
! 563: }
! 564:
! 565: zstream.next_in = buf;
! 566: zstream.avail_in = len;
! 567: zstream.next_out = out;
! 568: zstream.avail_out = size;
! 569:
! 570: rc = deflateInit2(&zstream, (int) level, Z_DEFLATED, wbits + 16, memlevel,
! 571: Z_DEFAULT_STRATEGY);
! 572:
! 573: if (rc != Z_OK) {
! 574: ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateInit2() failed: %d", rc);
! 575: goto done;
! 576: }
! 577:
! 578: ngx_log_debug4(NGX_LOG_DEBUG_HTTP, log, 0,
! 579: "deflate in: ni:%p no:%p ai:%ud ao:%ud",
! 580: zstream.next_in, zstream.next_out,
! 581: zstream.avail_in, zstream.avail_out);
! 582:
! 583: rc = deflate(&zstream, Z_FINISH);
! 584:
! 585: if (rc != Z_STREAM_END) {
! 586: ngx_log_error(NGX_LOG_ALERT, log, 0,
! 587: "deflate(Z_FINISH) failed: %d", rc);
! 588: goto done;
! 589: }
! 590:
! 591: ngx_log_debug5(NGX_LOG_DEBUG_HTTP, log, 0,
! 592: "deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
! 593: zstream.next_in, zstream.next_out,
! 594: zstream.avail_in, zstream.avail_out,
! 595: rc);
! 596:
! 597: size -= zstream.avail_out;
! 598:
! 599: rc = deflateEnd(&zstream);
! 600:
! 601: if (rc != Z_OK) {
! 602: ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateEnd() failed: %d", rc);
! 603: goto done;
! 604: }
! 605:
! 606: n = ngx_write_fd(fd, out, size);
! 607:
! 608: if (n != (ssize_t) size) {
! 609: err = (n == -1) ? ngx_errno : 0;
! 610:
! 611: ngx_destroy_pool(pool);
! 612:
! 613: ngx_set_errno(err);
! 614: return -1;
! 615: }
! 616:
! 617: done:
! 618:
! 619: ngx_destroy_pool(pool);
! 620:
! 621: /* simulate successful logging */
! 622: return len;
! 623: }
! 624:
! 625:
! 626: static void *
! 627: ngx_http_log_gzip_alloc(void *opaque, u_int items, u_int size)
! 628: {
! 629: ngx_pool_t *pool = opaque;
! 630:
! 631: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pool->log, 0,
! 632: "gzip alloc: n:%ud s:%ud", items, size);
! 633:
! 634: return ngx_palloc(pool, items * size);
! 635: }
! 636:
! 637:
! 638: static void
! 639: ngx_http_log_gzip_free(void *opaque, void *address)
! 640: {
! 641: #if 0
! 642: ngx_pool_t *pool = opaque;
! 643:
! 644: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pool->log, 0, "gzip free: %p", address);
! 645: #endif
! 646: }
! 647:
! 648: #endif
! 649:
! 650:
! 651: static void
! 652: ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log)
! 653: {
! 654: size_t len;
! 655: ssize_t n;
! 656: ngx_http_log_buf_t *buffer;
! 657:
! 658: buffer = file->data;
! 659:
! 660: len = buffer->pos - buffer->start;
! 661:
! 662: if (len == 0) {
! 663: return;
! 664: }
! 665:
! 666: #if (NGX_ZLIB)
! 667: if (buffer->gzip) {
! 668: n = ngx_http_log_gzip(file->fd, buffer->start, len, buffer->gzip, log);
! 669: } else {
! 670: n = ngx_write_fd(file->fd, buffer->start, len);
! 671: }
! 672: #else
! 673: n = ngx_write_fd(file->fd, buffer->start, len);
! 674: #endif
! 675:
! 676: if (n == -1) {
! 677: ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
! 678: ngx_write_fd_n " to \"%s\" failed",
! 679: file->name.data);
! 680:
! 681: } else if ((size_t) n != len) {
! 682: ngx_log_error(NGX_LOG_ALERT, log, 0,
! 683: ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
! 684: file->name.data, n, len);
! 685: }
! 686:
! 687: buffer->pos = buffer->start;
! 688:
! 689: if (buffer->event && buffer->event->timer_set) {
! 690: ngx_del_timer(buffer->event);
! 691: }
! 692: }
! 693:
! 694:
! 695: static void
! 696: ngx_http_log_flush_handler(ngx_event_t *ev)
! 697: {
! 698: ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0,
! 699: "http log buffer flush handler");
! 700:
! 701: ngx_http_log_flush(ev->data, ev->log);
! 702: }
! 703:
! 704:
! 705: static u_char *
! 706: ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf,
! 707: ngx_http_log_op_t *op)
! 708: {
! 709: size_t len;
! 710: uintptr_t data;
! 711:
! 712: len = op->len;
! 713: data = op->data;
! 714:
! 715: while (len--) {
! 716: *buf++ = (u_char) (data & 0xff);
! 717: data >>= 8;
! 718: }
! 719:
! 720: return buf;
! 721: }
! 722:
! 723:
! 724: static u_char *
! 725: ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf,
! 726: ngx_http_log_op_t *op)
! 727: {
! 728: return ngx_cpymem(buf, (u_char *) op->data, op->len);
! 729: }
! 730:
! 731:
! 732: static u_char *
! 733: ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
! 734: {
! 735: if (r->pipeline) {
! 736: *buf = 'p';
! 737: } else {
! 738: *buf = '.';
! 739: }
! 740:
! 741: return buf + 1;
! 742: }
! 743:
! 744:
! 745: static u_char *
! 746: ngx_http_log_time(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
! 747: {
! 748: return ngx_cpymem(buf, ngx_cached_http_log_time.data,
! 749: ngx_cached_http_log_time.len);
! 750: }
! 751:
! 752: static u_char *
! 753: ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
! 754: {
! 755: return ngx_cpymem(buf, ngx_cached_http_log_iso8601.data,
! 756: ngx_cached_http_log_iso8601.len);
! 757: }
! 758:
! 759: static u_char *
! 760: ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
! 761: {
! 762: ngx_time_t *tp;
! 763:
! 764: tp = ngx_timeofday();
! 765:
! 766: return ngx_sprintf(buf, "%T.%03M", tp->sec, tp->msec);
! 767: }
! 768:
! 769:
! 770: static u_char *
! 771: ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
! 772: ngx_http_log_op_t *op)
! 773: {
! 774: ngx_time_t *tp;
! 775: ngx_msec_int_t ms;
! 776:
! 777: tp = ngx_timeofday();
! 778:
! 779: ms = (ngx_msec_int_t)
! 780: ((tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec));
! 781: ms = ngx_max(ms, 0);
! 782:
! 783: return ngx_sprintf(buf, "%T.%03M", (time_t) ms / 1000, ms % 1000);
! 784: }
! 785:
! 786:
! 787: static u_char *
! 788: ngx_http_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
! 789: {
! 790: ngx_uint_t status;
! 791:
! 792: if (r->err_status) {
! 793: status = r->err_status;
! 794:
! 795: } else if (r->headers_out.status) {
! 796: status = r->headers_out.status;
! 797:
! 798: } else if (r->http_version == NGX_HTTP_VERSION_9) {
! 799: status = 9;
! 800:
! 801: } else {
! 802: status = 0;
! 803: }
! 804:
! 805: return ngx_sprintf(buf, "%03ui", status);
! 806: }
! 807:
! 808:
! 809: static u_char *
! 810: ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
! 811: ngx_http_log_op_t *op)
! 812: {
! 813: return ngx_sprintf(buf, "%O", r->connection->sent);
! 814: }
! 815:
! 816:
! 817: /*
! 818: * although there is a real $body_bytes_sent variable,
! 819: * this log operation code function is more optimized for logging
! 820: */
! 821:
! 822: static u_char *
! 823: ngx_http_log_body_bytes_sent(ngx_http_request_t *r, u_char *buf,
! 824: ngx_http_log_op_t *op)
! 825: {
! 826: off_t length;
! 827:
! 828: length = r->connection->sent - r->header_size;
! 829:
! 830: if (length > 0) {
! 831: return ngx_sprintf(buf, "%O", length);
! 832: }
! 833:
! 834: *buf = '0';
! 835:
! 836: return buf + 1;
! 837: }
! 838:
! 839:
! 840: static u_char *
! 841: ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
! 842: ngx_http_log_op_t *op)
! 843: {
! 844: return ngx_sprintf(buf, "%O", r->request_length);
! 845: }
! 846:
! 847:
! 848: static ngx_int_t
! 849: ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op,
! 850: ngx_str_t *value)
! 851: {
! 852: ngx_int_t index;
! 853:
! 854: index = ngx_http_get_variable_index(cf, value);
! 855: if (index == NGX_ERROR) {
! 856: return NGX_ERROR;
! 857: }
! 858:
! 859: op->len = 0;
! 860: op->getlen = ngx_http_log_variable_getlen;
! 861: op->run = ngx_http_log_variable;
! 862: op->data = index;
! 863:
! 864: return NGX_OK;
! 865: }
! 866:
! 867:
! 868: static size_t
! 869: ngx_http_log_variable_getlen(ngx_http_request_t *r, uintptr_t data)
! 870: {
! 871: uintptr_t len;
! 872: ngx_http_variable_value_t *value;
! 873:
! 874: value = ngx_http_get_indexed_variable(r, data);
! 875:
! 876: if (value == NULL || value->not_found) {
! 877: return 1;
! 878: }
! 879:
! 880: len = ngx_http_log_escape(NULL, value->data, value->len);
! 881:
! 882: value->escape = len ? 1 : 0;
! 883:
! 884: return value->len + len * 3;
! 885: }
! 886:
! 887:
! 888: static u_char *
! 889: ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
! 890: {
! 891: ngx_http_variable_value_t *value;
! 892:
! 893: value = ngx_http_get_indexed_variable(r, op->data);
! 894:
! 895: if (value == NULL || value->not_found) {
! 896: *buf = '-';
! 897: return buf + 1;
! 898: }
! 899:
! 900: if (value->escape == 0) {
! 901: return ngx_cpymem(buf, value->data, value->len);
! 902:
! 903: } else {
! 904: return (u_char *) ngx_http_log_escape(buf, value->data, value->len);
! 905: }
! 906: }
! 907:
! 908:
! 909: static uintptr_t
! 910: ngx_http_log_escape(u_char *dst, u_char *src, size_t size)
! 911: {
! 912: ngx_uint_t n;
! 913: static u_char hex[] = "0123456789ABCDEF";
! 914:
! 915: static uint32_t escape[] = {
! 916: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 917:
! 918: /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
! 919: 0x00000004, /* 0000 0000 0000 0000 0000 0000 0000 0100 */
! 920:
! 921: /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
! 922: 0x10000000, /* 0001 0000 0000 0000 0000 0000 0000 0000 */
! 923:
! 924: /* ~}| {zyx wvut srqp onml kjih gfed cba` */
! 925: 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
! 926:
! 927: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 928: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 929: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 930: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 931: };
! 932:
! 933:
! 934: if (dst == NULL) {
! 935:
! 936: /* find the number of the characters to be escaped */
! 937:
! 938: n = 0;
! 939:
! 940: while (size) {
! 941: if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
! 942: n++;
! 943: }
! 944: src++;
! 945: size--;
! 946: }
! 947:
! 948: return (uintptr_t) n;
! 949: }
! 950:
! 951: while (size) {
! 952: if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
! 953: *dst++ = '\\';
! 954: *dst++ = 'x';
! 955: *dst++ = hex[*src >> 4];
! 956: *dst++ = hex[*src & 0xf];
! 957: src++;
! 958:
! 959: } else {
! 960: *dst++ = *src++;
! 961: }
! 962: size--;
! 963: }
! 964:
! 965: return (uintptr_t) dst;
! 966: }
! 967:
! 968:
! 969: static void *
! 970: ngx_http_log_create_main_conf(ngx_conf_t *cf)
! 971: {
! 972: ngx_http_log_main_conf_t *conf;
! 973:
! 974: ngx_http_log_fmt_t *fmt;
! 975:
! 976: conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t));
! 977: if (conf == NULL) {
! 978: return NULL;
! 979: }
! 980:
! 981: if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t))
! 982: != NGX_OK)
! 983: {
! 984: return NULL;
! 985: }
! 986:
! 987: fmt = ngx_array_push(&conf->formats);
! 988: if (fmt == NULL) {
! 989: return NULL;
! 990: }
! 991:
! 992: ngx_str_set(&fmt->name, "combined");
! 993:
! 994: fmt->flushes = NULL;
! 995:
! 996: fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
! 997: if (fmt->ops == NULL) {
! 998: return NULL;
! 999: }
! 1000:
! 1001: return conf;
! 1002: }
! 1003:
! 1004:
! 1005: static void *
! 1006: ngx_http_log_create_loc_conf(ngx_conf_t *cf)
! 1007: {
! 1008: ngx_http_log_loc_conf_t *conf;
! 1009:
! 1010: conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t));
! 1011: if (conf == NULL) {
! 1012: return NULL;
! 1013: }
! 1014:
! 1015: conf->open_file_cache = NGX_CONF_UNSET_PTR;
! 1016:
! 1017: return conf;
! 1018: }
! 1019:
! 1020:
! 1021: static char *
! 1022: ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
! 1023: {
! 1024: ngx_http_log_loc_conf_t *prev = parent;
! 1025: ngx_http_log_loc_conf_t *conf = child;
! 1026:
! 1027: ngx_http_log_t *log;
! 1028: ngx_http_log_fmt_t *fmt;
! 1029: ngx_http_log_main_conf_t *lmcf;
! 1030:
! 1031: if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
! 1032:
! 1033: conf->open_file_cache = prev->open_file_cache;
! 1034: conf->open_file_cache_valid = prev->open_file_cache_valid;
! 1035: conf->open_file_cache_min_uses = prev->open_file_cache_min_uses;
! 1036:
! 1037: if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
! 1038: conf->open_file_cache = NULL;
! 1039: }
! 1040: }
! 1041:
! 1042: if (conf->logs || conf->off) {
! 1043: return NGX_CONF_OK;
! 1044: }
! 1045:
! 1046: conf->logs = prev->logs;
! 1047: conf->off = prev->off;
! 1048:
! 1049: if (conf->logs || conf->off) {
! 1050: return NGX_CONF_OK;
! 1051: }
! 1052:
! 1053: conf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
! 1054: if (conf->logs == NULL) {
! 1055: return NGX_CONF_ERROR;
! 1056: }
! 1057:
! 1058: log = ngx_array_push(conf->logs);
! 1059: if (log == NULL) {
! 1060: return NGX_CONF_ERROR;
! 1061: }
! 1062:
! 1063: log->file = ngx_conf_open_file(cf->cycle, &ngx_http_access_log);
! 1064: if (log->file == NULL) {
! 1065: return NGX_CONF_ERROR;
! 1066: }
! 1067:
! 1068: log->script = NULL;
! 1069: log->disk_full_time = 0;
! 1070: log->error_log_time = 0;
! 1071:
! 1072: lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
! 1073: fmt = lmcf->formats.elts;
! 1074:
! 1075: /* the default "combined" format */
! 1076: log->format = &fmt[0];
! 1077: lmcf->combined_used = 1;
! 1078:
! 1079: return NGX_CONF_OK;
! 1080: }
! 1081:
! 1082:
! 1083: static char *
! 1084: ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
! 1085: {
! 1086: ngx_http_log_loc_conf_t *llcf = conf;
! 1087:
! 1088: ssize_t size;
! 1089: ngx_int_t gzip;
! 1090: ngx_uint_t i, n;
! 1091: ngx_msec_t flush;
! 1092: ngx_str_t *value, name, s;
! 1093: ngx_http_log_t *log;
! 1094: ngx_http_log_buf_t *buffer;
! 1095: ngx_http_log_fmt_t *fmt;
! 1096: ngx_http_log_main_conf_t *lmcf;
! 1097: ngx_http_script_compile_t sc;
! 1098:
! 1099: value = cf->args->elts;
! 1100:
! 1101: if (ngx_strcmp(value[1].data, "off") == 0) {
! 1102: llcf->off = 1;
! 1103: if (cf->args->nelts == 2) {
! 1104: return NGX_CONF_OK;
! 1105: }
! 1106:
! 1107: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 1108: "invalid parameter \"%V\"", &value[2]);
! 1109: return NGX_CONF_ERROR;
! 1110: }
! 1111:
! 1112: if (llcf->logs == NULL) {
! 1113: llcf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
! 1114: if (llcf->logs == NULL) {
! 1115: return NGX_CONF_ERROR;
! 1116: }
! 1117: }
! 1118:
! 1119: lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
! 1120:
! 1121: log = ngx_array_push(llcf->logs);
! 1122: if (log == NULL) {
! 1123: return NGX_CONF_ERROR;
! 1124: }
! 1125:
! 1126: ngx_memzero(log, sizeof(ngx_http_log_t));
! 1127:
! 1128: n = ngx_http_script_variables_count(&value[1]);
! 1129:
! 1130: if (n == 0) {
! 1131: log->file = ngx_conf_open_file(cf->cycle, &value[1]);
! 1132: if (log->file == NULL) {
! 1133: return NGX_CONF_ERROR;
! 1134: }
! 1135:
! 1136: } else {
! 1137: if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) {
! 1138: return NGX_CONF_ERROR;
! 1139: }
! 1140:
! 1141: log->script = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_script_t));
! 1142: if (log->script == NULL) {
! 1143: return NGX_CONF_ERROR;
! 1144: }
! 1145:
! 1146: ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
! 1147:
! 1148: sc.cf = cf;
! 1149: sc.source = &value[1];
! 1150: sc.lengths = &log->script->lengths;
! 1151: sc.values = &log->script->values;
! 1152: sc.variables = n;
! 1153: sc.complete_lengths = 1;
! 1154: sc.complete_values = 1;
! 1155:
! 1156: if (ngx_http_script_compile(&sc) != NGX_OK) {
! 1157: return NGX_CONF_ERROR;
! 1158: }
! 1159: }
! 1160:
! 1161: if (cf->args->nelts >= 3) {
! 1162: name = value[2];
! 1163:
! 1164: if (ngx_strcmp(name.data, "combined") == 0) {
! 1165: lmcf->combined_used = 1;
! 1166: }
! 1167:
! 1168: } else {
! 1169: ngx_str_set(&name, "combined");
! 1170: lmcf->combined_used = 1;
! 1171: }
! 1172:
! 1173: fmt = lmcf->formats.elts;
! 1174: for (i = 0; i < lmcf->formats.nelts; i++) {
! 1175: if (fmt[i].name.len == name.len
! 1176: && ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
! 1177: {
! 1178: log->format = &fmt[i];
! 1179: break;
! 1180: }
! 1181: }
! 1182:
! 1183: if (log->format == NULL) {
! 1184: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 1185: "unknown log format \"%V\"", &name);
! 1186: return NGX_CONF_ERROR;
! 1187: }
! 1188:
! 1189: size = 0;
! 1190: flush = 0;
! 1191: gzip = 0;
! 1192:
! 1193: for (i = 3; i < cf->args->nelts; i++) {
! 1194:
! 1195: if (ngx_strncmp(value[i].data, "buffer=", 7) == 0) {
! 1196: s.len = value[i].len - 7;
! 1197: s.data = value[i].data + 7;
! 1198:
! 1199: size = ngx_parse_size(&s);
! 1200:
! 1201: if (size == NGX_ERROR || size == 0) {
! 1202: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 1203: "invalid buffer size \"%V\"", &s);
! 1204: return NGX_CONF_ERROR;
! 1205: }
! 1206:
! 1207: continue;
! 1208: }
! 1209:
! 1210: if (ngx_strncmp(value[i].data, "flush=", 6) == 0) {
! 1211: s.len = value[i].len - 6;
! 1212: s.data = value[i].data + 6;
! 1213:
! 1214: flush = ngx_parse_time(&s, 0);
! 1215:
! 1216: if (flush == (ngx_msec_t) NGX_ERROR || flush == 0) {
! 1217: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 1218: "invalid flush time \"%V\"", &s);
! 1219: return NGX_CONF_ERROR;
! 1220: }
! 1221:
! 1222: continue;
! 1223: }
! 1224:
! 1225: if (ngx_strncmp(value[i].data, "gzip", 4) == 0
! 1226: && (value[i].len == 4 || value[i].data[4] == '='))
! 1227: {
! 1228: #if (NGX_ZLIB)
! 1229: if (size == 0) {
! 1230: size = 64 * 1024;
! 1231: }
! 1232:
! 1233: if (value[i].len == 4) {
! 1234: gzip = Z_BEST_SPEED;
! 1235: continue;
! 1236: }
! 1237:
! 1238: s.len = value[i].len - 5;
! 1239: s.data = value[i].data + 5;
! 1240:
! 1241: gzip = ngx_atoi(s.data, s.len);
! 1242:
! 1243: if (gzip < 1 || gzip > 9) {
! 1244: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 1245: "invalid compression level \"%V\"", &s);
! 1246: return NGX_CONF_ERROR;
! 1247: }
! 1248:
! 1249: continue;
! 1250:
! 1251: #else
! 1252: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 1253: "nginx was built without zlib support");
! 1254: return NGX_CONF_ERROR;
! 1255: #endif
! 1256: }
! 1257:
! 1258: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 1259: "invalid parameter \"%V\"", &value[i]);
! 1260: return NGX_CONF_ERROR;
! 1261: }
! 1262:
! 1263: if (flush && size == 0) {
! 1264: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 1265: "no buffer is defined for access_log \"%V\"",
! 1266: &value[1]);
! 1267: return NGX_CONF_ERROR;
! 1268: }
! 1269:
! 1270: if (size) {
! 1271:
! 1272: if (log->script) {
! 1273: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 1274: "buffered logs cannot have variables in name");
! 1275: return NGX_CONF_ERROR;
! 1276: }
! 1277:
! 1278: if (log->file->data) {
! 1279: buffer = log->file->data;
! 1280:
! 1281: if (buffer->last - buffer->start != size
! 1282: || buffer->flush != flush
! 1283: || buffer->gzip != gzip)
! 1284: {
! 1285: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 1286: "access_log \"%V\" already defined "
! 1287: "with conflicting parameters",
! 1288: &value[1]);
! 1289: return NGX_CONF_ERROR;
! 1290: }
! 1291:
! 1292: return NGX_CONF_OK;
! 1293: }
! 1294:
! 1295: buffer = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_buf_t));
! 1296: if (buffer == NULL) {
! 1297: return NGX_CONF_ERROR;
! 1298: }
! 1299:
! 1300: buffer->start = ngx_pnalloc(cf->pool, size);
! 1301: if (buffer->start == NULL) {
! 1302: return NGX_CONF_ERROR;
! 1303: }
! 1304:
! 1305: buffer->pos = buffer->start;
! 1306: buffer->last = buffer->start + size;
! 1307:
! 1308: if (flush) {
! 1309: buffer->event = ngx_pcalloc(cf->pool, sizeof(ngx_event_t));
! 1310: if (buffer->event == NULL) {
! 1311: return NGX_CONF_ERROR;
! 1312: }
! 1313:
! 1314: buffer->event->data = log->file;
! 1315: buffer->event->handler = ngx_http_log_flush_handler;
! 1316: buffer->event->log = &cf->cycle->new_log;
! 1317:
! 1318: buffer->flush = flush;
! 1319: }
! 1320:
! 1321: buffer->gzip = gzip;
! 1322:
! 1323: log->file->flush = ngx_http_log_flush;
! 1324: log->file->data = buffer;
! 1325: }
! 1326:
! 1327: return NGX_CONF_OK;
! 1328: }
! 1329:
! 1330:
! 1331: static char *
! 1332: ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
! 1333: {
! 1334: ngx_http_log_main_conf_t *lmcf = conf;
! 1335:
! 1336: ngx_str_t *value;
! 1337: ngx_uint_t i;
! 1338: ngx_http_log_fmt_t *fmt;
! 1339:
! 1340: if (cf->cmd_type != NGX_HTTP_MAIN_CONF) {
! 1341: ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
! 1342: "the \"log_format\" directive may be used "
! 1343: "only on \"http\" level");
! 1344: }
! 1345:
! 1346: value = cf->args->elts;
! 1347:
! 1348: fmt = lmcf->formats.elts;
! 1349: for (i = 0; i < lmcf->formats.nelts; i++) {
! 1350: if (fmt[i].name.len == value[1].len
! 1351: && ngx_strcmp(fmt[i].name.data, value[1].data) == 0)
! 1352: {
! 1353: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 1354: "duplicate \"log_format\" name \"%V\"",
! 1355: &value[1]);
! 1356: return NGX_CONF_ERROR;
! 1357: }
! 1358: }
! 1359:
! 1360: fmt = ngx_array_push(&lmcf->formats);
! 1361: if (fmt == NULL) {
! 1362: return NGX_CONF_ERROR;
! 1363: }
! 1364:
! 1365: fmt->name = value[1];
! 1366:
! 1367: fmt->flushes = ngx_array_create(cf->pool, 4, sizeof(ngx_int_t));
! 1368: if (fmt->flushes == NULL) {
! 1369: return NGX_CONF_ERROR;
! 1370: }
! 1371:
! 1372: fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
! 1373: if (fmt->ops == NULL) {
! 1374: return NGX_CONF_ERROR;
! 1375: }
! 1376:
! 1377: return ngx_http_log_compile_format(cf, fmt->flushes, fmt->ops, cf->args, 2);
! 1378: }
! 1379:
! 1380:
! 1381: static char *
! 1382: ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,
! 1383: ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s)
! 1384: {
! 1385: u_char *data, *p, ch;
! 1386: size_t i, len;
! 1387: ngx_str_t *value, var;
! 1388: ngx_int_t *flush;
! 1389: ngx_uint_t bracket;
! 1390: ngx_http_log_op_t *op;
! 1391: ngx_http_log_var_t *v;
! 1392:
! 1393: value = args->elts;
! 1394:
! 1395: for ( /* void */ ; s < args->nelts; s++) {
! 1396:
! 1397: i = 0;
! 1398:
! 1399: while (i < value[s].len) {
! 1400:
! 1401: op = ngx_array_push(ops);
! 1402: if (op == NULL) {
! 1403: return NGX_CONF_ERROR;
! 1404: }
! 1405:
! 1406: data = &value[s].data[i];
! 1407:
! 1408: if (value[s].data[i] == '$') {
! 1409:
! 1410: if (++i == value[s].len) {
! 1411: goto invalid;
! 1412: }
! 1413:
! 1414: if (value[s].data[i] == '{') {
! 1415: bracket = 1;
! 1416:
! 1417: if (++i == value[s].len) {
! 1418: goto invalid;
! 1419: }
! 1420:
! 1421: var.data = &value[s].data[i];
! 1422:
! 1423: } else {
! 1424: bracket = 0;
! 1425: var.data = &value[s].data[i];
! 1426: }
! 1427:
! 1428: for (var.len = 0; i < value[s].len; i++, var.len++) {
! 1429: ch = value[s].data[i];
! 1430:
! 1431: if (ch == '}' && bracket) {
! 1432: i++;
! 1433: bracket = 0;
! 1434: break;
! 1435: }
! 1436:
! 1437: if ((ch >= 'A' && ch <= 'Z')
! 1438: || (ch >= 'a' && ch <= 'z')
! 1439: || (ch >= '0' && ch <= '9')
! 1440: || ch == '_')
! 1441: {
! 1442: continue;
! 1443: }
! 1444:
! 1445: break;
! 1446: }
! 1447:
! 1448: if (bracket) {
! 1449: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 1450: "the closing bracket in \"%V\" "
! 1451: "variable is missing", &var);
! 1452: return NGX_CONF_ERROR;
! 1453: }
! 1454:
! 1455: if (var.len == 0) {
! 1456: goto invalid;
! 1457: }
! 1458:
! 1459: for (v = ngx_http_log_vars; v->name.len; v++) {
! 1460:
! 1461: if (v->name.len == var.len
! 1462: && ngx_strncmp(v->name.data, var.data, var.len) == 0)
! 1463: {
! 1464: op->len = v->len;
! 1465: op->getlen = NULL;
! 1466: op->run = v->run;
! 1467: op->data = 0;
! 1468:
! 1469: goto found;
! 1470: }
! 1471: }
! 1472:
! 1473: if (ngx_http_log_variable_compile(cf, op, &var) != NGX_OK) {
! 1474: return NGX_CONF_ERROR;
! 1475: }
! 1476:
! 1477: if (flushes) {
! 1478:
! 1479: flush = ngx_array_push(flushes);
! 1480: if (flush == NULL) {
! 1481: return NGX_CONF_ERROR;
! 1482: }
! 1483:
! 1484: *flush = op->data; /* variable index */
! 1485: }
! 1486:
! 1487: found:
! 1488:
! 1489: continue;
! 1490: }
! 1491:
! 1492: i++;
! 1493:
! 1494: while (i < value[s].len && value[s].data[i] != '$') {
! 1495: i++;
! 1496: }
! 1497:
! 1498: len = &value[s].data[i] - data;
! 1499:
! 1500: if (len) {
! 1501:
! 1502: op->len = len;
! 1503: op->getlen = NULL;
! 1504:
! 1505: if (len <= sizeof(uintptr_t)) {
! 1506: op->run = ngx_http_log_copy_short;
! 1507: op->data = 0;
! 1508:
! 1509: while (len--) {
! 1510: op->data <<= 8;
! 1511: op->data |= data[len];
! 1512: }
! 1513:
! 1514: } else {
! 1515: op->run = ngx_http_log_copy_long;
! 1516:
! 1517: p = ngx_pnalloc(cf->pool, len);
! 1518: if (p == NULL) {
! 1519: return NGX_CONF_ERROR;
! 1520: }
! 1521:
! 1522: ngx_memcpy(p, data, len);
! 1523: op->data = (uintptr_t) p;
! 1524: }
! 1525: }
! 1526: }
! 1527: }
! 1528:
! 1529: return NGX_CONF_OK;
! 1530:
! 1531: invalid:
! 1532:
! 1533: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%s\"", data);
! 1534:
! 1535: return NGX_CONF_ERROR;
! 1536: }
! 1537:
! 1538:
! 1539: static char *
! 1540: ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
! 1541: {
! 1542: ngx_http_log_loc_conf_t *llcf = conf;
! 1543:
! 1544: time_t inactive, valid;
! 1545: ngx_str_t *value, s;
! 1546: ngx_int_t max, min_uses;
! 1547: ngx_uint_t i;
! 1548:
! 1549: if (llcf->open_file_cache != NGX_CONF_UNSET_PTR) {
! 1550: return "is duplicate";
! 1551: }
! 1552:
! 1553: value = cf->args->elts;
! 1554:
! 1555: max = 0;
! 1556: inactive = 10;
! 1557: valid = 60;
! 1558: min_uses = 1;
! 1559:
! 1560: for (i = 1; i < cf->args->nelts; i++) {
! 1561:
! 1562: if (ngx_strncmp(value[i].data, "max=", 4) == 0) {
! 1563:
! 1564: max = ngx_atoi(value[i].data + 4, value[i].len - 4);
! 1565: if (max == NGX_ERROR) {
! 1566: goto failed;
! 1567: }
! 1568:
! 1569: continue;
! 1570: }
! 1571:
! 1572: if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {
! 1573:
! 1574: s.len = value[i].len - 9;
! 1575: s.data = value[i].data + 9;
! 1576:
! 1577: inactive = ngx_parse_time(&s, 1);
! 1578: if (inactive == (time_t) NGX_ERROR) {
! 1579: goto failed;
! 1580: }
! 1581:
! 1582: continue;
! 1583: }
! 1584:
! 1585: if (ngx_strncmp(value[i].data, "min_uses=", 9) == 0) {
! 1586:
! 1587: min_uses = ngx_atoi(value[i].data + 9, value[i].len - 9);
! 1588: if (min_uses == NGX_ERROR) {
! 1589: goto failed;
! 1590: }
! 1591:
! 1592: continue;
! 1593: }
! 1594:
! 1595: if (ngx_strncmp(value[i].data, "valid=", 6) == 0) {
! 1596:
! 1597: s.len = value[i].len - 6;
! 1598: s.data = value[i].data + 6;
! 1599:
! 1600: valid = ngx_parse_time(&s, 1);
! 1601: if (valid == (time_t) NGX_ERROR) {
! 1602: goto failed;
! 1603: }
! 1604:
! 1605: continue;
! 1606: }
! 1607:
! 1608: if (ngx_strcmp(value[i].data, "off") == 0) {
! 1609:
! 1610: llcf->open_file_cache = NULL;
! 1611:
! 1612: continue;
! 1613: }
! 1614:
! 1615: failed:
! 1616:
! 1617: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 1618: "invalid \"open_log_file_cache\" parameter \"%V\"",
! 1619: &value[i]);
! 1620: return NGX_CONF_ERROR;
! 1621: }
! 1622:
! 1623: if (llcf->open_file_cache == NULL) {
! 1624: return NGX_CONF_OK;
! 1625: }
! 1626:
! 1627: if (max == 0) {
! 1628: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 1629: "\"open_log_file_cache\" must have \"max\" parameter");
! 1630: return NGX_CONF_ERROR;
! 1631: }
! 1632:
! 1633: llcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive);
! 1634:
! 1635: if (llcf->open_file_cache) {
! 1636:
! 1637: llcf->open_file_cache_valid = valid;
! 1638: llcf->open_file_cache_min_uses = min_uses;
! 1639:
! 1640: return NGX_CONF_OK;
! 1641: }
! 1642:
! 1643: return NGX_CONF_ERROR;
! 1644: }
! 1645:
! 1646:
! 1647: static ngx_int_t
! 1648: ngx_http_log_init(ngx_conf_t *cf)
! 1649: {
! 1650: ngx_str_t *value;
! 1651: ngx_array_t a;
! 1652: ngx_http_handler_pt *h;
! 1653: ngx_http_log_fmt_t *fmt;
! 1654: ngx_http_log_main_conf_t *lmcf;
! 1655: ngx_http_core_main_conf_t *cmcf;
! 1656:
! 1657: lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
! 1658:
! 1659: if (lmcf->combined_used) {
! 1660: if (ngx_array_init(&a, cf->pool, 1, sizeof(ngx_str_t)) != NGX_OK) {
! 1661: return NGX_ERROR;
! 1662: }
! 1663:
! 1664: value = ngx_array_push(&a);
! 1665: if (value == NULL) {
! 1666: return NGX_ERROR;
! 1667: }
! 1668:
! 1669: *value = ngx_http_combined_fmt;
! 1670: fmt = lmcf->formats.elts;
! 1671:
! 1672: if (ngx_http_log_compile_format(cf, NULL, fmt->ops, &a, 0)
! 1673: != NGX_CONF_OK)
! 1674: {
! 1675: return NGX_ERROR;
! 1676: }
! 1677: }
! 1678:
! 1679: cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
! 1680:
! 1681: h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers);
! 1682: if (h == NULL) {
! 1683: return NGX_ERROR;
! 1684: }
! 1685:
! 1686: *h = ngx_http_log_handler;
! 1687:
! 1688: return NGX_OK;
! 1689: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>