编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

Linux 软件开发人员指南:16 监控应用程序日志

wxchong 2024-11-02 13:54:10 开源技术 42 ℃ 0 评论


欢迎来到Linux日志记录的世界!作为软件开发人员,理解Linux中的日志记录,特别是使用systemd和journald这样的工具,是至关重要的。以下是您需要了解的概要。

日志是记录在软件应用程序或操作系统中发生的事件的记录。它是一种灵活的格式,对每个应用程序都是独特的,但日志的处理、存储和检索在现代系统上更加统一。作为开发人员,您需要理解日志,因为在Linux中可以访问的日志提供了对操作系统及其上运行的所有应用程序行为的洞察。您将利用这些知识来理解错误、跟踪应用程序性能和调试。日志是您在故障排除中的第一道防线,因此请准备好熟悉它们。

在本章中,我们将为您提供Unix和Linux日志记录的概述,并展示软件开发人员与日志交互的最常见的方式。您将看到:

系统和在其上运行的应用程序如何发出日志

在大多数现代Linux系统上,日志收集的位置

关于过去日志记录方式的一些历史知识,这在您将遇到的许多生产系统上仍然有用

在您排除应用程序故障时如何查找和查看日志

公司如何集中日志,以及在云环境中部署服务时的情况

我们还将提供一些提示,帮助您充分利用结构化日志记录,同时避免开发人员经常陷入的一些常见陷阱。

日志记录介绍

正如我们在介绍中看到的,日志只是信息性消息——记录在软件应用程序或操作系统中发生的事件。像许多Unix概念一样,很少有严格的规则:如果您编写了一个将时间戳写入文本文件的两行脚本,那可能就算作日志。一些日志是发送到系统上众所周知的文件位置的简单纯文本字符串,而其他日志则是由systemd等守护进程专门管理的高度结构化的二进制数据。

作为开发人员,您可能熟悉日志级别,这是表示软件中事件紧急性的标签。想想“错误”、“信息”和“调试”消息,您肯定在开发软件时在终端看到它们滚动过去。我们稍后将介绍这些常见的日志级别,但现在,您应该意识到现代、功能齐全的Linux环境中有三个主要的日志来源:系统、服务和非服务应用程序日志。日志的来源可以为您提供有关特定日志消息中发生的事情的重要上下文信息。

系统日志是由操作系统(“内核”)本身发送的日志。这些包括错误、关于硬件事件的消息、资源消耗和限制、配置和安全以及系统状态的值得注意的变化。

服务日志是由系统上运行的服务发出的。具体来说,在Linux上,它们是由systemd init系统管理的服务发出的,该系统通过名为journald的服务进行日志记录。它们可以提供对各种服务的健康状况和状态的洞察。

在您可能遇到的系统上,系统和服务日志都混合在journald中。我们将在本章中学习有关systemd和journald(以及journalctl)的所有内容。

非systemd管理的应用程序是不符合常规的,通常不通过journald进行日志记录。您将不得不通过每个应用程序的文档找到它们的日志文件,尽管表现良好的应用程序通常会在如/var/log/$APPLICATION_NAME/的目录中写入自己的日志文件,其中$APPLICATION_NAME是应用程序的名称。

当我们在本章中进行时,理解journald和journalctl命令的重要性将变得显而易见。然而,在我们深入之前,我们应该注意到Linux日志记录的一些细节。

Linux上的日志记录可能会变得...奇怪

您现在已经看到了,类Unix系统非常灵活。如果您不喜欢默认的做事方式,您可以打破传统,并配置事物以您想要的方式工作。

当您学习Unix和Linux的基础知识时,这也是一个巨大的缺点。许多事情——从软件配置到默认用户设置——可以以许多不同的方式配置,除了询问(有时,故障排除)之外,没有办法知道新环境中的惯例是什么。

在日志记录方面尤其如此,由于公司计算方式的最新变化,日志记录受到了特别的影响。几十年来,日志记录都以某种方式完成,当时大多数公司直接购买、配置和管理长期存在的物理服务器,这些服务器上安装了单个操作系统。随着工作负载转移到云中,事情转移到每个物理机器上运行多个操作系统(虚拟机)甚至每个操作系统上运行多个环境(容器),传统的日志记录工作方式也发生了变化。

这一切都是为了说,当您在新工作或团队中弄清楚日志记录时,问题不是“Linux上的日志记录是如何完成的?”而是“这里目前是如何完成日志记录的?”这实际上取决于您使用的软件的开发者所做的决策。在本章中学习日志记录时,我们建议您记住这一点。

