Node.js HTTP 요청 로깅을 위한 Morgan 미들웨어 활용 가이드

Morgan 미들웨어 소개

Morgan은 Node.js 환경에서 Express 및 Connect 기반 애플리케이션을 위한 HTTP 요청 로깅 미들웨어입니다. 서버로 들어오는 모든 HTTP 요청에 대한 상세 정보를 콘솔이나 파일로 기록하여 디버깅과 모니터링을 용이하게 합니다.

기본 사용법

Morgan은 format 문자열과 옵션 객체를 조합하여 초기화합니다. 형식 지정 방식에 따라 세 가지 주요 패턴을 지원합니다.

미들웨어 등록 기본 문법은 다음과 같습니다:

const morgan = require('morgan');
const app = require('express')();

app.use(morgan(options));

미들웨어에 전달하는 format과 options 매개변수를 통해 로깅 동작을 커스터마이징할 수 있습니다.

미리 정의된 형식 사용

Morgan은 여러 가지 사전 정의된 형식을 제공합니다. 가장 간결한 형식인 'tiny'를 적용하면 기본적인 요청 정보만 기록됩니다:

app.use(morgan('tiny'));

토큰 조합 형식 사용

필요한 토큰을 직접 조합하여 커스텀 형식을 만들 수 있습니다. 다음과 같이 메서드, URL, 상태 코드, 응답 시간 등을 조합합니다:

app.use(morgan(':method :url :status :res[content-length] - :response-time ms'));

함수 기반 커스텀 형식

복잡한 로직이 필요한 경우 함수 형태로 형식을 정의할 수 있습니다. 이 방식은 토큰에 접근하여 세부 정보를 가공할 수 있어 유연합니다:

app.use(morgan((tokens, incomingMessage, serverResponse) => {
    const statusCode = tokens.status(incomingMessage, serverResponse);
    const responseTime = tokens['response-time'](incomingMessage, serverResponse);
    
    return [
        tokens.method(incomingMessage, serverResponse),
        tokens.url(incomingMessage, serverResponse),
        statusCode,
        tokens.res(incomingMessage, serverResponse, 'content-length'),
        '-',
        responseTime,
        'ms'
    ].join(' ');
}));

설정 옵션

Morgan은 로깅 동작을 제어하는 여러 가지 옵션을 제공합니다. 주요 옵션들을 살펴보겠습니다.

immediate 옵션

immediate 속성을 true로 설정하면 응답 대신 요청이 완료될 때가 아닌 요청이 수신되는 즉시 로그를 기록합니다. 이 방식은 서버가 응답하기 전에 크래시가 발생하더라도 해당 요청이 있었다는 정보를 남길 수 있다는 장점이 있습니다. 그러나 이 시점에서는 응답 상태 코드나 콘텐츠 길이 등 응답 관련 정보가 아직 확정되지 않아 기록되지 않습니다:

app.use(morgan('combined', {
    immediate: true
}));

skip 옵션

skip 옵션은 특정 조건에 해당하는 요청만 로깅하거나 제외할 수 있게 해줍니다. 이 옵션에 함수를 전달하면 각 요청마다 해당 함수가 호출되며, 함수가 true를 반환하면 해당 요청에 대한 로깅이 건너뜁니다:

// 4xx 이상의 오류 상태 코드만 로깅
app.use(morgan('combined', {
    skip: function(request, response) {
        return response.statusCode < 400;
    }
}));

stream 옵션

stream 옵션은 로그 출력을 지정된 스트림으로 направ합니다. 기본값은 process.stdout이지만 파일 스트림이나 다른 출력 방식으로 변경할 수 있습니다:

const fs = require('fs');
const logStream = fs.createWriteStream('./logs/access.log', { flags: 'a' });

app.use(morgan('combined', {
    stream: logStream
}));

미리 정의된 로그 형식

Morgan은 다양한 용도에 맞는 미리 정의된 로그 형식을 제공합니다. 각 형식은 서로 다른 수준의 세부 정보를 포함합니다.

