systemd Journal

Lennart Poettering 发表长篇文档介绍 systemd 即将添加的新功能:Journal。

介绍 Journal

今天将为您介绍在过去的几周我们在致力实现一个 systemd 的新功能。这项新功能同时将帮助我们显著的简化最小化安装的 Linux 系统,同时带来一些新的概念,也会取代一个经典 Unix 系统中的部件。因此它需要一个比较长的介绍。所以请准备好一杯热巧克力,慢慢阅读。

背景:syslog

长久以来 syslog 是每一个 Unix 系统中的重要部件。在漫长的历史中在各种 Linux 发行版中都有不同的实现去完成类似的工作,它们采取的是逻辑相近,并使用基本相同的文件格式。

如其名所述,syslog 守护进程的任务是系统记录。它从应用程序和服务中获取格式各异的日志消息并保存到磁盘上。通常,这些消息唯一的元数据是组件名、优先级、时间戳、进程标签和 PID。这些属性由客户端传入,不经过验证就直接原样保存。很多这些属性都是可选的,不同的实现中具体的格式也是有很大变化的。有个 RFC 尝试逐渐改进和规范化消息格式,但是最重要的实现(比如 glibc’s syslog() 调用)基本无视了这些改进。

现实中,宽松的 syslog 日志消息格式带来了灵活和强大,但同时也成为它最大的不足。因为没有定义结构化的格式,系统的分析和日志消息处理变得十分混乱:在将其翻译为人类语言的过程中大量与消息生成源相关的上下文都丢失了。而且还有很多日志分析器会尝试通过分析人类语言来重构上下文。

Syslog 已经存在了差不多 30 年了,由于它的简单和普遍,成为系统管理员的一个重要工作。但是它切实存在的局限开始导致一些严重的问题:

  1. 消息的内容无法验证。每一个本地进程都可以声称自己是 Apache PID 4711,而 syslog 也就相信并保存到磁盘上。
  2. 数据格式散漫。自动化的日志分析器需要分析人类语言字符串来 a) 识别消息类型;b)分析其中的参数。这会导致灾难性的运用正则表达式,同时也意味着需要不断的跟进上游开发者,以免他在新版本中改变了哪怕一点点人类语言日志字符串。于是在这种方式下,为了不影响用户自定义的正则表达式,所有的日志消息将成为软件的 ABI,而这通常并不是开发者所期望的。
  3. 时间戳并不包含时区信息,尽管一些较新的实现提供对它的支持。
  4. Syslog 只是系统上众多日志系统的之一。其他的日志包括 utmp/wtmp, lastlog, audit, 内核日志, 固件日志, 和很多应用程序特定格式的日志。这不仅是毫无必要的复杂,并且掩盖了各个子系统之间日志的关系。
  5. 阅读日志文件很简单但是很低效,很多日志操作的复杂性为 O(n),进行索引基本不可能。
  6. syslog 的网络协议很简单但有限。由于它一般仅支持文件推送传输模式,没有保存和转发,所以同时有大量进程响应(Thundering Herd)或者包丢失将严重影响它的使用。
  7. 日志文件很容易被骇客篡改,容易将攻击信息从系统管理员眼皮底下掩盖起来。
  8. 没有访问控制。除非由系统管理员手动脚本控制,一个用户要不然拥有日志文件的完整权限,要不就一点儿都没有。
  9. 日志项目保存的元数据很有限,缺少一些关键信息,比如服务名、授权进程或者稳定的时间戳。
  10. 日志的自动化滚动是存在的,但是在大多数实现中都不甚理想:并不是持续监视磁盘使用上限,而是在固定时间点上执行滚动操作,因此遗留了 DoS 攻击的可能。
  11. 在一些实现中有更新速度限制,但是一般来说并不会考虑所建议的磁盘使用和服务指派信息。
  12. 一般都有磁盘上日志结构的压缩,但仅仅在滚动时生效,并且又增加了已经比较糟糕的日志操作复杂性。
  13. 经典的 Syslog 传统上并不处理系统启动早期和关机晚期的日志,尽管在最近的改进中(比如 systemd )增添了此功能。
  14. 无法记录二进制数据,在一些情况下恰好是必要的(比如 ATA SMART、SCSI 数据、固件转储)。

