正经人谁写日记啊?

img

欸欸欸,不好意思,来错片场了(手动狗头)。今天介绍的是项目中必不可少的一部分——日志。

日志系统

虽然正经人不写日记,但是正经项目一定要记录日志。总所周知啊,Gohub 就是一个非常正经的项目,虽然还没有到企业级这么高的层次,但是也差不多了。

在 Gohub 中,我们使用日志来记录整个系统的运行情况,可能但不限于:

  • HTTP 请求数据
  • 数据库 SQL 请求日志
  • Panic/Error 错误日志
  • 请求第三方接口日志(发送短信、发送邮件等)
  • ……

好了,是时候掏出祖传的几个问题了,什么是日志?该怎么设置日志?下面将会一一解答。

什么是日志

日志系统是一种记录系统活动、事件或消息的工具或机制。在计算机领域,日志系统通常用于记录应用程序、操作系统或者其他软件系统的运行时信息。这些信息可以包括错误、警告、调试信息、用户操作记录等等。

日志系统的主要目的是帮助开发人员或管理员了解系统的状态和运行情况,以便进行故障排除、性能优化、安全审计等工作。通过分析日志,可以追踪问题的根源,监视系统的健康状况,并且可以在系统发生故障或异常时进行及时的响应和处理。

日志系统通常具有以下特点:

  1. 可配置性: 可以根据需求配置日志记录的级别、格式、存储位置等参数。
  2. 实时性: 能够实时记录系统的运行状态,以便及时发现问题。
  3. 可扩展性: 能够处理大量的日志数据,并支持水平扩展以应对不断增长的系统负载。
  4. 安全性: 对日志数据进行安全存储和访问控制,以防止未经授权的访问或篡改。
  5. 分析性: 提供日志分析工具或接口,帮助用户对日志数据进行搜索、过滤、统计、可视化等操作。

常见的日志系统包括开源项目如ELK Stack(Elasticsearch、Logstash、Kibana)、Splunk、Fluentd等,以及云服务提供商提供的日志管理服务。

使用场景

本地开发

本地开发时,虽然我们可以很方便地使用 Debuger 来调试程序,但是日志将会是我们最廉价】最便捷地作物定位工具。

线上环境

日志是程序在生产环境下的健康监控。当程序出错时,或者某块业务逻辑出现问题,我们将依赖日志来知道具体哪一行代码出了问题。

如何记录?

使用环境 记录的载体 说明
开发环境(local) 命令行终端 高亮、打印调用堆栈
线上环境(production) 记录到日志文件 JSON 格式,方便导入专业的日志工具

日志系统在计算机领域有广泛的使用场景,以下是一些常见的应用场景:

  1. 故障排查与调试: 当系统出现错误或异常时,日志可以记录错误信息、异常堆栈跟踪等,帮助开发人员快速定位并修复问题。

  2. 性能优化: 通过分析系统的性能日志,可以了解系统各个组件的性能瓶颈,从而进行优化,提升系统整体性能。

  3. 安全审计与监控: 日志记录系统的操作、访问权限、安全事件等信息,有助于进行安全审计和监控,及时发现潜在的安全威胁。

  4. 用户行为分析: 在网络应用或移动应用中,记录用户的操作行为可以帮助分析用户偏好、行为趋势,从而进行个性化推荐、用户体验优化等工作。

  5. 合规性需求: 许多行业或政府监管机构要求企业记录和保留特定类型的数据,日志系统可以满足这些合规性需求,并提供必要的审计跟踪。

  6. 容灾备份与恢复: 日志记录系统的备份和恢复功能可以帮助恢复因硬件故障、自然灾害或人为错误导致的数据丢失或损坏。

  7. 业务分析与决策支持: 通过分析系统产生的日志数据,可以了解业务运营情况、用户行为趋势等,为业务决策提供数据支持。

  8. 监控与警报: 基于日志数据设定监控规则,当系统出现异常或达到预定的阈值时,触发警报并通知相关人员进行处理。

这些场景只是日志系统的一部分应用,实际上日志系统在各个领域都有着重要的作用,帮助保障系统的稳定性、安全性和可靠性。

日志的等级

日志系统通常定义了不同的日志等级,用于标识和区分不同类型的日志信息,常见的日志等级包括:

日志等级 说明
debug 信息量大,一般调试时打开。系统模块详细运行的日志,例如 HTTP 请求、数据库请求、发送邮件、发送短信
info 业务级别的运行日志,如用户登录、用户退出、订单撤销。
warn 感兴趣、需要引起关注的信息。 例如,调试时候打印调试信息(命令行输出会有高亮)。
error 记录错误信息,用于记录程序发生的错误,这些错误可能导致程序无法正常工作,但不会使程序完全崩溃。Panic 或者 Error。如数据库连接错误、HTTP 端口被占用等。一般生产环境使用的等级。

