Как зарегистрировать запрос и идентификатор транзакции в каждой строке журнала, используя Winston для Node JS?

Я создал службу Node JS REST, используя Express. У каждого запроса, который попадает в этот сервис, есть заголовки, такие как "X-org-ReqId" и "X-org-Tid", которые мне нужны для входа во все строки журнала, которые записываются во время выполнения этого запроса. По сути, мне нужно регистрировать некоторую контекстную информацию в каждой строке журнала, чтобы помочь мне выполнять транзакции / отслеживание запросов через несколько служб.

Я использую Winston Logger, инициализированный так:

var winston = require('winston');
var appLogger = new(winston.Logger)({
  transports: [
    new(winston.transports.Console)({
        level: 'info', //TODO: Should be changed to Error in prod
        colorize: true
    }),
    new(winston.transports.DailyRotateFile)({
        filename: '/var/log/org/my-service.log',
        datePattern: '.yyyy-MM-dd',
        tailable: true,
        // handleExceptions: true,
        json: true,
        logstash: true
    })
  ],
  exitOnError: false
});

appLogger.on('error', function(err) {
  console.error("Logger in error", err);
});

module.exports.logger = function() {
  return appLogger;
};

и в отдельных классах, где бы я ни хотел использовать это, я делаю так:

var logger = require('../config/logger').logger();

myObject.on("error", function (err) {
                logger.error("Error connecting bucket=" + bucketId , err);
});

Это создаст журнал следующим образом:

{"level":"info","message":"Error connecting bucket=2.....","timestamp":"2015-06-10T06:44:48.690Z"}

Winston по умолчанию добавляет метку времени к этому оператору журнала, но я также хочу регистрировать такие вещи, как req.headers['X-org-ReqId'] & req.headers['X-org-Tid'], чтобы я знал, какая транзакция была неудачной и в чем была ошибка.

Я хочу войти, как это:

{"level":"info","message":"Error connecting bucket=2....","timestamp":"2015-06-10T06:44:48.690Z", "tid":"a3e8b380-1caf-11e5-9a21-1697f925ec7b", "reqid":"aad28806-1caf-11e5-9a21-1697f925ec7b"}

В мире Java у нас был NDC, есть ли аналог в мире Node JS?

2 ответа

Я столкнулся с той же проблемой, что и вы. Возможно, это не лучший способ сделать что-то, потому что вы должны распространять объект 'req', но он работает.

Я хочу получить любое улучшение:)

Во-первых, я перезаписываю методы регистрации Winston в моем файле log.js:

// MyLogger definition
function MyLogger() {
    this.__proto__.__proto__.constructor.apply(this, arguments);
}

// Inheritance
MyLogger.prototype.__proto__ = winston.Logger.prototype;

// Overwriting methods
MyLogger.prototype.log = function() {
    var args = [];
    // Copying arguments not to modify them
    for (var i = 0; i < arguments.length; i++) {
        args[i] = arguments[i];
    }

    // Adding information in logs
    var lastArg = args[arguments.length - 1];
    if (typeof lastArg === 'object'
        && lastArg.headers) {
        args[arguments.length - 1] = {
            // Liste des infos ajoutées dans les logs
            requestId: lastArg.headers['x-request-id'] ? lastArg.headers['x-request-id'] : arguments[arguments.length - 1].id,
            host: arguments[arguments.length - 1].headers.host,
            pId: process.pid
        };
    }

    // Calling super
    this.__proto__.__proto__.log.apply(this, args);
}

MyLogger.prototype.error = function() {
    var args = ["error"];
    for (var i = 0; i < arguments.length; i++) {
        args[i + 1] = arguments[i];
    }
    this.__proto__.log.apply(this, args);
}
MyLogger.prototype.warn = function() {
    var args = ["warn"];
    for (var i = 0; i < arguments.length; i++) {
        args[i + 1] = arguments[i];
    }
    this.__proto__.log.apply(this, args);
}
MyLogger.prototype.info = function() {
    var args = ["info"];
    for (var i = 0; i < arguments.length; i++) {
        args[i + 1] = arguments[i];
    }
    this.__proto__.log.apply(this, args);
}
MyLogger.prototype.verbose = function() {
    var args = ["verbose"];
    for (var i = 0; i < arguments.length; i++) {
        args[i + 1] = arguments[i];
    }
    this.__proto__.log.apply(this, args);
}
MyLogger.prototype.debug = function() {
    var args = ["debug"];
    for (var i = 0; i < arguments.length; i++) {
        args[i + 1] = arguments[i];
    }
    this.__proto__.log.apply(this, args);
}
MyLogger.prototype.silly = function() {
    var args = ["silly"];
    for (var i = 0; i < arguments.length; i++) {
        args[i + 1] = arguments[i];
    }
    this.__proto__.log.apply(this, args);
}

var logger = new MyLogger({
    transports: [
        new winston.transports.File({
            level: config.LOG_LEVEL,
            filename: config.LOG_FILE,
            handleExceptions: true,
            json: true,
            maxsize: 5242880, //5MB
            maxFiles: 5,
            colorize: false
        }),
        new winston.transports.Console({
            level: config.LOG_LEVEL,
            handleExceptions: true,
            json: false,
            colorize: true
        })
    ],
     exitOnError: false
});

module.exports                  = logger;

Затем в каждом модуле, который нуждается в регистрации:

var logger          = require("../log.js");

...

logger.debug("My message", req);

Создает журнал в консоли и файл журнала JSON в журнале с каждой информацией, необходимой для отслеживания потока.

Следующим моим шагом было бы не распространять 'req' и получать необходимую информацию из контекста или сеанса.

Надеюсь, что помогло:)

моя двухцентовая идея,

Используйте logFormatter от winston, чтобы добавить дополнительные поля в каждый журнал: -

Один пример ниже:

      const { format} = require("winston");
var reqId = '123123' //function or const request id
const addRequestId = format((info, opts) => {
    if(reqId)
        info.reqId= reqId;
    return info;
});

Затем добавьте приведенную ниже конфигурацию при создании регистратора.

      var config = {
format: format.combine(
  addRequestId(),
  format.timestamp(new Date().toISOString()),
  format.json(),
),
transports: [new transports.Console()],
level: 'debug'
 }
const logger = createLogger(config);
Другие вопросы по тегам