很多这些问题在最近变得十分明显,例如觉察修改了日志文件的入侵行为通常仅能靠运气。此外,由于 syslog 的功能所限,目前部分用户常常要依靠一些闭源的组件来处理收集到的日志信息,使其变得有意义,访问更便捷。

日志是服务管理中关键的一部分。在 Unix 系统上,绝大多数的运行服务都连接到 syslog 来写入日志消息。在 systemd 中,我们将日志做为服务管理的核心部分:从 Fedora 16 开始所有启动的服务都将把标准输出和错误输出自动连接到 syslog 上。 不管服务是在启动早期还是正常操作中,它的输出结果都会保存到系统日志中。因此,由于日志如此重要,于是需要特别配置才能禁用它,将原先的“可选记录”策略转变为“可选不记录”策略。信息透明不再是明智的选择,而是默认选择。

在开发 systemd 的过程中 syslog 的局限变得愈加明显。例如:我们非常想添加的的一个简化系统管理工作的功能是当使用 “systemctl status foo.service”时,在通常服务信息的下面显示最近的 10 条日志信息。若是使用经典的 syslog 这个实现将是难以忍受的低效率、不可靠和不安全:需要对于所有日志文件的线性搜索(可能涉及实时解压的操作),并且存储的数据也是被修改过的,无法快捷的和 systemd 的服务名和运行环境匹配。

如果用一句话代替这些内容:传统的 syslog 在 30 年的发展中演变成为有很多严重局限的强大工具。

现在,我们将如何改变这个状况?

Journal

您可能已经从如上的描述中猜出了:我们正在开发一个解决已有日志问题,弥补以上不足并且增添了一些新功能的工具:Journal。

当然,构建一个全新的系统核心组件时,设计目标必须要明确:

  1. 简单性:代码少,依赖少,抽象开销最小。
  2. 零维护:日志是除错和监控系统的核心功能,因此它自己不能再是产生问题,在严酷的环境下也要能工作。举例说,这意味着系统要合理的应对如有限磁盘空间或者 /var 不可用等问题,避免自己引发磁盘空间问题(例如在扩展日志文件时在守护进程正确的实现日志文件滚动)。
  3. 健壮性:由 Journal 生成的数据文件应该可以由管理员直接访问,并且在使用 “scp” 或 “rsync” 之类的工具复制到其他主机上的时候依然可用。合理的处理不完整拷贝的情况。Journal 文件浏览客户端应该可以在没有 Journal 守护进程的情况下工作。
  4. 移植性:Journal 文件应该在所有类型的 Linux 系统上可用,无论它使用的何种 CPU 或者字节序。在嵌入式 ARM 系统上生成的 Journal 文件应该可以在 x86 的桌面系统上可以读取,如同本地生成的一般。
  5. 性能:以复杂性为前提,添加和浏览 Journal 操作应该足够快。最好实现 O(log n) 或者更快,即便在大型组织内的日志监控也有良好性能。
  6. 整合性:因为日志是服务的基础之一,Journal 应该和系统的其他部分紧密的整合起来,所以需要特别的声明才能不使用它。日志是服务管理器的核心责任,所以应该通过整合来反映这一点。
  7. 最小资源占用:Journal 数据文件需要较小,特别是和经典的 syslog 生成的数据相比时。
  8. 通用的事件存储:Journal 应该可以用来进行任何 Journal 条目的存储,无论其格式、元数据还是大小。
  9. 统一化:各种不同的日志存储技术应该统一起来,将所有的可记录事件保存在同一个数据存储中。所以 Journal 内容的全局上下文都会被保存并且可供日后查询。例如一条固件记录后通常会跟随一条内核记录,最终还会有一条用户态记录。重要的是当保存到硬盘上时这三者之间的关系不会丢失。
  10. 高级别工具的基础:Journal 应该提供一个通用的 API ,以便状态监控器、恢复工具、崩溃报告生成器和其他高级别的工作来访问 Journal 数据。
  11. 扩展性:和 Linux 的适用范围从嵌入式设备跨越到超级计算机集群一样,Journal 也应该可以有广泛。日志对于开发嵌入式设备和维护集群一样重要。为了保持较小占用,Journal 需要着重于常见的一般使用模式,同时对于一些特定的变化做一定考量。
  12. 通用性:做为操作系统的基础模块,Journal 应该可以通用,并能扩展以满足于一些应用程序特定的需求。格式应该是可扩展的,并且提供 API。
  13. 集群和网络:今日计算机很少是独立工作的了。所以有必要从 Journal 文件和工具的设计初始就考虑对于多主机安装配置的支持。
  14. 安全性:Journal 文件应该是可以验证的,让无法检测的修改不再可能。

