前端日志管理模块的设计与实现(前端日志管理模块的设计与实现方法)

一、问题背景

在项目中,我们会频繁用到 console.log() 来输出一些关键信息到控制台中,有助于开发调试,以及问题的排查,待项目上线后,这些调试日志又得及时清除。

同时在前端质量要求下,我们会做“前端埋点”,用于远程上报一些关键行为信息,用于在出问题时还原用户的操作路径,复现 BUG,从而解决问题,而各种各样的上报若是能在业务开发中抹平差异,也有助于研发提效。

因此,有必要在团队中封装日志工具(Logger),用于统一管理日志输出和格式化上报,降低开发者对多平台上报差异的心智负担。

二、需求概述

预期日志管理工具(Logger)需要有如下能力:

  1. 支持区分 info 、 warn 、 error 三种本地调试类型日志
  2. 支持远程上报自定义日志 report()
  3. 支持设置 namespace,用于区分代码执行的 scope
  4. 支持链式操作
  5. 区分生产环境和开发环境,生产环境禁止输出日志到控制台
  6. 支持功能可扩展

三、方案设计

在阅读完 Axios 的源码后,个人认为 Axios 里对于设计模式的应用是非常灵活,同理,一个好的日志工具也应当遵守着一定的软件设计模式原则。

作为项目中用到的日志工具,单例模式应当是更适合的选择!

Logger 的打印输出能力,本质上还是借助了 window.console 对象中的方法:

前端日志管理模块的设计与实现(前端日志管理模块的设计与实现方法)

Console 对象

在面向对象编程中,我们可以认为 console 是一个已经初始化的实例,同时也是一个单例,因为它是全局唯一。

而单例模式的最大好处就是全局唯一,对于做日志统一管理有着天然的友好支持基础。

四、实现细节 :mag:

接下来通过具体的代码,来逐一实现并完善我们的 Logger 日志工具类。

1、ES Module 下的单例模式

在 ESM 规范下,我们可以直接通过直接导出实例方式( export default new ClassName() ),来实现单例模式。

Logger 的基础结构就有了:

/** * 日志打印工具,统一管理日志输出&上报 */class Logger { /** 命名空间(scope),用于区分所在执行文件 */ private namespace: string constructor(namespace = 'unknown') { this.namespace = namespace }}export default new Logger()

2、可扩展的单例模式

参考 Axios 的设计 ,因此我们还提供 create() 方法,为创建新实例留一个入口方法。

/** * 创建新的 Logger 实例 * * @param namespace 命名空间 * @returns Logger */public create(namespace = 'unknown') { return new Logger(namespace);}

当需要重新定义一个 logger 实例时,就可以参考如下方式:

import logger from '@/utils/logger'const newLogger = logger.create('custom')logger.info(newLogger === logger) // [unknown] false

3、定义“打印”类日志方法

需要区分 info 、 warn 、 error 三种类型的日志,实现如下:

定义日志枚举类型:

const enum LogLevel { /** 普通日志 */ Log, /** 警告日志 */ Warning, /** 错误日志 */ Error,}const Styles = ['color: green;', 'color: orange;', 'color: red;']const Methods = ['info', 'warn', 'error'] as const

private _log(level: LogLevel, args: unknown[]) { if (!__DEV__) return console[Methods[level]](`%c${this.namespace}`, Styles[level], ...args)}/** * 打印输出信息 :bug: * * @param args 任意参数 */public info(...args: unknown[]) { this._log(LogLevel.Log, args) return this}/** * 打印输出警告信息 :grey_exclamation: * * @param args 任意参数 */public warn(...args: unknown[]) { this._log(LogLevel.Warning, args) return this}/** * 打印输出错误信息 :x: * * @param args 任意参数 */public error(...args: unknown[]) { this._log(LogLevel.Error, args) return this}

在 _log() 方法中,通过 __DEV__ 环境变量区分“生产”和“开发”:

if (!__DEV__) return

这种变量可以理解为“ 开关 ”:

生产环境则控制台不输出信息,在实际应用中,可以扩展“是否输出信息”的变量,来针对性扩展,例如线上需要通过特定参数展示调试日志,用于线上定位问题,那么就可以综合多个条件来决定是否输出控制台,毕竟编程最核心的问题是解决需求。