combined 형식

combined은 Apache의 표준 조합 로그 형식과 호환되는 가장 상세한 형식입니다. 클라이언트 IP, 사용자 식별자, 타임스탬프, 요청 메서드와 URL, HTTP 버전, 상태 코드, 콘텐츠 길이, 리퍼러, 사용자 에이전트 등 완전한 정보를 기록합니다:

:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"

common 형식

common은 Apache의 표준 일반 로그 형식으로 combined보다 간결합니다. 필수적인 요청 정보를 포함하지만 사용자 에이전트와 리퍼러 정보는 제외됩니다:

:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length]

dev 형식

dev 형식은 개발 환경에 최적화된 가독성 좋은 출력물을 제공합니다. 상태 코드에 따라 색상이 적용되어 시각적으로 구분하기 쉽습니다. 성공을 나타내는 2xx 상태 코드는 초록색, 클라이언트 오류를 나타내는 4xx는 노란색, 서버 오류를 나타내는 5xx는 빨간색으로 표시됩니다:

:method :url :status :response-time ms - :res[content-length]

short 형식

short는 기본 형식보다 짧으면서도 응답 시간을 포함합니다. combined보다 간결하지만 remote-addr과 remote-user 정보가 빠져 있어 빠르게 확인해야 할 때 유용합니다:

:remote-addr :remote-user :method :url HTTP/:http-version :status :res[content-length] - :response-time ms

tiny 형식

tiny는 가장 최소한의 정보만 출력하는 형식입니다. 메서드, URL, 상태 코드, 콘텐츠 길이, 응답 시간만 기록되어 로그 파일 크기를 최소화할 때 적합합니다:

:method :url :status :res[content-length] - :response-time ms

커스텀 토큰 생성

Morgan의 강력한 기능 중 하나는 자신만의 토큰을 정의할 수 있다는 점입니다. morgan.token() 메서드를 사용하여 애플리케이션에 필요한 특정 정보를 추출하는 커스텀 토큰을 만들 수 있습니다.

기본 토큰 정의

새로운 토큰을 정의하려면 토큰 이름과 콜백 함수를 전달합니다. 이 콜백 함수는 req와 res 객체를 매개변수로 받으며 문자열 값을 반환해야 합니다:

morgan.token('content-type', function(incomingMessage, serverResponse) {
    return incomingMessage.headers['content-type'];
});

동적 파라미터를 받는 토큰

토큰 함수는 선택적으로 추가 파라미터를 받을 수 있습니다. 이를 활용하면 더욱 유연한 토큰을 만들 수 있습니다. 예를 들어 헤더 값이나 커스텀 데이터를 추출하는 토큰을 만들 수 있습니다:

morgan.token('header-value', function(incomingMessage, serverResponse, param) {
    const headerName = param || 'x-custom-header';
    return incomingMessage.headers[headerName];
});

// 사용 예시
app.use(morgan(':header-value[Authorization]'));

토큰 오버라이드

이미 존재하는 토큰과 동일한 이름으로 morgan.token()을 호출하면 기존 토큰이 새로운 정의로 대체됩니다. 이 기능은 기본 제공 토큰의 동작을 수정해야 할 때 유용합니다:

// 기본 :date 토큰을 커스텀 형식으로 재정의
morgan.token('date', function(incomingMessage, serverResponse) {
    return new Date().toISOString();
});

실전 활용 팁

Morgan을 프로덕션 환경에서 효과적으로 활용하기 위한 몇 가지 권장사항을 소개합니다.

파일 로깅과 콘솔 로깅을 동시에 설정하면 개발 환경에서는 실시간 확인이 가능하고, 프로덕션에서는 상세한 로그 파일을 남길 수 있습니다. 또한 로테이션을 지원하는 라이브러리와 함께 사용하면 로그 파일이 무한히 커지는 것을 방지할 수 있습니다.

태그: Node.js Express morgan HTTP logging

9월 18일 07:22에 게시됨