说了很多设计目标,下面是一些我们实现过程的技术概览,并介绍新系统是如何工作的:

受 udev 事件启发,Journal 条目与环境组块相似。一个键值域,按照换行符分开,使用大写的变量名。和 udev 设备事件和真实环境组块相比,有一个主要不同:尽管毫无疑问主要值会是 ASCII 格式的字符串,也支持以二进制为值 -- 某些情况下可以用来添加 ATA SMART 健康信息、SCSI 数据、内核转储或固件转储。由代码生成的 Journal 条目可以包含多个域,既可以是已知的类型,也可以是服务/子系统/驱动特定的。

应用程序和服务可以通过将项目域传递给 systemd journald 服务来生成项目。该服务可以为项目增加一定数量的元数据。这些受信任域的值由 Journal 服务来决定且无法由客户端来伪造。一旦牵扯到硬件和内核设备,Journal 服务将为日志项目添加从 udev 数据库获得的当前设备信息,其中包含了所有设备名和符号链接,以及与 Journal 条目关联的其他设备数据。

由 Journal 守护进程添加的域将具有下划线前缀(“_”), 用来标示该区域是可信的,而不是由未知客户端提供的。应用程序自身无法传递以下划线开头的的域名称。这是一个样例展示在客户端传输基础上添加内容的日志条目展示:

_SERVICE=systemd-logind.service

MESSAGE=User harald logged in

MESSAGE_ID=422bc3d271414bc8bc9570f222f24a9

_EXE=/lib/systemd/systemd-logind

_COMM=systemd-logind

_CMDLINE=/lib/systemd/systemd-logind

_PID=4711

_UID=0

_GID=0

_SYSTEMD_CGROUP=/system/systemd-logind.service

_CGROUPS=cpu:/system/systemd-logind.service

PRIORITY=6

_BOOT_ID=422bc3d271414bc8bc95870f222f24a9

_MACHINE_ID=c686f3b205dd48e0b43ceb6eda479721

_HOSTNAME=waldi

LOGIN_USER=500

该样例条目是由 systemd logind 守护进程在用户 “harald” 登录时创建的。如您所见它自动添加了相当复杂的数据,包括一些重要的执行进程参数。更加详细的定义的域说明请参考:

Well Known Journal Fields

原生的 Journal 文件格式从经典的日志文件和 Git 仓库获得启发。它被设计来只将日志数据添加到末尾(用来保证基于 mmap() 的访问的健壮和原子性),以及一些在用来反映新添加内容的文件头元数据变更。这些用来组成项目的域以独立对象的方式保存在 Journal 文件中,当需要时被项目所引用。这将节省大量的磁盘空间,因为日志项目通常会有很多的重复(试想:每个本地的消息都会包含相同的 _HOSTNAME=_MACHINE_ID= 域)。数据域还会被压缩来节省磁盘空间。直接效果就是尽管 Journal 相比经典的 Syslog 明显记录了更多的元数据信息,但是磁盘占用却无明显变化。

磁盘上使用特定的 64位 LE(从小到大)偏移,目的是简化操作并保证我们可以存储大小可观的二进制数据。日志浏览工具和 journald 之间的无需同步,需要浏览 Journal 文件的客户端可以简单的使用 mmap() 访问文件,并使用文件变化通知来告知更新。

提供用于客户端访问 Journal 文件的库,用来实现对项目任意域的索引,以及通过单调化或者时序化时间戳的随机访问。客户端库会自动合并多个 Journal 文件使其看起来好像是一个统一的 Journal 项目流。这用来隐藏底层细节譬如已经归档的文件,或属于多个用户的 Journal 文件。在浏览接口上透明化的 Journal 文件合并是完全动态的:当创建新的 Journal 文件或者删除旧的文件时都会自动更新浏览视图。事实上,Journal 浏览期望做到即时性的,从而实现对 Journal 来源的实时监控。

Journal 客户端库头文件