在开发模式下,针对不同的信息类型,会标注不同的颜色:

前端日志管理模块的设计与实现(前端日志管理模块的设计与实现方法)

Chrome 浏览器下的效果

与此同时,在每个“输出”方法中都返回了 this (当前实例),因而便可以为 链式调用方法 提供了使用基础。

4、支持修改 namespace

namespace 最重要的作用是: 区分在不同组件或文件下的日志 ,便于问题定位排查。

由于 Logger 将所有的输出集中到了统一文件,在 console.log() 中文件定位永远是 Logger 类定义实现所在文件,因此需要 namespace 来区分。

新增 setNamespace() 方法:

/** * 设置命名空间(日志前缀) * @param namespace */public setNamespace(namespace = '') { this.namespace = `[${namespace}]` return this}

TypeScript 环境下,会提供代码提示,例如某个文件下输出错误信息的方式。而 setNamespace() 方法,并不是每次都需要调用的,只需在文件中调用一次即可。

5、埋点远程上报

在一些关键时机,例如进入页面、点击“付费按钮”等一些关键操作上,一般会加上一些上报到远程,用于记录用户操作路径,以此便于在出现问题后,复现 BUG 并“对症下药”。

而埋点上报一般有三类:代码埋点、可视化埋点、无痕埋点。

我们这里通过给 Logger 增加远程上报的方式就是代码埋点。

一般情况下,埋点上报属于“前端监控”方面,前端监控是一个独立的管理系统,它的职能是负责前端项目的监控、异常报警等,因此通常会有用于项目集成的前端 SDK

有了 Logger 实例,我们可以在 Logger 中直接统一集成“ 前端监控 SDK ”的主动上报方法即可!

在 Logger 类中新增三个方法:

reportLog()reportEvent()reportException()

