国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

輕松打造高效日志系統(tǒng)

系統(tǒng) 開發(fā)
本文介紹了如何設(shè)計(jì)并實(shí)現(xiàn)高效日志系統(tǒng),介紹了一個(gè)有效的日志系統(tǒng)需要考慮的關(guān)鍵問題,強(qiáng)調(diào)了日志在系統(tǒng)調(diào)試和監(jiān)控中的重要性。

作為開發(fā)者,經(jīng)常需要在調(diào)試時(shí)查看檢查日志,缺乏日志或者不清楚如何通過日志分析問題,就無法定位出錯(cuò)的代碼。

對(duì)于每天為成千上萬甚至上百萬用戶提供服務(wù)的系統(tǒng)來說,日志必不可少,因?yàn)椋?/p>

  • 日志可以幫助我們找到影響最終用戶的錯(cuò)誤。
  • 日志可以跟蹤系統(tǒng)的 "健康狀況",在系統(tǒng)出問題之前察覺到某些 "異常跡象"。
  • ……等等

由此可見,在開發(fā)或運(yùn)行系統(tǒng)時(shí),日志至關(guān)重要,因此,設(shè)計(jì)和實(shí)施完善的日志系統(tǒng)有助于簡(jiǎn)化監(jiān)控工作。

本文將分享我在設(shè)計(jì)和構(gòu)建日志系統(tǒng)方面的經(jīng)驗(yàn)和理解。希望通過這篇文章,你能:

  • 了解在操作系統(tǒng)中記錄日志的重要性。
  • 可以作為實(shí)施日志系統(tǒng)時(shí)的參考。

一、日志策略

下面列出了我們?cè)趯?shí)施日志系統(tǒng)之前應(yīng)該問自己的問題。

  • Why(為什么):日志記錄的目的是什么?
  • Who(誰): 哪個(gè)模塊將生成日志?
  • When(何時(shí)):何時(shí)輸出日志?
  • Where(哪里):在哪里輸出日志(發(fā)送到 Slack 或 BigQuery 等)
  • What(什么):日志能提供什么信息?
  • How(如何): 如何輸出日志?

二、日志級(jí)別

了解日志的目的后,應(yīng)該對(duì)日志進(jìn)行分級(jí)

Log level

Concept

How to handle

Example

FATAL

This Level hinder the operating of the system

Have to fix immediately

Can not connect to the DB

ERROR

Unexpected errors occur

Should be fixed as soon as you can

Can not send the email

WARN

Not an error, but are some problems like unexpected input or unexpected executing unexpected input or unexpected executing

Should be refactored regularly

Regularly delete data API

INFO

Notification when starting or ending an executing or a transaction.

Maybe outputting another needed information

Do not need to fix Output the body of the request or response

DEBUG

The information that relating to system status

Do not output in the production environment

Can be put inside a function

TRACE

Information that is more detailed than DEBUG

Do not output in the production environment


三、案例

定義日志級(jí)別后,必須明確要輸出的日志類型。

本節(jié)將針對(duì)每種日志類型回答以下六個(gè)問題。

  • Why(為什么)
  • Who(誰)
  • When(何時(shí))
  • Where(哪里)
  • What(什么)
  • How(如何)

1. 系統(tǒng)日志(System Log)

(1) Why: 當(dāng)系統(tǒng)出現(xiàn)錯(cuò)誤時(shí),系統(tǒng)日志將用于調(diào)試。

(2) Who: 系統(tǒng)本身將輸出日志。

(3) When:出錯(cuò)時(shí)輸出日志。

(4) Where:

  • FATAL / ERROR:通知開發(fā)人員立即處理。
  • WARN / INFO:在系統(tǒng)或日志管理工具中輸出。
  • DEBUG / TRACE:輸出到預(yù)發(fā)環(huán)境中的 console.log。

(5) What:

  • FATAL / ERROR:堆棧跟蹤。
  • WARN / INFO / DEBUG/ TRACE:要通知的內(nèi)容。

(6) How:

  • FATAL / ERROR:通過日志管理工具或 Slack、SMS......(推模式)輸出。
  • WARN / INFO / DEBUG / TRACE:通過日志管理工具或系統(tǒng)內(nèi)部輸出(拉模式)。