从非特权登录用户发来的消息将按照每用户分割为独立的 Journal 文件。使用 POSIX ACL 来实现读取权限控制,保证用户可以访问他自己的 Journal 文件。系统服务生成的 Journal 条目默认情况下无法被一般用户访问,除非他们属于一个特殊的 Unix 用户组。值得注意的是文件的分割是用来协助合适的访问控制的,但是全局的上下文并未因此丢失。客户端会通过所有消息强制按照统一的排序的方式将 Journal 文件合并起来,从而保证自动分配的序列号码的全局顺序。这意味着可以在不影响用户条目上下文的情况下实现访问控制。

Journal 的核心思路就是统一目前所用的各类日志记录技术。因此它将成为 wtmp 的替代品,启动早期记录器甚至授权记录后端。数据将从各种不同的来源生成:printk() 生成的内核消息,syslog(3) 生成的用户态消息,使用原生 API 生成的用户态条目,通过 /proc/proc/sys/kernel/core_pattern 生成的核心转储及更多。以后我们希望能有固件消息(UEFI 日志)的钩子,并扩展基于内核的日志来支持内核中结构化日志。因为在 Journal 数据结构中所有的域都是隐式的索引过的,所以跟 wtmp 相比从 Journal 的中提取用户数据是个很简单的操作。启动早期和运行时日志时统一的。只要 /var 不可用,所有的 Journal 条目便会自动保存在 /run 下,等待 /var 可用时再立刻写入。这意味着最终所有系统生成的消息,不管是在 POST 中由固件,还是在内核初始化,启动早期还是运行时,都将保存到索引的 Journal 文件中。

为了让条目可以被客户端工具识别出来,Journal 条目可选包含一个 128 位的标示符,由生成消息的服务设定于 MESSAGE_ID= 中。这个 ID 应该由开发者在开发过程中随机生成的。例如,一个 ID 表示“用户登出”而另外一个 ID 表示“用户登入”。所有这些事件的条目都分别包含 128 位的 ID,因此将很容易辨识出来并索引。这个 ID 完全可以和 RFC4122 UUID 类型四保持兼容,但是这严格的来说并不需要故也不强求。该设计会和其他采用 UUID 标示消息类型的日志系统保持兼容,比如 UEFI 固件日志。考虑到128 位 ID 的全局错误代码的随机本质,它们并不需要一个集中式的标准化机构来为某个特定的消息类型指定 ID。指定消息 ID 是完全可选的,我们认为只要少量的 Journal 的条目会包括它,比如那些需要被用户态识别出来的部分。如果一个开发者需要为他新引入的消息类型指定一个新 128 位 ID 的话,只需要运行 “cat /proc/sys/kernel/random/uuid” 即可,它会在每次运行的时候返回一个新的 UUID。这 128 位的 ID 亦可用于实现本地化的消息 UI,按照他在 UI 工具中寻找翻译过的消息,然后呈现给用户。

所有的条目都用现实时间和单调时间打上时间戳。为了使单调时间戳有意义,所有的消息同时也包含运行的 Linux 内核的启动 ID (比如 /proc/sys/kernel/random/boot_id)。精确度是 1 微妙,现实时间采用 UTC 计时以避免遭受和 syslog 类似的时区问题。

Journal 文件可以回滚、删除、复制到其他机器、合并或者更改。为了保证应用程序、同步公布和网络服务可靠的识别条目,所有 Journal 条目都可以用一个指针字符串标识。一个这样的字符串可以标识一个特定的消息,甚至在条目丢失或不可用时也保持不变,于是可以用来定位最近的下一个条目。

如果超过某个限额的话,journald 会自动回滚 Journal 文件。这被内建在磁盘空间分配的逻辑中,目的是避免单纯基于时间回滚的漏洞。回滚不仅考虑最大磁盘利用限制,并且还将监视通常的磁盘使用水平来保证磁盘上至少预留有一定空间。

由客户端发送的条目隐含的受到速率限制,避免未信任的客户端通过大量发送自身数据的方式冲掉 Journal 中的相关数据。这个速率依照可用磁盘空间调整,于是在磁盘空间富裕的时候速率会高些,而磁盘空间低时将会强制为较低的速率。

