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

时间:2018-06-16 07:09:34

标签: node.js google-app-engine google-appengine-node

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

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

2 个答案:

答案 0 :(得分:1)

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

enter image description here

要实现这一目标,您可以:

同时使用应用中的@google-cloud/trace-agent@google-cloud/logging-bunyan模块。执行此操作时,将使用正确的跟踪ID自动注释日志(请参阅docs for Bunyan)。

从请求标题中提取跟踪ID 如果您不想使用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');

答案 1 :(得分:0)

我有时也遇到相同的问题,并做了一些工作来解决。但是在上述解决方案中,如果您不要求,则在某些情况下可能无济于事。

所以这里是解决方案。

文件名:correlate-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 };

希望这对某人有帮助。