Winston: [3.0.0] 오류 개체가 구문 분석되거나 인쇄되지 않습니다.

에 만든 2018년 05월 29일  ·  68코멘트  ·  출처: winstonjs/winston

귀하의 환경에 대해 알려주십시오.

  • _ winston 버전? _
  • _ node -v 출력 : _ v8.11.1
  • _ 운영 체제? _ (Windows, macOS 또는 Linux) macOS
  • _Language? _ (모두 | TypeScript XX | ES6 / 7 | ES5 | Dart) 모두

무엇이 문제입니까?

노드 Error 개체를 로깅하면 빈 메시지가 표시됩니다.

예:

const winston = require('winston');
const { createLogger, format, transports } = winston;

const logger = createLogger({
  transports: [
    new transports.Console()
  ]
});

let err = new Error('this is a test');
logger.log({level: 'error', message: err});

결과 출력 :

% node test.js
{"level":"error","message":{}}

또한:

logger.error(new Error('hello'))

결과 :

{"level":"error"}

대신 어떤 일이 일어날 것으로 예상합니까?

메시지 키에 최소한 오류 메시지가 포함되어있을 것으로 예상합니다. 사용자 지정 포맷터를 사용해 보면 info 에도 오류 개체가 없으므로 어딘가에서 제거해야합니까?

기타 정보

어떻게 도와 드릴 수 있는지 알려주세요-PR을 톡톡 치우고 싶지만 [email protected] 주변의 길을 아직 찾지 못합니다.

bug important

가장 유용한 댓글

아니요, 이것은 로깅 라이브러리에 허용되지 않습니다.
유지 관리자는 사용자 정의 printf 형식 및 비 json 형식을 정의하고 logger.error ( "something", err) 및 logger와 같은 오류를 기록 할 수있는 경우에도 오류를 기록하는 방법이 표시된 문서에 잘 강조된 예제를 배치해야합니다. .error (err)
Winston은 훌륭해 보였지만이 문제는 엄청나게 받아 들일 수 없습니다.

모든 68 댓글

이에 대한 테스트 커버리지 가 있지만 분명히 더 필요합니다. 커버 아래에서 진행되는 작업 :

  1. Error 인스턴스가 objectMode 스트림 파이프 체인을 따라 전달됩니다.
  2. 의 기본 형식 Logger 있다 json (참조 : json 형식으로 코드 logform )
  3. messagestack 의 속성 Error 발생하는 비 열거 있습니다 JSON.stringify 하나가 기대하지 않는 출력 무언가를.
console.log(JSON.stringify(new Error('lol nothing here')));
// '{}'

디자인 관점에서 winston@3 는 성능을 높이기 위해 정확히 이런 종류의 문제에 대해 formats 를 도입했습니다. 성능에 대해 말하자면, 흥미롭게도 pino 는 여기서 흥미로운 일을합니다 . 아마도 솔루션은 기본 json 형식으로 asJson 와 유사한 것을 구현하는 것입니다.

누구든지 빠른 해결 방법을 찾고 있다면 지금은 로거 형식에 enumerateErrorFormat 를 포함 할 수 있습니다. 다음 주 3.0.0 이전 (또는 3.0.1 이후)에이 문제를 해결하기를 바랍니다.

const winston = require('../');
const { createLogger, format, transports } = winston;

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

const logger = createLogger({
  format: format.combine(
    enumerateErrorFormat(),
    format.json()
  ),
  transports: [
    new transports.Console()
  ]
});

// Error as message
console.log('Run FIRST test...');
logger.log({ level: 'error', message: new Error('FIRST test error') });

// Error as info (one argument)
console.log('\nRun SECOND test...');
const err = new Error('SECOND test error');
err.level = 'info';
logger.info(err);

// Error as info (two arguments);
console.log('\nRun THIRD test...');
logger.log('info', new Error('THIRD test error'));

@indexzero , 해결 방법을 따르려고했지만 작동하지 않습니다. 이유를 아십니까?

포맷터 :
``` javascript const level = settings.debug ? 'debug' : 'info'; const printFormat = winston.format.printf(info => $ {info.timestamp}-$ {info.level} : $ {info.message}`);
const enumerateErrorFormat = winston.format (info => {
if (info.message instanceof Error) {
info.message = Object.assign ({
메시지 : info.message.message,
스택 : info.message.stack,
}, info.message);
}
if (info instanceof Error) {
return Object.assign ({
메시지 : info.message,
스택 : info.stack,
}, 정보);
}
반환 정보;
});

const consoleLogger = winston.createLogger ({
수평,
형식 : winston.format.timestamp (),
전송 : [
new winston.transports.Console ({
형식 : winston.format.combine (
winston.format.colorize (),
enumerateErrorFormat (),
printFormat,
),
}),
],
});
Code: 자바 스크립트
{
// 오류를 발생시키는 일부 코드
} catch (err) {
logger.error (err);
}
Output:
2018-06-28T21 : 17 : 25.140Z-오류 : 정의되지 않음
Info object: 자바 스크립트
{레벨 : '\ u001b [31merror \ u001b [39m', 타임 스탬프 : '2018-06-28T21 : 17 : 25.140Z', [Symbol (level)] : 'error'}
````
오류 로그에서 메시지 속성은 어디에 있습니까?

@sandrocsimas 작동하려면 로거의 기본 포맷터에 enumerateErrorFormat 함수를 제공해야한다는 것을 알았습니다.

포맷터

const consoleLogger = winston.createLogger({
  level,
  format: winston.format.combine(
    winston.format.timestamp(),
    enumerateErrorFormat()
  ),
  transports: [
    new winston.transports.Console({
      format: winston.format.combine(
        winston.format.colorize(),
        printFormat,
      ),
    }),
  ],
});

난 아직도 왜 그런지 이해가 안 돼

@sandrocsimas와 동일한 버그가 발생하고 있다고 생각합니다.

내 로거 구성은 다음과 같습니다.

logger.js

const winston = require('winston');
const {configure, format} = winston;
const {combine, colorize, timestamp, printf} = format;

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

const myConsoleFormat = printf(info => {
  console.log('** Info Object: **');
  console.log(info);
  console.log('** Winston Output: **');
  return `${info.level}: ${info.message}`;
});

winston.configure({
  transports: [
    new winston.transports.Console({
      format: combine(
        colorize(),
        enumerateErrorFormat(),
        myConsoleFormat
      ),
    })
  ]
});

이 코드 블록으로 테스트하면 :

테스트 A

const logger = require('winston');
try {
  throw(new Error());
} catch (err) {
  logger.error(err);
}

new Error() 에 메시지 값이 포함되지 않은 경우 다음 출력이 표시됩니다.

출력 A

** Info Object: **
{ message: 
   { message: '',
     stack: 'Error\n    at Object.<anonymous> (app.js:21:9)\n    at Module._compile (module.js:652:30)\n    at Object.Module._extensions..js (module.js:663:10)\n    at Module.load (module.js:565:32)\n    at tryModuleLoad (module.js:505:12)\n    at Function.Module._load (module.js:497:3)\n    at Module.require (module.js:596:17)\n    at require (internal/module.js:11:18)\n    at Object.<anonymous> (server.js:11:13)\n    at Module._compile (module.js:652:30)' },
  level: '\u001b[31merror\u001b[39m',
  [Symbol(level)]: 'error',
  [Symbol(message)]: '{"message":{},"level":"error"}' }