发送日志消息

虽然在大多数情况下,服务将通过库记录,或者简单地写入stdout,但类Unix系统提供了一个命令,该命令将日志记录到syslog服务器。我们将在下面看看这意味着什么。由于syslogd和systemd无论您使用什么样的系统都提供了一个syslog服务器,因此有一个统一的命令发送日志消息:

logger Hello World!

这将记录Hello World。logger命令有许多选项,当调试任何问题时,它可能是一个有价值的工具,当您想要在shell脚本中记录日志,或者当您解释日志记录的工作原理时。

systemd日志

当系统使用systemd时,journald接管了日志记录方面。当您排除运行systemd的Linux机器的故障时,这是您应该首先查找日志的地方。默认情况下,journald捕获所有受监督进程的所有输出。在stderr上发出的任何内容都被视为错误。因此,除非软件被配置或硬编码为记录到不是stderr/stdout的位置,否则您将在systemd日志中找到日志。

记录到journald的日志可以通过journalctl命令进行查询。它提供了一种基于个别服务、时间和系统重启的查询方法,并允许使用类似于tail命令的选项。让我们开始练习使用journalctl。

示例journalctl命令

使用journalctl的基础知识很简单。想想看;当您排除应用程序的故障时,您需要能够对它的日志做什么?

首先,您将想要能够找到并查看当前的日志集。journalctl将为您提供这一点,但您很快就会意识到您实际上并不想要所有日志,只是最近的日志。因此,让我们使用-n标志进行过滤。

要查看journald中最后100条日志消息,请尝试此命令:

journalctl -n 100

这将打印出系统记录的最后100行。您会注意到,这与本书前面解释的tail命令类似。如果您跟随了,这些行可能包含上面的“Hello World!”消息。

跟踪单位的活跃日志

您可能还想实时查看日志。例如,在启动期间跟踪应用程序日志可以帮助您确切地看到何时出现问题:

journalctl -fu unitname

-f标志代表“跟随”,-u标志代表“单位”——您要过滤日志的系统单位(或“服务”)。

按时间过滤

即使您过滤到特定的单位,您可能仍然会被匹配的日志数量所淹没。在此处按时间过滤可能会很有用,特别是当您尝试将已知的外部问题(停机、错误等)与从那一刻开始的应用程序日志相关联时。为此,请使用--since和--until:

journalctl --since "2021-01-01 00:00:00"

您也可以使用一些简写,例如今天:

journalctl --until today

您也可以使用–until设置过滤的结束时间,并将这些组合起来以获得相当具体的过滤。例如:

journalctl --since "2021-01-01 00:00:00" --until "1小时前"

注意

查看和按时间过滤日志的一个注意事项是,您几乎总是希望使用journalctl的--utc选项,该选项以UTC显示时间戳。当您帮助运维团队排除停机故障时,这几乎完全是使用UTC时间进行的,以防止时区相关的混淆。

还有其他过滤器,用于用户/组ID等。

过滤特定日志级别

