Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Logging POST data from $request_body

I have my config setup to handle a bunch of GET requests which render pixels that work fine to handle analytics and parse query strings for logging. With an additional third party data stream, I need to handle a POST request to a given url that has JSON in an expected loggable format inside of it's request body. I don't want to use a secondary server with proxy_pass and just want to log the whole response into an associated log file like what it does with GET requests. A snippet of some code that I'm using looks like the following:

GET request (which works great):

location ^~ /rl.gif {   set $rl_lcid $arg_lcid;   if ($http_cookie ~* "lcid=(.*\S)")   {     set $rl_lcid $cookie_lcid;   }   empty_gif;   log_format my_tracking '{ "guid" : "$rl_lcid", "data" : "$arg__rlcdnsegs" }';   access_log  /mnt/logs/nginx/my.access.log my_tracking;   rewrite ^(.*)$ http://my/url?id=$cookie_lcid? redirect; } 

Here is kinda what I am trying to do: POST request (which does not work):

location /bk {   log_format bk_tracking $request_body;   access_log  /mnt/logs/nginx/bk.access.log bk_tracking; } 

Curling curl http://myurl/bk -d name=example gives me a 404 page not found.

Then I tried:

location /bk.gif {   empty_gif;   log_format bk_tracking $request_body;   access_log  /mnt/logs/nginx/bk.access.log bk_tracking; } 

Curling curl http://myurl/bk.gif -d name=example gives me a 405 Not Allowed.

My current version is nginx/0.7.62. Any help in the right direction is very much appreciated! Thanks!

UPDATE So now my post looks like this:

location /bk {   if ($request_method != POST) {     return 405;   }   proxy_pass $scheme://127.0.0.1:$server_port/dummy;   log_format my_tracking $request_body;   access_log  /mnt/logs/nginx/my.access.log my_tracking; } location /dummy { set $test 0; } 

It is logging the post data correctly, but returns a 404 on the requesters end. If I change the above code to return a 200 like so:

location /bk {   if ($request_method != POST) {     return 405;   }   proxy_pass $scheme://127.0.0.1:$server_port/dummy;   log_format my_tracking $request_body;   access_log  /mnt/logs/nginx/my.access.log my_tracking;   return 200; } location /dummy { set $test 0; } 

Then it return the 200 correctly, but no longer records the post data.

ANOTHER UPDATE Kinda found a working solution. Hopefully this can help other on their way.

like image 434
Chris Barretto Avatar asked Feb 08 '11 22:02

Chris Barretto


People also ask

Can Nginx read post data?

By default, NGINX does not log POST data since it can be bulky and take up disk space. However, sometimes you may need to log POST data for debugging purposes.

How do I log into a HTTP POST request?

You can log POST request details by using dumpio module for Apache, which allows logging of HTTP request body.


2 Answers

This solution works like a charm (updated in 2017 to honor that log_format needs to be in the http part of the nginx config):

log_format postdata $request_body;  server {     # (...)      location = /post.php {        access_log  /var/log/nginx/postdata.log  postdata;        fastcgi_pass php_cgi;     } } 

I think the trick is making nginx believe that you will call a cgi script.

like image 64
ahofmann Avatar answered Sep 19 '22 12:09

ahofmann


Try echo_read_request_body.

"echo_read_request_body ... Explicitly reads request body so that the $request_body variable will always have non-empty values (unless the body is so big that it has been saved by Nginx to a local temporary file)."

location /log {   log_format postdata $request_body;   access_log /mnt/logs/nginx/my_tracking.access.log postdata;   echo_read_request_body; } 
like image 40
boqapt Avatar answered Sep 20 '22 12:09

boqapt