** Winston Output: **
error: [object Object]

error: [object Object] 가 정확히 예상했던 것입니다.

그러나이 코드 블록으로 테스트하면 :

테스트 B

const logger = require('winston');
try {
  throw(new Error('This causes error: undefined'));
} catch (err) {
  logger.error(err);
}

new Error() 에 메시지 값이 포함되어있는 경우 다음과 같은 출력이 표시됩니다.

출력 B

** Info Object: **
{ level: '\u001b[31merror\u001b[39m',
  [Symbol(level)]: 'error',
  [Symbol(message)]: '{"level":"error"}' }
** Winston Output: **
error: undefined

보시다시피 @sandrocsimas 가 얻는 것과 동일한 error: undefined 습니다. error: [object Object] 예상했습니다.

이 코드 블록을 시도하면 다음과 같습니다.

테스트 C

const logger = require('winston');
try {
  throw(new Error('This should work'));
} catch (err) {
  logger.log({level: 'error', message: err});
}

어디에서 사용 logger.log 대신 logger.error 내가 출력 A와 동일한 출력 이상을 얻을

나는 같은 문제를 가지고있다. 나는 윈스턴에서 처음입니다. @indexzero 솔루션을 시도했지만 작동하지 않습니다. 해결책이 있습니까?

@ nvtuan305 , @indexzero 의 솔루션을 정확히 시도 logger.log({level: ____, message: err}); logger.info , logger.error , logger.<level> 하는 경우에는 작동하지 않습니다. . 위에서 지정한 버그이며 이후 릴리스에서 수정되어야한다고 거의 확신합니다.

내가 뭔가를 놓치고 있습니까, 아니면 console.log / error / warn에서 쉽게 얻을 수있는 동일한 출력을 얻는 것이 완전히 골치 아픈 일입니까 (또는 불가능합니까?)?

try {
   // ...
  throw new Error('foo');
} catch (e) {
  console.error('Caught error:', e);  // convenient, informative
  logger.error('Caught error:', e);  // nope, the second parameter is something else (couldn't find docs)
  logger.error(`Caught error: ${e}`);  // stack lost
  logger.error(`Caught error: ${JSON.stringify(e)}`);  // Caught error: {}
}

동일한 출력을 얻는 동등한 winston 코드는 무엇입니까?
console.error('Caught error:', error); ?

로거 개체의 편의 메서드에서 가져온 매개 변수에 대한 문서는 어디에 있습니까?

@dandv

logger.error('Caught error:', e);

console.log() 과 달리 winston의 logger.<level>(message) 는 message라는 매개 변수를 하나만 사용하므로 작동하지 않습니다. 해당 메시지 매개 변수는 객체 또는 문자열입니다 (내가 틀렸다면 누군가 나를 정정하지만 그것이 내 이해입니다).

logger.log({level: <level>, message: <message>}) 를 사용할 수도 있습니다. 이 두 기능에 대해 자세히 알아 보려면 문서의이 부분을 읽는 것이 좋습니다. Winston Docs on Log Levels . 로깅 수준 사용 을 읽으십시오.

logger.error(`Caught error: ${e}`);

왜 이것이 스택을 출력하지 않는지 확실하게 말할 수는 없지만 이것이 winston의 문제가 아니라는 것을 압니다. console.log(`Caught error: ${e}`) 를 시도하면 스택도 포함되지 않습니다. 템플릿 리터럴을 많이 사용하지 않았기 때문에 템플릿 리터럴이 개체와 잘 작동하지 않거나 자바 스크립트의 console.log가 개체를 오류 개체로 인식하여 메시지 속성 만 출력합니다. 그게 내 추측이다.

logger.error(`Caught error: ${JSON.stringify(e)}`)

이것은이 버그 스레드가 무엇에 관한 것인지의 핵심입니다. 먼저 자바 스크립트에 대한 기술적 세부 사항을 이해해야합니다. console.log(`Caught error: ${JSON.stringify(e)}`) 시도하면 동일한 출력 Caught error: {} 도 얻을 수 있습니다. @indexzero가 설명했듯이 :

messagestack 의 속성 Error 발생하는 비 열거 있습니다 JSON.stringify 하나가 기대하지 않는 출력 무언가를.

기본적으로 messagestack 속성은 열거 할 수 없기 때문에 message JSON.stringify 는 빈 개체 {} 끝나는 속성을 건너 뜁니다. 열거 가능성을 더 잘 이해하려면이 열거 가능성 및 속성 소유권을 읽는 것이 좋습니다.

다행히도, winston 3.0이 설계된 방식 (winston 팀의 소품) 때문에 @indexzero 가 제공 한 해결 방법이 있습니다. 설명을 도와 드리겠습니다. 먼저이 함수를 만듭니다.

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

문서 Streams, objectMode 및 info 개체 에서 info 개체에는 info.levelinfo.message 두 가지 속성이 있습니다. 즉, info.message 그 당신이 전달 된 모든 인 경우 속성은 오류 개체입니다. 우리는 새로운 객체를 생성 어디 message.stackmessage.message (이라고 생각 Error.stackError.message )는 이제 열거 가능하며 해당 오류 개체에 첨부 될 수있는 다른 속성을 포함합니다.

다음으로 위의 enumerateErrorFormat() 함수를 사용하는이 로거를 만듭니다.

const logger = createLogger({
  format: format.combine(
    enumerateErrorFormat(),
    format.json()
  ),
  transports: [
    new transports.Console()
  ]
});

이것은 당신이 전달하는 message 무엇이든 가져와 그것이 오류 객체인지 확인합니다. 그렇다면 열거 문제가 해결됩니다. 그런 다음 format.json 메시지를 전달하여 모든 개체를 문자열 화합니다 (오류 여부). 객체가 아니라면 문자열이고 format.json effectivley는 아무 작업도 수행하지 않으며 집에 무료입니다!

그래도 오류 개체가 일반적으로 기록되므로 enumerateErrorFormat 를 만들 필요가 없다면 좋을 것입니다. 내가 이해하는대로 winston 팀은 이후 버전에서 릴리스 될 수정 작업을하고 있습니다.

몇 가지 마지막 메모. 메시지가 오류 개체 인 logger.log({level: <level>, message: <message>}) 를 사용하는 경우에만 작동합니다. 예:

try {
  throw(new Error('This should work'));
} catch (err) {
  logger.log({level: 'error', message: err});
}

위의 다른 게시물에서 설명한 것처럼이 코드가 작동하지 않는 winston에는 또 다른 버그가 있습니다.

try {
  throw(new Error('This will not work'));
} catch (err) {
  logger.error(err);
}

어떤 이유로 info.message 속성은 logger.error(err) 사용할 때 정의되지 않습니다. @indexzero 가 이것을 알아낼 수 있기를 바랍니다.

트윗 담아 가기 logger.log({level: 'error', message: err}); 사용해 보았는데 작동합니다.

logger.error 등으로이 문제를 해결할 수 있습니까?

logger.log 를 사용하는 것은 번거롭고 장황합니다. 특히 logger.error 하면 여러 인수를 쉽게 추가 할 수 있기 때문입니다.

