Firebase 功能:在 stackdriver 控制台中使用 winston 进行日志记录
Firebase functions: logging with winston in stackdriver console
我做不到 winston logger to write logs to stackdriver console. I deploy my functions as google firebase functions (using firebase deploy
)。 console
日志记录工作正常,但我们没有在项目中使用这样的工具。
我尝试了什么:
- 使用https://github.com/greglearns/winston-stderr
输出到stderr
- 使用 https://www.npmjs.com/package/@google-cloud/logging-winston(
winston.add(require('@google-cloud/logging-winston')); winston.log('error', 'Winston error!');
并添加项目 ID projectId
/ 服务帐户 JSON 凭据文件 keyFilename
等参数);
- 使用https://github.com/findanyemail/winston-transport-stackdriver-error-reporting。也没有运气。我仍然看不到 stackdriver 中的日志。
请提出建议...我厌倦了实验(每次重新部署都需要时间)
最后我做了什么 - 实现了 custom transport,它实际上在后台调用了 console.log
。这有帮助。
const winston = require('winston');
const util = require('util');
const ClassicConsoleLoggerTransport = winston.transports.CustomLogger = function (options) {
options = options || {};
this.name = 'ClassicConsoleLoggerTransport';
this.level = options.level || 'info';
// Configure your storage backing as you see fit
};
util.inherits(ClassicConsoleLoggerTransport, winston.Transport);
ClassicConsoleLoggerTransport.prototype.log = function (level, msg, meta, callback) {
let args = [msg, '---', meta];
switch (level) {
case 'verbose':
case 'debug':
console.log.apply(null, args);
break;
case 'notice':
case 'info':
console.info.apply(null, args);
break;
case 'warn':
case 'warning':
console.warn.apply(null, args);
break;
case 'error':
case 'crit':
case 'alert':
case 'emerg':
console.error.apply(null, args);
break;
default:
console.log.apply(null, args);
}
callback(null, true);
};
Winston 的默认控制台传输失败,因为它在可用时使用 console._stdout.write
,而 Firebase Functions 不接受。
现在有一个 Google Cloud transport package for Stackdriver 您可以试试。还没有使用过它,如果您使用的是 Winston 3,它需要节点 ^8.11.2
。
node.js 温斯顿设置的文档是 here and here
我在下面添加了完整的 logger.js
设置。
重要的一点是:
const format = winston.format.combine(winston.format.colorize({ all: true }))
const console = new winston.transports.Console({ format: winston.format.combine(format) })
const options = this.#explicitSetup ? { projectId: appConfig.firebase.options.projectId, keyFilename: `${rootDirname}/service-account-file.json` } : {}
const loggingWinston = new LoggingWinston(options)
const transports = emulators ? [console] : [console, loggingWinston]
this.#logger = winston.createLogger({
level: this.#defaultLevel,
transports
})
基本上,如果模拟器是 运行,则使用控制台记录器,否则使用控制台记录器和堆栈驱动程序传输。您可以通过在本地主机上 ping 函数端点(例如,您创建的 /ping 端点)来检查模拟器是否 运行。如果它不存在,那么模拟器就不是 运行 或者这是一个生产环境。还要注意使用显式设置的能力,从而传入 projectId
和 keyFilename
。
可以在此处创建 keyFilename
的 JSON 文件:
https://cloud.google.com/docs/authentication/getting-started
我的完整 logger.js
代码如下:
import winston from 'winston'
import { LoggingWinston } from '@google-cloud/logging-winston'
import { appConfig } from '../app-config.js'
import { rootDirname } from './root-dirname.js'
import { isObjectLike } from 'lodash-es'
// https://cloud.google.com/logging/docs/setup/nodejs
export class Logger {
#logger
#defaultLevel = 'debug'
#explicitSetup = false
constructor() {
this.error = this.error.bind(this)
this.warn = this.warn.bind(this)
this.info = this.info.bind(this)
this.debug = this.debug.bind(this)
this.log = this.log.bind(this)
}
init(emulators) {
//
winston.addColors({
error: 'red',
warn: 'yellow',
info: 'bold cyan',
debug: 'bold green'
})
const format = winston.format.combine(winston.format.colorize({ all: true }))
const console = new winston.transports.Console({ format: winston.format.combine(format) })
const options = this.#explicitSetup ? { projectId: appConfig.firebase.options.projectId, keyFilename: `${rootDirname}/service-account-file.json` } : {}
const loggingWinston = new LoggingWinston(options)
const transports = emulators ? [console] : [console, loggingWinston]
this.#logger = winston.createLogger({
level: this.#defaultLevel,
transports
})
}
error(...args) {
this.#logger.error(this.#argsToString(args))
}
warn(...args) {
this.#logger.warn(this.#argsToString(args))
}
info(...args) {
this.#logger.info(this.#argsToString(args))
}
debug(...args) {
this.#logger.debug(this.#argsToString(args))
}
log(...args) {
this.#logger[this.#defaultLevel](this.#argsToString(args))
}
#argsToString(args) {
return args.map(arg => {
const str = isObjectLike(arg) ? JSON.stringify(arg) : arg.toString()
return str.trim()
}).join(' \u2022\u2022 ')
}
}
const blogger = new Logger()
export const logger = blogger
我做不到 winston logger to write logs to stackdriver console. I deploy my functions as google firebase functions (using firebase deploy
)。 console
日志记录工作正常,但我们没有在项目中使用这样的工具。
我尝试了什么:
- 使用https://github.com/greglearns/winston-stderr 输出到stderr
- 使用 https://www.npmjs.com/package/@google-cloud/logging-winston(
winston.add(require('@google-cloud/logging-winston')); winston.log('error', 'Winston error!');
并添加项目 IDprojectId
/ 服务帐户 JSON 凭据文件keyFilename
等参数); - 使用https://github.com/findanyemail/winston-transport-stackdriver-error-reporting。也没有运气。我仍然看不到 stackdriver 中的日志。
请提出建议...我厌倦了实验(每次重新部署都需要时间)
最后我做了什么 - 实现了 custom transport,它实际上在后台调用了 console.log
。这有帮助。
const winston = require('winston');
const util = require('util');
const ClassicConsoleLoggerTransport = winston.transports.CustomLogger = function (options) {
options = options || {};
this.name = 'ClassicConsoleLoggerTransport';
this.level = options.level || 'info';
// Configure your storage backing as you see fit
};
util.inherits(ClassicConsoleLoggerTransport, winston.Transport);
ClassicConsoleLoggerTransport.prototype.log = function (level, msg, meta, callback) {
let args = [msg, '---', meta];
switch (level) {
case 'verbose':
case 'debug':
console.log.apply(null, args);
break;
case 'notice':
case 'info':
console.info.apply(null, args);
break;
case 'warn':
case 'warning':
console.warn.apply(null, args);
break;
case 'error':
case 'crit':
case 'alert':
case 'emerg':
console.error.apply(null, args);
break;
default:
console.log.apply(null, args);
}
callback(null, true);
};
Winston 的默认控制台传输失败,因为它在可用时使用 console._stdout.write
,而 Firebase Functions 不接受。
现在有一个 Google Cloud transport package for Stackdriver 您可以试试。还没有使用过它,如果您使用的是 Winston 3,它需要节点 ^8.11.2
。
node.js 温斯顿设置的文档是 here and here
我在下面添加了完整的 logger.js
设置。
重要的一点是:
const format = winston.format.combine(winston.format.colorize({ all: true }))
const console = new winston.transports.Console({ format: winston.format.combine(format) })
const options = this.#explicitSetup ? { projectId: appConfig.firebase.options.projectId, keyFilename: `${rootDirname}/service-account-file.json` } : {}
const loggingWinston = new LoggingWinston(options)
const transports = emulators ? [console] : [console, loggingWinston]
this.#logger = winston.createLogger({
level: this.#defaultLevel,
transports
})
基本上,如果模拟器是 运行,则使用控制台记录器,否则使用控制台记录器和堆栈驱动程序传输。您可以通过在本地主机上 ping 函数端点(例如,您创建的 /ping 端点)来检查模拟器是否 运行。如果它不存在,那么模拟器就不是 运行 或者这是一个生产环境。还要注意使用显式设置的能力,从而传入 projectId
和 keyFilename
。
可以在此处创建 keyFilename
的 JSON 文件:
https://cloud.google.com/docs/authentication/getting-started
我的完整 logger.js
代码如下:
import winston from 'winston'
import { LoggingWinston } from '@google-cloud/logging-winston'
import { appConfig } from '../app-config.js'
import { rootDirname } from './root-dirname.js'
import { isObjectLike } from 'lodash-es'
// https://cloud.google.com/logging/docs/setup/nodejs
export class Logger {
#logger
#defaultLevel = 'debug'
#explicitSetup = false
constructor() {
this.error = this.error.bind(this)
this.warn = this.warn.bind(this)
this.info = this.info.bind(this)
this.debug = this.debug.bind(this)
this.log = this.log.bind(this)
}
init(emulators) {
//
winston.addColors({
error: 'red',
warn: 'yellow',
info: 'bold cyan',
debug: 'bold green'
})
const format = winston.format.combine(winston.format.colorize({ all: true }))
const console = new winston.transports.Console({ format: winston.format.combine(format) })
const options = this.#explicitSetup ? { projectId: appConfig.firebase.options.projectId, keyFilename: `${rootDirname}/service-account-file.json` } : {}
const loggingWinston = new LoggingWinston(options)
const transports = emulators ? [console] : [console, loggingWinston]
this.#logger = winston.createLogger({
level: this.#defaultLevel,
transports
})
}
error(...args) {
this.#logger.error(this.#argsToString(args))
}
warn(...args) {
this.#logger.warn(this.#argsToString(args))
}
info(...args) {
this.#logger.info(this.#argsToString(args))
}
debug(...args) {
this.#logger.debug(this.#argsToString(args))
}
log(...args) {
this.#logger[this.#defaultLevel](this.#argsToString(args))
}
#argsToString(args) {
return args.map(arg => {
const str = isObjectLike(arg) ? JSON.stringify(arg) : arg.toString()
return str.trim()
}).join(' \u2022\u2022 ')
}
}
const blogger = new Logger()
export const logger = blogger