njs icon indicating copy to clipboard operation
njs copied to clipboard

How to write from njs to console in a custom format?

Open nettnikl opened this issue 3 years ago • 4 comments

Situation

I'm trying to setup logging for a set of nginx instances in my company. These are heavily relying on njs scripts for the functionality, and produce information that is critical to collect in the given environment.

However the responsibles would like to receive json formatted logs.

Question

Is it possible to log the output of njs in json?

Possible Solutions

Similar to the access_log with log_format specifying a json-like format - seems not possible (similar to how it is impossible to specify it for error messages in general).

Access to console.write, which is not possible during non-cli sessions (scripted, as in this cases, only the HTTP client with its ngx.log is available). The ngx.log however prints with a big format, not easily parseable for services down the line, as it's not json.

Related

https://github.com/nginx/njs/issues/76

https://stackoverflow.com/questions/4246756/is-it-possible-to-specify-custom-error-log-format-on-nginx https://stackoverflow.com/questions/16711573/nginx-error-log-format-documentation https://serverfault.com/questions/805855/how-to-change-the-timestamp-format-in-error-logs?rq=1

nettnikl avatar Jul 19 '22 14:07 nettnikl

Hi @nettnikl

js_var $testlog;

log_format testlog escape=none '$remote_addr - $remote_user [$time_local] "$request" '
                               '$status $testlog;
server {
    listen 8888;
    location /test {
        js_content test.testlog;
    }
    access_log  /var/log/nginx/access.log  testlog;
}
function testlog(r) {
    r.variables['testlog'] = JSON.stringify({ a: new Date(), b: 'test', c: 123});
    r.return(204);
}
$ curl localhost:8888/test
$ tail /var/log/nginx/access.log -n 1
127.0.0.1 -  [19/Jul/2022:18:32:47 +0300] "GET /test HTTP/1.1" 204 {"a":"2022-07-19T15:32:47.171Z","b":"test","c":123}

drsm avatar Jul 19 '22 15:07 drsm

Hi @drsm , thanks for your reply and the smart solution!

Sadly, this is not applicable for my use case, so let me explain. We are actually using this approach for access logs. However, during one request, there are multiple log entries to be written. So, if i don't want to do a subrequest to a dedicated log-endpoint for each log entry to write, i will have to find a way to print multiple lines. Preferably while the request is being handled, not collected in the end.

nettnikl avatar Jul 19 '22 17:07 nettnikl

@nettnikl

However, during one request, there are multiple log entries to be written.

So, why not to aggregate 'em into array?

var logdata = [];
function logsome(data) {
  logdata.push(data);
}
function logflush(r) {
  r.variables['whatever'] = JSON.stringify(logdata);
}

i will have to find a way to print multiple lines

Maybe fs.writeFileSync as a last resort.

drsm avatar Jul 19 '22 18:07 drsm

Thank you again for your suggestions! I will look into both the following day(s).

nettnikl avatar Jul 19 '22 21:07 nettnikl