안녕하세요, 제가 조사 중입니다. @indexzero : 기본적으로 enumerateErrorFormat 기능을 기본적으로 json 포맷터에 추가하는 것이 가장 좋은 방법이라고 생각하십니까? 우리가 따로 걱정할 필요가 있는가에 대한 경우 meta 입니다 Error 하지 단지 object (나는 우리가 또한 그 사건을 처리하지 않는 경우 사람들이 불평 것 같은데요?) ? 또한 master 하고 있지만 logger.error 위의 @indexzero / @ SamuelMaddox17 의 솔루션으로 나를 위해 작동하는 것처럼 보입니다.

const winston = require('winston');
const format = winston.format;

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

const logger = winston.createLogger({
  level: 'debug',
  format: format.combine(
    enumerateErrorFormat(),
    format.json()
  ),
  transports: [
    new winston.transports.Console(),
  ],
});

logger.error(new Error('whatever'));

추가 조사를 통해 위에서 설명한 logger.error 문제는 기본 로거를 사용할 때만 문제가되는 것 같습니다. @DABH , 나는 당신의 코드를 시험해 보았고 그것은 나를 위해 작동하지만 기본 로거로 전환하면 작동하지 않습니다.

const winston = require('winston');
const format = winston.format;

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

winston.configure({
  transports: [
    new winston.transports.Console({
      level: 'debug',
      format: format.combine(
        enumerateErrorFormat(),
        format.json()
      ),
    })
  ]
});

winston.error(new Error('whatever'));

둘째, json 형식에 enumerateErrorFormat 을 추가해야한다는 데 동의합니다. 그리고 아마도 meta 정도일 것입니다.

마지막으로, @DABH 가 제공 한 코드 예제로 인해 스택이 "예쁘게 인쇄"되지 않습니다. 적어도 macOS High Sierra를 실행하는 내 컴퓨터에서. 이것은 나에게 보이는 것입니다.

{"message":"whatever","stack":"Error: whatever\n    at Object.<anonymous> (/Users/samuelmaddox/Desktop/winston-test/index.js:33:14)\n    at Module._compile (internal/modules/cjs/loader.js:689:30)\n    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)\n    at Module.load (internal/modules/cjs/loader.js:599:32)\n    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)\n    at Function.Module._load (internal/modules/cjs/loader.js:530:3)\n    at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)\n    at startup (internal/bootstrap/node.js:266:19)\n    at bootstrapNodeJSCore (internal/bootstrap/node.js:596:3)","level":"error"}

보시다시피 to JSON 함수로 오류를 출력 할 때 줄 바꿈 문자 \n 는 실제 줄 바꿈을 만들지 않습니다. 이것은 객체를 가져와 JSON으로 변환 할 때 예상되는 동작이지만, 적어도 콘솔에 로깅 할 때는 로거에서 실제로 원하는 동작이 아닐 수 있습니다.

@DABH를 더 찾아 주셔서 감사합니다

참고로 이것은 내가 이것을 조금 가지고 노는 후 얻은 곳입니다.

import winston from 'winston';
const format = winston.format;

const printNice = format.printf(info => {
    const {level, message} = info;
    return `Logging Level: ${level} - Logging Message: ${message}`;
});

const enumerateErrorFormat = format(info => {
    if (info.message instanceof Error) {
        info.message = Object.assign({
            message: `${info.message.message}\n============\n${info.message.stack}`
        }, info.message);
    }

    if (info instanceof Error) {
        return Object.assign({
            message: `${info.message}\n============\n${info.stack}`
        }, info);
    }

    return info;
});

const logger = winston.createLogger({
    format: format.combine(
        enumerateErrorFormat(),
        format.json()
    ),
    transports: [
        new winston.transports.Console({
            format: format.combine(
                format.colorize(),
                printNice,
            ),
        })
    ]
});

export default logger;

문제는이 버그로 인해 발생합니다 : https://github.com/winstonjs/winston-transport/issues/31

우리는 확실히 문제없이 winston2.x에서이 양식을 사용했습니다. winston.err('some message', err);winston.error(err) 위의 enumerateErrorFormatwinston.error(err) 수정하지만 err을 두 번째 매개 변수로 사용하는 사용 사례는 수정하지 않습니다.

안녕하세요.

logger.log ({레벨 : ____, 메시지 : err});

그것은 thx 작동

좋아요, 뭔가 발견했습니다. 9 월 3 일의 내 의견이 잘못되었습니다. 이것은 기본 로거의 문제가 아닙니다. 이것은 level 및 / 또는 format 를 정의하는 곳의 문제입니다. @DABH 는 이전 코드입니다.

const winston = require('winston');
const format = winston.format;

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

const logger = winston.createLogger({
  level: 'debug',
  format: format.combine(
    enumerateErrorFormat(),
    format.json()
  ),
  transports: [
    new winston.transports.Console(),
  ],
});

logger.error(new Error('whatever'));

이것을 제거하는 경우 :

const logger = winston.createLogger({
  level: 'debug',
  format: format.combine(
    enumerateErrorFormat(),
    format.json()
  ),
  transports: [
    new winston.transports.Console(),
  ],
});

그리고 이것을 다음으로 바꿉니다.

const logger = winston.createLogger({
  transports: [
    new winston.transports.Console({
      level: 'debug',
      format: format.combine(
        enumerateErrorFormat(),
        format.json()
      ),
    }),
  ],
});

그러면 info.message === undefined 문제가 나타납니다. 각 전송에 대한 수준과 형식을 지정하는 것이 좋습니다. 그리고 나는 이것이 Winston 2.0에서 허용되었다고 거의 확신합니다.

다음은 쉽게 실행하고 테스트 할 수 있도록 코드를 변경 한 코드 샘플입니다.

const winston = require('winston');
const format = winston.format;

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

const logger = winston.createLogger({
  transports: [
    new winston.transports.Console({
      level: 'debug',
      format: format.combine(
        enumerateErrorFormat(),
        format.json()
      ),
    }),
  ],
});

logger.error(new Error('whatever'));

이것이 문제의 근원을 찾는 데 도움이되기를 바랍니다.

https://github.com/winstonjs/winston/pull/1527을 만들었습니다.

여기에는 모든 옵션이 포함됩니다. 그러나 일부 테스트는 실패하므로 지금은 닫았습니다. 수정 사항이 주어지면 실패 할 것으로 예상되지만 테스트를 수정 / 삭제하라는 전화를 걸 수있는 위치에 있다고 생각하지 않습니다.

실패한 빌드는 여기 https://travis-ci.org/winstonjs/winston/jobs/453012141 이며 테스트 코드를 읽을 때 테스트가 실패하는 이유가 분명합니다.
https://github.com/winstonjs/winston/blob/c42ab7fdc51b88db180a7dd90c52ce04ddd4e054/test/logger.test.js#L668

생각?

문제가이 줄에 있다고 생각합니다
const 정보 = (msg && !(msg instanceof Error) && msg.message && msg) || {
메시지 : msg
};
@crowleym이 지적한대로 instanceof Error 확인을 추가하면 문제가 해결되는 것 같습니다.

