[PATCH 1 of 2] Access log: Support for disabling escaping

Johannes Baiter Johannes.Baiter at bsb-muenchen.de
Thu Feb 22 16:08:07 UTC 2018


This patch adds a "none" option for the "escape" parameter on the
"log_format" directive.

Selecting this option will perform no escaping of variables in the
access log output and write the variable to the file as-is.
The use case for this is more freedom for custom logging setups.

In our case, we use structured logging in JSON. For this, we build a
JSON string in a Lua script that is then stored in a nginx variable.
The log_format in this case is simply the variable:

  # The script sets the $json_log variable
  log_by_lua_file /etc/nginx/lua/scripts/json_logging.lua;
  log_format json $json_log;

  access_log /local/nginx/log/access.log json;
  error_log /local/nginx/log/error.log;

Both "default" and "json" do not work in this case, since either will
result in invalid JSON output.
Updated test suites for both ngx_http and ngx_stream are provided in
the second patch.


# HG changeset patch
# User Johannes Baiter <johannes.baiter at bsb-muenchen.de>
# Date 1519312196 -3600
#      Thu Feb 22 16:09:56 2018 +0100
# Node ID 267e08661efcb58a9b4cd5fd941486b88a37f4f4
# Parent  aa60f5799a4cbfc6887ef099c588e84a75c69785
Access log: support for disabling escaping.

diff -r aa60f5799a4c -r 267e08661efc
src/http/modules/ngx_http_log_module.c
--- a/src/http/modules/ngx_http_log_module.c	Thu Feb 22 12:42:29 2018
+0300
+++ b/src/http/modules/ngx_http_log_module.c	Thu Feb 22 16:09:56 2018
+0100
@@ -90,6 +90,13 @@
 } ngx_http_log_var_t;
 
 
+typedef enum {
+    ngx_http_log_escape_default = 0,
+    ngx_http_log_escape_json,
+    ngx_http_log_escape_none
+} ngx_http_log_escape_t;
+
+
 static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t
*log,
     u_char *buf, size_t len);
 static ssize_t ngx_http_log_script_write(ngx_http_request_t *r,
@@ -126,12 +133,16 @@
     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_uint_t json);
+    ngx_http_log_op_t *op, ngx_str_t *value, ngx_http_log_escape_t
escape);
 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_unescaped_variable_getlen(ngx_http_request_t *r,
+    uintptr_t data);
+static u_char *ngx_http_log_unescaped_variable(ngx_http_request_t *r,
u_char *buf,
+    ngx_http_log_op_t *op);
 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,
@@ -905,7 +916,7 @@
 
 static ngx_int_t
 ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op,
-    ngx_str_t *value, ngx_uint_t json)
+    ngx_str_t *value, ngx_http_log_escape_t escape)
 {
     ngx_int_t  index;
 
@@ -916,10 +927,12 @@
 
     op->len = 0;
 
-    if (json) {
+    if (escape == ngx_http_log_escape_json) {
         op->getlen = ngx_http_log_json_variable_getlen;
         op->run = ngx_http_log_json_variable;
-
+    } else if (escape == ngx_http_log_escape_none) {
+        op->getlen = ngx_http_log_unescaped_variable_getlen;
+        op->run = ngx_http_log_unescaped_variable;
     } else {
         op->getlen = ngx_http_log_variable_getlen;
         op->run = ngx_http_log_variable;
@@ -1033,6 +1046,38 @@
 
 
 static size_t
+ngx_http_log_unescaped_variable_getlen(ngx_http_request_t *r,
uintptr_t data)
+{
+    ngx_http_variable_value_t  *value;
+
+    value = ngx_http_get_indexed_variable(r, data);
+
+    if (value == NULL || value->not_found) {
+        return 0;
+    }
+
+    value->escape = 0;
+    return value->len;
+}
+
+
+static u_char *
+ngx_http_log_unescaped_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;
+    }
+
+    return ngx_cpymem(buf, value->data, value->len);
+}
+
+
+static size_t
 ngx_http_log_json_variable_getlen(ngx_http_request_t *r, uintptr_t
data)
 {
     uintptr_t                   len;
@@ -1536,19 +1581,21 @@
     size_t               i, len;
     ngx_str_t           *value, var;
     ngx_int_t           *flush;
-    ngx_uint_t           bracket, json;
+    ngx_uint_t           bracket;
     ngx_http_log_op_t   *op;
     ngx_http_log_var_t  *v;
+    ngx_http_log_escape_t escape;
 
-    json = 0;
+    escape = ngx_http_log_escape_default;
     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;
-
+            escape = ngx_http_log_escape_json;
+        } else if (ngx_strcmp(data, "none") == 0) {
+            escape = ngx_http_log_escape_none;
         } else if (ngx_strcmp(data, "default") != 0) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                "unknown log format escaping \"%s\"",
data);
@@ -1636,7 +1683,7 @@
                     }
                 }
 
