Выражать тело реакции каротажа
Название должно быть довольно само собой разумеющимся.
В целях отладки я хотел бы выразить, чтобы напечатать код ответа и тело для каждого обслуживаемого запроса. Печать кода ответа достаточно проста, но печать тела ответа сложнее, так как кажется, что тело ответа не доступно в качестве свойства.
Не работает следующее:
var express = require('express');
var app = express();
// define custom logging format
express.logger.format('detailed', function (token, req, res) {
return req.method + ': ' + req.path + ' -> ' + res.statusCode + ': ' + res.body + '\n';
});
// register logging middleware and use custom logging format
app.use(express.logger('detailed'));
// setup routes
app.get(..... omitted ...);
// start server
app.listen(8080);
Конечно, я мог бы легко распечатать ответы на клиенте, который отправил запрос, но я бы предпочел делать и на стороне сервера.
PS: Если это помогает, все мои ответы - json, но, надеюсь, есть решение, которое работает с общими ответами.
Ответы
Ответ 1
Не уверен, что это самое простое решение, но вы можете написать промежуточное программное обеспечение для перехвата данных, записанных в ответ. Убедитесь, что вы отключили app.compress()
.
function logResponseBody(req, res, next) {
var oldWrite = res.write,
oldEnd = res.end;
var chunks = [];
res.write = function (chunk) {
chunks.push(chunk);
oldWrite.apply(res, arguments);
};
res.end = function (chunk) {
if (chunk)
chunks.push(chunk);
var body = Buffer.concat(chunks).toString('utf8');
console.log(req.path, body);
oldEnd.apply(res, arguments);
};
next();
}
app.use(logResponseBody);
Ответ 2
Я столкнулся с проблемой, используя подход, предложенный Лораном. Иногда chunk является строкой и поэтому вызывает проблемы при вызове Buffer.concat(). В любом случае, я обнаружил незначительные изменения фиксированных вещей:
function logResponseBody(req, res, next) {
var oldWrite = res.write,
oldEnd = res.end;
var chunks = [];
res.write = function (chunk) {
chunks.push(new Buffer(chunk));
oldWrite.apply(res, arguments);
};
res.end = function (chunk) {
if (chunk)
chunks.push(new Buffer(chunk));
var body = Buffer.concat(chunks).toString('utf8');
console.log(req.path, body);
oldEnd.apply(res, arguments);
};
next();
}
app.use(logResponseBody);
Ответ 3
Вы можете использовать express-winston и настроить с помощью:
expressWinston.requestWhitelist.push('body');
expressWinston.responseWhitelist.push('body');
Пример в coffeescript:
expressWinston.requestWhitelist.push('body')
expressWinston.responseWhitelist.push('body')
app.use(expressWinston.logger({
transports: [
new winston.transports.Console({
json: true,
colorize: true
})
],
meta: true, // optional: control whether you want to log the meta data about the request (default to true)
msg: "HTTP {{req.method}} {{req.url}}", // optional: customize the default logging message. E.g. "{{res.statusCode}} {{req.method}} {{res.responseTime}}ms {{req.url}}"
expressFormat: true, // Use the default Express/morgan request formatting, with the same colors. Enabling this will override any msg and colorStatus if true. Will only output colors on transports with colorize set to true
colorStatus: true, // Color the status code, using the Express/morgan color palette (default green, 3XX cyan, 4XX yellow, 5XX red). Will not be recognized if expressFormat is true
ignoreRoute: function (req, res) { return false; } // optional: allows to skip some log messages based on request and/or response
}));
Ответ 4
Приведенный выше код имеет проблемы с ES6. Используйте код ниже
function logReqRes(req, res, next) {
const oldWrite = res.write;
const oldEnd = res.end;
const chunks = [];
res.write = (...restArgs) => {
chunks.push(Buffer.from(restArgs[0]));
oldWrite.apply(res, restArgs);
};
res.end = (...restArgs) => {
if (restArgs[0]) {
chunks.push(Buffer.from(restArgs[0]));
}
const body = Buffer.concat(chunks).toString('utf8');
console.log({
time: new Date().toUTCString(),
fromIP: req.headers['x-forwarded-for'] ||
req.connection.remoteAddress,
method: req.method,
originalUri: req.originalUrl,
uri: req.url,
requestData: req.body,
responseData: body,
referer: req.headers.referer || '',
ua: req.headers['user-agent']
});
// console.log(body);
oldEnd.apply(res, restArgs);
};
next();
}
module.exports = logReqRes;
Ответ 5
Я на самом деле сделал этот отличный маленький NPM, чтобы решить эту проблему, надеюсь, вам понравится!
https://www.npmjs.com/package/morgan-body
![morgan-body in action!]()
Ответ 6
Я нашел, что простейшим решением этой проблемы было добавление свойства body
к объекту res при отправке ответа, к которому позже может обращаться регистратор. Я добавляю это в свое собственное пространство имен, которое я поддерживаю на объектах req и res, чтобы избежать коллизий имен. например
res[MY_NAMESPACE].body = ...
У меня есть метод утилиты, который форматирует все ответы на мой стандартизованный ответ API/JSON, поэтому добавление этого одного лайнера показывало тело ответа, когда ведение журнала запускается с помощью onFinished
события res.
Ответ 7
Возможно, это поможет кому-то, кто хочет зарегистрировать ответ. Итак, мы используем промежуточное программное обеспечение для перехвата запроса непосредственно перед его передачей клиенту. Затем, если мы используем метод res.send для отправки данных, переопределите метод в промежуточном программном обеспечении и убедитесь, что консоль регистрирует тело. Если вы планируете использовать только res.send, то это должно работать нормально, но если вы используете res.end или res.sendFile, то перезапишите эти методы и регистрируйте только требуемые вещи (очевидно, что запись всего потока октетов файла никогда не должна быть зарегистрирован для целей исполнения.
Здесь я использую pino в качестве регистратора. Создано как синглтон-сервис.
//LoggingResponseRouter.js
var loggingResponseRouter = require('express').Router();
var loggingService = require('./../service/loggingService');
var appMethodInstance = require('./../constants/appMethod');
var path = require('path');
var fs = require('fs');
var timeZone = require('moment-timezone');
var pino = require('pino')();
loggingResponseRouter.use((req, res, next) => {
// set the fileName it needs to log
appMethodInstance.setFileName(__filename.substring(__filename.lastIndexOf(path.sep) + 1, __filename.length - 3));
//loggingService.debugAndInfolog().info('logging response body', appMethodInstance.getFileName());
let send = res.send;
res.send = function(body){
loggingService.debugAndInfolog().info('Response body before sending: ', body);
send.call(this, body);
}
next();
});
module.exports = loggingResponseRouter;
Основной файл - Main.js
const corsRouter = require('./app/modules/shared/router/corsRouter');
const logRequestRouter = require('./app/modules/shared/router/loggingRequestRouter');
const loggingResponseRouter = require('./app/modules/shared/router/loggingResponseRouter');
const express = require('express');
var path = require('path');
const app = express();
// define bodyparser middleware
const bodyParser = require('body-parser');
const port = process.env.PORT || 3000;
// Now use the middleware prior to any others
app.use(bodyParser.json());
// use this to read url form encoded values as wwell
app.use(bodyParser.urlencoded({extended:true}));
console.log('before calling cors router in main js');
app.use(corsRouter);
app.use(logRequestRouter);
app.use(loggingResponseRouter);
app.get('/api', (req, res) => {
console.log('inside api call');
res.send('aapi');
});
app.listen(port, () => {
console.log('starting the server');
});
И это loggingService - loggingService.js
var pino = require('pino');
var os = require('os');
var appMethodInstance = require('./../constants/appMethod');
var pinoPretty = require('pino-pretty');
var moment = require('moment');
var timeZone = require('moment-timezone');
class Logger{
constructor(){
this.appName = 'Feedback-backend';
this.filenameval = '';
}
getFileName(){
console.log('inside get filename');
console.log(appMethodInstance.getFileName());
if(appMethodInstance.getFileName() === null || appMethodInstance.getFileName() === undefined){
this.filenameval = 'bootstrapping...'
}else {
this.filenameval = appMethodInstance.getFileName();
}
console.log('end');
return this.filenameval;
}
debugAndInfolog(){
return pino({
name: 'feedback-backend',
base: {
pid: process.pid,
fileName: this.getFileName(),
moduleName: 'modulename',
timestamp: timeZone().tz('America/New_York').format('YYYY-MM-DD HH:mm:ss.ms'),
hostName: os.hostname()
},
level: 'info',
timestamp: timeZone().tz('America/New_York').format('YYYY-MM-DD HH:mm:ss.ms'),
messageKey: 'logMessage',
prettyPrint: {
messageKey: 'logMessage'
}
});
}
errorAndFatalLog(){
return pino({
name: 'feedback-backend',
base: {
pid: process.pid,
fileName: this.getFileName(),
moduleName: 'modulename',
timestamp: timeZone().tz('America/New_York').format('YYYY-MM-DD HH:mm:ss.ms'),
hostName: os.hostname()
},
level: 'error',
timestamp: timeZone().tz('America/New_York').format('YYYY-MM-DD HH:mm:ss.ms'),
prettyPrint: {
messageKey: 'FeedbackApp'
}
});
}
}
module.exports = new Logger();