winston format 사용 시, object 출력

백엔드 쪽에서, morgan을 winston으로 교체하는 과정에서 object가 console.log 와는 다른 형태로 출력되는 것을 확인.

여러 웹 사이트를 뒤지다 보니, JSON.stringify() 를 사용하면 된다고도 하고, util.format을 사용하면 된다고도 합니다.

둘 모두 적용해 보니, 어떤 것을 사용하던 관계는 없는 것 같은데, 일단 사용 예는 아래의 GIST 코드를 붙여서 올립니다.

다만, object 내의 object는 recursive 하게 변경해주지 않는 것 같은데... 이 부분까진 그닥 필요가 없어서.... -_-;

 

아래의 샘플로그 처럼, 하나의 object를 출력 할 때, 해당 object 문자열의 앞에 매번 포멧팅된 문자열이 나오는 것이 싫으시다면(로그 용량 같은 문제?), 아래와 같이 printf 함수 내용을 수정하시면 됩니다.

// Before
printf(({ level, message, timestamp }) => {
  level = level.toUpperCase()

  return util.format('%o', message).trim().split('\n').map((line) => {
    return `${timestamp} [${level}]: ${line}`
  }).join('\n')
})

// After
printf(({ level, message, timestamp }) => {
  level = level.toUpperCase()
  return `${timestamp} [${level}]: ${util.format('%o', message)}`
})

 

Winston format 에서 object 출력을 위한 코드와 샘플로그 예

2021-07-10T06:54:54.902Z [DEBUG]: {
2021-07-10T06:54:54.902Z [DEBUG]: openapi: '3.0.0',
2021-07-10T06:54:54.902Z [DEBUG]: info: {
2021-07-10T06:54:54.902Z [DEBUG]: title: 'Library API',
2021-07-10T06:54:54.902Z [DEBUG]: version: '1.0.0',
2021-07-10T06:54:54.902Z [DEBUG]: description: 'A Simple Express Library API'
2021-07-10T06:54:54.902Z [DEBUG]: },
2021-07-10T06:54:54.902Z [DEBUG]: servers: [ { url: 'http://localhost:18888' }, [length]: 1 ],
2021-07-10T06:54:54.902Z [DEBUG]: paths: {
2021-07-10T06:54:54.902Z [DEBUG]: '/api/v1/books': {
2021-07-10T06:54:54.902Z [DEBUG]: get: {
2021-07-10T06:54:54.902Z [DEBUG]: summary: 'Returns the list of all the books',
2021-07-10T06:54:54.902Z [DEBUG]: tags: [ 'Books', [length]: 1 ],
2021-07-10T06:54:54.902Z [DEBUG]: responses: { '200': [Object] }
2021-07-10T06:54:54.902Z [DEBUG]: },
2021-07-10T06:54:54.902Z [DEBUG]: post: {
2021-07-10T06:54:54.902Z [DEBUG]: summary: 'Create a new book',
2021-07-10T06:54:54.902Z [DEBUG]: tags: [ 'Books', [length]: 1 ],
2021-07-10T06:54:54.902Z [DEBUG]: requestBody: { required: true, content: [Object] },
2021-07-10T06:54:54.902Z [DEBUG]: responses: { '200': [Object], '404': [Object], '500': [Object] }
2021-07-10T06:54:54.902Z [DEBUG]: }
2021-07-10T06:54:54.902Z [DEBUG]: },
2021-07-10T06:54:54.902Z [DEBUG]: '/api/v1/books/{id}': {
2021-07-10T06:54:54.902Z [DEBUG]: get: {
2021-07-10T06:54:54.902Z [DEBUG]: summary: 'Get the book by id',
2021-07-10T06:54:54.902Z [DEBUG]: tags: [ 'Books', [length]: 1 ],
2021-07-10T06:54:54.902Z [DEBUG]: parameters: [ [Object], [length]: 1 ],
2021-07-10T06:54:54.902Z [DEBUG]: responses: { '200': [Object], '404': [Object] }
2021-07-10T06:54:54.902Z [DEBUG]: },
2021-07-10T06:54:54.902Z [DEBUG]: put: {
2021-07-10T06:54:54.902Z [DEBUG]: summary: 'Get the book by id',
2021-07-10T06:54:54.902Z [DEBUG]: tags: [ 'Books', [length]: 1 ],
2021-07-10T06:54:54.902Z [DEBUG]: parameters: [ [Object], [length]: 1 ],
2021-07-10T06:54:54.902Z [DEBUG]: requestBody: { required: true, content: [Object] },
2021-07-10T06:54:54.902Z [DEBUG]: responses: { '200': [Object], '404': [Object], '500': [Object] }
2021-07-10T06:54:54.902Z [DEBUG]: },
2021-07-10T06:54:54.902Z [DEBUG]: delete: {
2021-07-10T06:54:54.902Z [DEBUG]: summary: 'Remove the book by id',
2021-07-10T06:54:54.902Z [DEBUG]: tags: [ 'Books', [length]: 1 ],
2021-07-10T06:54:54.902Z [DEBUG]: parameters: [ [Object], [length]: 1 ],
2021-07-10T06:54:54.902Z [DEBUG]: responses: { '200': [Object], '404': [Object], '500': [Object] }
2021-07-10T06:54:54.902Z [DEBUG]: }
2021-07-10T06:54:54.902Z [DEBUG]: }
2021-07-10T06:54:54.902Z [DEBUG]: },
2021-07-10T06:54:54.902Z [DEBUG]: components: {
2021-07-10T06:54:54.902Z [DEBUG]: schemas: {
2021-07-10T06:54:54.902Z [DEBUG]: Book: {
2021-07-10T06:54:54.902Z [DEBUG]: type: 'object',
2021-07-10T06:54:54.902Z [DEBUG]: required: [ 'title', 'author', [length]: 2 ],
2021-07-10T06:54:54.902Z [DEBUG]: properties: { id: [Object], title: [Object], author: [Object] },
2021-07-10T06:54:54.902Z [DEBUG]: example: {
2021-07-10T06:54:54.902Z [DEBUG]: id: 'd5fE_asz',
2021-07-10T06:54:54.902Z [DEBUG]: title: 'The New Turing Omnibus',
2021-07-10T06:54:54.902Z [DEBUG]: author: 'Alexander K. Dewdney'
2021-07-10T06:54:54.902Z [DEBUG]: }
2021-07-10T06:54:54.902Z [DEBUG]: }
2021-07-10T06:54:54.902Z [DEBUG]: }
2021-07-10T06:54:54.902Z [DEBUG]: },
2021-07-10T06:54:54.902Z [DEBUG]: tags: [ [length]: 0 ]
2021-07-10T06:54:54.902Z [DEBUG]: }
2021-07-10T06:54:55.139Z [INFO]: 'listening on 18888'
view raw sample.log hosted with ❤ by GitHub
const winston = require('winston')
const util = require('util')
const { combine, timestamp, printf } = winston.format;
const COMMON_OPT = {
handleExceptions: true,
json: false,
format: combine(
timestamp(),
printf(({ level, message, timestamp }) => {
level = level.toUpperCase()
return util.format('%o', message).trim().split('\n').map((line) => {
return `${timestamp} [${level}]: ${line}`
}).join('\n')
})
)
}
let logger = new winston.createLogger({
transports: [
new winston.transports.Console({
...COMMON_OPT,
level: 'debug',
colorize: true,
})
],
exitOnError: false,
})
module.exports = {
logger,
}

Comment