日志等级规则:

  • 日志等级在两个地方使用;
    • 配置信息(config)中可以配置日志等级;
    • 代码中调用不同的方法(Debug()Info()…)记录不同等级的日志。
  • 日志等级具备过滤信息的属性;
  • 配置信息里设置为高等级时,低于这个等级的信息将忽略。如日志等级设为 warn ,只有 Warn()Error() 方法记录的日志会有效,Debug()Info() 方法记录的日志会被忽略;

日志过载

日志过载是指日志系统产生的日志数量超出了处理能力或存储容量,导致系统无法有效地处理和存储所有的日志信息。这种情况可能会对系统的性能、稳定性和安全性造成负面影响。

日志过载可能出现在以下几种情况下:

  1. 异常情况爆发: 当系统遭遇大规模的异常或错误时,日志系统可能会产生大量的错误日志,导致日志系统过载。

  2. 频繁的警告信息: 如果系统产生大量的警告信息,而这些警告信息又被记录在日志中,就会增加日志系统的负担。

  3. 日志频率过高: 如果系统的日志频率过高,比如记录了过多的调试信息或者每个请求都生成了大量的日志记录,就会导致日志系统过载。

  4. 存储容量不足: 如果日志系统的存储容量不足以存储所有的日志数据,就会导致部分日志被丢弃或被覆盖,从而丧失了一部分重要的信息。

  5. 日志记录不当: 如果日志记录的内容过于冗长或者包含了大量的无关信息,会增加日志系统的负担,导致日志过载。

日志过载可能会导致以下问题:

  • 性能下降: 过多的日志记录会占用系统资源,降低系统的性能和响应速度。
  • 数据丢失: 如果日志系统无法处理所有的日志数据,部分重要的日志信息可能会被丢弃,导致问题的排查和分析变得困难。
  • 安全风险: 日志过载可能会导致系统无法及时记录和响应安全事件,增加系统遭受攻击的风险。

为了避免日志过载,需要合理配置日志系统的参数,包括日志等级、存储策略、日志格式等,并定期清理和归档历史日志数据,确保日志系统能够有效地处理和存储日志信息。

记录日志的行为完全掌控在开发者手上。日志等级的错误使用,会导致日志信息过载,有违『快速定位问题』的设计初衷。

所以记录日志时,参与项目的开发者之间需要做好约定,或者说规范

  • 功能模块的详细运行情况,使用 Debug() 方法,如 HTTP 请求日志、数据库 SQL 日志;
  • 业务级别的运行日志,使用 Info(),如果信息量太大,例如说一个请求会记录十几条 Info() 日志,要改用 Debug()
  • 控制好记录日志的量,切勿滥用,滥用会导致日志信息过载;
  • 开发调试时,使用 Warn() ,调试完成后记得删除调试信息;
  • 保持 warn 及以上日志级别的干净;
  • 线上环境开启 error 等级,接到错误反馈时,再开启 debug 进行调试,调试完成后重新设置为 error 等级,保持线上日志的干净;
  • 系统运行出错,才能使用 Error() 记录,如数据库连接出错,或出现 500 错误。

杂项

.gitignore 文件

在开发 Go 项目时,我们的项目目录下经常会出现一些文件,例如编译文件、log 文件、编辑器配置文件、系统生成的一些文件,这些文件我们不希望提交到代码仓库中。

在任何当前工作的 Git 仓库中,每个文件都是这样的:

  • 追踪的(tracked)- 这些是 Git 所知道的所有文件或目录。这些是新添加(用 git add 添加)和提交(用 git commit 提交)到主仓库的文件和目录。
  • 未被追踪的(untracked) - 这些是在工作目录中创建的,但还没有被暂存(或用 git add 命令添加)的任何新文件或目录。
  • 被忽略的(ignored) - 这些是 Git 知道的要全部排除、忽略或在 Git 仓库中不需要注意的所有文件或目录。本质上,这是一种告诉 Git 哪些未被追踪的文件应该保持不被追踪并且永远不会被提交的方法。

所有被忽略的文件都会被保存在一个 .gitignore 文件中。

.gitignore 文件是一个纯文本文件,包含了项目中所有指定的文件和文件夹的列表,这些文件和文件夹是 Git 应该忽略和不追踪的。

