node.js에서 오류 로그 잘 발표하기 (pino)

무심결에 해봤는데 제대로 기록하지 못해 잘못된 수사에 시달렸다.
로거 사용pino.
오류 클래스는 제작의 기본 Application Errormake-error-cause를 사용합니다.
다시 던지는 오류는 모두 이 Application Error를 상속합니다.
import { BaseError } from "make-error-cause";

class ApplicationError extends BaseError {}
class RequestFailedError extends ApplicationError {}
잘못된 재투하와 일지는 이런 느낌이에요.
import pino from "pino";

const logger = pino();
const request = async () => {
  try {
    await fetch("/example");
  } catch (e) {
    throw e instanceof Error
      ? new RequestFailedError("Failed to request /example", e)
      : e;
  }
};
const main = async () => {
  try {
    await request();
  } catch (e) {
    logger.error(e);
  }
};
make-error-cause를 사용하면 함정이 많은 오류 계승만 일반적으로 계승하면 되고 오류 메시지도 추가할 수 있습니다.
console.error를 사용하면,make-error-cause의 오류도 아래와 같은 원시 오류를 표시합니다.
RequestFailedError: Failed to request /example
    at /Users/airtoxin/repositories/s/src/logging.ts:25:9
    at step (/Users/airtoxin/repositories/s/src/logging.ts:48:23)
    at Object.throw (/Users/airtoxin/repositories/s/src/logging.ts:29:53)
    at rejected (/Users/airtoxin/repositories/s/src/logging.ts:21:65)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)

The following exception was the direct cause of the above exception:

TypeError: Failed to parse URL from /example
    at new Request (/Users/airtoxin/repositories/s/node_modules/undici/lib/fetch/request.js:84:15)
    at Agent.fetch (/Users/airtoxin/repositories/s/node_modules/undici/lib/fetch/index.js:121:25)
    at fetch (/Users/airtoxin/repositories/s/node_modules/undici/index.js:102:22)
    at /Users/airtoxin/repositories/s/src/logging.ts:22:16
    at step (/Users/airtoxin/repositories/s/src/logging.ts:48:23)
    at Object.next (/Users/airtoxin/repositories/s/src/logging.ts:29:53)
    at /Users/airtoxin/repositories/s/src/logging.ts:23:71
    at new Promise (<anonymous>)
    at __awaiter (/Users/airtoxin/repositories/s/src/logging.ts:19:12)
    at request (/Users/airtoxin/repositories/s/src/logging.ts:20:17)

The following exception was the direct cause of the above exception:

TypeError: Invalid URL
    at new NodeError (node:internal/errors:371:5)
    at onParseError (node:internal/url:552:9)
    at new URL (node:internal/url:628:5)
    at new Request (/Users/airtoxin/repositories/s/node_modules/undici/lib/fetch/request.js:82:21)
    at Agent.fetch (/Users/airtoxin/repositories/s/node_modules/undici/lib/fetch/index.js:121:25)
    at fetch (/Users/airtoxin/repositories/s/node_modules/undici/index.js:102:22)
    at /Users/airtoxin/repositories/s/src/logging.ts:22:16
    at step (/Users/airtoxin/repositories/s/src/logging.ts:48:23)
    at Object.next (/Users/airtoxin/repositories/s/src/logging.ts:29:53)
    at /Users/airtoxin/repositories/s/src/logging.ts:23:71 {
  input: '/example',
  code: 'ERR_INVALID_URL'
}
pino를 사용한 오류 로그도 나올 것으로 기대되지만, 실제로는 상기 코드로 오류 로그를 만들어 보려고 합니다.
[1651700227725] ERROR (43608 on hexa.local): Failed to request /example
    err: {
      "type": "RequestFailedError",
      "message": "Failed to request /example",
      "stack":
          RequestFailedError: Failed to request /example
              at /Users/airtoxin/repositories/s/src/logging.ts:25:9
              at step (/Users/airtoxin/repositories/s/src/logging.ts:48:23)
              at Object.throw (/Users/airtoxin/repositories/s/src/logging.ts:29:53)
              at rejected (/Users/airtoxin/repositories/s/src/logging.ts:21:65)
              at processTicksAndRejections (node:internal/process/task_queues:96:5)
    }
, 잘못된 정보만 다시 던집니다.(보기 좋게 pino-pretty 착용)
정보를 늘리기 위해 다시 던진 것임에도 불구하고 이렇게 되면 정보가 줄어 오히려 다시 던지지 않는 게 좋다.

해결책


pino 오류 직렬화기를 사용자 정의합니다.
import { fullStack } from "make-error-cause";

const logger = pino({
  serializers: {
    err(value) {
      if (value instanceof Error) {
        return fullStack(value);
      } else {
        return value;
      }
    },
  },
});
이 레코더를 사용하여 오류 로그를 출력할 때
RequestFailedError: Failed to request /example
    at /Users/airtoxin/repositories/s/src/logging.ts:25:9
    at step (/Users/airtoxin/repositories/s/src/logging.ts:48:23)
    at Object.throw (/Users/airtoxin/repositories/s/src/logging.ts:29:53)
    at rejected (/Users/airtoxin/repositories/s/src/logging.ts:21:65)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)

The following exception was the direct cause of the above exception:

TypeError: Failed to parse URL from /example
    at new Request (/Users/airtoxin/repositories/s/node_modules/undici/lib/fetch/request.js:84:15)
    at Agent.fetch (/Users/airtoxin/repositories/s/node_modules/undici/lib/fetch/index.js:121:25)
    at fetch (/Users/airtoxin/repositories/s/node_modules/undici/index.js:102:22)
    at /Users/airtoxin/repositories/s/src/logging.ts:22:16
    at step (/Users/airtoxin/repositories/s/src/logging.ts:48:23)
    at Object.next (/Users/airtoxin/repositories/s/src/logging.ts:29:53)
    at /Users/airtoxin/repositories/s/src/logging.ts:23:71
    at new Promise (<anonymous>)
    at __awaiter (/Users/airtoxin/repositories/s/src/logging.ts:19:12)
    at request (/Users/airtoxin/repositories/s/src/logging.ts:20:17)

The following exception was the direct cause of the above exception:

TypeError: Invalid URL
    at new NodeError (node:internal/errors:371:5)
    at onParseError (node:internal/url:552:9)
    at new URL (node:internal/url:628:5)
    at new Request (/Users/airtoxin/repositories/s/node_modules/undici/lib/fetch/request.js:82:21)
    at Agent.fetch (/Users/airtoxin/repositories/s/node_modules/undici/lib/fetch/index.js:121:25)
    at fetch (/Users/airtoxin/repositories/s/node_modules/undici/index.js:102:22)
    at /Users/airtoxin/repositories/s/src/logging.ts:22:16
    at step (/Users/airtoxin/repositories/s/src/logging.ts:48:23)
    at Object.next (/Users/airtoxin/repositories/s/src/logging.ts:29:53)
    at /Users/airtoxin/repositories/s/src/logging.ts:23:71 {
  input: '/example',
  code: 'ERR_INVALID_URL'
}
모든 오류 스택이 표시됩니다.
pino 이외의 Roger도 시리아의 정의가 있기 때문에 그런 곳에서make-error-causefullStack 함수를 사용하면 될 것이다.

좋은 웹페이지 즐겨찾기