/** * 远程上报 * TODO: 根据基建环境自定义扩展 */public reportLog() { this.info() // 用于在本地输出}public reportEvent() { this.info()}public reportException() { this.error()}

至于为什么添加着两个方法,实际是根据“前端监控 SDK”提供的 api 来决定

例如常见的 “Sentry – 应用监控错误溯源” 平台,针对主动上报,提供了三种方法,通常为了保持一致性,降低心智负担,因此新增对应的三个上报方法。

具体的上报参数和逻辑,则需要大家根据自己的业务区扩展。

五、Logger 的可扩展性 ⚙️

从上面 Logger 类的实现,可以发现一个明显的问题,如果业务需要扩展功能,则需要修改 Logger 类内部的方法,Logger 类中的方法和逻辑,我们可以理解为是所有业务都通用的,业务定制化的功能应该通过额外扩展方式来完善。

那有没有什么办法,可以实现不修改方法,而扩展 Logger 的功能呐?

1、扩展方案

有几个方案:

  1. 继承 Logger 类扩展。
  2. 增加回调函数作为参数。

个人推荐第二个方案,但如果每一次调用,都按照如下方式:

logger.info('message', () => {})

但这种设计比较粗糙

2、拦截器

参考 Axios 的拦截器设计,也就是 AOP(面向切面编程模式)的设计思想,来扩展 _log() 方法。

新增类型申明:

/** * 日志的配置类型 */type LoggerConfigType = { /** 命名空间 */ namespace?: string}/** * 拦截器函数类型 */type InterceptorFuncType = (config: LoggerConfigType) => void

将 Logger 的配置集中的 config 私有变量中,并新增 addBeforeFunc() 和 addAfterFunc() 两个方法,用于新增自定义“拦截器”函数

前端日志管理模块的设计与实现(前端日志管理模块的设计与实现方法)

其中一个细节是,日志打印之后的拦截器,按照 FCLS (First Come Last Serve,先到后服务)的策略,和 Axios 的响应拦截器执行顺序对齐,与此同时,拦截器函数中会注入当前 Logger 的 config 配置。

通过简单的“ 拦截器 ”,即可实现功能的扩展,这种方式的功能扩展不会影响到主体功能,后期的维护升级是无侵入性的,还算比较优雅的,是吧!

3、其他方案

这里还可以考虑更多设计,例如参考 发布订阅设计模式 来改造,通过生命周期的关键点,被动触发,主动通知并执行所有订阅了对应消息的事件,可以参阅《 聊一聊发布订阅设计模式》

也可以用 插件模式 方式来实现扩展,类似发布订阅模式,给 _log() 函数添加执行的钩子函数 (回调函数),例如这种设计下,把“埋点上报”等功能拆分成插件,再实现一个简单的事件队列模型,集成一下子!

六、总结

至此,一个基本的日志工具就实现完成了,但并未完完全全遵守设计原则,这里在生产实践中还需要封装、抽离相应“职责”,增加可维护性。

在团队中以此作为基础结构,然后针对团队、项目、业务的特点做适当的扩展,构建符合当前团队特性的通用日志工具模块,应该也不是什么难事!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

(0)
上一篇 2022年11月12日 上午8:41
下一篇 2022年11月12日 上午8:43

相关推荐

  • 今年青海省畜牧业生产形势良好增产已成定局

      青海新闻网讯 今年,我省紧紧结合各地实际,采取草地生态畜牧业建设和农区畜禽规模养殖发展“双轮”驱动,狠抓有机畜产品生产基地建设和牦牛、藏羊高效养殖技术推…

    科研百科 2022年6月7日
    290
  • 医院项目结题延期申请理由

    医院项目结题延期申请理由 尊敬的评审专家: 我是XXX医院的XXX,代表医院向评审专家提交本次医院项目结题延期申请。 本次医院项目由我们医院的医生和技术人员组成,旨在为病人提供高质…

    科研百科 2024年10月4日
    20
  • 党建活动经费列入行政预算

    党建活动经费列入行政预算 近年来,随着全面从严治党的深入推进,党建活动经费已经成为各级组织部门的重要预算之一。作为党的组织建设的重要支出,党建活动经费的列入能够更好地保障党员和组织…

    科研百科 2024年11月15日
    1
  • 华阴公安交警机关党支部:强化措施 突出重点 彰显党建工作成效

    渭南政法网(通讯员 潘化团)今年以来,华阴市公安局交警大队机关党支部按照市局党委和大队党总支的总体部署要求,围绕党建工作中心和重点,强化组织领导,狠抓措施落实,积极创新工作模式,深…

    科研百科 2024年2月7日
    125
  • 使用项目管理

    使用项目管理 项目管理是一种有效的工具,可以帮助组织实现目标并提高效率。它涉及到规划,执行和控制项目的过程,确保项目在规定的时间,预算和范围内完成。使用项目管理可以帮助组织实现其目…

    科研百科 2024年8月12日
    52
  • penetwork

    penetwork: 探索智能合约与区块链结合的未来 随着区块链技术的发展,智能合约已经成为越来越多业务领域中的应用。而penetwork则是一个将区块链技术与物理世界结合的工具,…

    科研百科 2025年1月2日
    0
  • 市政道路排水施工(市政道路排水工程科研项目)

    市政道路排水工程科研项目 随着城市化进程的不断推进,市政道路排水工程作为城市基础设施建设的重要组成部分,越来越受到人们的关注。在道路排水系统中,排水系统是最为重要的一部分,其设计、…

    科研百科 2024年4月5日
    137
  • 部队档案管理系统

    部队档案管理系统 随着军队规模的不断发展,部队档案管理系统成为了军队管理中不可或缺的一部分。一个有效的部队档案管理系统可以帮助军队管理其文件、文件记录、文档和资料等,确保部队信息的…

    科研百科 2024年5月31日
    72
  • 抖店批量邀约达人软件 抖店无货源 自动批量邀约达人软件(抖音达人批量邀约)

    目前在精选联盟的达人广场,商家可以通过发送邀约来联系达人,而且每天可以发送1000条邀约。如果人工去邀约的人,找达人,筛选商品,发送消息,一个人一天也发送不了多少邀约。这个时候我们…

    科研百科 2023年4月17日
    479
  • 青海生态畜牧业合作社达 961个

      日前,记者从青海省生态畜牧业建设十周年总结大会上获悉,经过10年的艰辛探索与实践,青海省坚持以组建生态畜牧业合作社为切入点,合理利用草地资源为基础,转变生产经营方式为核心,建立…

    科研百科 2022年5月14日
    363