【问题标题】:Passing a unique session ID to Winston logger将唯一的会话 ID 传递给 Winston 记录器
【发布时间】:2021-03-03 12:07:38
【问题描述】:

我试图弄清楚当发出 HTTP 请求时,是否有办法在所有 winston 记录器调用中使用唯一(每个请求)会话 ID。

详细说明:

假设每分钟有数百个请求访问一个网站,每个请求都通过不同的函数来注销各种消息。

我的目标是使用 winston 记录器记录消息,包括每个请求的唯一会话 ID,直到发送响应。

我使用 express-session 库中的 app.use(session(...)) 为请求生成一个唯一的会话 ID。

使用 morgan,HTTP 日志会打印出一个唯一的会话 ID,如下所示:

logger = winston.createLogger(...);

const myStream = {
  write: (text: string) => {
    logger.info(text);
  }
}

morgan.token('sessionid', function (req, res) { return req['sessionID'] });
app.use(morgan(':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"  ["SESSION_ID :sessionid"]', { stream: myStream }));

但是,我还想在代码中其他地方的其他 logger.* 函数中使用相同的会话 ID。我可以这样做,但是随着同时请求的数量(使用 k6 负载测试)增加,会话 ID 会被另一个请求的新会话 ID 覆盖。

我在 winston 传输中使用请求中的会话 ID 的代码是:

public static initializeLogger(appInstance: express.Application) {

        if (!appInstance) throw new Error(`Cannot initialize logger. Invalid express.Application instance passed. Logging may not be available`);
        
        appInstance.use((req, res, next) => {
            //this.m_sessionID = req["sessionID"];
            this.m_logger.clear();
            this.m_logger = winston.createLogger({
                level: LOG_LEVEL,
                levels: winston.config.syslog.levels,
                format: winston.format.json(),
                transports: [
                    new winston.transports.Console({ format: winston.format.simple() }),
                    new winston.transports.File({ filename: 'error.log', level: 'error' }),
                    new winston.transports.File({ filename: 'debug.log', level: 'debug' }),
                    new WinstonCloudWatch({
                        logGroupName: CLOUDWATCH_LOG_GROUP_NAME,
                        logStreamName: function () {
                            let date = new Date().toISOString().split('T')[0];
                            return 'k-server-logs-' + date;
                        },
                        awsRegion: AWS_REGION,
                        awsAccessKeyId: process.env.AWS_ACCESS_KEY_ID,
                        awsSecretKey: process.env.AWS_SECRET_ACCESS_KEY,
                        retentionInDays: process.env.CLOUDWATCH_LOG_RETENTION_DAYS ? Number(process.env.CLOUDWATCH_LOG_RETENTION_DAYS) : 30,
                        messageFormatter: (log) => {
                            return `${JSON.stringify({
                                message: log.message,
                                sessionID: req["sessionID"],
                                level: log.level
                            })}`
                        }
                    })
                ],
            });
            next();
        });
    }

我希望将 winston 记录器放入 app.use(...) 中间件中,以便为 winston 记录器设置 cloudwatch 传输,并在每个请求进入时使用 req.sessionID。

但是,此设置不起作用。如果我同时发送 10 个请求,此代码会中断,并且 sessionID 会错误地标记在记录器上。* 消息和/或在多条消息中重复。

我查看了其他实现,例如 https://solidgeargroup.com/en/express-logging-global-unique-request-identificator-nodejs/,但无法使其正常工作。

希望得到一些建议 - 我确定我的设置已关闭。

提前谢谢你。

【问题讨论】:

    标签: session winston morgan


    【解决方案1】:

    来自https://solidgeargroup.com/en/express-logging-global-unique-request-identificator-nodejs/的关键提示

    使用 express-http-context,它有一个 set 和 get 函数,可以确保唯一的 session ID 在你的代码中可用。

    import httpContext from 'express-http-context';
    ...
    ...
    logger.add(new WinstonCloudWatch({
                    level:LOG_LEVEL,
                    logGroupName: CLOUDWATCH_LOG_GROUP_NAME,
                    logStreamName: function () {
                        let date = new Date().toISOString().split('T')[0];
                        return `${process.env.CLOUDWATCH_LOG_FILE_NAMEPREFIX}-logs-${date}`;
                    },
                    awsRegion: AWS_REGION,
                    awsAccessKeyId: process.env.AWS_ACCESS_KEY_ID,
                    awsSecretKey: process.env.AWS_SECRET_ACCESS_KEY,
                    retentionInDays: process.env.CLOUDWATCH_LOG_RETENTION_DAYS ? Number(process.env.CLOUDWATCH_LOG_RETENTION_DAYS) : 30,
                    messageFormatter: (log) => {
                        return `${JSON.stringify({
                            message: log.message,
                            **sessionID: httpContext.get('reqId')**,
                            level: log.level
                        })}`
                    }
    }));
    

    【讨论】:

      猜你喜欢
      • 2013-03-07
      • 2014-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-17
      • 1970-01-01
      • 2017-10-26
      • 1970-01-01
      相关资源
      最近更新 更多