在初始版本的 journald 中对于网络支持会非常简陋:要在网络中分享 Journal 文件的话,使用比如 scp、rsync 或者 NFS 复制到一个集中化主机上。Journal 浏览器客户端将会透明化的合并这些文件,如果需要的话进行交叉存储。在稍候的版本中我们计划最低限度的扩展 Journal 来支持实时远程日志,通过用本地 Journal 文件做为缓存的存储-转发逻辑来实现 PUSH 和 PULL 两种模式。不管使用何种模式,Journal 的底层格式设计适用于扩展到大规模主机环境,所有的条目都会用机器 ID 和主机名来标示。目的是实现一种有效的 Journal 监控工具完成透明化、实时的多重主机日志浏览任务,并且留给管理员按照自己需要调整传输方式的空间,比如是否实时功能比避免大量进程响应(Thundering Herd)更重要等。

互联网是个险象丛生的地方。对于重要网站的入侵已经变得愈加常见。在成功的渗透之后,攻击者通常会通过编辑日志文件的方式掩藏他的踪迹。 这类修改在传统的 syslog 下很难检测:因为它用的是没有加密认证的纯文本,所以无法获知变更。从 Git 中获得启发,Journal 中的所有条目都是加密哈希过的,且在文件中包含先前条目的哈希值。这样的结果是一个条目链,每一个条目都可以认证之前的全部。如果最顶端的哈希通常都保存在一个只读的位置,整个链条都可以通过它认证。检测攻击者的修改将变得十分容易。

如上所述日志是服务管理的必要部分。这不仅意味着服务本身的日志输出将传递到 Journal,并且将为额外的服务事件生成 Journal 条目,比如当服务开始、错误推出、停止或崩溃之时。

Journal 的守护进程 journald 首先将取代目前 systemd 分发的两个日志相关迷你守护进程(systemd-kmsg-syslogd and systemd-stdout-syslog-bridge)。长期目标是在多种安装配置中取代传统的 syslog 守护进程,而不造成冲突。由于运行服务的减少(由 3 降为 1)以及相比全尺寸的 syslog 守护进程少很多代码的 journald,Linux 系统的资源消耗将会减低。

当前状态

目前为止,核心的功能和和全部重要的算法已经实现并放置在 systemd git 的 Journal 分支中。但是代码目前还不完善,缺少一些上面提到的功能。

这篇博文是用来澄清一些社区中对于我们计划、选择和原因的误解。

我们计划在 Fedora 17 中初步实现,不过在首次亮相中只选择与极少几个部件关联。rsyslog 会和它一起运行,用户可能会很难注意到它,除了 “systemctl status” 将会显示所有服务的最近日志信息,以及尝试使用我们的客户端工具,比如 “journalctl” 来搜索索引的 Journal 时。

常见问题及回答

我们一直在和不同知识背景的人讨论,收集想法、建议和批评。有一些问题经常被重复提到,下面就是我们的回答:

Journal 很酷,但是 systemd 很糟糕。我可以不用 systemd 而单独使用 journald 么?

不行。日志是服务管理的核心部分。Journal 和 systemd 紧密结合从而保证系统的每一个部分都可以监控,查询和除错。生成的 Journal 项目是从 systemd 的不同部分查询出来的。实际上,systemd 和 journald 是如此紧密耦合以至于拆分开的举动毫无意义。不过正如所说,这是自由软件,您可以随自己愿望修改代码。最后,您认为 systemd 很糟糕的想法是错误的。

运行 Journal 会破坏 rsyslog/syslog-ng 么?

不会。您可以同时运行 rsyslog 或 syslog-ng 及 journald,syslog 消息会双双记录在 rsyslog/syslog-ng 和 Journal 中。但是,Journal 将记录一些纯文本的 syslog 所不具备的丰富元信息。

我的应用程序需要在磁盘保存传统的纯文本日志。我可以配置 Journald 生成么?

不能。如果您需要这样做的话,只要和 Journal 同时运行一个传统的 syslog 实现如 rsyslog, 即可帮助您生成想要的文件。

为什么 Journal 不生成传统的日志文件?

简单来说,传统的日志文件无法索引,并且其速度随着复杂度按照函数 O(n) 降低。原生的 Journal 文件格式下关键操作速度随着复杂度按照 O(log(n)) 降低,性能更佳。更多原因请参考上面章节。

我可以连接一个 syslog 协议兼容的远程 RFC 到 Journal 么?

在目前您不可以,并且 Journal 也不太可能会默认支持这个。但是编写一个可行的转换器或者网关应该不困难。

我在嵌入式设备上使用 systemd 于是对永久性保存日志不感兴趣,我可以移除 Journal 么?