-                if (ngx_http_log_variable_compile(cf, op, &var, json)
+                if (ngx_http_log_variable_compile(cf, op, &var,
escape)
                     != NGX_OK)
                 {
                     return NGX_CONF_ERROR;
diff -r aa60f5799a4c -r 267e08661efc
src/stream/ngx_stream_log_module.c
--- a/src/stream/ngx_stream_log_module.c	Thu Feb 22 12:42:29 2018
+0300
+++ b/src/stream/ngx_stream_log_module.c	Thu Feb 22 16:09:56 2018
+0100
@@ -89,6 +89,13 @@
 } ngx_stream_log_var_t;
 
 
+typedef enum {
+    ngx_stream_log_escape_default = 0,
+    ngx_stream_log_escape_json,
+    ngx_stream_log_escape_none
+} ngx_stream_log_escape_t;
+
+
 static void ngx_stream_log_write(ngx_stream_session_t *s,
ngx_stream_log_t *log,
     u_char *buf, size_t len);
 static ssize_t ngx_stream_log_script_write(ngx_stream_session_t *s,
@@ -106,7 +113,7 @@
 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_uint_t json);
+    ngx_stream_log_op_t *op, ngx_str_t *value, ngx_stream_log_escape_t
escape);
 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,
@@ -682,7 +689,7 @@
 
 static ngx_int_t
 ngx_stream_log_variable_compile(ngx_conf_t *cf, ngx_stream_log_op_t
*op,
-    ngx_str_t *value, ngx_uint_t json)
+    ngx_str_t *value, ngx_stream_log_escape_t escape)
 {
     ngx_int_t  index;
 
@@ -693,10 +700,14 @@
 
     op->len = 0;
 
-    if (json) {
+    if (escape == ngx_stream_log_escape_json) {
         op->getlen = ngx_stream_log_json_variable_getlen;
         op->run = ngx_stream_log_json_variable;
 
+    } else if (escape == ngx_stream_log_escape_none) {
+        op->getlen = ngx_stream_log_unescaped_variable_getlen;
+        op->run = ngx_stream_log_unescaped_variable;
+
     } else {
         op->getlen = ngx_stream_log_variable_getlen;
         op->run = ngx_stream_log_variable;
@@ -811,6 +822,38 @@
 
 
 static size_t
+ngx_stream_log_unescaped_variable_getlen(ngx_stream_session_t *s,
uintptr_t data)
+{
+    ngx_stream_variable_value_t  *value;
+
+    value = ngx_stream_get_indexed_variable(s, data);
+
+    if (value == NULL || value->not_found) {
+        return 0;
+    }
+
+    value->escape = 0;
+    return value->len;
+}
+
+
+static u_char *
+ngx_http_log_unescaped_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;
+    }
+
+    return ngx_cpymem(buf, value->data, value->len);
+}
+
+
+static size_t
 ngx_stream_log_json_variable_getlen(ngx_stream_session_t *s, uintptr_t
data)
 {
     uintptr_t                     len;
@@ -1265,17 +1308,21 @@
     size_t                 i, len;
     ngx_str_t             *value, var;
     ngx_int_t             *flush;
-    ngx_uint_t             bracket, json;
+    ngx_uint_t             bracket;
     ngx_stream_log_op_t   *op;
+    ngx_stream_log_escape_t escape;
 
-    json = 0;
+    escape = ngx_stream_log_escape_default;
     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;
+            escape = ngx_stream_log_escape_json;
+
+        } else if (ngx_strcmp(data, "none") == 0) {
+            escape = ngx_stream_log_escape_none;
 
         } else if (ngx_strcmp(data, "default") != 0) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -1350,7 +1397,7 @@
                     goto invalid;
                 }
 
-                if (ngx_stream_log_variable_compile(cf, op, &var,
json)
+                if (ngx_stream_log_variable_compile(cf, op, &var,
escape)
                     != NGX_OK)
                 {
                     return NGX_CONF_ERROR;



More information about the nginx-devel mailing list