Winston과 Morgan 및 Typescript를 사용하여 ExpressJS에 더 나은 로그 제공

Typescript를 사용하여 Winston 및 Morgan Logger와 함께 ExpressJS 응용 프로그램을 구성하는 방법에 대한 단계별 가이드

A great log system is one of the easiest ways to check your application behavior and it’s our first weapon to look into bugs


ExpressJS 애플리케이션을 시작하거나 이미 시작한 경우, 어떻게 해야만 훌륭하고 조직적인 로그 시스템을 만들 수 있습니까?
문제는 많은 응용 프로그램들이 전면적인 로그 시스템이 없고, 심지어는 간단한 컨트롤러를 사용한다는 것이다.도처에 일지다.
이 문서에서는 Winston과 Morgan 구성 로그를 사용하는 방법에 대해 설명합니다.

TL;박사


여기에서 완전히 구성된 project ((complete 지점 사용) 을 찾을 수 있습니다.
나는 본문에 단원 테스트를 추가하지 않았지만, 아래의 코드는 전면적인 테스트를 거쳤다.위의 저장소에서 모든 테스트를 찾을 수 있습니다.
ExpressJS GraphQL API를 시작하려면 좋은 템플릿이 필요합니까?내 것 사용: https://github.com/vassalloandrea/express-template

우리 시작하자.


우선 ExpressJS 애플리케이션이 필요합니다.이 저장소를 복제할 수 있습니다.
git clone https://github.com/vassalloandrea/medium-morgan-winston-example.git

서버 시작


이 항목은 처음부터 기본 설정으로 만들어졌습니다.다음 명령을 사용하여 서버를 시작합니다.
cd medium-morgan-winston-example
npm install
npm run dev

윈스턴을 설치하다


Winston는 많은 유용한 기능에 대한 응용 프로그램 로그를 설정하고 사용자 정의하는 데 사용되는 유용한 라이브러리입니다.

To use the plainconsole.log without a third-party library, we need to write a lot of code and reinvent the wheel understanding all the edge cases caught by Winston in these years.


다음은 우리가 프로젝트 내부에서 실현해야 할 주요 기능이다.
  • 로그 레벨 구분: 오류, 경고, 정보, HTTP, 디버깅
  • 색상 구분, 로그 레벨당 색상 추가
  • 응용 환경에 따라 서로 다른 로그 단계를 표시하거나 숨긴다.e. 예를 들어 프로그램이 생산 환경에서 실행될 때 우리는 모든 로그를 표시하지 않습니다.
  • 로그 줄마다 시간 스탬프 추가
  • 로그를 파일에 저장
  • npm install winston
    

    윈스턴


    아래 몇 줄에서, 우리 기록기는 간단한 설정을 가지고 있다.항목을 복사하여 붙여넣습니다.다음 경로를 사용할 수 있습니다: src/lib/logger.혹은 유사한 물건.
    나는 앞으로 모든 줄을 설명할 것이다.
    import winston from 'winston'
    
    const levels = {
      error: 0,
      warn: 1,
      info: 2,
      http: 3,
      debug: 4,
    }
    
    const level = () => {
      const env = process.env.NODE_ENV || 'development'
      const isDevelopment = env === 'development'
      return isDevelopment ? 'debug' : 'warn'
    }
    
    const colors = {
      error: 'red',
      warn: 'yellow',
      info: 'green',
      http: 'magenta',
      debug: 'white',
    }
    
    winston.addColors(colors)
    
    const format = winston.format.combine(
      winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss:ms' }),
      winston.format.colorize({ all: true }),
      winston.format.printf(
        (info) => `${info.timestamp} ${info.level}: ${info.message}`,
      ),
    )
    
    const transports = [
      new winston.transports.Console(),
      new winston.transports.File({
        filename: 'logs/error.log',
        level: 'error',
      }),
      new winston.transports.File({ filename: 'logs/all.log' }),
    ]
    
    const Logger = winston.createLogger({
      level: level(),
      levels,
      format,
      transports,
    })
    
    export default Logger
    
    이제 애플리케이션의 모든 위치에서 Logger 함수를 사용하여 가져올 수 있습니다.
    ExpressJS 서버가 정의된 index.ts 파일로 이동하고 모든 콘솔을 교체합니다.사용자 정의 기록기 방법을 사용하여 로그를 기록합니다.
    import express from "express";
    
    import Logger from "./lib/logger";
    
    const app = express();
    const PORT = 3000;
    
    app.get("/logger", (_, res) => {
      Logger.error("This is an error log");
      Logger.warn("This is a warn log");
      Logger.info("This is a info log");
      Logger.http("This is a http log");
      Logger.debug("This is a debug log");
    
      res.send("Hello world");
    });
    
    app.listen(PORT, () => {
      Logger.debug(`Server is up and running @ http://localhost:${PORT}`);
    });
    
    서버를 부팅하고 loggerendpoint를 탐색한 결과를 확인합니다.

    보시다시피, 기록기는 로그의 심각성에 따라 다른 색으로 로그를 표시합니다. 또 다른 중요한 기능은 모든 로그가 all.log 디렉터리에 있는 error.log 파일과 logs 파일에 인쇄된다는 것입니다.

    구성에 대한 자세한 내용


    구성 파일은 간단합니다.다음 파일의 주석을 확인하십시오.
    import winston from 'winston'
    
    // Define your severity levels. 
    // With them, You can create log files, 
    // see or hide levels based on the running ENV.
    const levels = {
      error: 0,
      warn: 1,
      info: 2,
      http: 3,
      debug: 4,
    }
    
    // This method set the current severity based on 
    // the current NODE_ENV: show all the log levels 
    // if the server was run in development mode; otherwise, 
    // if it was run in production, show only warn and error messages.
    const level = () => {
      const env = process.env.NODE_ENV || 'development'
      const isDevelopment = env === 'development'
      return isDevelopment ? 'debug' : 'warn'
    }
    
    // Define different colors for each level. 
    // Colors make the log message more visible,
    // adding the ability to focus or ignore messages.
    const colors = {
      error: 'red',
      warn: 'yellow',
      info: 'green',
      http: 'magenta',
      debug: 'white',
    }
    
    // Tell winston that you want to link the colors 
    // defined above to the severity levels.
    winston.addColors(colors)
    
    // Chose the aspect of your log customizing the log format.
    const format = winston.format.combine(
      // Add the message timestamp with the preferred format
      winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss:ms' }),
      // Tell Winston that the logs must be colored
      winston.format.colorize({ all: true }),
      // Define the format of the message showing the timestamp, the level and the message
      winston.format.printf(
        (info) => `${info.timestamp} ${info.level}: ${info.message}`,
      ),
    )
    
    // Define which transports the logger must use to print out messages. 
    // In this example, we are using three different transports 
    const transports = [
      // Allow the use the console to print the messages
      new winston.transports.Console(),
      // Allow to print all the error level messages inside the error.log file
      new winston.transports.File({
        filename: 'logs/error.log',
        level: 'error',
      }),
      // Allow to print all the error message inside the all.log file
      // (also the error log that are also printed inside the error.log(
      new winston.transports.File({ filename: 'logs/all.log' }),
    ]
    
    // Create the logger instance that has to be exported 
    // and used to log messages.
    const Logger = winston.createLogger({
      level: level(),
      levels,
      format,
      transports,
    })
    
    export default Logger
    

    상황을 평가해 보다


    현재, 우리는 기능의 복잡성에 따라 로그를 추가하고, 응용 프로그램 코드에 도구를 추가할 수 있다.

    With Winston, you can also change the log severity at the runtime using an ENV variable.


    ExpressJS는 요청을 처리하는 데 사용되기 때문에 요청 기록기를 추가하여 모든 요청 정보를 자동으로 기록해야 합니다.Winston과 쉽게 통합할 수 있는 라이브러리를 사용해서 이 목표를 실현해야 한다.

    모건을 설치하다


    Morgan는 요청 로그를 사용자정의하는 데 필요한 NodeJS 중간부품입니다.
    윈스턴과의 결합은 매우 간단하다.Winston 구성에 추가된 HTTP 심각도 수준을 기억하십니까?좋아, 모건 중간부품으로 만들어졌어.
    npm install morgan @types/morgan
    

    모건 배치


    다음 몇 줄은 Morgan 중간부품의 간단한 설정입니다.항목을 복사하여 붙여넣습니다.src/config/morganMiddleware.ts 또는 유사한 경로를 사용할 수 있습니다.
    다음 설정을 이해하거나 확장하기 위해 주석을 읽으십시오.
    import morgan, { StreamOptions } from "morgan";
    
    import Logger from "../lib/logger";
    
    // Override the stream method by telling
    // Morgan to use our custom logger instead of the console.log.
    const stream: StreamOptions = {
      // Use the http severity
      write: (message) => Logger.http(message),
    };
    
    // Skip all the Morgan http log if the 
    // application is not running in development mode.
    // This method is not really needed here since 
    // we already told to the logger that it should print
    // only warning and error messages in production.
    const skip = () => {
      const env = process.env.NODE_ENV || "development";
      return env !== "development";
    };
    
    // Build the morgan middleware
    const morganMiddleware = morgan(
      // Define message format string (this is the default one).
      // The message format is made from tokens, and each token is
      // defined inside the Morgan library.
      // You can create your custom token to show what do you want from a request.
      ":method :url :status :res[content-length] - :response-time ms",
      // Options: in this case, I overwrote the stream and the skip logic.
      // See the methods above.
      { stream, skip }
    );
    
    export default morganMiddleware;
    
    이 중간부품을 index.ts 파일의 ExpressJS 서버에 추가하려면:
    import morganMiddleware from './config/morganMiddleware'
    
    ...
    ...
    
    const PORT = 3000;
    
    app.use(morganMiddleware)
    
    app.get("/logger", (_, res) => {
    
    ...
    
    서버를 시작하고 액세스를 요청loggerendpoint:

    다음은 요청 로그의 다른 예입니다.

    구성 사용


    이게 다야!나는 이 설정이 너희들 모두가 코드에 대한 테스트를 돕고 숨겨진 버그를 더욱 쉽게 발견할 수 있기를 바란다.🐛
    너는 이 문장을 좋아하니?박수를 치고 댓글을 남겨주세요.🙏
    ExpressJS 애플리케이션에 도움이 필요합니까?Hire me

    GraphQL Morgan 구성을 통한 심화


    이 섹션은 GraphQL을 사용하는 프로젝트에 대한 심화일 뿐입니다.
    기본적으로GraphQL은 하나의 루트만 있기 때문에, 의미를 부여하기 위해 Morgan 설정을 변경해야 합니다.
    import morgan, { StreamOptions } from "morgan";
    
    import { IncomingMessage } from "http";
    
    import Logger from "../lib/logger";
    
    interface Request extends IncomingMessage {
      body: {
        query: String;
      };
    }
    
    const stream: StreamOptions = {
      write: (message) =>
        Logger.http(message.substring(0, message.lastIndexOf("\n"))),
    };
    
    const skip = () => {
      const env = process.env.NODE_ENV || "development";
      return env !== "development";
    };
    
    const registerGraphQLToken = () => {
      morgan.token("graphql-query", (req: Request) => `GraphQL ${req.body.query}`);
    };
    
    registerGraphQLToken();
    
    const morganMiddleware = morgan(
      ":method :url :status :res[content-length] - :response-time ms\n:graphql-query",
      { stream, skip }
    );
    
    export default morganMiddleware;
    

    좋은 웹페이지 즐겨찾기