如果您知道您正在寻找错误,您可以告诉journalctl只向您显示错误(或在https://wiki.archlinux.org/title/Systemd/Journal#Priority_level 中列出的任何其他日志级别,按关键性的降序排列:emerg、alert、crit、err、warning、notice、info、debug):

journalctl -p err

检查上一次启动的日志

有时事情变得非常疯狂,一个故障实际上会导致重启。在这些情况下,您将想要查看系统上一次启动的日志。您可以使用--list-boots查看所有可用的启动:

journalctl --list-boots

然后使用-b参数从列表中选择特定的启动。在这种情况下,我们想要标记为2的启动:

journalctl -b –2

-b标志本身意味着“当前系统启动。”

内核消息

在介绍中,我们提到系统级日志消息是由操作系统(在Linux术语中为“内核”)发送的。要仅查看这些消息,请使用--k(或出于历史原因,使用--dmesg)标志。

Docker容器中的日志记录

在Docker容器中,处理日志的最常见方式是简单地假设容器的主进程是我们想要输出的进程,并且它正在将日志记录到标准输出(stdout)。容器编排器(即Kubernetes和Nomad等工具),以及负责执行容器的各种云服务,将假定stdout是相关日志将去的地方,并根据配置相应地转发。我们将在下面的集中日志记录部分中更详细地讨论这一点。

Syslog基础知识

与我们向您展示的systemd/journald日志记录相比,syslog可能看起来有点过时。我们宁愿认为它有着悠久的历史——尽管自20世纪80年代以来就已经存在,但它仍然是一个有用、灵活且广泛使用的日志记录工具。更重要的是,您几乎可以肯定在真实的生产系统上遇到它,因此了解基础知识以避免在时间紧迫的停机期间措手不及是值得的。

在类Unix系统上,向syslog记录日志通常等同于向/var/log中的文件记录,大多数消息通常发送到/var/log/messages。然而,请记住,/var/log中的并非所有内容都一定通过了syslog。各种软件还实现了它们自己的写入日志文件的方式,完全跳过了syslog守护进程。

这通过syslog摄取所有发送给它的日志,根据各种参数(如下文提到的设施)将它们输出到文件中。在几乎所有系统上,这的默认值是/var/log/messages。如果您按照上述操作,并且您的系统使用syslog,那么您也会在这里找到上面的“Hello World!”消息。

Syslog是日志记录的标准化协议。虽然,在撰写本文时,syslogd主要处理日志行,但当前的标准[RFC 5424]也允许进行结构化日志记录。然而,由于这并不广泛支持,我们将简要介绍其作为基于行/消息的日志记录协议的基本概念。如果您根本不与syslog交互,可以跳过本节。

如前所述,syslog是一个协议。虽然它最常用于软件,例如想要在本地记录日志的数据库,但生产设置通常有一个集中的日志服务器,日志会被发送到那里。作为一个协议,各种软件(如PostgreSQL、nginx等)可以使用此协议发出日志,各种与日志相关的软件,如Logstash、Loki、syslogd、syslog-ng等可以摄取其日志。它通常使用端口514(UDP)或端口6514(TCP)。

设施

由于syslog是20世纪80年代的一个非常古老的协议,它的一些概念可能看起来过时。它使用预定义的设施来指定日志消息的类型。每个设施都有自己的代码:

0: kern - 内核消息。

1: user - 用户级消息。这些通常由进程使用。

2: mail - 邮件系统。邮件服务器、SMTP、IMAP和POP3最有用。与垃圾邮件相关的守护进程和软件通常在这里记录日志。

3: daemon - 系统守护进程。与操作系统(如NTP)相关的守护进程在这里记录日志。

4: auth - 安全/认证消息。您通常会在这里找到登录尝试,例如,通过SSH在本地登录,但也可以是各种其他服务。

5: syslog - 由syslogd内部生成的消息。这些将与syslog本身相关的消息。

6: lpr - 行打印机子系统。与打印机相关的日志。

7: news - 网络新闻子系统。这是历史上的,不再典型使用。

8: uucp - UUCP子系统。这是历史上的,不再典型使用。

9: cron - Cron子系统。与cron作业相关的日志。这些对于调试cron作业非常有用。

10: authpriv - 安全/认证消息。这与auth类似,但通常被认为记录在一组更受限制的目标中。大多数Linux软件在这里而不是auth中记录日志。

11: ftp - FTP守护进程。大多数是历史上的。FTP服务器的日志。

12: ntp - NTP子系统。网络时间协议(NTP)的日志,即时钟同步。

13: security - 日志审计。与安全相关的事件。

14: console - 日志警报。与“本地控制台”相关的消息。

15: solaris-cron - 时钟守护进程。

16到23: local0到local7 - 用于本地的设施,即本地软件。例如,PostgreSQL在记录到syslog时,默认记录到local0。

在许多系统上,您将发现/var/log/中的文件与这些设施的名称类似。因此,例如,如果您需要调试一个不使用journald的系统上的cron作业,您很可能会找到输出在/var/log/cron、/var/cron/log、/var/log/messages或类似的文件中。

请记住,在每个设施中记录的确切内容并没有标准化。您可能会遇到不同操作系统或类似软件可能不同意记录到哪个设施的情况。

严重性级别

这是一个您可能更熟悉的概念。消息带有七个不同级别之一的严重性:

0: emerg - 紧急

0: alert - 警报

0: crit - 严重

0: err - 错误

0: warning - 警告

0: notice - 通知

0: info - 信息

0: debug - 调试

与设施一样,每个严重性级别究竟是什么取决于所使用的软件。

配置和实现

Syslog有许多实现。这些通常允许您根据设施和严重性级别配置过滤,并保存和转发消息。一些系统带有名为syslogd、rsyslog或syslog-ng的服务,可以在/etc/syslog.conf、/etc/syslog-ng/中配置。Loki、Logstash和其他分布式日志管理工具各自有它们自己的日志记录配置方式,通常在一个三重结构中,一个地方定义输入,另一个过滤和转换,第三个存储或转发输出。

日志记录技巧

每个人的日志记录方式都略有不同,而且什么被认为是最佳实践可能因项目和时间而异。然而,有一些您应该意识到的事情。

在使用结构化日志记录时的关键字

当使用任何类型的结构化日志记录时,尝试确保共享常见的关键字,如请求和用户ID,同时也尽量避免为类似但不是完全相同的事情使用冲突的关键字。根据后端数据库,您也可能在这里遇到类型问题,例如,在用户可能是整数、字符串或其自己的嵌套结构(如JSON对象)的键的情况下。

有时,通过为每个服务创建命名空间,并保留一份“全局使用”的键列表及其定义,可以避免任何重叠。

严重性

在开发软件时,有一个内部文档解释哪个严重性具有哪个含义是有意义的。这避免了像公开可访问服务的失败登录尝试,或爬虫请求过时网站的404错误代码等情况引发警报,并在半夜唤醒同事。但即使不是这样,它也可以使调试和了解问题变得更容易。

因此,明确区分以下情况是个好主意:

可能表明有问题的情况

不应该发生,但可能发生的情况

清楚表明错误或更严重问题的情况

随着软件的发展和添加服务,日志往往会变得更加复杂,因此从一开始就清楚地了解要记录什么以及何时记录是一个不错的投资。

集中日志记录

在企业环境中,通常会集中日志记录。这样做更容易在调试问题时连接点。这也意味着在分布式应用程序中,不必单独查看每个物理或虚拟机或容器上的每个日志。这些集中日志记录服务通常使查询大量日志变得容易和快速,特别是当公司使用结构化日志记录和服务遵循统一的日志结构时。

这些日志记录服务要么是它们自己的产品,如rsyslog、Loki、ELK堆栈(Elastic Search、Logstash和Kibana)和Graylog,要么是托管服务。例如,它们可以是刚刚提到的服务的托管变体,或特定于云的日志记录解决方案,如Google的操作套件(以前称为Stackdriver)、AWS CloudWatch或Azure Monitor。这些系统之间有许多相似之处,它们提供了从文件“运输”日志或通过某种API运输日志的机制,过滤和重构它们,最终将它们保存到最终存储中,准备被查询。

在微服务架构中,传递上下文(如请求ID)是很常见的,这样客户端的请求就可以轻松地通过各种服务进行跟踪,这对于调试涉及许多服务的架构至关重要。

如前所述,这些系统大多数都有将日志运输到中央日志服务器或集群的机制。它们被称为Logstash(ELK堆栈中的L)和Promtail(与Loki一起使用),通常提供多种摄取日志的方式。例如,它们可能被配置为创建HTTP服务器,充当syslog服务器,接入journald,读取任何其他日志运输服务,使用云API,或简单地尾部文件。它们要么作为系统的额外守护进程运行,作为Kubernetes中的Pod,或作为Nomad设置的一部分。由于它们旨在使用任何软件允许集中日志记录,它们倾向于允许各种日志输入,并且在设置方面通常非常灵活——例如,允许通过在各个日志运输服务之间转发来创建层次结构。在像Kubernetes和Nomad这样的容器编排器上,这通常是通过一个“边车容器”实现的,该容器与您的应用程序容器一起运行,并在将日志运输到目的地之前从Pod/分配/节点中的所有容器捕获日志。


正如你所看到的,尽管有许多技术和产品围绕着日志记录,但它们都可以归入上述至少一个类别,所以当你在环境中集中日志记录时,这应该让你了解各个部分是如何相互关联的。

结论 日志记录在现代生产环境中可能是一个不断变化的目标。学习和试验本章涵盖的基础知识应该能为你提供良好的基础。我们希望,熟悉syslog和journalctl也将为你提供低层次的理解和历史视角,这将使你更容易理解未来的日志记录即服务解决方案实际上是如何在幕后工作的。

我们认为你将发现,你在本章学到的技能在设计、调试和优化你创建和部署的应用程序时,给了你一个实用、可衡量的优势。正如你所看到的,掌握journald的基础知识,可以让你迅速诊断和确定问题,无论是与你的应用程序具体相关还是与更大的Linux系统相关。对替代的和历史上的Linux日志记录方法有一些了解,将帮助你在故障排除系统(或长时间没有更新的人)时。

这不仅仅是关于解决问题;这也关于让你的生活更容易,让你的工作更好。此外,这是一项让你脱颖而出的技能。简而言之,熟悉Linux日志记录使你成为一个更聪明、更有效的开发人员。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表