我有一个运行在Google Kubernetes Engine的Docker容器中的Node.js应用程序。我已经建立了一个日志类,它使用Winston
(v3.2.1)定义了两个传输;一个登录到控制台,另一个登录到@google-cloud/logging-winston
Stackdriver (使用(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_ENV
为development
,则使用控制台记录器,否则使用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中对我来说正常工作。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句