不可以。但是您可以告诉 systemd 您不需要永久性日志。通过移除(或者一开始就不创建)/var/log/journal 目录,在这种情况下 journald 仅会将记录到 /run/log/journal (如同在早期启动的情况下)。/run 是临时的并且会在重启时丢失,和 /var 不同。在此之上您可以将 Journal 使用的最大磁盘空间设置为一个很小的值。

人人都说 UUID 是有问题的。为何还要用 UUID 来表示消息呢?

UUID 规格的确是奇形怪状且不必要的复杂。因此我们推荐只要和 UUID 类型4保持一致即可,不用理会 RFC 4122。实际上 UUID 已经在 Linux 上成功的应用了很长时间,所有发行版默认都是依据文件系统 UUID 来执行挂载的。

但是 UUID 从来没正常工作过!比如 MAC 地址是重复的并且所有我的 USB 设备都使用的同一个。为什么要坚持使用它呢?

我们实际上一直在使用它,比如像上面说的在文件系统中,它工作的很好。硬件都包含有序列号,不少厂商初始化为 1-2-3-4-5,但是它和 UUID 没什么关系。设备序列号并不是 UUID,不要混淆!

另外,我们并没有强制使用它们。如上所述它是完全可选的,并且只需要并赋予到需要后来识别出来的消息上即可。

但我在代码中引入了一个 UUID 来标识一个消息类型,其他人使用了该段代码做为别的工作的模板,那么 Journal 就会坏掉了。

不,这不对。为什么?很简单,因为同样的 128位 ID 将会用来指定同一个错误/条件/项目类型,不管来源是什么。比如同样的 128位 ID 将会用来标识“在块设备上存在坏扇区”,而不管是哪个设备或驱动器生成了这个消息。如果用户态软件需要在不同的服务、驱动或设备之间区分开 Journal 项的话,请使用其他额外的匹配服务/设备/驱动的 Journal 信息域。

不过从另一个角度讲,您指出的实际上是个好事情。我们特别鼓励人们在他们的软件中重用消息 ID,而不是创造新的。

但是 printf()/printk() 格式化字符串是标识消息类型的更好选择!

现实并不是这样的。格式化字符串到头来不过只是人类语言的模板。将人类语言用于消息类型识别是不可靠的:每个修正的错误拼写都会影响消息类型,并且导致 Journal 客户端识别消息错误。每次对一个 Journal 消息进行扩充或者重写的时候,将会导致 ABI 破坏。让人类语言变为 ABI 是致命的错误。事实上,将所有消息类型变为 ABI 的方式在经典的正则表达式匹配条件下风险很大。OTOH 消息标识可以在改变人类语言字符串时保持不变,因此很好的将 ABI 和人类语言分割开了。

你们一点儿都不懂!你们应该使用源代码文件名和位置作为消息的标识符!

这并不可行,因为这将使源代码位置变为 ABI:问一次开发者在头文件中增加一行将导致全部消息 ID 的改变。这将是个大问题。

谁会来组织和管理 UUID 的命名空间并生成 UUID?Who would organize and manage the UUID namespace and generate UUIDs? 认真点儿,我们不需要更多官僚机制的人!

128 位随机 ID 的好处之一就是它的命名空间并不需要管理。所有人都可以从 /proc/sys/kernel/random/uuid 里取出一个随机 UUID 为他所用。只要需要,开发者可以生成任意多的 UUID 而不需要询问任意集中管理体制。UUID 允许我们拥有一个共同点的命名空间而无需官僚机制。

但是 UUID?你是认真的么?你是哪个星球来的!?人人都知道像 LANANA 这样的中介是为应用程序指定全球唯一消息标识 ID 的理想选择!

Linux 并不是一个孤岛。我们需要在 Journal 中与其他基础架构中所使用消息 ID 无缝整合起来。因此我们选择了有用途的并且已经在他处实践过的。同样,UUID 只不过是为了无需集中管理的唯一标识符。为什么要在没必要的时候选择一个人手不足的官僚的集中注册中心的?

喏,你应该使用逆序的域名表示消息类型,像 Java 一样!

实质上,比较字符串要比比较固定长度的 ID 更加复杂。并且,实事求是的说这不能解决命名空间的问题,因为估计有 90% 的消息类型将在同个命名空间内:org.freedesktop resp. org.kernel.

但是 ASN.1 OID 可以成为很好的消息类型区分符!

