Mercurial > hg > nginx
comparison src/http/modules/ngx_http_log_module.c @ 4988:3849bb380605
Access log: the "gzip" parameter of the "access_log" directive.
Note: this requires zlib version 1.2.0.4 or above to work.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Sun, 23 Dec 2012 19:09:33 +0000 |
parents | 3efc49b156d9 |
children | f1a91825730a 3169a9b2250d |
comparison
equal
deleted
inserted
replaced
4987:66d001c5378c | 4988:3849bb380605 |
---|---|
6 | 6 |
7 | 7 |
8 #include <ngx_config.h> | 8 #include <ngx_config.h> |
9 #include <ngx_core.h> | 9 #include <ngx_core.h> |
10 #include <ngx_http.h> | 10 #include <ngx_http.h> |
11 | |
12 #if (NGX_ZLIB) | |
13 #include <zlib.h> | |
14 #endif | |
11 | 15 |
12 | 16 |
13 typedef struct ngx_http_log_op_s ngx_http_log_op_t; | 17 typedef struct ngx_http_log_op_s ngx_http_log_op_t; |
14 | 18 |
15 typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf, | 19 typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf, |
45 u_char *pos; | 49 u_char *pos; |
46 u_char *last; | 50 u_char *last; |
47 | 51 |
48 ngx_event_t *event; | 52 ngx_event_t *event; |
49 ngx_msec_t flush; | 53 ngx_msec_t flush; |
54 ngx_int_t gzip; | |
50 } ngx_http_log_buf_t; | 55 } ngx_http_log_buf_t; |
51 | 56 |
52 | 57 |
53 typedef struct { | 58 typedef struct { |
54 ngx_array_t *lengths; | 59 ngx_array_t *lengths; |
85 | 90 |
86 static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, | 91 static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, |
87 u_char *buf, size_t len); | 92 u_char *buf, size_t len); |
88 static ssize_t ngx_http_log_script_write(ngx_http_request_t *r, | 93 static ssize_t ngx_http_log_script_write(ngx_http_request_t *r, |
89 ngx_http_log_script_t *script, u_char **name, u_char *buf, size_t len); | 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 | |
90 | 103 |
91 static void ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log); | 104 static void ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log); |
92 static void ngx_http_log_flush_handler(ngx_event_t *ev); | 105 static void ngx_http_log_flush_handler(ngx_event_t *ev); |
93 | 106 |
94 static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, | 107 static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, |
329 | 342 |
330 static void | 343 static void |
331 ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf, | 344 ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf, |
332 size_t len) | 345 size_t len) |
333 { | 346 { |
334 u_char *name; | 347 u_char *name; |
335 time_t now; | 348 time_t now; |
336 ssize_t n; | 349 ssize_t n; |
337 ngx_err_t err; | 350 ngx_err_t err; |
351 #if (NGX_ZLIB) | |
352 ngx_http_log_buf_t *buffer; | |
353 #endif | |
338 | 354 |
339 if (log->script == NULL) { | 355 if (log->script == NULL) { |
340 name = log->file->name.data; | 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 | |
341 n = ngx_write_fd(log->file->fd, buf, len); | 368 n = ngx_write_fd(log->file->fd, buf, len); |
369 #endif | |
342 | 370 |
343 } else { | 371 } else { |
344 name = NULL; | 372 name = NULL; |
345 n = ngx_http_log_script_write(r, log->script, &name, buf, len); | 373 n = ngx_http_log_script_write(r, log->script, &name, buf, len); |
346 } | 374 } |
484 | 512 |
485 return n; | 513 return n; |
486 } | 514 } |
487 | 515 |
488 | 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 | |
489 static void | 651 static void |
490 ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log) | 652 ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log) |
491 { | 653 { |
492 size_t len; | 654 size_t len; |
493 ssize_t n; | 655 ssize_t n; |
499 | 661 |
500 if (len == 0) { | 662 if (len == 0) { |
501 return; | 663 return; |
502 } | 664 } |
503 | 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 | |
504 n = ngx_write_fd(file->fd, buffer->start, len); | 673 n = ngx_write_fd(file->fd, buffer->start, len); |
674 #endif | |
505 | 675 |
506 if (n == -1) { | 676 if (n == -1) { |
507 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | 677 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, |
508 ngx_write_fd_n " to \"%s\" failed", | 678 ngx_write_fd_n " to \"%s\" failed", |
509 file->name.data); | 679 file->name.data); |
914 ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | 1084 ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
915 { | 1085 { |
916 ngx_http_log_loc_conf_t *llcf = conf; | 1086 ngx_http_log_loc_conf_t *llcf = conf; |
917 | 1087 |
918 ssize_t size; | 1088 ssize_t size; |
1089 ngx_int_t gzip; | |
919 ngx_uint_t i, n; | 1090 ngx_uint_t i, n; |
920 ngx_msec_t flush; | 1091 ngx_msec_t flush; |
921 ngx_str_t *value, name, s; | 1092 ngx_str_t *value, name, s; |
922 ngx_http_log_t *log; | 1093 ngx_http_log_t *log; |
923 ngx_http_log_buf_t *buffer; | 1094 ngx_http_log_buf_t *buffer; |
1015 return NGX_CONF_ERROR; | 1186 return NGX_CONF_ERROR; |
1016 } | 1187 } |
1017 | 1188 |
1018 size = 0; | 1189 size = 0; |
1019 flush = 0; | 1190 flush = 0; |
1191 gzip = 0; | |
1020 | 1192 |
1021 for (i = 3; i < cf->args->nelts; i++) { | 1193 for (i = 3; i < cf->args->nelts; i++) { |
1022 | 1194 |
1023 if (ngx_strncmp(value[i].data, "buffer=", 7) == 0) { | 1195 if (ngx_strncmp(value[i].data, "buffer=", 7) == 0) { |
1024 s.len = value[i].len - 7; | 1196 s.len = value[i].len - 7; |
1046 "invalid flush time \"%V\"", &s); | 1218 "invalid flush time \"%V\"", &s); |
1047 return NGX_CONF_ERROR; | 1219 return NGX_CONF_ERROR; |
1048 } | 1220 } |
1049 | 1221 |
1050 continue; | 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 | |
1051 } | 1256 } |
1052 | 1257 |
1053 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 1258 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
1054 "invalid parameter \"%V\"", &value[i]); | 1259 "invalid parameter \"%V\"", &value[i]); |
1055 return NGX_CONF_ERROR; | 1260 return NGX_CONF_ERROR; |
1072 | 1277 |
1073 if (log->file->data) { | 1278 if (log->file->data) { |
1074 buffer = log->file->data; | 1279 buffer = log->file->data; |
1075 | 1280 |
1076 if (buffer->last - buffer->start != size | 1281 if (buffer->last - buffer->start != size |
1077 || buffer->flush != flush) | 1282 || buffer->flush != flush |
1283 || buffer->gzip != gzip) | |
1078 { | 1284 { |
1079 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 1285 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
1080 "access_log \"%V\" already defined " | 1286 "access_log \"%V\" already defined " |
1081 "with conflicting parameters", | 1287 "with conflicting parameters", |
1082 &value[1]); | 1288 &value[1]); |
1109 buffer->event->handler = ngx_http_log_flush_handler; | 1315 buffer->event->handler = ngx_http_log_flush_handler; |
1110 buffer->event->log = &cf->cycle->new_log; | 1316 buffer->event->log = &cf->cycle->new_log; |
1111 | 1317 |
1112 buffer->flush = flush; | 1318 buffer->flush = flush; |
1113 } | 1319 } |
1320 | |
1321 buffer->gzip = gzip; | |
1114 | 1322 |
1115 log->file->flush = ngx_http_log_flush; | 1323 log->file->flush = ngx_http_log_flush; |
1116 log->file->data = buffer; | 1324 log->file->data = buffer; |
1117 } | 1325 } |
1118 | 1326 |