.gitignore 中,可以通过提及特定文件或文件夹的名称或模式来告诉 Git 只忽略一个文件或一个文件夹。也可以用同样的方法告诉 Git 忽略多个文件或文件夹。

配置信息的设置

在项目中,配置信息通常指的是一些参数、选项或设置,这些信息用于指导项目的行为、功能或外部依赖的配置。

Gohub 中的配置信息,将分为两个层级:

  • env
  • config

.env

一般来讲,项目会运行在多个环境下,例如:

  • local —— 本地开发环境(我的机器上、其他开发同事的机器上)
  • testing —— 自动化测试环境
  • stage —— 接近线上环境的测试环境,方便其他成员访问和测试(编辑人员、产品经理、项目经理)
  • production —— 线上生产环境

不同的环境下,我们将使用不同的配置。例如 local 环境里,发送短信使用的是测试账号,production 环境下,我们将使用验证了公司信息的发信账号。

.env 文件通常用于存储环境变量和敏感配置信息,它的作用包括:

  1. 配置管理: .env 文件可以用来集中管理项目的配置信息,如数据库连接信息、API 密钥、密码、密钥等。将这些配置信息存储在 .env 文件中有助于统一管理,减少硬编码,提高项目的灵活性和可维护性。
  2. 环境分离: 使用 .env 文件可以将不同环境(如开发环境、测试环境和生产环境)的配置信息分离开来,避免在代码中硬编码不同环境下的配置,提高代码的可移植性和可重用性。
  3. 安全性: .env 文件通常位于项目根目录之外,并且可以通过 .gitignore 文件排除在版本控制系统中,从而保护敏感信息不被泄露到公共代码仓库中,提高项目的安全性。
  4. 便捷性: 通过 .env 文件,可以方便地修改和管理项目的配置信息,无需修改源代码,减少了部署和维护的复杂性。
  5. 跨平台兼容性: .env 文件的格式通常是简单的键值对格式,易于解析和处理,可以跨多种编程语言和操作系统使用。

单独的 .env 的设计,是满足一台机器一套环境变量的需求。多个 .env 文件是满足一台机器上运行多套环境变量的需求

开发时,除了 local 环境变量,很多时候还需要 testing 测试相关的环境变量,testing 的配置有别于 local 。例如测试时,一般需要使用不同的数据库,这样才能不污染我们的开发数据库。

我们可以利用程序参数,在命令行运行主程序时,传参 --env=testing 的参数,程序接收到这个参数后会读取 .env.testing 文件,而不是 .env 文件。

--env 的参数不需要限制值,取到以后直接读取对应的文件即可。以下是几个例子:

  • --env=testing 读取 .env.testing 文件,用以在测试环境使用不同的数据库
  • --env=production 读取 .env.production 文件,用以在本地环境中调试线上的第三方服务配置信息(短信、邮件)

config

config 是将配置信息存放于 config 目录下,按照单独的逻辑区分单独的配置文件,例如数据库连接信息存放于 config/database.go 文件下。

config 里加载 .env 里的配置项,且可设置缺省值。

既然有 .env 文件,为何还要 config 呢?

config 可以提高配置方案灵活度。在 config 里,我们可以为每个配置项设置默认值。也可以做一些简单的数学运算,或者调用 Go 函数进行默认值的处理。我们甚至可以为配置项设置一个回调函数。

config 文件是要加入代码版本控制器中的,这些代码是固定的。如果要修改一个 config 配置项,就修改其对应的 .env 文件中的配置项即可。

总结

本文较短,主要记录了在 Gohub 开发设计日志时学到的相关的知识。其实在这个项目中用户使用的功能并没有什么太大的变化,即使增加了一些功能也都只是一种变式,核心并没有发生太大的变化,因此也就没有像之前一样逐个功能地去记录。那为什么还要去做新的项目呢,主要是因为舍友吧两个教程都买了,白嫖完了第一个肯定要继续白嫖第二个了。

做完第二个项目发现虽然一个叫 Gohub,一个叫 Goblog,两个看起来好像一样,但是实际开发地体验简直就是天上地下。Goblog 入门项目开发,学习怎么搭建 Web 应用;Gohub 才是真正的后端开发,更加专业,也让我学到了更多的东西。后悔啊,为什么上学期开始学 Go 的时候不好好写项目呢,要不然面试的时候也不会被拷打的那么惨了。不过这两个月确实还是学到了不少东西,比前两年半(没有玩梗,非常认真)加一起的都多了。

参考文献

传统艺能了,每篇文章都像一个模子里刻出来的,不过本文并没有参考什么文章,只参考了教程和 ChatGPT的回答。