여전히 이것을 다루는 사람을 위해 이것은 내가 생각해 낸 해결 방법 포맷터입니다 (내 logger.js 모듈의 스 니펫).

const { format, transports, createLogger }     = require("winston");
const { combine, timestamp, colorize, printf } = format;

function devFormat() {
    const formatMessage = info => `${info.level}: ${info.timestamp} ${info.message}`;
    const formatError   = info => `${info.level}: ${info.timestamp}\n\n${info.stack}\n`;
    const format        = info => info instanceof Error ? formatError(info) : formatMessage(info);

    return combine(timestamp(), printf(format));
}

어떤 이유로 logger.error(new Error("hello"))winston.createLogger 🤔에서 포매터를 전역으로 정의한 다음 포매터에서 info 에 Error 객체를 가져 오는 경우에만 작동합니다.

당신이 전송 당 포맷을 정의하는 경우에 당신은 사용해야 logger.log({level: "error", message: new Error("FAILED")}) 하고를 통해 오류 개체를 처리 info.message 대신 info 오류 개체에 액세스 할 수 있습니다.

전송 옵션에서 형식 필드를 설정할 때 버그가 있다고 생각합니까?

그것들은 나의 2 센트이고 나를 위해 일한 것입니다. 저는 Winston을 처음 접했고 JavaScript에 익숙하지 않으므로 아무 것도 인용하지 마십시오.

내 접근 방식은 근본 원인을 해결하려는 시도였습니다. 그러나 repo 소유자로부터 많은 관심을 얻지 못합니다 ...

네, 이해합니다. 나는 Winston을 처음 사용하고 아마도 그것을 잘못 사용하거나 아직 그이면의 개념을 충분히 이해하지 못했다고 생각했기 때문에 문자 그대로 이것을 알아내는 데 많은 시간을 보냈습니다.

그러나 운 좋게도 나는 다른 것을 보여준 몇 개의 스레드 (이것 포함)를 우연히 발견했습니다. 바라건대 그들은이 문제를 해결하여 해결 방법을 계속 사용할 필요가 없습니다.

이것은에 의해 발생할 수 있습니다 wintson-transport , 참조 https://github.com/winstonjs/winston-transport/issues/31를 문제 및 대한 https://github.com/winstonjs/winston-transport/pull/ PR의 경우

오류 개체의 직접 로깅은 열거 할 수없는 속성 때문에 항상 엉망입니다. 개인적으로 나는 이것을 나쁜 관행이라고 생각하지만, 커뮤니티의 충분한 사람들은 우리가 그것을 지원해야한다는 요구 사항으로 그것에 대해 단호합니다.

이와 같은 동작을 지원하는 형식으로 https://github.com/winstonjs/logform/pull/59 를 채택하는 것을 고려하십시오. 플러스 측면에서는 오류를 로그 메시지로 처리 할 때 매우 일반적인 모든 엣지 케이스를 캡슐화합니다. 단점은 사용자가 선택해야 할 또 다른 형식입니다 ( .splat() 와 유사).

@indexzero 동의하는 경향이 있지만 직접 오류 로깅은 여러 Error 유형을 다르게 표시해야하는 경우 사용자 지정 로깅 형식 / printf와 결합 할 때 유용 할 수 있으며 Winston 2.x에서 시도하는 것을 기억하지 못합니다. 이 관행은 상자에서 벗어난 것처럼 싸워야합니다.

따라서 enumerateErrorFormat에 대해 제안 된 솔루션은 작동하지만 logger.error('some message', err) 형식을 지원하지 않습니다. info.message 또는 info 모두 instanceof Error 이기 때문입니다. 또한이 솔루션의 또 다른 문제를 지적하고 싶습니다. 현재 superagent 에서 반환 된 오류를 기록하고 있습니다.

    try {
      const response = await request
        .get('https://some/endpoint')
        .set('Authorization', bearerToken);
      logger.info('successfully received response');
      return response.body;
    } catch (e) {
      logger.error('An error was caught while getting programs');
      logger.error(e); // <<< THE ERROR LOG  
    }

Object.assign을 사용하면 스택을 식히고 메시지가 설정됩니다! 그러나 오류의 일부였던 다른 정보도 기록됩니다. 오류가 Authorization Headers (이 경우 오류 객체의 일부로 포함됨)와 같은 민감한 데이터가있는 경우 매우 위험 할 수 있습니다.

그러나 당신은 말할 수 있습니다. 이것은 winston의 잘못이 아니며 수퍼 에이전트가이 데이터를 오류에 추가하는 winston의 잘못이 아닙니다. 나는 동의한다! 그러나 모든 것이 info 개체에 평평하게 저장되기 때문에 이전 정보를 유지하고 나머지를 재정의하지 않는 것이 매우 어려워집니다.

logger.error를 사용할 때 거의 좋을 것입니다. 두 번째 매개 변수가 오류라고 가정하고 info 개체에 info.error 로 넣은 다음 다른 방법으로 로깅하면 인터페이스는 { level: "error", error: YOUR ERROR OBJECT}

나는 정말로 여기에서 뱉어 냈지만 새로운 인터페이스는 확실히 약간 실망 스러웠습니다 (정보에 관한 모든 것).

내가 말한 요점을 자세히 설명하기 위해 e가 오류 유형 인 logger.error( e ) 라고 가정합니다.

그런 다음 코드에서 winston을 다음과 같이 구성했습니다.

winston.configure({
    format: combine(
      timestamp(),
      enumerateErrorFormat(),
      ...
    ),
  });

타임 스탬프가 오류 개체에 밀리고 있습니다 😱. 정말 말이 되나요? 당신이 보낸 에러 객체가 동적으로 새로운 prop을 받고 있다는 것을 생각해보십시오. 타임 스탬프.

이 문제에 대한 전반적인 최선의 해결책은 다음 구문을 지원하는 것입니다.

logger.error('An error occurred when doing something important', { error: e } );

그런 다음 내부적으로 오류 필드를 찾는 오류 포맷터를 만들 수 있습니다!

이 사람들에 대한 업데이트 :

다음 이틀 안에이 봉제 및 배송을 희망합니다. [email protected] 트래커의 다음 호입니다.

안녕하세요 여러분 – https://github.com/winstonjs/winston/pull/1562 를 확인 3.2.0 릴리스 체크리스트의 마지막 항목이므로 PR이 꿰매면 릴리스 할 수 있습니다.

수정 사항이 게시 될 때까지 다음 해결 방법을 사용합니다.

logger.error = item => {
  logger.log({ level: 'error', message: item instanceof Error ? item.stack : item });
};

최신 winston (3.2.1)을 사용 중이며 logger.error 오류를 전달할 때 여전히 undefined 됩니다.

@ezze 에는 훌륭한 솔루션이 있었지만 스택 추적은 새 줄로 강제됩니다. 다음은 한 줄로 된 약간 수정 된 버전입니다 (로그 파일의 간단한 grep에 의해 포착 됨).

logger.error = item => {
  const message = item instanceof Error
    ? item.stack.replace('\n', '').replace('    ', ' - trace: ')
    : item;
  logger.log({ level: 'error', message });
};

출력 <Error message> - trace: <stack trace>

최신 winston으로이 작업을 수행하는 더 쉬운 방법이 있다면 @indexzero에 알려주십시오. 나는 도서관에 처음 왔으며 문서를 따르고 있었다.