兄弟,没搞错吧?

现在我有了更好的主意,不如用 URL 做为类型 ID 吧?

实际上相比逆序域名的方式它并未好多少,不是么?

但是如果你们在每个项目上都要生成一个 UUID 的话,很快便会穷尽我的熵池的!

再度一遍博文,很显然您并没有仔细阅读。 128 位的消息 ID 是由开发者在开发过程中指定的,并不是在运行时。大多数项目在整个开发过程中几乎不可能生成超过 30 个,这个数量哪怕在 10 年前的机器的熵池中都是微不足道的。

你们这些用户态的小屁孩们,先是强迫我在系统中使用 20 个 CPU 进程分组,现在又要强迫我在系统中使用恶心的 UUID?

先不谈我们并没有强迫您使用 20 个进程分组的事实,您几乎肯定已经在使用 UUID 了,因为您的文件系统是在启动过程中依据 UUID 加载的。将这些当作是实现的具体细节,而您并不喜欢它,那么您就没必要在消息中添加它。影响的只是消息无法被再度识别,除非使用极度复杂的正则表达式。不过或许这就是您想要的?无论怎样,我们没有强迫任何人做任何事。

所以你们是依照发送用户的 ID 来分割 Journal 项目的了。那么你怎么能保证用户不会伪装身份呢?

幸运的是,Linux 内核支持 SCM_CREDENTIALS,可以提供我们无法伪造的消息发送者信息。

Journal 文件格式会标准化么?哪里可以找到磁盘上数据结构的说明?

截至目前我们还没有打算要将格式其标准化,保留在需要时进行变更的权力。我们会逐步完善磁盘上格式的文档,但是目前我们不希望能有程序直接读取、写入和修改 Journal 文件。对其的访问可以通过一个共享库和命令行程序实现。(不过再一次,这是自由软件,您随时可以阅读源代码!)

为什么你们这些人又搞重复发明?为什么不只把你们想要的增加到已有的 syslog?如果您只想清理日志格式的话,syslog 足够了。

有些情况下改进现有方案是一种方式,但是当需要的变化太大时,有正确的原因并且对以前解决方案提供了良好的兼容性的重新发明却是更好的选择。我们相信我们有着正确的原因,并且我们在努力提供最大可能的兼容性。

不,仅仅修复日志格式没法带来很多变革。不仅无法实现最基本的二进制文件或敏感的结构化日志,也没有索引或者访问控制。

是不是 Journal 将完全抛弃 syslog ?

不,首先,syslog API syslog(3) 作为写入日志的第一级别接口被支持,并且将持续用作主要的简单文本日志 API。但是只要元数据(特别是二进制元数据)被加入到条目中,便会转而使用原生的 Journal API。

其次,Journal 是个全新的产物。从另一个方面说,Syslog 是一个工业标准(尽管是定义的相当孱弱,日志格式几乎都没有统一),并且被广泛接受,存在于为数众多的操作系统、应用程序和设备中。因此,syslog 依然是很重要的并且将继续存在于许多安装配置中。Journal 守护进程并不使用 RFC syslog 协议,将来也不太可能会。当需要一个 syslog 兼容协议的地方,依然需要使用经典的 syslog 实现方案。为了保证此项工作,我们确保 Journal 的实现可以和本地的 syslog 守护进程协作,且将需要的消息转发给 syslog,使其可以像如同没有 journald 中介一般的工作。

需要您的加入!

在决定这个设计之前,我们了解一些高负荷的日志用户,包括那些拥有超过 100 台活跃主机的用户。我们也和一些可能成为主要 Journal 用户的工程师聊过。我们对于使用惯例和扩展性问题尤其感兴趣。但是,每一个安装配置都有自己的需求,因此,如果您在上面的设计描述中看到了某个用于您特定需要的重要功能没有实现的话,我们希望您能和我们去的联系。上面的设计着重于日志记录的底层。目前我们并不负责特定的 UI,所以如果有这方面的需求话请稍候再留下意见。另外,现在还没到圣诞节,因此我们无法实现所有愿望(请不要失望),但是我们很在意的去了解它们,甚至可以保证至少我们会去考虑它们!先谢过了!

英文原文

消息来源:Phoronix

PS: 感谢 @csslayer 指出了 rsyslog 作者对该文提出的不同意见,感兴趣的朋友请阅读

Read More: