morgan-body
morgan-body copied to clipboard
Response body not logged when used with swagger generated nodejs
Hi, I'm using morgan-body together with winston in my nodejs server code generated using swagger editor (https://editor.swagger.io/) but the response body doesn't seems to get logged.
Postman result shows a response object being returned:
Below is my implementation: index.js
'use strict';
var path = require('path');
var http = require('http');
var express = require('express');
var cors = require('cors')
const bodyParser = require("body-parser");
const morganBody = require('morgan-body');
var logger = require('./utils/logger')
var oas3Tools = require('oas3-tools');
var serverPort = process.env.PORT || 3002;
// swaggerRouter configuration
var options = {
routing: {
controllers: path.join(__dirname, './controllers')
},
};
var expressAppConfig = oas3Tools.expressAppConfig(path.join(__dirname, 'api/openapi.yaml'), options);
// var app = expressAppConfig.getApp();
const openApiApp = expressAppConfig.getApp();
const app = express();
app.use(cors())
app.use(bodyParser.json({limit: '5mb'}));
const loggerStream = {
write: message => {
logger.info(message);
},
};
morganBody(app, {
noColors: true,
prettify: false,
stream: loggerStream,
timezone: 'Asia/Singapore',
dateTimeFormat: 'iso'
});
// workaround for middleware: https://github.com/bug-hunters/oas3-tools/issues/19
for (let i = 2; i < openApiApp._router.stack.length; i++) {
app._router.stack.push(openApiApp._router.stack[i])
}
// Initialize the Swagger middleware
http.createServer(app).listen(serverPort, function () {
console.log('Your server is listening on port %d (http://localhost:%d)', serverPort, serverPort);
console.log('Swagger-ui is available on http://localhost:%d/docs', serverPort);
});
logger.js
const winston = require('winston');
const fs = require('fs')
const DailyRotateFile = require('winston-daily-rotate-file');
const logDir = "./logs";
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir);
}
const timezoned = () => {
return new Date().toLocaleString('en-GB', {
timeZone: 'Asia/Singapore'
});
};
const logFormat = winston.format.combine(
winston.format.timestamp({format: timezoned}),
winston.format.align(),
winston.format.printf(
info => `${info.timestamp} [${info.level.toUpperCase()}] ${info.message}`,
)
);
const transport = new DailyRotateFile({
filename: logDir + '/test-%DATE%.log',
datePattern: 'YYYY-MM-DD',
level: 'info',
});
const logger = winston.createLogger({
format: logFormat,
transports: [
transport,
new winston.transports.Console({
level: 'info',}),
]});
module.exports = logger;
Any idea how to get the response body logged?
You have not shown your 'companies' route handler code to confirm, but I have noticed morgan-body only logs the response body for json responses if you use express' response.json(...) to generate it:
(req, res) => {
res.json(...);
}
If instead you manually build the response, like below, then morgan-body will NOT log the response body:
(req, res) => {
res.writeHead(code, { 'Content-Type': 'application/json' });
res.end(...);
}
Hi @mlilley, thanks for the clarification. The response is indeed the latter so I guess it expected that the response body won't be logged. Below is the controller code (Company.js) for reference:
var utils = require('../utils/writer.js');
var Company = require('../service/CompanyService');
module.exports.addCompany = function addCompany (req, res, next, body) {
Company.addCompany(body)
.then(function (response) {
utils.writeJson(res, response);
})
.catch(function (response) {
utils.writeJson(res, response, 500);
});
};
writer.js
var ResponsePayload = function(code, payload) {
this.code = code;
this.payload = payload;
}
exports.respondWithCode = function(code, payload) {
return new ResponsePayload(code, payload);
}
var writeJson = exports.writeJson = function(response, arg1, arg2) {
var code;
var payload;
if(arg1 && arg1 instanceof ResponsePayload) {
writeJson(response, arg1.payload, arg1.code);
return;
}
if(arg2 && Number.isInteger(arg2)) {
code = arg2;
}
else {
if(arg1 && Number.isInteger(arg1)) {
code = arg1;
}
}
if(code && arg1) {
payload = arg1;
}
else if(arg1) {
payload = arg1;
}
if(!code) {
// if no response code given, we default to 200
code = 200;
}
if(typeof payload === 'object') {
payload = JSON.stringify(payload, null, 2);
}
response.writeHead(code, {'Content-Type': 'application/json'});
response.end(payload);
}
So it's not clear to me why morgan-body would require the use of .json() - perhaps this should be logged as a bug.
In the mean time, I suggest you replace your last 2 lines with response.status(code).json(payload);
and remove any stringification of payload... and you should be good to go.
thank you @mlilley, this is totally fair! Honestly morgan-body is something I originally published for myself to use across projects and it has since become way more popular than I could have imagined :)
right now I don't have time to work on it, but this would probably be an easy fix, appreciate you pitching in with helping answer issues