这是针对更通用的用例对对象(JSON/数组/其他)的不同处理的提议。
简而言之,这个提议包括两件事。
各种用户(例如#1377、#1381、我自己)已经注意到,V3 中对象/数组的处理与 V2 不同。 在 V2 中,这些对象类型将存储在options.meta
字段中,并且可以与消息、级别和对象分开处理。
在 V3 中,只有一个场景/转换,其中 options.meta 的处理方式与 V2 中相同。 这是在使用 logform.splat 转换时。 仅当日志中存在令牌时,Splat 才会正确解析元数据。 例如:
logger.log('info', 'this is a string I want to splat %s', 'together', {an: 'object'})
将导致:
info: this is a string I want to splat together {"meta":{"an":"object"}} // with .simple() transform
如果用户不想使用 logform.splat,则不会处理 info.meta。 相反,元对象将在 info[SPLAT] 中保持不变。
添加一个将所有 info[SPLAT] 复制到 info[meta] 的 logform 将既满足 V2 用户的期望,又更加灵活。 (或者,直接将 info[SPLAT] 添加到记录器输出并提供有关 info[meta] => info[SPLAT] 的文档是可以接受的。)
一个新的转换(例如 logform.captureAllMeta 只是为了命名)可能很简单:
// file captureAllMeta.js psuedo-code
module.exports = transform((info, opts) => {
if (info[SPLAT]) {
info.meta = info[SPLAT]
return info;
});
相当于
format.combine(
format.splat(),
...
)
会成为
format.combine(
format.splat(),
format.captureAllMeta(),
...
// still need to have a formatter for options.meta. maybe a separate feature request.
)
extraSplat代码可以从 splat() 中删除,因为它在后续(新)转换中处理。
一个额外的好处是,如果用户不想使用 format.splat(),他们仍然可以将 format.captureAllMeta() 作为独立的转换包含在内。
现在知道 info[SPLAT] 存储了 info[meta] 中缺少的内容,这可以被认为是知识/文档差距。
扩展 V2 到 V3 的兼容性。
是的,我可以尽我所能来支持这一点。
winston
版本?_winston@2
winston@3
node -v
输出:_ 6.10.0这是带有输出的 V2 传输代码示例:
logger = winston.createLogger({
transports: [
new (winston.transports.Console)({
timestamp: function () {
return dateFormat(Date.now(), "HH:MM:ss.l");
},
formatter: function (options) {
// Return string will be passed to logger.
return options.timestamp() + ' ' + winston.config.colorize(options.level, options.level.toUpperCase()) + ' ' + (undefined !== options.message ? options.message : '') +
(options.meta && Object.keys(options.meta).length ? '\n\t' + JSON.stringify(options.meta) : '');
},
colorize: true,
level: container.settings.get('logLevel') || 'info',
stderrLevels: [],
handleExceptions: true,
humanReadableUnhandledException: true
})
]
});
// results of Winston<strong i="33">@2</strong>
08:31:30.363 DEBUG Server starting complete.
["Server https started.","Server http started.","Server SSDP started.","Server MDNS started."]
在 V3 中,我尝试使用以下代码复制它,但结果没有显示数组。
const processObj = logform.format(info => {
console.log('raw: ', raw)
return info
}
)
const myFormat = printf(info => {
info.timestamp = dateFormat(Date.now(), "m/d/yy HH:MM:ss.l")
return `${info.timestamp} ${info.level}: ${info.message}`;
});
logger = createLogger({
level: container.settings.get('logLevel') || 'info',
format: combine(
processObj(),
format.json(),
timestamp({format: () => new Date().toLocaleString()}),
format.colorize(),
format.align(),
format.splat(),
myFormat
),
transports: [new transports.Console()]
});
logger.exceptions.handle()
logger.exitOnError = false;
results = [ 'Not starting https server.', 'Server http started.', 'Server SSDP started.', 'Server MDNS started.']
logger.debug('Server status', results)
// results of winston<strong i="6">@3</strong> -- missing the results array
6/25/18 08:16:30.501 debug: Server starting complete.
我昨晚做了这个工作,并创建了一个带有实现上述代码的分支。 如果您希望我为此在 Logform 中创建 PR,请告诉我。
这是我使用的测试文件...
'use strict';
const winston = require('winston');
const logform = require('logform')
const {SPLAT} = require('triple-beam');
const {createLogger, format, transports} = require('winston');
var logger = createLogger({
format: format.combine(
format.splat()
, format.captureAllMeta()
,
logform.format.printf(info => {
// return `${info.timestamp} [${info.label}] ${info.level}: ${info.message}`;
if ((!info.meta.length)) {
return (`${info.level}: ${info.message}`);
}
else {
return (`${info.level}: ${info.message}\n\t${JSON.stringify(info.meta)}`);
}
})
),
transports: [new transports.Console()]
});
let count = 1
logger.log('info', count + '. this is a string I want to splat %s', 'together', {an: 'object'})
count += 1
console.log('---')
logger.log('info', count + '.this is a string followed by an object and an array', {an: 'object'}, ['an', 'array'])
count += 1
console.log('---')
logger.log('info', count + '.this is a string followed by an object and an array', ['an', 'array'], {an: 'object'})
count += 1
console.log('---')
logger.log('info', count + '. string followed by', 'a string')
console.log('---')
count += 1
logger.log('info', count + '. string followed by 2', 'separate', 'strings')
console.log('---')
count += 1
logger.log('info', count + '. string followed by', {an: 'object'})
console.log('---')
count += 1
logger.log('info', count + '. string followed by 2', {an: 'object'}, ['an', 'array'])
console.log('---')
count += 1
logger.log('info', count + '. string with token followed by string %s', 'string')
console.log('---')
count += 1
logger.log('info', count + '. string with token followed by obj %j', {idunno: 'notsure'})
console.log('---')
count += 1
logger.log('info', count + '. string with token followed by string %s and then objects', 'or here', {an: 'object'}, ['i', 'am', 'missed'])
console.log('---')
count += 1
logger.log('info', count + '. string with two tokens %s %s followed by one ', 'string')
console.log('---')
count += 1
logger.log('info', count + '. string with two tokens %s %j followed by one string and one object', 'string', {an: 'object'}, [1,2,3])
count += 1
console.log('---')
logger.info({message: 'just an object', [SPLAT]: {more:'stuff'}})
count += 1
console.log('---')
logger.info(['an','array'])
count += 1
console.log('---')
logger.info(['an','array',{with:'object'}])
count += 1
console.log('---')
logger.log({
level: 'info',
message: '%d: The answer to life, the universe and everything',
splat: [42]
})
count += 1
console.log('---')
logger.log({
level: 'info',
message: '%d: The answer to life, the universe and everything',
splat: [43],
[Symbol.for('splat')]: [44]
})
count += 1
console.log('---')
logger.log({
level: 'info',
message: '%d: The answer to life, the universe and everything'
})
count += 1
console.log('---')
具有以下输出...
info: 1. this is a string I want to splat together
[{"an":"object"}]
---
info: 2.this is a string followed by an object and an array
[{"an":"object"},["an","array"]]
---
info: 3.this is a string followed by an object and an array
[["an","array"],{"an":"object"}]
---
info: 4. string followed by
["a string"]
---
info: 5. string followed by 2
["separate","strings"]
---
info: 6. string followed by
[{"an":"object"}]
---
info: 7. string followed by 2
[{"an":"object"},["an","array"]]
---
info: 8. string with token followed by string string
---
info: 9. string with token followed by obj {"idunno":"notsure"}
---
info: 10. string with token followed by string or here and then objects
[{"an":"object"},["i","am","missed"]]
---
info: 11. string with two tokens string %s followed by one
---
info: 12. string with two tokens string {"an":"object"} followed by one string and one object
[[1,2,3]]
---
info: just an object
[{"more":"stuff"}]
---
info: an,array
---
info: an,array,[object Object] // expected... no %j token
---
info: 42: The answer to life, the universe and everything
---
info: 44: The answer to life, the universe and everything
---
info: %d: The answer to life, the universe and everything
---
除了 info[SPLAT] 之外,还为我的 info.splat 代码添加了支持。
需要这样的东西。 基本上,如果您不能在不触及现有日志语句的情况下升级到 v3,并且能够在插值后将元数据作为单独的对象获取,那么对于大多数现有用户来说,v3 是不适合的。 我不知道为什么有人认为将关卡、消息和元数据混合到一个大对象中是个好主意。 冲突的时机已经成熟。 info[Symbol.for('splat)] 也不可靠,因为它将插值值和元数据混合在一起。 我们想要元分离。
所以我刚刚意识到使用 format.splat() 确实会在信息中添加一个元对象,但前提是你还使用了插值。 如果您不使用插值,则元数据只是混合到 info 对象中。
此外,当使用插值和元时,format.simple() 将元输出为 {meta:{METAOBJ}} 而不是像 v2 那样仅 {METAOBJ}。
最有用的评论
所以我刚刚意识到使用 format.splat() 确实会在信息中添加一个元对象,但前提是你还使用了插值。 如果您不使用插值,则元数据只是混合到 info 对象中。
此外,当使用插值和元时,format.simple() 将元输出为 {meta:{METAOBJ}} 而不是像 v2 那样仅 {METAOBJ}。