방금 PR에 게시 한 링크를 봤습니다. logger.error 오류를 전달하려면 메시지 문자열이 필요하고 오류가 발생한다는 의미입니까?

try {
  someThing();
} catch(error) {
  logger.error(error); // what I would like to do
  logger.error('special message', error); // what I believe is required?
}

@ the-vampiire이 스레드가 말한 두 가지 문제가 발생했습니다. 첫 번째는 원래 포스터가 제기 한 문제이고 두 번째는 내가 제기 한 문제인데, 이는 귀하의 문제와 동일합니다. 원래 포스터 문제 만 고친 것 같아요. 나는 더 많은 것을 확인하기 위해 더 확인하고 그 경우에 새로운 문제를 열려고했습니다. 안타깝게도 더 깊이 잠수 할 시간이 없었습니다. 그동안 err 가 오류 개체 인 logger.log({level: 'error', message: err}); 를 사용하면 작동합니다.

여전히이 문제가 발생하고이를 파악하는 데 많은 시간이 걸리지 않았으므로 @ the-vampiire의 솔루션이 잘 작동합니다.

이 티켓은 왜 닫혀 있습니까?

logger.error를 재정의하는 것은 error ()에 단일 인수로 전달되는 Error 객체에 타임 스탬프 속성을 추가하지 않기 때문에 지금까지 최상의 솔루션입니다. 대부분의 사람들은 Error 객체가 변경 불가능하다고 예상합니다. logger.info 및 다른 모든 레벨 관련 메서드도 재정의하지 않으면 예상대로 작동하지 않는 것이 놀랍습니다. 다시 말하지만, 개체 유형에 관계없이 개체를 수정하려는 경우가 아니면 Winston 로거 메서드로 직접 보내지 마십시오.

이 기능은 [email protected] 부터 지원됩니다.

사용 예 :

const winston = require('winston');
const { transports, format } = winston;

const print = format.printf((info) => {
  const log = `${info.level}: ${info.message}`;

  return info.stack
    ? `${log}\n${info.stack}`
    : log;
});

const logger = winston.createLogger({
  level: 'debug',
  format: format.combine(
    format.errors({ stack: true }),
    print,
  ),
  transports: [new transports.Console()],
});

const error = new Error('Ooops');

logger.error(error);
logger.error('An error occurred:', error);

cc @ HRK44 @ the-vampiire

나는 또한 여전히 문제가 있습니다.
logger.error(error); 와 같은 오류를 호출하면 undefined .
logger.error('Something went wrong', error) 처럼 호출하는 경우에만 완전한 오류가 발생하고 구문 분석 할 수 있습니다.

나는 또한 여전히 문제가 있습니다.
logger.error(error); 와 같은 오류를 호출하면 undefined .
logger.error('Something went wrong', error) 처럼 호출하는 경우에만 완전한 오류가 발생하고 구문 분석 할 수 있습니다.
이것을 추가 했습니까?

format.errors({ stack: true })

예, 여전히 같은 문제입니다. 요점으로 재현하려고합니다.

@ OBrown92 오늘도 같은 문제에 직면했습니다. format.errors({ stack: true }) 는 전송이 아닌 로거에 적용되면 작동하는지 확인할 수 있습니다. 이 경우 logger.error(error);logger.error('Something went wrong', error) 있습니다. 그러나 format.errors({ stack: true }) 를 선택한 전송에 적용하려고하면 문제가 있습니다. 이 경우 undefined 대해 logger.error(error); 를 얻지 만 logger.error('Something went wrong', error) 는 제대로 작동합니다.

예상되는 동작인지 버그인지 확실하지 않지만 원인을 찾는 데 많은 시간을 보냈으므로 문제를 해결하거나 문서 어딘가에 언급하십시오. 정말 도움이 될 것입니다.

어쨌든이 훌륭한 프로젝트에 대한 귀하의 작업에 대해 매우 감사합니다.

나는 같은 문제에 직면 하여이 패키지 utils-deep-clone을 작성했습니다 . 확인 해봐.

format.errors is not a function ... 놀랍군요.

뿡뿡
winston 패키지에서 형식을 가져 왔습니까?
사용 예 :
const { format } = require('winston')
또는
const winston = require('winston'); const { format } = winston;

@aybhalala yepp, 오류 스택이없이 printf 전달되는 것은 중요하지 않습니다.

업데이트 : 이것에 여전히 문제가 있기 때문에 나는 한동안 다음을 해왔고 훌륭하게 작동했습니다.

// Grab the default winston logger
const winston = require('winston');

const { format } = winston;
const { combine, timestamp } = format;

// Custom format function that will look for an error object and log out the stack and if 
// its not production, the error itself
const myFormat = format.printf((info) => {
  const { timestamp: tmsmp, level, message, error, ...rest } = info;
  let log = `${tmsmp} - ${level}:\t${message}`;
  // Only if there is an error
  if ( error ) {
    if ( error.stack) log = `${log}\n${error.stack}`;
    if (process.env.NODE_ENV !== 'production') log = `${log}\n${JSON.stringify(error, null, 2)}`;
  }
  // Check if rest is object
  if ( !( Object.keys(rest).length === 0 && rest.constructor === Object ) ) {
    log = `${log}\n${JSON.stringify(rest, null, 2)}`;
  }
  return log;
});

 winston.configure({
    transports: [
      new winston.transports.Console({
        level: 'debug',
        timestamp: true,
        handleExceptions: true
    }),
  ];
    format: combine(
      trace(),
      timestamp(),
      myFormat
    ),
  });


// Finally you log like this
logger.error('An error occurred!!!', { error } );

^^ 예상되는 사용법입니다. 단순한 필사자들은 이것을 결코 알아 내지 못할 것이기 때문에 문서화되어야합니다.

단순한 필사자는 이것을 결코 알아 내지 못할 것이기 때문에 문서화되어야합니다.

😂 그 메이트에게 +1

제 3 자 전송 ( @google-cloud/logging-winston )과 함께 winston을 사용하므로 구문에 대한 제어력이 약간 떨어집니다. 또한 이것이 더 직관적이라고 생각합니다.

const error = new Error('something bad happened');
logger.error('was doing this and', error);

콘솔에 로그인 할 때 스택을 메시지에 연결합니다. 그러나 결과는 다음과 같습니다.

ERROR was doing this andsomething bad happened Error: something bad happened <rest of the stack.>

winston이 meta.message 를 원본 메시지에 연결하기 때문에 이상한 andsomething 와 스택에도 인쇄되는 중복 메시지가 있습니다. 이것은 # 1660에 설명되어 있습니다.

# 1664가이 문제를 해결하려는 것 같습니다. 그 동안 나는 연결을 "실행 취소"하는 포맷터를 작성했습니다. https://github.com/winstonjs/winston/issues/1660#issuecomment -512226578

@dandv

logger.error('Caught error:', e);

console.log() 과 달리 winston의 logger.<level>(message) 는 message라는 매개 변수를 하나만 사용하므로 작동하지 않습니다. 해당 메시지 매개 변수는 객체 또는 문자열입니다 (내가 틀렸다면 누군가 나를 정정하지만 그것이 내 이해입니다).