2. 訪問日志(Access Log)

  • Why: 輸出日志以跟蹤發(fā)送和接收請(qǐng)求的過程。
  • Who: 系統(tǒng)本身或基礎(chǔ)設(shè)施。
  • When: 在發(fā)送或接收請(qǐng)求時(shí)輸出。
  • Where: 在 INFO 級(jí)別和拉模式中。由于日志量可能很大,必須注意查找日志的速度。
  • What: 輸出誰、如何、何時(shí)進(jìn)入系統(tǒng)。
  • How: 根據(jù)目的不同,可能會(huì)有一些差異。

3. 操作日志(Action Log)

  • Why: 分析用戶操作,從而在此基礎(chǔ)上改進(jìn)服務(wù)。
  • Who: 系統(tǒng)本身或外部工具。
  • When: 某些操作發(fā)生時(shí)。
  • Where: 日志分析工具(BigQuery 等)。
  • What: 取決于目的。
  • How: 根據(jù)目的不同,可能會(huì)有一些差異。

4. 認(rèn)證日志(Auth Log)

  • Why: 跟蹤用戶驗(yàn)證的輸出。
  • Who: 系統(tǒng)本身。
  • When: 驗(yàn)證用戶。
  • Where: 在 INFO 級(jí)別和拉模式中。
  • What: 輸出認(rèn)證的時(shí)間、用戶、方式。
  • How: 根據(jù)認(rèn)證方法不同,可能會(huì)有一些差異。

四、示例

概念就介紹到這里,下面來看一個(gè)示例項(xiàng)目。

有關(guān)代碼的更多詳情,請(qǐng)參閱Github[2]。

1. 選擇日志庫

我選擇 log4js[3] 庫,原因很簡(jiǎn)單,因?yàn)?log4js 構(gòu)建日志級(jí)別的方式與我的想法一致。

2. 實(shí)施

步驟 1 - 定義日志類

首先定義日志類:

class Logger {
  public default: log4js.Logger;
  public system: log4js.Logger;
  public api: log4js.Logger;
  public access_req: log4js.Logger;
  public access_res: log4js.Logger;
  public sql: log4js.Logger;
  public auth: log4js.Logger;

  public fatal: log4js.Logger;
  public error: log4js.Logger;
  public warn: log4js.Logger;
  public info: log4js.Logger;
  public debug: log4js.Logger;
  public trace: log4js.Logger;

constructor() {
    log4js.configure(loggerConfig);

    this.system = log4js.getLogger('system');
    this.api = log4js.getLogger('api');
    this.access_req = log4js.getLogger('access_req');
    this.access_res = log4js.getLogger('access_res');
    this.sql = log4js.getLogger('sql');
    this.auth = log4js.getLogger('auth');

    this.fatal = log4js.getLogger('fatal');
    this.fatal.level = log4js.levels.FATAL;

    this.error = log4js.getLogger('error');
    this.error.level = log4js.levels.ERROR;

    this.warn = log4js.getLogger('warn');
    this.warn.level = log4js.levels.WARN;

    this.info = log4js.getLogger('info');
    this.info.level = log4js.levels.INFO;

    this.debug = log4js.getLogger('debug');
    this.debug.level = log4js.levels.DEBUG;

    this.trace = log4js.getLogger('trace');
    this.trace.level = log4js.levels.TRACE;
  }
}

在 Logger 類中定義了日志級(jí)別:

  • fatal
  • error
  • warn
  • info
  • debug
  • trace

基于此,我又定義了日志類型:

  • system
  • api
  • access_req
  • access_res
  • sql
  • auth

第 2 步 - 將 Logger 應(yīng)用到項(xiàng)目中

將 Logger 類應(yīng)用到由 NestJS[4] 框架實(shí)現(xiàn)的項(xiàng)目中。

通過 NestJS 的 Interceptor(攔截器[5])功能,將日志類注入到項(xiàng)目中。

選擇 Interceptor 的原因是 NestJS 攔截器不僅能封裝請(qǐng)求流,還能封裝從 API 輸入和輸出的響應(yīng)流,因此使用攔截器是捕獲請(qǐng)求日志和響應(yīng)日志的最簡(jiǎn)單方法。我是這樣定義 LoggerInterceptor 類的:

