Skip to content

Instantly share code, notes, and snippets.

@kaichao
Last active October 30, 2024 14:56
Show Gist options
  • Save kaichao/077340aa66e8cdf858577a93a9fe1b0d to your computer and use it in GitHub Desktop.
Save kaichao/077340aa66e8cdf858577a93a9fe1b0d to your computer and use it in GitHub Desktop.
nginx: Log complete request/response with all headers

1. switch nginx image to openresty/openresty

2. add the following to server/location (/etc/nginx/conf.d/default.conf)

   set $req_header "";
   set $resp_header "";
   header_filter_by_lua_block{ 
      local h = ngx.req.get_headers();
      for k, v in pairs(h) do
         ngx.var.req_header = ngx.var.req_header .. k.."="..v.." ";
      end
      local rh = ngx.resp.get_headers();
      for k, v in pairs(rh) do
         ngx.var.resp_header = ngx.var.resp_header .. k.."="..v.." ";
      end
   }

   lua_need_request_body on;
   set $resp_body "";
   body_filter_by_lua_block {
      local resp_body = string.sub(ngx.arg[1], 1, 1000)
      ngx.ctx.buffered = (ngx.ctx.buffered or "") .. resp_body
      if ngx.arg[2] then
         ngx.var.resp_body = ngx.ctx.buffered
      end
   }

   # access_log  /dev/stdout log_req_resp;
   access_log   /var/log/nginx-access.log log_req_resp;

3. add the following to http (/usr/local/openresty/nginx/conf/nginx.conf)

   log_format log_req_resp '$remote_addr - $remote_user [$time_local] '
      '"$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" '
      '$request_time req_header:"$req_header" resp_header:"$resp_header" '
      'req_body:"$request_body" resp_body:"$resp_body"';   

individual headers

request headers:$http_<header> 
 sent headers: $sent_http_<header>
@kovacs-andras
Copy link

kovacs-andras commented Mar 13, 2023

It works! 谢谢 / many thanks!

@c00kiemonstr
Copy link

After an hour of looking for an answer, this is what I needed. Thank you!

@zwurv
Copy link

zwurv commented Nov 23, 2023

This works great, thanks :)

@AronllStone
Copy link

You are a rock! Thanks!

@mvillafuertem
Copy link

@kaichao I can only use the nginx image due to company policy, any idea how to get the same result without changing the image?

@kaichao
Copy link
Author

kaichao commented Oct 8, 2024

@mvillafuertem

Map your nginx.conf into the container, is this what you need?

docker run -d -v /your-path/nginx.conf:/etc/nginx.conf openresty/openresty

@Luke-Williams9
Copy link

This isn't working, Its not recognizing the log format "nginx: [emerg] unknown log format "log_req_resp" in /etc/nginx/conf.d/libre.conf:42"
I have confirmed that my openresty container can see the config. here is its nginx.conf:

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    
    log_format log_req_resp '$remote_addr - $remote_user [$time_local] '
                            '"$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" '
                            '$request_time req_header:"$req_header" resp_header:"$resp_header" '
                            'req_body:"$request_body" resp_body:"$resp_body"'; 

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;
    
    resolver  127.0.0.11 valid=30s;

    include /etc/nginx/conf.d/*.conf;
}

and here is the server conf:


server {
    listen 80;
    server_name libre.*;

    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name libre.*;

    include /etc/nginx/snippets/ssl.conf;
    include /etc/nginx/snippets/authelia-location.conf;

    set $upstream http://librenms:8000;

    location / {
        set $req_header "";
        set $resp_header "";
        header_filter_by_lua_block{ 
            local h = ngx.req.get_headers();
            for k, v in pairs(h) do
                ngx.var.req_header = ngx.var.req_header .. k.."="..v.." ";
            end
            local rh = ngx.resp.get_headers();
            for k, v in pairs(rh) do
                ngx.var.resp_header = ngx.var.resp_header .. k.."="..v.." ";
            end
        }

        lua_need_request_body on;
        set $resp_body "";
        body_filter_by_lua_block {
            local resp_body = string.sub(ngx.arg[1], 1, 1000)
            ngx.ctx.buffered = (ngx.ctx.buffered or "") .. resp_body
            if ngx.arg[2] then
                ngx.var.resp_body = ngx.ctx.buffered
            end
        }

        access_log  /dev/stdout log_req_resp;
        include /etc/nginx/snippets/proxy.conf;
        include /etc/nginx/snippets/authelia-authrequest.conf;
        proxy_pass $upstream; 
    }
}

What am I doing wrong?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment