Это предложение по другой обработке объектов (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].
Добавление формы журнала, которая копирует всю информацию [SPLAT] в информацию [meta], удовлетворит ожидания пользователей версии 2 и будет более гибким. (В качестве альтернативы может быть приемлемо прямое добавление информации [SPLAT] к выходным данным регистратора и предоставление документации по информации [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."]
В версии 3 я попытался воспроизвести это с помощью следующего кода, но в результате массив не отображался.
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.
Я работал над этим прошлой ночью и создал ветку с кодом, реализующим вышеизложенное. Дайте мне знать, если вы хотите, чтобы я создал для этого PR в Logform.
Вот тестовый файл, который я использовал...
'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() добавляет к информации метаобъект, НО только если вы также использовали интерполяцию. Если вы не используете интерполяцию, метаданные просто смешиваются с информационным объектом.
Также при использовании интерполяции и метаданных format.simple() выводит метаданные как {meta:{METAOBJ}}, а не просто {METAOBJ}, как v2.
Самый полезный комментарий
Итак, я только что понял, что использование format.splat() добавляет к информации метаобъект, НО только если вы также использовали интерполяцию. Если вы не используете интерполяцию, метаданные просто смешиваются с информационным объектом.
Также при использовании интерполяции и метаданных format.simple() выводит метаданные как {meta:{METAOBJ}}, а не просто {METAOBJ}, как v2.