export class LoggerInterceptor implements NestInterceptor {
  intercept(
    context: ExecutionContext,
    next: CallHandler<any>
  ): Observable<any> | Promise<Observable<any>> {
    // intercept() method will "wrap" request/ response stream

    /*
     * Get request object from context
     * After that, pass request object to "requestLogger" function
     * to output the log
     */
    const request = context.switchToHttp().getRequest();
    requestLogger(request);

    /*
     * Get response object from context
     * After that pass response object to "responseLogger" & "responseErrorLogger" functions for ouputting the log or
     * error log
     */
    const response = context.switchToHttp().getResponse();

    return next.handle().pipe(
      // 200 - Success Response
      map((data) => {
        responseLogger({ requestId: request._id, response, data });
      }),
      // 4xx, 5xx - Error Response
      tap(null, (exception: HttpException | Error) => {
        try {
          responseErrorLogger({ requestId: request._id, exception });
        } catch (e) {
          logger.access_res.error(e);
        }
      })
    );
  }
}

定義了三種方法:

  • requestLogger: 用于記錄請(qǐng)求信息。
  • responseLogger: 用于記錄響應(yīng)信息。
  • responseErrorLogger: 用于記錄錯(cuò)誤信息。

像這樣:

const MaskField = {
Email: 'email',
Password: 'password',
} asconst;

type MaskField = (typeof MaskField)[keyof typeof MaskField];

const _maskFields = (object: FixType, fields: MaskField[]): FixType => {
const maskOptions = {
    maskWith: '*',
    unmaskedStartCharacters: 0,
    unmaskedEndCharacters: 0,
  };

for (let i = 0; i < fields.length; i++) {
    switch (fields[i]) {
      case MaskField.Email: {
        object[MaskField.Email] = maskData.maskEmail2(
          object[MaskField.Email],
          maskOptions
        );
      }
      case MaskField.Password: {
        object[MaskField.Password] = maskData.maskPassword(
          object[MaskField.Password],
          maskOptions
        );
      }
    }
  }

return object;
};

exportconst requestLogger = (request: Request) => {
const { ip, originalUrl, method, params, query, body, headers } = request;

// logTemplate includes: now(time), ip, http_method, url, request_object
const logTemplate = '%s %s %s %s %s';
const now = dayjs().format('YYYY-MM-DD HH:mm:ss.SSS');

const logContent = util.formatWithOptions(
    { colors: true },
    logTemplate,
    now,
    ip,
    method,
    originalUrl,
    JSON.stringify({
      method,
      url: originalUrl,
      userAgent: headers['user-agent'],
      body: _maskFields(body, [MaskField.Email, MaskField.Password]),
      params,
      query,
    })
  );

// Using access_req logger object have been defined before.
  logger.access_req.info(logContent);
};

// Ouptput success response log
exportconst responseLogger = (input: {
requestId: number;
  response: Response;
  data: any;
}) => {
const { requestId, response, data } = input;

const log: ResponseLog = {
    requestId,
    statusCode: response.statusCode,
    data,
  };

// Using access_res logger object have been defined before.
  logger.access_res.info(JSON.stringify(log));
};

// Ouptput error response log
exportconst responseErrorLogger = (input: {
requestId: number;
  exception: HttpException | Error;
}) => {
const { requestId, exception } = input;

const log: ResponseLog = {
    requestId,
    statusCode:
      exception instanceof HttpException ? exception.getStatus() : null,
    message: exception?.stack || exception?.message,
  };

// Using access_res logger object have been defined before.
  logger.access_res.info(JSON.stringify(log));
  logger.access_res.error(exception);
};

定義完 LoggerInterceptor 后,將此攔截器應(yīng)用到應(yīng)用程序中:

const app = await NestFactory.create(AppModule);

app.useGlobalInterceptors(new LoggerInterceptor());

在 NestJS 應(yīng)用程序中應(yīng)用自定義攔截器并不難,因?yàn)檫@是 NestJS 的內(nèi)置功能。

對(duì)于 fatal 和 debug 日志,我將在用例層或基礎(chǔ)架構(gòu)層中使用,以達(dá)到以下目的:

  • 通知無法連接數(shù)據(jù)庫等致命錯(cuò)誤。
  • 當(dāng)用戶遇到問題時(shí)進(jìn)行調(diào)試。

只要這樣做:

logger.fatal.error('Error message');

可以將 fatal 日志輸出到控制臺(tái)或 Slack 等通知管道......

結(jié)果如下:

首先是訪問請(qǐng)求日志和響應(yīng)日志(當(dāng)沒有發(fā)生錯(cuò)誤時(shí))。

