Search code examples
node.jsexpressnginxwinstonmorgan

How to properly use morgan with nginx?


  • Server: Ubuntu 18.04
  • Node: 9.11.2
  • Npm: 6.6.0
  • Morgan: 1.9.1
  • Winston: 3.1.0
  • Nginx: 1.14.0 (Ubuntu)

I have a nodejs application on an ubuntu server with nginx. Install winston and morgan for the error log, but my application does not use winston, it only registers http requests in my nginx access.log file (var/log/nginx/access.log). Neither does it generate the app.log file that I need. It is as if my application for some reason ignores the use of morgan with winston.

My app.js

var express = require('express');
var compression = require('compression')
var path = require('path');
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var author = require('./routes/author');
var post = require('./routes/post');
var user = require('./routes/user');
var photo = require('./routes/photo');

var winston = require('./lib/config/winston');

var app = express();

app.use(morgan('combined', { stream: winston.stream }));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(compression());

var PAGING_COUNT = 10;
var MAX_PAGING_COUNT = 50;

app.use(function(req, res, next) {
  var s, c;
  if(!req.query) {
    s = 0;
    c = PAGING_COUNT;
  }
  else {
    var s = parseInt(req.query.s);
    var c = parseInt(req.query.c);
    if(!s) s = 0;
    if(!c) c = PAGING_COUNT;
  }
  if(c > MAX_PAGING_COUNT) {
    var err = new Error('Limit Request');
    err.status = 400;
    return next(err);
  }
  req.paging = { start: s, count: c};
  next();
});

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, api_key, Authorization");
  res.header("Access-Control-Expose-Headers", "Origin, X-Requested-With, Content-Type, Accept, api_key, Authorization");
  res.header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE");
  next();
});

app.use('/author', author);
app.use('/post', post);
app.use('/user', user);
app.use('/photo', photo);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500).send(err.message);
});

module.exports = app;

My winston.js (./lib/config/winston.js)

var winston = require('winston');
var appRoot = require('app-root-path');

// Defino las configuraciones personalizadas para cada transporte (file, console).
var options = {
    file: {
      level: 'info',
      filename: `${appRoot}/logs/app.log`,
      handleExceptions: true,
      json: true,
      maxsize: 5242880, // 5MB
      maxFiles: 5,
      colorize: false,
    },
    console: {
      level: 'debug',
      handleExceptions: true,
      json: false,
      colorize: true,
    },
  };

// Nueva instancia de Winston
var logger = winston.createLogger({
    transports: [
        new winston.transports.File(options.file),
        new winston.transports.Console(options.console)
    ],
    exitOnError: false, // do not exit on handled exceptions
  });

// Funcion de flujo que permite a Winston capturar resultados de Morgan
logger.stream = {
    write: function(message, encoding) {
      // Uso el nivel 'info' para que la salida sea recogida por ambos transportes (file y console)
      logger.info(message);
    },
  };

module.exports = logger;

My nginx server configuration

server {
    listen 80;
    listen [::]:80;

    #your subdomain
    server_name api.mydomain.com;

    location /v1/ {
        rewrite ^/v1/?(.*) /$1 break;
        proxy_buffering off;
        #your aplication port
        proxy_pass http://localhost:9000;
    }

    location /start/ {
        rewrite ^/start/?(.*) /$1 break;
        proxy_buffering off;
        #your aplication port
        proxy_pass http://localhost:8080;
    }
}
server {
    server_name storage.mydomain.com;
    root /home/ubuntu/app-backend/public/;
    index index.html;
    location /files {
        try_files $uri =404;
    }
}
server {
    listen 80;
    listen [::]:80;
    #point to build directory
    root /home/ubuntu/app-frontend/build;
    index index.html index.htm;

    server_name admin.mydomain.com;
    location / {
        root /home/ubuntu/app-frontend/build;
        try_files $uri $uri/ /index.html;
    }
}

On my local server I get the following

{"message":"::1 - - [23/Jan/2019:04:36:41 +0000] \"PUT /author/push/012c2cab HTTP/1.1\" 200 17 \"http://localhost:3000/home/page/1\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36\"\n","level":"info"}

in my production server I get the following

MY_IP - - [23/Jan/2019:06:35:33 +0000] "PUT /v1/author/push/6a839012 HTTP/1.1" 500 20 "http://admin.mydomain.com/home/page/1" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36"

My files: my files


Solution

  • You dont use stream for either morgan nor winston

    You have to use Stream Transport

    var accessLogStream = fs.createWriteStream(path.join(__dirname, 'app.log'), { flags: 'a' })
    
    logger.add(new winston.transports.Stream({
      stream: accessLogStream 
      /* other options */
    }));
    

    and then use the accessLogStream for morgan morgan - write logs to a file

    app.use(morgan('combined', { stream: accessLogStream }))