У меня есть приложение Node.js, которое работает в контейнере Docker в Google Kubernetes Engine. Я установил класс ведения журнала, который использует 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_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);
}
}