coding/Node.js

로그 남기기 2 - morgan 사용

JIN_Coder 2022. 9. 10. 01:27

로그를 남기기 위해 winston 사용 방법에 대해 정리한 이전 게시글을 보고 보는 것을 추천한다.

https://jin-coder.tistory.com/140

 

winston은 배포 환경에서 로그 기록 파일에 저장하는 기능을 주로 하고, 

morgan은 개발이나 배포 환경에서 콘솔 로그 대신 자동으로 로그들을 보여줄 수 있게 한다.

그러기 때문에 morgan을 사용한 미들웨어를 통해 자동으로 로그를 만들고, winston을 이용해 그 로그를 파일에 기록하여 사용한다.

 

 

1. morgan 설치

npm install morgan

 

2. morgan 코드 작성

winston과 같은 위치인 ./config/morganMiddleware.js에 코드를 작성한다.

morgan은 미들웨어로 만들어 사용할 것이다.

 

winston과 마찬가지로 참고 블로그의 전체 코드를 기반으로 내 입맛에 맞게 수정하였다.

전체 코드는 아래에 작성하고, 부분적으로 간략히 살펴보자

 

2.1 개발환경 따른 포맷 형식 설정

const morgan = require('morgan');
const logger = require('./winston');
require('dotenv').config();

const format = () => {
  const result =
    process.env.NODE_ENV === 'production'
      ? '[:remote-addr - :remote-user] ":method :url HTTP/:http-version" :status :response-time ms - :res[content-length] ":referrer" ":user-agent"'
      : ':method :url :status :response-time ms - :res[content-length]';
  return result;
};

우선 필요한 모듈을 불러와준다. 

 

포맷 환경에 맞게 포맷을 설정한다.

배포 환경인 경우 어떤 사용자가 무슨 메서드를 통해 어디 url에 접근해서 어떤 상태의 응답을 받아가고, 사용자의 인터넷 환경을 알아야 하기 때문에 좀 더 디테일한 형식을 사용하고,

개발환경의 경우 내가 주로 사용하기 때문에 무슨 메서드를 통해 어디 url에 접근해서 어떤 응답을 얼마 만에 가져갔는지 등에 더 주목하기 때문에 개발환경에 맞는 포맷을 설정한다.

각 포맷은 직접 커스텀하여 사용할 수 있다.

 

2.2 stream 옵션 / 스킵 여부

// 로그 작성을 위한 Output stream옵션.
const stream = {
  write: (message) => {
    logger.info(message);
  },
};

// 로깅 스킵 여부 (만일 배포환경이면, 코드가 400 미만라면 함수를 리턴해 버려서 로그 기록 안함. 코드가 400 이상이면 로그 기록함)
const skip = (_, res) => {
  if (process.env.NODE_ENV === 'production') {
    return res.statusCode < 400;
  }
  return false;
};

stream을 통해 어떤 레벨의 로그를 기록할 것인지 정의한다.

사실 morgan 미들웨어를 최상단에 위치하여 모든 api를 통과할 예정이므로 info를 설정해서 모든 로그를 찍히게 하고, error의 경우는 에러 핸들러에 위치하게 하여 에러를 추가적으로 기록한다.

 

skip은 개발 및 배포 환경에서 중요한 것은 정상적인 로그보단 err 로그이다.

배포 환경에서 정상적인 로그도 모두 기록하면 파일의 크기와 수가 늘어나 우려가 있기 때문에 400보다 작은 staustCode라면 로그를 기록하지 않게 정의한다.

 

2.3 미들웨어의 형태

//? 적용될 moran 미들웨어 형태
const morganMiddleware = morgan(format(), { stream, skip });
/*
morgan('dev', {
   stream = {
       write: (message) => {
          // console.log(message);
          logger.info(message);
       },
    },
   skip = (_, res) => {
      if (process.env.NODE_ENV === 'production') {
         return res.ststusCode < 400;
      }
      return false;
   };
})
*/

module.exports = morganMiddleware;

2.1, 2.2를 통해 미들웨어의 옵션들을 정의했다고 생각한다면

2.3에서 옵션들을 가지고 미들웨어를 만들어 exports 하여 밖에서도 사용할 수 있게 한다.

주석 친 부분은 옵션을 따로 정의하지 않고, 한 번에 썼을 경우의 모습이다.

 

