changeset 6840:0cf4e82e7c48

Access log: support for json escaping.
author Valentin Bartenev <vbart@nginx.com>
date Thu, 15 Dec 2016 16:25:42 +0300
parents 32714e608629
children e7cb5deb951d
files src/http/modules/ngx_http_log_module.c src/stream/ngx_stream_log_module.c
diffstat 2 files changed, 154 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/src/http/modules/ngx_http_log_module.c
+++ b/src/http/modules/ngx_http_log_module.c
@@ -126,12 +126,16 @@ static u_char *ngx_http_log_request_leng
     ngx_http_log_op_t *op);
 
 static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf,
-    ngx_http_log_op_t *op, ngx_str_t *value);
+    ngx_http_log_op_t *op, ngx_str_t *value, ngx_uint_t json);
 static size_t ngx_http_log_variable_getlen(ngx_http_request_t *r,
     uintptr_t data);
 static u_char *ngx_http_log_variable(ngx_http_request_t *r, u_char *buf,
     ngx_http_log_op_t *op);
 static uintptr_t ngx_http_log_escape(u_char *dst, u_char *src, size_t size);
+static size_t ngx_http_log_json_variable_getlen(ngx_http_request_t *r,
+    uintptr_t data);
+static u_char *ngx_http_log_json_variable(ngx_http_request_t *r, u_char *buf,
+    ngx_http_log_op_t *op);
 
 
 static void *ngx_http_log_create_main_conf(ngx_conf_t *cf);
