4

I need to parse nginx access_log and associate records with user accounts. To do so, I decided to use a custom header:

  1. App sends custom header (like x-userid)
  2. Nginx stores that value in access_log with custom log format $sent_http_x_userid
  3. The header is being cleared and so the client doesn't see it with more_clear_headers 'x-userid'

Logging works just fine, I can see the proper userids in access_log. However, if I turn on the clearing part, the access_log shows '-' instead of actual userid.

Am I doing something wrong? Is it possible to log the header from the app before sending it to the client and then empty it with nginx?

Is there a better way to make this work? The app is PHP7, nginx is 1.10.3

Val Petruchek
  • 53
  • 2
  • 2
  • 5

2 Answers2

6

As $sent_http_x_userid variable name literally means that header was sent to client. When you clean it, nginx will not send it and there will be no variable $sent_http_x_userid.

But what you actually need is to log header that you've received from upstream. For that there is $upstream_http_x_userid variable that you can write to log.

And if you don't want to pass this header to client, there is proxy_hide_header directive.

So all together could look like this

log_format coolname '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent [uid=$upstream_http_x_userid] '
                    '"$http_referer" "$http_user_agent"';

server {
    ...
    access_log /var/log/nginx/cool.log coolname;

    location /whatever {
        proxy_pass http://your-app;
        proxy_hide_header x-userid;
    }
}

Alexey Ten
  • 8,435
  • 1
  • 34
  • 36
0

I thought this would be simple, just store the header's contents in a variable (using "set"), and use that variable in your log_format, disregarding the cleared header. But that failed miserably: the set command is executed before calling the backend (when the upstream headers have yet to be set).

But using LUA was succesful:

            set $saved_uid "X";
            header_filter_by_lua_block {
              ngx.var.saved_uid = ngx.var.upstream_http_x_userid;
            }
            more_clear_headers 'x-userid';

and use the variable in log_format:

log_format coolname
  '$remote_addr - $remote_user [$time_local] '
  '"$request" $status $body_bytes_sent [uid=$saved_uid] '
  '"$http_referer" "$http_user_agent"';
Gerard H. Pille
  • 2,569
  • 1
  • 13
  • 11