In Node.js è abbastanza semplice leggere il file di log degli accessi di nginx.

Poiché Node.js viene solitamente eseguito sotto un'utenza che non può accedere alla directory /var/log/nginx, dobbiamo copiare inizialmente il file di log nella directory dell'app cambiandone il proprietario.

cat /var/log/nginx/access.log > /home/user/app/logs/access.log && chown user:user /home/user/app/logs/access.log

Quindi creiamo un cron job per rendere automatica e periodica questa operazione.


export VISUAL=nano; crontab -e

Possiamo ad esempio eseguirla una volta al giorno.

5 4 * * * cat /var/log/nginx/access.log > /home/user/app/logs/access.log && chown user:user /home/user/app/logs/access.log

Riavviamo quindi il servizio cron.

service cron restart

Si può usare questo servizio online per i valori temporali da assegnare al cron job. Non è necessario eseguirlo con troppa frequenza se vogliamo preservare le prestazioni ottimali del server.

In Node.js dobbiamo leggere i contenuti del file e creare un array di righe in ordine inverso perché nginx conserva i record partendo dal meno recente.

'use strict';

const fs = require('fs');

const readLog = () => {
    const logFile = './logs/access.log';
    return new Promise((resolve, reject) => {
        fs.readFile(logFile, 'utf8', (err, contents) => {
            if(err) { reject(err); }
            resolve(contents.toString().split(/\n/).reverse());
        });
    });
};

module.exports = readLog;

Ora possiamo usare questa funzione nella nostra applicazione.

'use strict';

const readLog = require('./readlog');
const app = require('express')();

app.set('view engine', 'ejs');

app.get('/log', async (req, res) => {
    try {
        const entries = await readLog();
        res.render('log', {entries: entries});
    } catch(err) { res.sendStatus(500); }
});

app.listen(8080);

Il nostro template EJS mostrerà ad esempio un semplice elenco.

<% if(entries.length > 0) { %>
<ol>
    <% entries.forEach(function(entry) { %>
        <li><%= entry %></li>
    <% }); %>
</ol>
<% } else { %>
   <p>No results to show.</p>
<% } %>

Come si può notare, una volta avuto accesso ai dati il task non è difficile.