可以看到,與請(qǐng)求相關(guān)的信息,如 method、body 等都已清晰顯示。

如果出錯(cuò):

同時(shí)顯示錯(cuò)誤類型和錯(cuò)誤信息。

fatal 日志會(huì)是這樣的:

同樣會(huì)輸出錯(cuò)誤信息和錯(cuò)誤類型。

五、結(jié)論

本文分享了如何設(shè)計(jì)和實(shí)施一個(gè)基本的日志系統(tǒng)。

通過簡(jiǎn)單的示例,希望你能理解建立日志系統(tǒng)的重要性和必要性,這將有助于系統(tǒng)的運(yùn)行和調(diào)試。

參考資料:

  • [1] Design And Building A Logging System: https://levelup.gitconnected.com/design-and-building-a-logging-system-fd5dcad110ed
  • [2] NewAnigram-BE-DDD: https://github.com/tuananhhedspibk/NewAnigram-BE-DDD
  • [3] log4js: https://github.com/log4js-node/log4js-node
  • [4] NestJS: https://docs.nestjs.com
  • [5] NestJS Interceptor: https://docs.nestjs.com/interceptors
責(zé)任編輯:趙寧寧 來源: DeepNoMind
相關(guān)推薦

2025-07-14 05:00:00

監(jiān)控系統(tǒng)工具

2023-11-16 08:53:05

NumPy庫Python

2011-01-19 10:42:15

2024-01-03 10:03:26

PythonTCP服務(wù)器

2010-06-23 11:41:00

高校企業(yè)高效數(shù)據(jù)中心

2009-05-05 13:19:53

戴爾高效企業(yè)

2010-02-22 15:00:47

2012-08-06 11:55:10

災(zāi)備系統(tǒng)深信服易寶支付

2025-01-03 09:34:54

2009-12-11 15:37:58

Linux日志處理

2019-12-12 09:30:31

工具代碼開發(fā)

2010-01-11 15:12:30

VB.NET特殊窗體

2013-08-13 14:11:39

2025-05-12 10:02:05

2014-10-27 14:09:01

華為

2010-05-12 15:39:49

IT運(yùn)維信息化建設(shè)北塔

2024-06-13 10:52:43

2010-01-14 11:00:48

VB.NET文件合并
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

