如何在从GKE登录到Stackdriver时选择性地设置Winston传输



我有一个Node.js应用程序,它在Google Kubernetes引擎的Docker容器中运行。我已经建立了一个日志类,它使用Winston(v3.2.1(,并定义了两个传输;一个登录到控制台,一个登录Stackdriver(使用@google-cloud/logging-winston(v3.0.0((

定义了这两种传输后,一切都很好,我可以在Stackdriver中看到日志。控制台日志将转到projects/[project-id]/logs/stdout,Stackdriver日志则转到projects/[project-id]/logs/winston_log

然而,我想配置记录器,以便在本地调试时,日志只发送到控制台,在GKE中运行时,日志仅发送到Stackdriver,如下所示:

// Configure console logger
private readonly consoleLogger = new winston.transports.Console({
format: combine(
colorize(),
simple(),
printf(context => {
return `[${context.level}]${context.message}`;
}),
),
});
// Configure Stackdriver logger
private readonly stackdriverLogger = new LoggingWinston({
serviceContext: {
service: this.serviceName,
},
});
// Create Winston logger
private readonly logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: json(),
defaultMeta: {
service: this.serviceName,
},
// This line does not work:
transports: [process.env.NODE_ENV === 'development' ? this.consoleLogger : this.stackdriverLogger],
});

这里的目的是,如果NODE_ENVdevelopment,则使用控制台记录器,否则使用Stackdriver记录器。然而,当我将其部署到GKE时,我在Stackdriver控制台日志中看到以下错误(projects/[project-id]/logs/winston_log中没有任何错误(:

[winston] Attempt to write logs with no transports { // Logged message }

当我使用NODE_ENV=development在我的开发机器上本地运行此代码时,我会在本地控制台中看到日志,如果我设置了NODE_ENV=production,则会在Stackdriver中看到日志。

如果我删除了三元运算符,并定义了两个传输并部署到GKE,我看不到上面的错误,并且日志记录对两个传输都正确:

transports: [this.consoleLogger, this.stackdriverLogger],

有人能帮我正确配置吗?

编辑

添加了上下文的完整Logger.ts文件:

import { LoggerService } from '@nestjs/common';
import * as winston from 'winston';
const { colorize, combine, json, printf, simple } = winston.format;
import { LoggingWinston } from '@google-cloud/logging-winston';
import cls from 'cls-hooked';
import { ConfigManager } from '../config';
import { TraceId } from '../middleware/traceId/constants';
export class Logger implements LoggerService {
private readonly serviceName: string = process.env.SERVICE_NAME;
private readonly consoleLogger = new winston.transports.Console({
format: combine(
colorise(),
simple(),
printf(context => {
return `[${context.level}]${context.message}`;
}),
),
});
private stackdriverLogger = new LoggingWinston({
serviceContext: {
service: this.serviceName,
},
});
private readonly logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: json(),
defaultMeta: {
service: this.serviceName,
},
transports: [process.env.NODE_ENV === 'development' ? this.consoleLogger : this.stackdriverLogger]
});
constructor(private readonly context?: string) {}
public verbose(message: string, context?: string) {
const log = this.buildLog(message, context);
this.logger.verbose(log.message, log.metadata);
}
public debug(message: string, context?: string) {
const log = this.buildLog(message, context);
this.logger.debug(log.message, log.metadata);
}
public log(message: string, context?: string) {
const log = this.buildLog(message, context);
this.logger.info(log.message, log.metadata);
}
public warn(message: string, context?: string) {
const log = this.buildLog(message, context);
this.logger.warn(log.message, log.metadata);
}
public error(message: string, trace?: string, context?: string) {
const log = this.buildLog(message, context, trace);
this.logger.error(log.message, log.metadata);
}
private buildLog(message: string, context?: string, trace?: string) {
const ctx = context || this.context;
const traceId = this.getTraceId();
return {
message: `[${ctx}] ${message}`,
metadata: {
traceId,
source: ctx,
stackTrace: trace,
},
};
}
private getTraceId(): string {
const clsNamespace = cls.getNamespace(TraceId.Namespace);
if (!clsNamespace) {
return null;
}
return clsNamespace.get(TraceId.Key);
}
}

所以问题是@google-cloud/logging-winston包中有一个错误,导致它抛出这个错误:

UnhandledPromiseRejectionWarning: FetchError: request to http://169.254.169.254/computeMetadata/v1/instance failed, reason: connect ECONNREFUSED 169.254.169.254:80

此问题现已在3.0.6版本中得到修复-请参阅https://github.com/googleapis/nodejs-logging-winston/issues/389#issuecomment-593727968.

更新@google-cloud/logging-winston后,Winston日志在Stackdriver中对我来说工作正常。

最新更新