morgan미들웨어 전체 코드

const morgan = require('morgan');
const logger = require('./winston');
require('dotenv').config();

const format = () => {
  const result =
    process.env.NODE_ENV === 'production'
      ? '[:remote-addr - :remote-user] ":method :url HTTP/:http-version" :status :response-time ms - :res[content-length] ":referrer" ":user-agent"'
      : ':method :url :status :response-time ms - :res[content-length]';
  return result;
};

// 로그 작성을 위한 Output stream옵션.
const stream = {
  write: (message) => {
    logger.info(message);
  },
};

// 로깅 스킵 여부 (만일 배포환경이면, 코드가 400 미만라면 함수를 리턴해 버려서 로그 기록 안함. 코드가 400 이상이면 로그 기록함)
const skip = (_, res) => {
  if (process.env.NODE_ENV === 'production') {
    return res.statusCode < 400;
  }
  return false;
};

//? 적용될 moran 미들웨어 형태
const morganMiddleware = morgan(format(), { stream, skip });

module.exports = morganMiddleware;

 

 

3. 에러 핸들러 코드 추가 작성

const logger = require('../config/winston');
const ErrorCustom = require('./errorCustom');

module.exports = (err, req, res, next) => {
  console.log(err);
  logger.error(err);
  if (err instanceof ErrorCustom) {
    return res.status(err.code).json({ ok: false, errMsg: err.message });
  }

  return res.status(500).json({ ok: false, errMsg: err.message });
};

현재 try catch문으로 예외 처리된 에러를 에러 핸들러에서 관리하고 있기 때문에

에러가 발생했을 때 에러 로그를 기록할 수 있도록 한다.

logger.error(err)를 통해 기본적인 api통신 로그도 찍고, 에러가 발생하면 여기서 err로그로 기록한다.

 

 

4. app.js 실제 적용

//app.js

const express = require('express');
const Router = require('./routes/index');
const errorHandler = require('./advice/errorHandler');
const morganMiddleware = require('./config/morganMiddleware');
 
// ...
 
app.use(morganMiddleware)
app.use('/api', Router);
app.get('/', (req, res) => {
  res.status(200).json({ massage: '연동 잘 됨.' });
});
app.use(errorHandler);

app.listen(port, () => {
  console.log(port, '포트로 서버가 열렸어요!');
});

morganMiddleware가 최상단에서 모든 api요청에 대한 로그를 기록하고

이후 api 통신이 이루어진다.

하나 에러가 발생한다면 에러는 에러 핸들러에 도달하여 처리가 될 때 error로그를 추가적으로 기록하여 로그를 관리한다.

 

 

이렇게 winston과 morgan을 같이 사용해서 모든 로그 기록들을 관리하는 법을 정리했다.

사실 누군가 정리된 코드를 가져와서 사용하는 건 쉽지만, 어떻게 동작하는지, 내 입맛대로 커스텀하는 부분이 쉽지는 않았다. 여러 코드를 보고 따라 해보고 하면서 나한테 맞도록 해보았다.

그래도 한번 배워두면 여러모로 사용할 수 있어 좋을 것 같다.

 

 

 

 

[NODE] 📚 Winston 모듈 사용법 - 서버 로그 관리

Winston 모듈 어떤 서버든지 실제로 서비스를 운영하려면 로그를 꼼꼼히 남기는 것은 필수이다. Log는 에러를 파악할 수 있는 열쇠이기 때문에 서버를 운영한다고 하면 로그 시스템을 구축해서 시

inpa.tistory.com

 

[EXPRESS] 📚 morgan 미들웨어 💯 사용법 정리

morgan 모듈 morgan에 연결 후 포트에 접속하면 기존 로그 외에 추가적인 로그를 볼 수 있다. 위 코드를 실행하여 3000번 포트에 들어간 후 콘솔을 보면 아래와 같은 로그가 찍혀있는 것을 볼 수 있다.

inpa.tistory.com

 

'coding > Node.js' 카테고리의 다른 글

readline 모듈  (0) 2022.11.12
node-schedule  (0) 2022.09.14
로그 남기기 1 - winston 사용  (0) 2022.09.09
socket.io - 실시간 채팅 / 채팅방 구현  (2) 2022.09.07
소켓 / 웹소켓  (0) 2022.09.05