13

I have a small api I have built using Node.js and express. I am trying to create a logger and I need log the request body AND response body.

app.use((req, res) => {

    console.log(req);            

    res.on("finish", () => {

        console.log(res);

    });

});

"express": "^4.16.3",

However, i am not able to find the body in the req or res object. Please tell me how i can get them. thanks.

hong4rc
  • 3,999
  • 4
  • 21
  • 40
Kay
  • 17,906
  • 63
  • 162
  • 270
  • 2
    Are you using a `body-parser` module? – Sid Sep 13 '18 at 09:24
  • @Sid i believe that module is deprecated now and no need to use it with latest version of express. – Kay Sep 13 '18 at 09:27
  • express 4.x docs mention that you do need body-parsing middlewares to get `req.body` property. reference - http://expressjs.com/en/4x/api.html#req – planet_hunter Sep 13 '18 at 09:47
  • Doesen't it infer that by saying to use the `express.json([options])` which is based on body-parser. – Kay Sep 13 '18 at 09:49
  • Kay, have you tried to access `req.body`? – Sid Sep 13 '18 at 09:53
  • @Sid yes req.body works fine i guess i can alter this question for only res.body? – Kay Sep 13 '18 at 10:13
  • Yes, also please add details to your question to make us understand exactly what you are looking to achieve – Sid Sep 13 '18 at 10:24
  • Does this answer your question? [express logging response body](https://stackoverflow.com/questions/19215042/express-logging-response-body) – pixel Feb 04 '21 at 16:51

7 Answers7

14

For res.body try the following snippet:

const endMiddleware = (req, res, next) => {
  const defaultWrite = res.write;
  const defaultEnd = res.end;
  const chunks = [];

  res.write = (...restArgs) => {
    chunks.push(new Buffer(restArgs[0]));
    defaultWrite.apply(res, restArgs);
  };

  res.end = (...restArgs) => {
    if (restArgs[0]) {
      chunks.push(new Buffer(restArgs[0]));
    }
    const body = Buffer.concat(chunks).toString('utf8');

    console.log(body);

    defaultEnd.apply(res, restArgs);
  };

  next();
};

app.use(endMiddleware)

// test
// HTTP GET /
res.status(200).send({ isAlive: true });
Sid
  • 14,176
  • 7
  • 40
  • 48
11

You need body-parser that will create body object for you in your request.
To do that npm install body-parser

var bodyParser = require('body-parser')//add this

app.use(bodyParser())//add this before any route or before using req.body

app.use((req, res) => {
  console.log(req.body); // this is what you want           

  res.on("finish", () => {

    console.log(res);

  });

});
hong4rc
  • 3,999
  • 4
  • 21
  • 40
Rajan Lagah
  • 2,373
  • 1
  • 24
  • 40
7

Ran into this problem but didn't like the solutions. An easy way is to simply wrap the original res.send or res.json with your logger.

Put this as middleware before your routes.

app.use(function responseLogger(req, res, next) {
  const originalSendFunc = res.send.bind(res);
  res.send = function(body) {
    console.log(body);    // do whatever here
    return originalSendFunc(body);
  };
  next();
});

https://github.com/expressjs/express/blob/master/lib/response.js

res.send has signature of function(body) { return this; }

James
  • 110
  • 2
  • 6
4

Here is a working example using the built in PassThrough stream. Remember to use the express.json() built in middleware to enable request body parsing.

After that, you need to intercept all writes to the response stream. Writes will happen on calling write or end, so replace those functions and capture the arguments in a separate stream.

Use res.on('finish', ...) to gather all the written data into a Buffer using Buffer.concat and print it.

const express = require('express');
const { PassThrough } = require('stream')

const app = express();

app.use(express.json());

app.use((req, res, next) => {
    const defaultWrite = res.write.bind(res);
    const defaultEnd = res.end.bind(res);
    const ps = new PassThrough();
    const chunks = [];

    ps.on('data', data => chunks.push(data));

    res.write = (...args) => {
        ps.write(...args);
        defaultWrite(...args);
    }

    res.end = (...args) => {
        ps.end(...args);
        defaultEnd(...args);
    }

    res.on('finish', () => {
        console.log("req.body", req.body);
        console.log("res.body", Buffer.concat(chunks).toString());
    })

    next();
})

app.use('/', (req, res) => {
    res.send("Hello");
});

app.listen(3000);
lenkan
  • 4,089
  • 1
  • 14
  • 12
0

There is ready made module https://www.npmjs.com/package/morgan-body

const express = require('express')
const morganBody = require("morgan-body")
const bodyParser = require("body-parser")

const app = express()
const port = 8888

// must parse body before morganBody as body will be logged
app.use(bodyParser.json());

// hook morganBody to express app
morganBody(app, {logAllReqHeader:true, maxBodyLength:5000});

app.get('/', (req, res) => {
  res.send('Hello World!')

})

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`)
})
DaveX
  • 147
  • 1
  • 4
0
Hi was looking for same as complete log of request and response as middleware in express js. Found the solution as well w

    /*Added by vikram parihar for log  */
const moment = require('moment');
const rfs = require("rotating-file-stream");
const geoip = require('geoip-lite');
const { PassThrough } = require('stream')
let path = require('path');

const accessLogStream = rfs.createStream('access.log', {
    interval: '1M', // rotate daily
    compress: true,
    path: path.join(__dirname, '../../log')
});

module.exports = function (req, res, next) {
    try {
        let geo = geoip.lookup(req.ip);
        let country = geo ? geo.country : "Unknown";
        let region = geo ? geo.region : "Unknown";
        let log = {
            "time": moment().format('YYYY/MM/DD HH:mm:ss'),
            "host": req.hostname,
            "ip": req.ip,
            "originalUrl": req.originalUrl,
            "geo": {
                "browser": req.headers["user-agent"],
                "Language": req.headers["accept-language"],
                "Country": country,
                "Region": region,
            },
            "method": req.method,
            "path": req.path,
            "url": req.url,
            "body": req.body,
            "params": req.params,
            "query": req.query,
            "response": {
                "body": res.body
            }
        };
        const defaultWrite = res.write.bind(res);
        const defaultEnd = res.end.bind(res);
        const ps = new PassThrough();
        const chunks = [];

        ps.on('data', data => chunks.push(data));

        res.write = (...args) => {
            ps.write(...args);
            defaultWrite(...args);
        }

        res.end = (...args) => {
            ps.end(...args);
            defaultEnd(...args);
        }
        res.on('finish', () => {
            log.response.body = Buffer.concat(chunks).toString()
            accessLogStream.write(JSON.stringify(log) + "\n");
        })
    } catch (error) {
        console.log(error)
        next(error)
    }
    next();
}
-2

install npm install body-parser

and use this snippet,

var express = require('express')
var bodyParser = require('body-parser')
 
var app = express()
 
// create application/json parser
var jsonParser = bodyParser.json()
 
to get json response
app.use(jsonParser, function (req, res) {
  console.log(req.body); // or console.log(res.body);
})
Mohideen bin Mohammed
  • 18,813
  • 10
  • 112
  • 118