logger.log({level: <level>, message: <message>}) 를 사용할 수도 있습니다. 이 두 기능에 대해 자세히 알아 보려면 문서의이 부분을 읽는 것이 좋습니다. Winston Docs on Log Levels . 로깅 수준 사용 을 읽으십시오.

logger.error(`Caught error: ${e}`);

왜 이것이 스택을 출력하지 않는지 확실하게 말할 수는 없지만 이것이 winston의 문제가 아니라는 것을 압니다. console.log(`Caught error: ${e}`) 를 시도하면 스택도 포함되지 않습니다. 템플릿 리터럴을 많이 사용하지 않았기 때문에 템플릿 리터럴이 개체와 잘 작동하지 않거나 자바 스크립트의 console.log가 개체를 오류 개체로 인식하여 메시지 속성 만 출력합니다. 그게 내 추측이다.

logger.error(`Caught error: ${JSON.stringify(e)}`)

이것은이 버그 스레드가 무엇에 관한 것인지의 핵심입니다. 먼저 자바 스크립트에 대한 기술적 세부 사항을 이해해야합니다. console.log(`Caught error: ${JSON.stringify(e)}`) 시도하면 동일한 출력 Caught error: {} 도 얻을 수 있습니다. @indexzero가 설명했듯이 :

messagestack 의 속성 Error 발생하는 비 열거 있습니다 JSON.stringify 하나가 기대하지 않는 출력 무언가를.

기본적으로 messagestack 속성은 열거 할 수 없기 때문에 message JSON.stringify 는 빈 개체 {} 끝나는 속성을 건너 뜁니다. 열거 가능성을 더 잘 이해하려면이 열거 가능성 및 속성 소유권을 읽는 것이 좋습니다.

다행히도, winston 3.0이 설계된 방식 (winston 팀의 소품) 때문에 @indexzero 가 제공 한 해결 방법이 있습니다. 설명을 도와 드리겠습니다. 먼저이 함수를 만듭니다.

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

문서 Streams, objectMode 및 info 개체 에서 info 개체에는 info.levelinfo.message 속성이 있습니다. 즉, info.message 그 당신이 전달 된 모든 인 경우 속성은 오류 개체입니다. 우리는 새로운 객체를 생성 어디 message.stackmessage.message (이라고 생각 Error.stackError.message )는 이제 열거 가능하며 해당 오류 개체에 첨부 될 수있는 다른 속성을 포함합니다.

다음으로 위의 enumerateErrorFormat() 함수를 사용하는이 로거를 만듭니다.

const logger = createLogger({
  format: format.combine(
    enumerateErrorFormat(),
    format.json()
  ),
  transports: [
    new transports.Console()
  ]
});

이것은 당신이 전달하는 message 무엇이든 가져와 그것이 오류 객체인지 확인합니다. 그렇다면 열거 문제가 해결됩니다. 그런 다음 format.json 메시지를 전달하여 모든 개체 (오류 여부)를 문자열 화합니다. 객체가 아니라면 문자열이고 format.json effectivley는 아무 작업도 수행하지 않으며 집에 무료입니다!

그래도 오류 개체가 일반적으로 기록되기 때문에 enumerateErrorFormat 를 만들 필요가 없다면 좋을 것입니다. 내가 이해하는대로 winston 팀은 이후 버전에서 릴리스 될 수정 작업을하고 있습니다.

몇 가지 마지막 메모. 메시지가 오류 개체 인 logger.log({level: <level>, message: <message>}) 를 사용하는 경우에만 작동합니다. 예:

try {
  throw(new Error('This should work'));
} catch (err) {
  logger.log({level: 'error', message: err});
}

위의 다른 게시물에서 설명한 것처럼이 코드가 작동하지 않는 winston에는 또 다른 버그가 있습니다.

try {
  throw(new Error('This will not work'));
} catch (err) {
  logger.error(err);
}

어떤 이유로 info.message 속성은 logger.error(err) 사용할 때 정의되지 않습니다. @indexzero 가 이것을 알아낼 수 있기를 바랍니다.

아주 좋은 설명입니다. logger.error( Caught error : $ {e} ); 문자열 리터럴이 자바 스크립트에서 작동하는 방식 때문에 스택이 손실됩니다. `${e}`e.toString() 와 정확히 동일하므로 오류 메시지 만 인쇄하는 것이 예상되는 동작입니다.

이것은 여전히 ​​문제입니까? 여전히 이것에 문제가 있습니다.

const { createLogger, format, transports } = require('winston')

const { combine } = format

const errorFormatter = format((info) => {
  console.log(info)
  return info
})


const consoleTransport = new transports.Console({
  format: combine(errorFormatter()),
})

const logger = createLogger({
  transports: [
    consoleTransport,
  ],
})

try {
  throw new Error('Error message')
} catch(err) {
  logger.error(err) // info doesnt have the error object
  logger.error('', err) // info have the error object
}

이것은 여전히 ​​문제입니까? 여전히 이것에 문제가 있습니다.

const { createLogger, format, transports } = require('winston')

const { combine } = format

const errorFormatter = format((info) => {
  console.log(info)
  return info
})


const consoleTransport = new transports.Console({
  format: combine(errorFormatter()),
})

const logger = createLogger({
  transports: [
    consoleTransport,
  ],
})

try {
  throw new Error('Error message')
} catch(err) {
  logger.error(err) // info doesnt have the error object
  logger.error('', err) // info have the error object
}

여기에 같은 문제 ...

소스 코드를 살펴본 후 어떤 매개 변수가 허용되는지 확인할 수 있습니다.

interface LeveledLogMethod {
(메시지 : 문자열, 콜백 : LogCallback) : Logger;
(메시지 : 문자열, 메타 : 모두, 콜백 : LogCallback) : Logger;
(메시지 : 문자열, ... meta : any []) : Logger;
(infoObject : 개체) : 로거;
}

따라서 오류 객체를 첫 번째 매개 변수로 전달하면 문자열 만 이해하므로 오류 메시지 만 취하고 두 번째 매개 변수에 오류를 전달하면 info.stack에서 스택 추적에 액세스 할 수 있습니다.

btw 나는 문서의 어느 곳에서도 이것을 찾을 수 없었습니다.

두 가지 솔루션을 찾았습니다. 첫 번째 방법은 부모 로거의 logform 에 언급 된 format.errors 사용한 다음 format.printf 를 사용하여 messageFormatter를 만들고 조건부로 다음에서 추출 된 stack 필드를 추가하는 것입니다. info ( format.errors({ stack: true}) 추가됩니다).

내가 선호하는 다른 솔루션은 winston 레벨 로거를 해킹하는 것입니다.

const addArgs = format((info) => {
  const args: any[] = info[Symbol.for('splat')]
  info.args = args ? [...args] : []
  return info
})

const messageFormatter = format.printf(info => {
  const { timestamp: timeString = '', message, args = [] } = info
  const formattedMsgWithArgs = util.formatWithOptions({ colors: true }, message, ...args)
  const msg = `${timeString} - ${info.level}: ${formattedMsgWithArgs}`
  return msg
})

const logger = createLogger({
  format: format.combine(
    addArgs(),
    format.timestamp({ format: 'HH:mm:ss.SSS' })
  ),

  transports: [
    new transports.Console({
      format: format.combine(format.colorize(), messageFormatter),
    }),
  ],
})

