App Engine Node.js:如何 link 应用程序日志和请求日志

App Engine Node.js: how to link app logs and requests logs

我在 App Engine Standard 和 Flexible 上使用 Node.js。

在日志查看器中,是否可以显示嵌套在请求日志中的应用程序日志?

是的,可以关联应用程序日志和请求日志。这是日志查看器中的最终结果:

要实现此目的,您可以:

同时使用 @google-cloud/trace-agent and @google-cloud/logging-bunyan modules in your application. When you do so, your logs are automatically annotated with the correct Trace ID (see docs for Bunyan).

从请求中提取跟踪 ID header 如果不想使用Trace模块,可以从请求header中提取trace ID,使用下面的代码提取traceId

const traceHeader = req && req.headers ? req.headers['x-cloud-trace-context'] || '' : '';
const traceId = traceHeader ? traceHeader.split('/')[0] : '';

然后,您需要填充日志条目的 trace 属性。使用 Bunyan 记录器时,使用以下代码:

logger.info({
  'logging.googleapis.com/trace': `projects/${project}/traces/${traceId}`
}, 'your message');

我以前也遇到过同样的问题,并采取了一些解决方法来解决这个问题。但是在上述解决方案中,在某些您不需要 res 对象引用的用例中可能无济于事。

这里是解决方案。它会将请求日志下的所有日志分组。

也创建了 -> NPM Module

文件名:相关-logs.js

import bunyan from 'bunyan';
import { LOGGING_TRACE_KEY } from '@google-cloud/logging-bunyan';
import cls from 'cls-hooked';
import uuid from 'uuid/v1';

/**
 * CreateLogger will return loggerContextMiddleware and log.
 * Bind the loggerContextMiddleware on top to corelate other middleware logs. `app.use(loggerContextMiddleware);`
 * then you can log like this anywhere `log.info('This is helpful to see corelated logs in nodejs.)` and it will show with-in reqeust log.
 * @param {*} options
 */
export default function createLogger(projectId, bunyanLoggerOptions) {
  if (!projectId || !bunyanLoggerOptions) throw new Error('Please pass the required fields projectId and bunyanLoggerOption');

  const ns = cls.createNamespace(`logger/${uuid()}`); // To create unique namespace.
  const logger = bunyan.createLogger(bunyanLoggerOptions);

  /**
     * Express Middleware to add request context to logger for corelating the logs in GCP.
     * @param {*} req
     * @param {*} res
     * @param {*} next
     */
  const loggerContextMiddleware = (req, res, next) => {
    const traceHeader = (req && req.headers && req.headers['x-cloud-trace-context']) || '';
    if (traceHeader) {
      ns.bindEmitter(req);
      ns.bindEmitter(res);

      const traceId = traceHeader ? traceHeader.split('/')[0] : '';

      const trace = `projects/${projectId}/traces/${traceId}`;

      ns.run(() => {
        ns.set('trace', trace);
        next();
      });
    } else {
      next();
    }
  };

  /**
     * Helper method to get the trace id from CLS hook.
     */
  function getTrace() {
    if (ns && ns.active) return ns.get('trace');
    return '';
  }

  /**
     * Simple wrapper to avoid pushing dev logs to cloud.
     * @param {*} level
     * @param {*} msg
     */
  function printLog(level, ...msg) {
    const trace = getTrace();
    if (trace) { logger[level]({ [LOGGING_TRACE_KEY]: trace }, ...msg); } else { logger[level](...msg); }
  }

  /**
     * Little wrapper to abstract the log level.
     */
  const log = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'].reduce((prev, curr) => ({ [curr]: (...msg) => printLog(curr, ...msg), ...prev }), {});

  return { loggerContextMiddleware, log };
}

文件名:logger.js

import { LoggingBunyan } from '@google-cloud/logging-bunyan';
import createLogger from '../lib/corelate-logs';
import { getProjectId, ifDev } from './config';

// Creates a Bunyan Stackdriver Logging client
const loggingBunyan = new LoggingBunyan();

let loggerOption;

if (ifDev()) {
  const bunyanDebugStream = require('bunyan-debug-stream'); // eslint-disable-line
  loggerOption = {
    name: 'my-service',
    streams: [{
      level: 'info',
      type: 'raw',
      stream: bunyanDebugStream({
        forceColor: true,
      }),
    }],
    serializers: bunyanDebugStream.serializers,
  };
} else {
  loggerOption = {
    name: 'my-service',
    level: 'info',
    streams: [loggingBunyan.stream('info')],
  };
}


const { loggerContextMiddleware, log } = createLogger(getProjectId() || 'dev', loggerOption);

export { loggerContextMiddleware, log };

希望这对某人有所帮助。