Esta é uma proposta de manipulação diferenciada de objetos (JSON/array/other) para casos de uso mais versáteis.
Em suma, esta proposta abrange duas coisas.
Vários usuários (por exemplo, #1377, #1381, eu mesmo) notaram que o tratamento de objetos/matrizes é diferente em V3 de V2. Na V2 esses tipos de objetos seriam armazenados no campo options.meta
e poderiam ser processados separadamente da mensagem, nível e objetos.
Na V3, há apenas um cenário/transformação em que options.meta é processado da mesma forma que na V2. Isso ocorre ao usar a transformação logform.splat. O Splat analisará corretamente o meta somente quando um token estiver presente no log. POR EXEMPLO:
logger.log('info', 'this is a string I want to splat %s', 'together', {an: 'object'})
vai resultar em:
info: this is a string I want to splat together {"meta":{"an":"object"}} // with .simple() transform
Se os usuários não quiserem usar o logform.splat, o info.meta não será processado. Em vez disso, os objetos meta serão deixados intocados em info[SPLAT].
Adicionar um formulário de log que copia todas as informações[SPLAT] para info[meta] atenderá às expectativas dos usuários da V2 e será mais flexível. (Como alternativa, adicionar diretamente o info[SPLAT] à saída do registrador e fornecer documentação sobre info[meta] => info[SPLAT] pode ser aceitável.)
Uma nova transformação (por exemplo, logform.captureAllMeta apenas para nomear) pode ser tão simples quanto:
// file captureAllMeta.js psuedo-code
module.exports = transform((info, opts) => {
if (info[SPLAT]) {
info.meta = info[SPLAT]
return info;
});
O equivalente de
format.combine(
format.splat(),
...
)
se tornaria
format.combine(
format.splat(),
format.captureAllMeta(),
...
// still need to have a formatter for options.meta. maybe a separate feature request.
)
O código extraSplat pode ser removido de splat(), pois é tratado na transformação subsequente (nova).
Um benefício adicional é que, se os usuários não quiserem usar format.splat(), eles ainda poderão incluir format.captureAllMeta() como uma transformação independente.
Agora sabendo que info[SPLAT] armazena o que está faltando em info[meta], isso pode ser considerado uma lacuna de conhecimento/documentação.
Estende a compatibilidade V2 para V3.
Sim, eu posso fazer o meu melhor para apoiar isso.
winston
versão?_winston@2
winston@3
node -v
saídas:_ 6.10.0Aqui está uma amostra de um código de transporte V2 com saída:
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."]
Na V3, tentei replicar isso com o código a seguir, mas o resultado não exibiu o array.
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.
Eu trabalhei nisso ontem à noite e criei uma ramificação com código que implementa o acima. Deixe-me saber se você quer que eu crie um PR no Logform para isso.
Aqui está um arquivo de teste que eu usei ...
'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('---')
com as seguintes saídas...
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
---
Adicionado suporte ao meu código para info.splat além de info[SPLAT].
Algo assim é necessário. Basicamente, se você não puder atualizar para a v3 sem tocar nas instruções de log existentes E conseguir obter meta como um objeto SEPARADO APÓS a interpolação, a v3 não é inicial para a maioria dos usuários existentes. Não tenho ideia de por que alguém pensou que era uma boa ideia misturar nível, mensagem e meta em um grande objeto. Está maduro para conflitos. info[Symbol.for('splat)] também não é confiável porque irá misturar valores de interpolação e meta juntos. Queremos meta SEPARADO.
Então, acabei de perceber que usar format.splat() adiciona um objeto meta às informações, MAS apenas se você também usar interpolação. Se você não usar interpolação, o meta será apenas misturado ao objeto info.
Além disso, ao usar interpolação e meta, o format.simple() gera a meta como {meta:{METAOBJ}} em vez de apenas {METAOBJ} como v2.
Comentários muito úteis
Então, acabei de perceber que usar format.splat() adiciona um objeto meta às informações, MAS apenas se você também usar interpolação. Se você não usar interpolação, o meta será apenas misturado ao objeto info.
Além disso, ao usar interpolação e meta, o format.simple() gera a meta como {meta:{METAOBJ}} em vez de apenas {METAOBJ} como v2.