@@ -909,7 +913,7 @@ ngx_http_log_request_length(ngx_http_req
 
 static ngx_int_t
 ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op,
-    ngx_str_t *value)
+    ngx_str_t *value, ngx_uint_t json)
 {
     ngx_int_t  index;
 
@@ -919,8 +923,16 @@ ngx_http_log_variable_compile(ngx_conf_t
     }
 
     op->len = 0;
-    op->getlen = ngx_http_log_variable_getlen;
-    op->run = ngx_http_log_variable;
+
+    if (json) {
+        op->getlen = ngx_http_log_json_variable_getlen;
+        op->run = ngx_http_log_json_variable;
+
+    } else {
+        op->getlen = ngx_http_log_variable_getlen;
+        op->run = ngx_http_log_variable;
+    }
+
     op->data = index;
 
     return NGX_OK;
@@ -1028,6 +1040,47 @@ ngx_http_log_escape(u_char *dst, u_char 
 }
 
 
+static size_t
+ngx_http_log_json_variable_getlen(ngx_http_request_t *r, uintptr_t data)
+{
+    uintptr_t                   len;
+    ngx_http_variable_value_t  *value;
+
+    value = ngx_http_get_indexed_variable(r, data);
+
+    if (value == NULL || value->not_found) {
+        return 0;
+    }
+
+    len = ngx_escape_json(NULL, value->data, value->len);
+
+    value->escape = len ? 1 : 0;
+
+    return value->len + len;
+}
+
+
+static u_char *
+ngx_http_log_json_variable(ngx_http_request_t *r, u_char *buf,
+    ngx_http_log_op_t *op)
+{
+    ngx_http_variable_value_t  *value;
+
+    value = ngx_http_get_indexed_variable(r, op->data);
+
+    if (value == NULL || value->not_found) {
+        return buf;
+    }
+
+    if (value->escape == 0) {
+        return ngx_cpymem(buf, value->data, value->len);
+
+    } else {
+        return (u_char *) ngx_escape_json(buf, value->data, value->len);
+    }
+}
+
+
 static void *
 ngx_http_log_create_main_conf(ngx_conf_t *cf)
 {
@@ -1491,12 +1544,28 @@ ngx_http_log_compile_format(ngx_conf_t *
     size_t               i, len;
     ngx_str_t           *value, var;
     ngx_int_t           *flush;
-    ngx_uint_t           bracket;
+    ngx_uint_t           bracket, json;
     ngx_http_log_op_t   *op;
     ngx_http_log_var_t  *v;
 
+    json = 0;
     value = args->elts;
 
+    if (s < args->nelts && ngx_strncmp(value[s].data, "escape=", 7) == 0) {
+        data = value[s].data + 7;
+
+        if (ngx_strcmp(data, "json") == 0) {
+            json = 1;
+
+        } else if (ngx_strcmp(data, "default") != 0) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "unknown log format escaping \"%s\"", data);
+            return NGX_CONF_ERROR;
+        }
+
+        s++;
+    }
+
     for ( /* void */ ; s < args->nelts; s++) {
 
         i = 0;
@@ -1575,7 +1644,9 @@ ngx_http_log_compile_format(ngx_conf_t *
                     }
                 }
 
-                if (ngx_http_log_variable_compile(cf, op, &var) != NGX_OK) {
+                if (ngx_http_log_variable_compile(cf, op, &var, json)
+                    != NGX_OK)
+                {
                     return NGX_CONF_ERROR;
                 }
 
--- a/src/stream/ngx_stream_log_module.c
+++ b/src/stream/ngx_stream_log_module.c
@@ -106,12 +106,16 @@ static void ngx_stream_log_flush(ngx_ope
 static void ngx_stream_log_flush_handler(ngx_event_t *ev);
 
 static ngx_int_t ngx_stream_log_variable_compile(ngx_conf_t *cf,
-    ngx_stream_log_op_t *op, ngx_str_t *value);
+    ngx_stream_log_op_t *op, ngx_str_t *value, ngx_uint_t json);
 static size_t ngx_stream_log_variable_getlen(ngx_stream_session_t *s,
     uintptr_t data);
 static u_char *ngx_stream_log_variable(ngx_stream_session_t *s, u_char *buf,
     ngx_stream_log_op_t *op);
 static uintptr_t ngx_stream_log_escape(u_char *dst, u_char *src, size_t size);
+static size_t ngx_stream_log_json_variable_getlen(ngx_stream_session_t *s,
+    uintptr_t data);
+static u_char *ngx_stream_log_json_variable(ngx_stream_session_t *s,
+    u_char *buf, ngx_stream_log_op_t *op);
 
 
 static void *ngx_stream_log_create_main_conf(ngx_conf_t *cf);
@@ -686,7 +690,7 @@ ngx_stream_log_copy_long(ngx_stream_sess
 
 static ngx_int_t
 ngx_stream_log_variable_compile(ngx_conf_t *cf, ngx_stream_log_op_t *op,
-    ngx_str_t *value)
+    ngx_str_t *value, ngx_uint_t json)
 {
     ngx_int_t  index;
 
@@ -696,8 +700,16 @@ ngx_stream_log_variable_compile(ngx_conf
     }
 
     op->len = 0;
-    op->getlen = ngx_stream_log_variable_getlen;
-    op->run = ngx_stream_log_variable;
+
+    if (json) {
+        op->getlen = ngx_stream_log_json_variable_getlen;
+        op->run = ngx_stream_log_json_variable;
+
+    } else {
+        op->getlen = ngx_stream_log_variable_getlen;
+        op->run = ngx_stream_log_variable;
+    }
+
     op->data = index;
 
     return NGX_OK;
@@ -806,6 +818,47 @@ ngx_stream_log_escape(u_char *dst, u_cha
 }
 
 
+static size_t
+ngx_stream_log_json_variable_getlen(ngx_stream_session_t *s, uintptr_t data)
+{
+    uintptr_t                     len;
+    ngx_stream_variable_value_t  *value;
+
+    value = ngx_stream_get_indexed_variable(s, data);
+
+    if (value == NULL || value->not_found) {
+        return 0;
+    }
+
+    len = ngx_escape_json(NULL, value->data, value->len);
+
+    value->escape = len ? 1 : 0;
+
+    return value->len + len;
+}
+
+
+static u_char *
+ngx_stream_log_json_variable(ngx_stream_session_t *s, u_char *buf,
+    ngx_stream_log_op_t *op)
+{
+    ngx_stream_variable_value_t  *value;
+
+    value = ngx_stream_get_indexed_variable(s, op->data);
+
+    if (value == NULL || value->not_found) {
+        return buf;
+    }
+
+    if (value->escape == 0) {
+        return ngx_cpymem(buf, value->data, value->len);
+
+    } else {
+        return (u_char *) ngx_escape_json(buf, value->data, value->len);
+    }
+}
+
+
 static void *
 ngx_stream_log_create_main_conf(ngx_conf_t *cf)
 {
@@ -1220,11 +1273,27 @@ ngx_stream_log_compile_format(ngx_conf_t
     size_t                 i, len;
     ngx_str_t             *value, var;
     ngx_int_t             *flush;
-    ngx_uint_t             bracket;
+    ngx_uint_t             bracket, json;
     ngx_stream_log_op_t   *op;
 
+    json = 0;
     value = args->elts;
 
+    if (s < args->nelts && ngx_strncmp(value[s].data, "escape=", 7) == 0) {
+        data = value[s].data + 7;
+
+        if (ngx_strcmp(data, "json") == 0) {
+            json = 1;
+
+        } else if (ngx_strcmp(data, "default") != 0) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "unknown log format escaping \"%s\"", data);
+            return NGX_CONF_ERROR;
+        }
+
+        s++;
+    }
+
     for ( /* void */ ; s < args->nelts; s++) {
 
         i = 0;
@@ -1289,7 +1358,9 @@ ngx_stream_log_compile_format(ngx_conf_t
                     goto invalid;
                 }
 
-                if (ngx_stream_log_variable_compile(cf, op, &var) != NGX_OK) {
+                if (ngx_stream_log_variable_compile(cf, op, &var, json)
+                    != NGX_OK)
+                {
                     return NGX_CONF_ERROR;
                 }