久久美女艺术照精彩视频福利播放| 99xxxx成人网| 欧美日韩亚洲激情| 大片在线观看网站免费收看| 国产精品专区免费| 欧美日韩国产精品一区二区不卡中文| 国产一区免费| 9999国产精品| 欧美在线视频观看免费网站| 18网站在线观看| 色婷婷av一区| caoporn超碰97| 丁香一区二区三区| 国产一区二区免费在线观看| 精品国产亚洲一区二区三区在线| 欧美日韩精品一区视频| www.黄色网址.com| 久久久久久夜| 96sao精品视频在线观看| 精品精品精品| 久久久久久久亚洲精品| 成人午夜888| 一道本无吗dⅴd在线播放一区| 亚洲七七久久综合桃花剧情介绍| 欧美日韩免费不卡视频一区二区三区 | 日韩久久久久| 欧美日韩一区成人| 鲁一鲁一鲁一鲁一色| 国产精品一区不卡| 国产精品视频大全| 久久激情电影| 97免费视频在线播放| 你懂的一区二区三区| 欧美一级视频免费在线观看| 日韩在线无毛| 欧美日韩免费观看一区三区| 9191在线播放| 欧美丝袜美女中出在线| 国产一区二区三区小说| 懂色中文一区二区在线播放| 精品视频第一区| 丝袜诱惑制服诱惑色一区在线观看| 亚洲xxx大片| 伊人情人综合网| 日韩久久久久久久久久久久| 日韩一级欧洲| 国产精品电影在线观看| 日日骚欧美日韩| 无码人妻少妇伦在线电影| 亚洲风情在线资源站| 日本电影全部在线观看网站视频| 日韩一区二区三区视频| 欧美日韩欧美| 91精品国产综合久久婷婷香蕉 | 久久在线视频免费观看| 美女av一区二区| 免费日韩一区二区三区| 日韩欧美在线电影| 一区二区三区国产豹纹内裤在线| 91桃色在线观看| 97成人在线视频| 成人高潮a毛片免费观看网站| 91久久国产婷婷一区二区| 懂色av中文一区二区三区| 成人欧美一区二区三区黑人麻豆 | 亚洲精品成人| 四虎免费av| 欧美精品一区二区久久婷婷| 欧美理论电影大全| 亚洲精品怡红院| 亚洲韩国青草视频| 国产精品99久久免费| 亚洲一区二区在线看| 欧美网站大全在线观看| 加勒比色老久久爱综合网| 日本一区二区三区免费观看| 国产一区二区精品久久99| av免费在线播放网站| 伊人青青综合网站| 亚洲中无吗在线| yiren22综合网成人| 91沈先生在线观看| 欧美性生交大片免费| 国产一区二区电影在线观看| 国产精品日韩高清| 亚洲www啪成人一区二区麻豆| 乱中年女人伦av一区二区| 一本色道婷婷久久欧美| 日韩三级视频在线看| 欧美电影一区| 四虎在线观看| 日韩在线观看免费av| 9国产精品视频| av免费在线网站| 亚洲av首页在线| 56国语精品自产拍在线观看| 精品中文视频| 欧洲亚洲一区二区| 久久精品视频网站| 亚洲色图欧美在线| 亚洲九九精品| x88av蜜桃臀一区二区| 精品国产乱码久久久久久88av| 91九色最新地址| 国产精品亚洲专一区二区三区 | 精品国产1区2区3区| 国产精品1区2区3区在线观看| 成人在线视频免费| 男女羞羞网站| 黄色免费高清视频| 欧美国产日韩一区二区| 国产一区二区在线影院| 日本一区精品视频| 最近中文字幕mv2018在线高清 | 久久大胆人体| 国内外成人激情视频| 欧美亚洲在线视频| 在线成人av影院| 亚洲男女毛片无遮挡| 欧美日本三区| 国产欧美黑人| 青青草国产精品| 国产精品吊钟奶在线| 欧美午夜精品久久久久久久| 中文日韩在线| 午夜精品久久| 一区二区三区视频免费观看| 激情亚洲综合网| 日韩伦理一区二区三区av在线| 97成人超碰免| 久久久久久国产精品三级玉女聊斋| 欧美三级电影精品| 最新成人av在线| 国产精品无遮挡| 91香蕉视频污在线| 国产一区二区三区在线观看精品| 成人激情电影在线| 999国产精品一区| 在线观看国产视频| 男人日女人逼逼| 国产真人做爰毛片视频直播 | 亚洲免费二区| 日韩欧美一区免费| 久久porn| 麻豆影视在线观看_| 日日噜噜夜夜狠狠| 日本免费一区二区三区| 精品国产乱码久久久久久丨区2区| 亚洲一区亚洲二区亚洲三区| 欧美黑人巨大精品一区二区| 久久噜噜噜精品国产亚洲综合| 欧美日韩一区二区精品| 中文字幕一区二区视频| 亚洲精华国产欧美| 在线亚洲观看| 国产一区二区三区在线观看免费视频 | 国产成人精品免费视| 粉嫩av国产一区二区三区| 9国产精品午夜| 天天做夜夜做人人爱精品| www.成人| 久操精品在线| 综合精品一区| 国产高清不卡一区| 一区二区三区国产豹纹内裤在线| 色综合久久久网| 亚洲综合成人在线| 欧美日韩国产a| 欧美一二三区在线观看| 欧美日韩一区二区不卡| 宅男66日本亚洲欧美视频| 欧美精品videos| 欧美一区二区三区在线播放 | 久久久久久久久久久免费 | 国产www视频在线观看| xvideos.蜜桃一区二区| 亚洲.欧美.日本.国产综合在线 | 国产精品av一区二区| 日韩成人激情| 青青草97国产精品免费观看| 日本一区二区三区在线不卡| 日韩欧美中文字幕公布| 欧美巨乳在线观看| 日韩电影免费观看在| 国产av熟女一区二区三区| 男人艹女人网站| 午夜av在线播放| 偷拍精品福利视频导航| 激情久久五月天| 欧美最新大片在线看| 热久久99这里有精品| 一区二区视频国产| 麻豆影视在线观看| 欧美色图国产精品| 日本一区二区动态图| 日韩电影第一页| 中国人体摄影一区二区三区| www免费视频观看在线| 午夜影院欧美| 欧美三区免费完整视频在线观看|