const levels = ['debug', 'info', 'error']
levels.forEach((level) => {
  logger[level] = (msg: any, ...remains: any) => {
    if(typeof msg != "string") {
      return logger.log(level, '', msg, ...remains)
    }

    logger.log(level, msg, ...remains)
  }  
})

이 방법으로 console.log 와 유사한 오류 로깅을 얻을 수 있습니다.

_parent_ 로거에 format.errors 이 (가) 있어야하는 방법에 대한 @tiagonapoli 의 의견이

winston.loggers.add("default");
const log = winston.loggers.get("default");
/* get a `transportOptions` object and a `transportType` */
transportOptions.format = logform.format.combine(
  logform.format.errors({ stack: true }),
  logform.format.timestamp(),
  logform.format.printf(myFormatter)
);
log.add(new winston.transports[transportType](transportOptions);

Error 개체의 처리는 마치 문자열 인 것처럼 수행됩니다. 그러나 다음과 같이하면 :

winston.loggers.add("default");
const log = winston.loggers.get("default");
log.format = logform.format.errors({ stack: true });
/* get a `transportOptions` object and a `transportType` */
transportOptions.format = logform.format.combine(
  logform.format.timestamp(),
  logform.format.printf(myFormatter)
);
log.add(new winston.transports[transportType](transportOptions);

Error 개체 처리가 올바르게 작동합니다.

여기에서 버그는 행동에 차이가 없어야한다는 것 같습니다.

그래서 이것은 1 년 후에도 여전히 수정되지 않습니까? 윈스턴 로거 코드를 해킹해야 작동합니까?

예, 이것은 Winston이 상대적으로 간단한 사용 사례보다 훨씬 더 많은 문제처럼 보이기 시작한 충분한 두통을주었습니다. 정말 필요한 것을 제공합니다.

여러분, 정말요? 답답하네요 ...

나는 커미터는 아니지만 이것이 깨지지 않았기 때문에 이것이“고정”되지 않을 것이라고 말하는 것이 맞을 것입니다. Winston은 사용할 가치가 있습니다. 구성하기 만하면됩니다. 저에게 가장 좋은 조언은 위의 https://github.com/winstonjs/winston/issues/1338#issuecomment -506354691입니다.

아직 ?

업데이트 : 이것에 여전히 문제가 있기 때문에 나는 한동안 다음을 해왔고 훌륭하게 작동했습니다.

// Grab the default winston logger
const winston = require('winston');

const { format } = winston;
const { combine, timestamp } = format;

// Custom format function that will look for an error object and log out the stack and if 
// its not production, the error itself
const myFormat = format.printf((info) => {
  const { timestamp: tmsmp, level, message, error, ...rest } = info;
  let log = `${tmsmp} - ${level}:\t${message}`;
  // Only if there is an error
  if ( error ) {
    if ( error.stack) log = `${log}\n${error.stack}`;
    if (process.env.NODE_ENV !== 'production') log = `${log}\n${JSON.stringify(error, null, 2)}`;
  }
  // Check if rest is object
  if ( !( Object.keys(rest).length === 0 && rest.constructor === Object ) ) {
    log = `${log}\n${JSON.stringify(rest, null, 2)}`;
  }
  return log;
});

 winston.configure({
    transports: [
      new winston.transports.Console({
        level: 'debug',
        timestamp: true,
        handleExceptions: true
    }),
  ];
    format: combine(
      trace(),
      timestamp(),
      myFormat
    ),
  });


// Finally you log like this
logger.error('An error occurred!!!', { error } );

흔적은 어디에서 왔습니까?

아니요, 이것은 로깅 라이브러리에 허용되지 않습니다.
유지 관리자는 사용자 정의 printf 형식 및 비 json 형식을 정의하고 logger.error ( "something", err) 및 logger와 같은 오류를 기록 할 수있는 경우에도 오류를 기록하는 방법이 표시된 문서에 잘 강조된 예제를 배치해야합니다. .error (err)
Winston은 훌륭해 보였지만이 문제는 엄청나게 받아 들일 수 없습니다.

이것은 Winston을 사용하여 오류를 기록하는 방법입니다. 독특하지 않으며 위의 많은 친구들도 동일한 개념을 기반으로 한 작업 솔루션을 가지고 있습니다.

배경
저는 @jsdevtools/ono 을 (를) 사용하여 임의의 개체 유형을 사용자 지정 오류로 래핑하고 있지만이 솔루션은 기본 노드 오류 (예 : fs eperm 오류) 및 사용자 지정 오류 클래스에서 여전히 잘 작동하는 것 같습니다.

설명
기본적으로 format.errors({stack:true})format.metadata() 의존합니다. https://github.com/winstonjs/winston/issues/1338#issuecomment -532327143에서 언급했듯이 이것은 부모 포맷터에 있어야합니다.

메타 데이터는 모든 오류 개체의 사용자 지정 속성을 info.metadata 로 이동하는 데 도움이됩니다.

오류 메시지, 스택 추적 및 오류 개체 속성의 세 가지 유형의 정보를 인쇄하고 싶었습니다. 오류 메시지는 이미 일반 텍스트입니다. pretty-error 모듈을 사용하여 info.metadata.stack 스택을 예쁘게 인쇄했습니다. 오류 개체의 속성의 경우 스택 추적이 다시 표시되는 것을 원하지 않았으므로 개체를 복제하고 stacktrace 속성을 삭제했습니다. 그런 다음 winston이 의존하는 동일한 stringify 모듈 인 fast-safe-stringify 사용하여 오류 개체를 예쁘게 인쇄했습니다.

    const lodash = require("lodash");
    const path = require("path");
    const winston = require("winston");
    const { default: stringify } = require("fast-safe-stringify");
    const logDir = "D:/temp/logs";

    // pretty formatting
    const PrettyError = require("pretty-error");
    const pe = new PrettyError();
    pe.withoutColors()
        .appendStyle({
            'pretty-error > trace':
            {
                display: 'inline'
            },
            'pretty-error > trace > item':
            {
                marginBottom: 0,
                bullet: '"*"'
            }
        })
        // @ts-ignore
        .alias(/.*[\\\/]CelebrityQuery/i, "<project>")
        .alias(/\[CelebrityQuery\][\\\/]?/i, "")
        .skip(/** <strong i="23">@type</strong> {(_:any) => boolean} */ (traceline => {
            if (traceline && traceline.dir) {
                return traceline.dir.toString().startsWith("internal");
            }
            return false;
        }))
        .skipNodeFiles();

    const consoleFormat = winston.format.combine(
        winston.format.colorize(),
        winston.format.timestamp({
            format: 'DD MMM HH:mm:ss'
        }),
        winston.format.printf(info => {
            if (!lodash.isEmpty(info.metadata) && info.metadata.hasOwnProperty("stack")) {
                let dup = lodash.clone(info.metadata);
                delete dup.stack;
                const errBody = stringify(dup, undefined, 4);
                const stack = pe.render({ stack: info.metadata.stack });
                return `${info.timestamp} ${info.level} ${info.message}${errBody}\n${stack}`;
            } else if (lodash.isString(info.message)) {
                return `${info.timestamp} ${info.level} ${info.message}`;
            } else {
                return `${info.timestamp} ${info.level} ${stringify(info.message, undefined, 4)}`;
            }
        })
    );
    const logFormat = winston.format.combine(winston.format.timestamp(), winston.format.json());
    return winston.createLogger({
        level: 'debug',
        format: winston.format.combine(
            winston.format.errors({ stack: true }),
            winston.format.metadata()
        ),
        transports: [
            new winston.transports.Console({
                format: consoleFormat,
                level: 'info',
            }),
            new winston.transports.File({
                filename: path.join(logDir, "stdout.json"),
                format: logFormat,
                level: 'debug',
                maxsize: 1000000,
                tailable: true
            })
        ]
    });

Log Screenshot

추신 : 또한 https://github.com/winstonjs/winston/issues/1338#issuecomment -506354691에 언급 된 솔루션이 좋은 대안이 될 수 있습니다. 사용 예 : logger.warn("Oh no", { error: new Error() }) 참조 후, info.error 사용자 정의 포맷터에.

@tiagonapoli 부모 로거에서 format.errors 사용에 대한 솔루션이 에게

const logger = createLogger({
  transports: loggerTransports,
});

logger.format = format.errors({ stack: true });

이 로거를 구성하는 것은 상당히 고통 스럽습니다 ... console.log 처럼 동작하지 않을 수 있습니까?

@ will093 여기도 동일합니다. 그 문제를 다시 다루었 고 왜 내 console.log 가 멋지고 깨끗하고 winston 형식이 똥인지 이해하지 못합니다.

내 2 ¢

// Enable console logging when not in production
if (process.env.NODE_ENV !== "production") {
    logger.add(new transports.Console({
        format: format.combine(
            format.colorize(),
            format.simple(),
            format.printf(info => {
                const { level, ...rest } = info;
                let rtn = "";
                // rtn += info.timestamp;
                rtn += "[" + info.level + "] ";
                if (rest.stack) {
                    rtn += rest.message.replace(rest.stack.split("\n")[0].substr(7),"");
                    rtn += "\n";
                    rtn += "[" + level + "] ";
                    rtn += rest.stack.replace(/\n/g, `\n[${level}]\t`);
                } else {
                    rtn += rest.message;
                }
                return rtn;
            }),
        ),
    }));
}

logger.error("Error during schema stitching", e);

image

@tiagonapoli@ will093 의 부모에만 추가하는 솔루션을 사용하는 것이 직접 로깅 오류를 지원하고 여전히 메시지를 로깅하는 가장 쉬운 방법 인 것 같습니다. 여기 타임 스탬프가있는 최소 설정의 전체 예가 있습니다.

const createLogger = () => {
  const logFormatter = winston.format.printf(info => {
    let { timestamp, level, code, stack, message } = info;

    // print out http error code w/ a space if we have one
    code = code ? ` ${code}` : '';
    // print the stack if we have it, message otherwise.
    message = stack || message;

    return `${timestamp} ${level}${code}: ${message}`;
  });

  return winston.createLogger({
    level: 'info',
    // put the errors formatter in the parent for some reason, only needed there:
    format: winston.format.errors({ stack: true }),
    transports: new winston.transports.Console({
      format: winston.format.combine(
        winston.format.timestamp(),
        logFormatter
      ),
  });
};

logger.error(error) 와 같은 오류로 호출 될 때 스택과 함께 작동하고 logger.error('a regular message') 와 같이 호출 될 때 문자열과 함께 작동하며 내 로그에서 다음과 같이 보입니다.

2020-09-23T20:05:30.30Z info: Feathers application started on http://localhost:3030
2020-09-23T20:05:35.40Z info: job queue - redis ready, registering queues...
2020-09-23T20:05:40.25Z error 401: NotAuthenticated: invalid authorization header
    at new NotAuthenticated (/path/to/server/node_modules/@feathersjs/errors/lib/index.js:94:17)
    at Object.<anonymous> (/path/to/server/src/hooks/authentication.js:123:456)
    at /path/to/server/node_modules/@feathersjs/commons/lib/hooks.js:116:46

이것은 winston의 logger.error('message here', error) -incompatibility w / console.log 를 해결하려고 시도 하지 않습니다. @tiagonapoli 의 더 많은 관련 솔루션이 수행하는 것 같습니다.

또한 json 로그가 마음에 들면 여기에 logFormatter 를 삭제하고 winston.format.json() 를 사용하면 스택이 여전히 포함되지만 예쁘지는 않습니다.

업데이트 : 이것에 여전히 문제가 있기 때문에 나는 한동안 다음을 해왔고 훌륭하게 작동했습니다.

// Grab the default winston logger
const winston = require('winston');

const { format } = winston;
const { combine, timestamp } = format;

// Custom format function that will look for an error object and log out the stack and if 
// its not production, the error itself
const myFormat = format.printf((info) => {
  const { timestamp: tmsmp, level, message, error, ...rest } = info;
  let log = `${tmsmp} - ${level}:\t${message}`;
  // Only if there is an error
  if ( error ) {
    if ( error.stack) log = `${log}\n${error.stack}`;
    if (process.env.NODE_ENV !== 'production') log = `${log}\n${JSON.stringify(error, null, 2)}`;
  }
  // Check if rest is object
  if ( !( Object.keys(rest).length === 0 && rest.constructor === Object ) ) {
    log = `${log}\n${JSON.stringify(rest, null, 2)}`;
  }
  return log;
});

 winston.configure({
    transports: [
      new winston.transports.Console({
        level: 'debug',
        timestamp: true,
        handleExceptions: true
    }),
  ];
    format: combine(
      trace(),
      timestamp(),
      myFormat
    ),
  });


// Finally you log like this
logger.error('An error occurred!!!', { error } );

trace () 정의는 어디에 있습니까?

업데이트 : 이것에 여전히 문제가 있기 때문에 나는 한동안 다음을 해왔고 훌륭하게 작동했습니다.

// Grab the default winston logger
const winston = require('winston');

const { format } = winston;
const { combine, timestamp } = format;

// Custom format function that will look for an error object and log out the stack and if 
// its not production, the error itself
const myFormat = format.printf((info) => {
  const { timestamp: tmsmp, level, message, error, ...rest } = info;
  let log = `${tmsmp} - ${level}:\t${message}`;
  // Only if there is an error
  if ( error ) {
    if ( error.stack) log = `${log}\n${error.stack}`;
    if (process.env.NODE_ENV !== 'production') log = `${log}\n${JSON.stringify(error, null, 2)}`;
  }
  // Check if rest is object
  if ( !( Object.keys(rest).length === 0 && rest.constructor === Object ) ) {
    log = `${log}\n${JSON.stringify(rest, null, 2)}`;
  }
  return log;
});

 winston.configure({
    transports: [
      new winston.transports.Console({
        level: 'debug',
        timestamp: true,
        handleExceptions: true
    }),
  ];
    format: combine(
      trace(),
      timestamp(),
      myFormat
    ),
  });


// Finally you log like this
logger.error('An error occurred!!!', { error } );

흔적은 어디에서 왔습니까?

이것에 대한 대답이 있습니까?

이 페이지가 도움이 되었나요?
0 / 5 - 0 등급