要在两个服务(许可证和组织)中开始使用Spring Cloud Sleuth,我们需要在两个服务的pom.xml文件中添加一个Maven依赖项:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
这个依赖项会拉取Spring Cloud Sleuth所需的所有核心库。就这样,一旦这个依赖项被拉进来,服务现在就会完成如下功能。
(1)检查每个传入的HTTP服务,并确定调用中是否存在Spring Cloud Sleuth跟踪信息。如果Spring Cloud Sleuth跟踪数据确实存在,则将捕获传递到微服务的跟踪信息,并将跟踪信息提供给服务以进行日志记录和处理。
(2)将Spring Cloud Sleuth跟踪信息添加到Spring MDC,以便微服务创建的每个日志语句都添加到日志中。
(3)将Spring Cloud跟踪信息注入服务发出的每个出站HTTP调用以及Spring消息传递通道的消息中。
9.1.2 剖析Spring Cloud Sleuth跟踪
如果一切创建正确,则在服务应用程序代码中编写的任何日志语句现在都将包含Spring Cloud Sleuth跟踪信息。例如,图9-1展示了如果要在组织服务上执行HTTP GET请求http://localhost:5555/api/organization/v1/organizations/e254f8c-c442-4ebe- a82a-e2fc1d1ff78a,服务将输出什么结果。
图9-1 Spring Cloud Sleuth为服务编写的每个日志条目添加了4条跟踪信息,这些数据有助于将用户请求的服务调用绑定在一起
Spring Cloud Sleuth将向每个日志条目添加以下4条信息(与图9-1中的数字对应)。
(1)服务的应用程序名称——这是创建日志条目时所在的应用程序的名称。在默认情况下,Spring Cloud Sleuth将应用程序的名称(spring.application.name)作为在跟踪中写入的名称。
(2)跟踪ID(trace ID)——跟踪ID是关联ID的等价术语,它是表示整个事务的唯一编号。
(3)跨度ID(span ID)——跨度ID是表示整个事务中某一部分的唯一ID。参与事务的每个服务都将具有自己的跨度ID。当与Zipkin集成来可视化事务时,跨度ID尤其重要。
(4)是否将跟踪数据发送到Zipkin——在大容量服务中,生成的跟踪数据量可能是海量的,并且不会增加大量的价值。Spring Cloud Sleuth让开发人员确定何时以及如何将事务发送给Zipkin。Spring Cloud Sleuth跟踪块末尾的true/false指示器用于指示是否将跟踪信息发送到Zipkin。
到目前为止,我们只查看了单个服务调用产生的日志数据。让我们来看看通过GEThttp://localhost:5555/api/licensing/v1/organizations/e254f8c-c442-4ebe- a82a-e2fc1d1ff78a/licenses/f3831f8c-c338-4ebe-a82a-e2fc-1d1ff78a调用许可证服务时会发生什么。记住,许可证服务还必须向组织服务发出调用。图9-2展示了来自两个服务调用的日志记录输出。
图9-2 当一个事务中涉及多个服务时,可以看到它们具有相同的跟踪ID
查看图9-2可以看出许可证服务和组织服务都具有相同的跟踪ID——a9e3e1786b74d302。但是,许可证服务的跨度ID是a9e3e1786b74d302(与事务ID的值相同),而组织服务的跨度ID是3867263ed85ffbf4。
只需添加一些POM的依赖项,我们就已经替换了在第5章和第6章中构建的所有关联ID的基础设施。就我个人而言,在这个世界上,没有什么比用别人的代码代替复杂的、基础设施风格的代码更让我开心的了。
9.2 日志聚合与Spring Cloud Sleuth
在大型的微服务环境中(特别是在云环境中),日志记录数据是调试问题的关键工具。但是,因为基于微服务的应用程序的功能被分解为小型的细粒度的服务,并且单个服务类型可以有多个服务实例,所以尝试绑定来自多个服务的日志数据以解决用户的问题可能非常困难。试图跨多个服务器调试问题的开发人员通常不得不尝试以下操作。
登录到多个服务器以检查每个服务器上的日志。这是一项非常费力的任务,尤其是在所涉及的服务具有不同的事务量,导致日志以不同的速率滚动的时候。
编写尝试解析日志并标识相关的日志条目的本地查询脚本。由于每个查询可能不同,因此开发人员经常会遇到大量的自定义脚本,用于从日志中查询数据。
延长停止服务的进程的恢复,因为开发人员需要备份驻留在服务器上的日志。如果托管服务的服务器彻底崩溃,则日志通常会丢失。
上面列出的每一个问题都是我遇到过的实际问题。在分布式服务器上调试问题是一件很糟糕的工作,并且常常会明显增加识别和解决问题所需的时间。
一种更好的方法是,将所有服务实例的日志实时流到一个集中的聚合点,在那里可以对日志数据进行索引并进行搜索。图9-3在概念层面展示了这种“统一”的日志记录架构是如何工作的。
图9-3 将聚合日志与跨服务日志条目的唯一事务ID结合,更易于管理分布式事务的调试
幸运的是,有多个开源产品和商业产品可以帮助我们实现前面描述的日志记录架构。此外,还存在多个实现模型,可供开发人员在内部部署、本地管理或者基于云的解决方案之间进行选择。表9-1总结了可用于日志记录基础设施的几个选择。
表9-1 与Spring Boot组合使用的日志聚合方案的选项
很难从上面选出哪个是最好的。每个组织都各不相同,并且有不同的需求。
在本章中,我们将以Papertrail为例,介绍如何将Spring Cloud Sleuth支持的日志集成到统一的日志记录平台中。选择Papertrail出于以下3个原因。
(1)它有一个免费增值模式,可以注册一个免费的账户。
(2)它非常容易创建,特别是和Docker这样的容器运行时工作。
(3)它是基于云的。虽然我认为良好的日志基础设施对于微服务应用程序是至关重要的,但我不认为大多数组织都有时间或技术才能去正确地创建和管理一个日志记录平台。
9.2.1 Spring Cloud Sleuth与Papertrail集成实战
在图9-3中,我们看到了一个通用的统一日志架构。现在我们来看看如何使用Spring Cloud Sleuth和Papertrail来实现相同的架构。
为了让Papertrail与我们的环境一起工作,我们必须采取以下措施。
(1)创建一个Papertrail账户并配置一个Papertrail syslog连接器。
(2)定义一个Logspout Docker容器,以从所有Docker容器捕获标准输出。
(3)通过基于来自Spring Cloud Sleuth的关联ID发出查询来测试这一实现。
图9-4展示了这一实现的最终状态,以及Spring Cloud Sleuth和Papertrail如何与解决方案融合。
图9-4 使用原生Docker功能、Logspout和Papertrail可以快速实现统一的日志记录架构
9.2.2 创建Papertrail账户并配置syslog连接器
我们将从创建一个Papertrail账号开始。要开始使用PaperTrail,应访问https://papertrailapp.com并点击绿色的“Start Logging-Free Plan”按钮。图9-5展示了这个界面。
图9-5 首先,在Papertrail上创建一个账户
Papertrail不需要大量的信息去启动,只需要一个有效的电子邮箱地址即可。填写完账户信息后, 将出现一个界面,用于创建记录数据的第一个系统。图9-6展示了这个界面。
图9-6 接下来,选择如何将日志数据发送到Papertrail
在默认情况下,Papertrail允许开发人员通过Syslog调用向它发送日志数据。Syslog是源于UNIX的日志消息传递格式,它允许通过TCP和UDP发送日志消息。Papertrail将自动定义一个Syslog端口,可以使用它来写入日志消息。在本章的讨论中,我们将使用这个默认端口。图9-7展示了syslog 连接字符串,在点击图9-6所示的“Add your first system”按钮时,它将自动生成。
图9-7 Papertrail使用Syslog作为向它发送数据的机制之一
到目前为止,我们已经设置完Papertrail。接下来,我们必须配置Docker环境,以便将运行服务的每个容器的输出捕获到图9-7中定义的远程syslog端点。
注意
图9-7中的连接字符串是我的账户特有的。读者需要确保自己使用了Papertrail为自己生成的连接字符串,或者通过Papertrail Settings→Log destinations菜单选项来定义一个连接字符串。
9.2.3 将Docker输出重定向到Papertrail
通常情况下,如果在虚拟机中运行每个服务,那么必须配置每个服务的日志记录配置,以便将它的日志信息发送到一个远程syslog端点(如通过Papertrail公开的那个端点)。
幸运的是,Docker让从物理机或虚拟机上运行的Docker容器中捕获所有输出变得非常容易。Docker守护进程通过一个名为docker.sock的Unix套接字来与所有Docker容器进行通信。在Docker所在的服务器上,每个容器都可以连接到docker.sock,并接收由该服务器上运行的所有其他容器生成的所有消息。用最简单的术语来说,docker.sock就像一个管道,容器可以插入其中,并捕获Docker运行时环境中进行的全部活动,这些Docker运行时环境是在Docker守护进程运行的虚拟服务器上的。
我们将使用一个名为Logspout的“Docker化”软件,它会监听docker.sock套接字,然后捕获在Docker运行时生成的任意标准输出消息,并将它们重定向输出到远程syslog(Papertrail)。要建立Logspout容器,必须要向docker-compose.yml文件添加一个条目,它用于启动本章代码示例使用的所有Docker容器。我们需要修改docker/common/docker-compose.yml文件以添加以下条目:
logspout:
image: gliderlabs/logspout
volumes:
- /var/run/docker.sock: /var/run/docker.sock
注意
在上面的代码片段中,读者需要将command属性中的值替换为Papertrail提供的值。如果读者使用上述Logspout代码片段,Logspout容器会很乐意将日志条目写入我的Papertrail账户。
现在,当读者启动本章中Docker环境时,所有发送到容器标准输出的数据都将发送到Papertrail。在启动完第9章的Docker示例之后,读者通过登录自己的Papertrail账户,然后点击界面右上角的“Events”按钮,就可以看到数据都发送到Papertrail。
图9-8展示了发送到Papertrail的数据的示例。
图9-8 在定义了Logspout Docker容器的情况下,写入每个容器标准输出的数据将被发送到Papertrail
为什么不使用Docker日志驱动程序
Docker 1.6及更高版本允许开发人员定义其他日志驱动程序,以记录在每个容器中写入的stdout/stderr 消息。其中一个日志记录驱动程序是 syslog 驱动程序,它可用于将消息写入远程syslog监听器。
为什么我会选择Logspout而不是使用标准的 Docker 日志驱动程序?主要原因是灵活性。Logspout提供了定制日志数据发送到日志聚合平台的功能。Logspout提供的功能有以下几个。
能够一次将日志数据发送到多个端点。许多公司都希望将自己的日志数据发送到一个日志聚合平台,同时还需要安全监控工具,用于监控生成的日志中的敏感数据。
在一个集中的位置过滤哪些容器将发送它们的日志数据。使用Docker驱动程序,开发人员需要在docker-compose.yml文件中为每个容器手动设置日志驱动程序,而Logspout则允许开发人员在集中式配置中定义特定容器甚至特定字符串模式的过滤器。
自定义HTTP路由,允许应用程序通过特定的HTTP端点来写入日志信息。这个特性允许开发人员完成一些事情,例如将特定的日志消息写入特定的下游日志聚合平台。举个例子,开发人员可能会将一般的日志消息从stdout/stderr转到Papertrail,与此同时,可能会希望将特定应用程序审核信息发送到内部的Elasticsearch服务器。
与syslog以外的协议集成。Logspout可以通过UDP和TCP协议发送消息。此外,Logspout还具有第三方模块,可以将Docker的stdout/stderr整合到Elasticsearch中。
9.2.4 在Papertrail中搜索Spring Cloud Sleuth的跟踪ID
现在,日志正在流向Papertrail,我们可以真正开始感激Spring Cloud Sleuth将跟踪ID添加到所有日志条目中。要查询与单个事务相关的所有日志条目,只需在Papertrail的事件界面的查询框中输入跟踪ID并进行查询即可。图9-9展示了如何使用在9.1.2节中使用的Spring Cloud Sleuth 跟踪ID a9e3e1786b74d302来执行查询。
图9-9 跟踪ID可用于筛选与单个事务相关的所有日志条目
统一日志记录和对平凡的赞美
不要低估拥有一个统一的日志架构和服务关联策略的重要性。这似乎是一项平凡的任务,但在我撰写这一章的时候,我使用了类似于Papertrail的日志聚合工具为我正在开发的一个项目跟踪3个不同服务之间的竞态条件。事实表明,这个竞态条件已经存在了一年多时间了,但处于竞态条件下的服务一直运行良好,直到我们增加了一点儿负载并加入另一个参与者才导致问题出现。
我们用了1.5周的时间进行日志查询,并遍历了几十个独特场景的跟踪输出之后才发现了这个问题。如果没有聚合的日志记录平台,我们也就不会发现这个问题。这次经历再次肯定了以下几件事。
(1)确保在服务开发的早期定义和实现日志策略——一旦项目开展起来,实现日志基础设施会是一项冗长的、有时很困难的工作并且还会耗费大量时间。
(2)日志记录是微服务基础设施的一个关键部分——在实现你自己的日志记录方案或是尝试实现内部部署的日志记录方案之前,一定要再三考虑清楚。花在基于云的日志记录平台上的钱是值得的。
(3)学习日志记录工具——几乎每个日志平台都有一个查询语言来查询合并的日志。日志是信息和度量的一个极其重要的来源。它们本质上是另一种类型的数据库,花在学习查询上的时间将会带来巨大的回报。
9.1.1 将Spring Cloud Sleuth添加到许可证服务和组织服务中
要在两个服务(许可证和组织)中开始使用Spring Cloud Sleuth,我们需要在两个服务的pom.xml文件中添加一个Maven依赖项:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
这个依赖项会拉取Spring Cloud Sleuth所需的所有核心库。就这样,一旦这个依赖项被拉进来,服务现在就会完成如下功能。
(1)检查每个传入的HTTP服务,并确定调用中是否存在Spring Cloud Sleuth跟踪信息。如果Spring Cloud Sleuth跟踪数据确实存在,则将捕获传递到微服务的跟踪信息,并将跟踪信息提供给服务以进行日志记录和处理。
(2)将Spring Cloud Sleuth跟踪信息添加到Spring MDC,以便微服务创建的每个日志语句都添加到日志中。
(3)将Spring Cloud跟踪信息注入服务发出的每个出站HTTP调用以及Spring消息传递通道的消息中。
9.1.2 剖析Spring Cloud Sleuth跟踪
如果一切创建正确,则在服务应用程序代码中编写的任何日志语句现在都将包含Spring Cloud Sleuth跟踪信息。例如,图9-1展示了如果要在组织服务上执行HTTP GET请求http://localhost:5555/api/organization/v1/organizations/e254f8c-c442-4ebe- a82a-e2fc1d1ff78a,服务将输出什么结果。
图9-1 Spring Cloud Sleuth为服务编写的每个日志条目添加了4条跟踪信息,这些数据有助于将用户请求的服务调用绑定在一起
Spring Cloud Sleuth将向每个日志条目添加以下4条信息(与图9-1中的数字对应)。
(1)服务的应用程序名称——这是创建日志条目时所在的应用程序的名称。在默认情况下,Spring Cloud Sleuth将应用程序的名称(spring.application.name)作为在跟踪中写入的名称。
(2)跟踪ID(trace ID)——跟踪ID是关联ID的等价术语,它是表示整个事务的唯一编号。
(3)跨度ID(span ID)——跨度ID是表示整个事务中某一部分的唯一ID。参与事务的每个服务都将具有自己的跨度ID。当与Zipkin集成来可视化事务时,跨度ID尤其重要。
(4)是否将跟踪数据发送到Zipkin——在大容量服务中,生成的跟踪数据量可能是海量的,并且不会增加大量的价值。Spring Cloud Sleuth让开发人员确定何时以及如何将事务发送给Zipkin。Spring Cloud Sleuth跟踪块末尾的true/false指示器用于指示是否将跟踪信息发送到Zipkin。
到目前为止,我们只查看了单个服务调用产生的日志数据。让我们来看看通过GEThttp://localhost:5555/api/licensing/v1/organizations/e254f8c-c442-4ebe- a82a-e2fc1d1ff78a/licenses/f3831f8c-c338-4ebe-a82a-e2fc-1d1ff78a调用许可证服务时会发生什么。记住,许可证服务还必须向组织服务发出调用。图9-2展示了来自两个服务调用的日志记录输出。
图9-2 当一个事务中涉及多个服务时,可以看到它们具有相同的跟踪ID
查看图9-2可以看出许可证服务和组织服务都具有相同的跟踪ID——a9e3e1786b74d302。但是,许可证服务的跨度ID是a9e3e1786b74d302(与事务ID的值相同),而组织服务的跨度ID是3867263ed85ffbf4。
只需添加一些POM的依赖项,我们就已经替换了在第5章和第6章中构建的所有关联ID的基础设施。就我个人而言,在这个世界上,没有什么比用别人的代码代替复杂的、基础设施风格的代码更让我开心的了。
9.2 日志聚合与Spring Cloud Sleuth
在大型的微服务环境中(特别是在云环境中),日志记录数据是调试问题的关键工具。但是,因为基于微服务的应用程序的功能被分解为小型的细粒度的服务,并且单个服务类型可以有多个服务实例,所以尝试绑定来自多个服务的日志数据以解决用户的问题可能非常困难。试图跨多个服务器调试问题的开发人员通常不得不尝试以下操作。
登录到多个服务器以检查每个服务器上的日志。这是一项非常费力的任务,尤其是在所涉及的服务具有不同的事务量,导致日志以不同的速率滚动的时候。
编写尝试解析日志并标识相关的日志条目的本地查询脚本。由于每个查询可能不同,因此开发人员经常会遇到大量的自定义脚本,用于从日志中查询数据。
延长停止服务的进程的恢复,因为开发人员需要备份驻留在服务器上的日志。如果托管服务的服务器彻底崩溃,则日志通常会丢失。
上面列出的每一个问题都是我遇到过的实际问题。在分布式服务器上调试问题是一件很糟糕的工作,并且常常会明显增加识别和解决问题所需的时间。
一种更好的方法是,将所有服务实例的日志实时流到一个集中的聚合点,在那里可以对日志数据进行索引并进行搜索。图9-3在概念层面展示了这种“统一”的日志记录架构是如何工作的。
图9-3 将聚合日志与跨服务日志条目的唯一事务ID结合,更易于管理分布式事务的调试
幸运的是,有多个开源产品和商业产品可以帮助我们实现前面描述的日志记录架构。此外,还存在多个实现模型,可供开发人员在内部部署、本地管理或者基于云的解决方案之间进行选择。表9-1总结了可用于日志记录基础设施的几个选择。
表9-1 与Spring Boot组合使用的日志聚合方案的选项
很难从上面选出哪个是最好的。每个组织都各不相同,并且有不同的需求。
在本章中,我们将以Papertrail为例,介绍如何将Spring Cloud Sleuth支持的日志集成到统一的日志记录平台中。选择Papertrail出于以下3个原因。
(1)它有一个免费增值模式,可以注册一个免费的账户。
(2)它非常容易创建,特别是和Docker这样的容器运行时工作。
(3)它是基于云的。虽然我认为良好的日志基础设施对于微服务应用程序是至关重要的,但我不认为大多数组织都有时间或技术才能去正确地创建和管理一个日志记录平台。
9.2.1 Spring Cloud Sleuth与Papertrail集成实战
在图9-3中,我们看到了一个通用的统一日志架构。现在我们来看看如何使用Spring Cloud Sleuth和Papertrail来实现相同的架构。
为了让Papertrail与我们的环境一起工作,我们必须采取以下措施。
(1)创建一个Papertrail账户并配置一个Papertrail syslog连接器。
(2)定义一个Logspout Docker容器,以从所有Docker容器捕获标准输出。
(3)通过基于来自Spring Cloud Sleuth的关联ID发出查询来测试这一实现。
图9-4展示了这一实现的最终状态,以及Spring Cloud Sleuth和Papertrail如何与解决方案融合。
图9-4 使用原生Docker功能、Logspout和Papertrail可以快速实现统一的日志记录架构
9.2.2 创建Papertrail账户并配置syslog连接器
我们将从创建一个Papertrail账号开始。要开始使用PaperTrail,应访问https://papertrailapp.com并点击绿色的“Start Logging-Free Plan”按钮。图9-5展示了这个界面。
图9-5 首先,在Papertrail上创建一个账户
Papertrail不需要大量的信息去启动,只需要一个有效的电子邮箱地址即可。填写完账户信息后, 将出现一个界面,用于创建记录数据的第一个系统。图9-6展示了这个界面。
图9-6 接下来,选择如何将日志数据发送到Papertrail
在默认情况下,Papertrail允许开发人员通过Syslog调用向它发送日志数据。Syslog是源于UNIX的日志消息传递格式,它允许通过TCP和UDP发送日志消息。Papertrail将自动定义一个Syslog端口,可以使用它来写入日志消息。在本章的讨论中,我们将使用这个默认端口。图9-7展示了syslog 连接字符串,在点击图9-6所示的“Add your first system”按钮时,它将自动生成。
图9-7 Papertrail使用Syslog作为向它发送数据的机制之一
到目前为止,我们已经设置完Papertrail。接下来,我们必须配置Docker环境,以便将运行服务的每个容器的输出捕获到图9-7中定义的远程syslog端点。
注意
图9-7中的连接字符串是我的账户特有的。读者需要确保自己使用了Papertrail为自己生成的连接字符串,或者通过Papertrail Settings→Log destinations菜单选项来定义一个连接字符串。
9.2.3 将Docker输出重定向到Papertrail
通常情况下,如果在虚拟机中运行每个服务,那么必须配置每个服务的日志记录配置,以便将它的日志信息发送到一个远程syslog端点(如通过Papertrail公开的那个端点)。
幸运的是,Docker让从物理机或虚拟机上运行的Docker容器中捕获所有输出变得非常容易。Docker守护进程通过一个名为docker.sock的Unix套接字来与所有Docker容器进行通信。在Docker所在的服务器上,每个容器都可以连接到docker.sock,并接收由该服务器上运行的所有其他容器生成的所有消息。用最简单的术语来说,docker.sock就像一个管道,容器可以插入其中,并捕获Docker运行时环境中进行的全部活动,这些Docker运行时环境是在Docker守护进程运行的虚拟服务器上的。
我们将使用一个名为Logspout的“Docker化”软件,它会监听docker.sock套接字,然后捕获在Docker运行时生成的任意标准输出消息,并将它们重定向输出到远程syslog(Papertrail)。要建立Logspout容器,必须要向docker-compose.yml文件添加一个条目,它用于启动本章代码示例使用的所有Docker容器。我们需要修改docker/common/docker-compose.yml文件以添加以下条目:
logspout:
image: gliderlabs/logspout
volumes:
- /var/run/docker.sock: /var/run/docker.sock
注意
在上面的代码片段中,读者需要将command属性中的值替换为Papertrail提供的值。如果读者使用上述Logspout代码片段,Logspout容器会很乐意将日志条目写入我的Papertrail账户。
现在,当读者启动本章中Docker环境时,所有发送到容器标准输出的数据都将发送到Papertrail。在启动完第9章的Docker示例之后,读者通过登录自己的Papertrail账户,然后点击界面右上角的“Events”按钮,就可以看到数据都发送到Papertrail。
图9-8展示了发送到Papertrail的数据的示例。
图9-8 在定义了Logspout Docker容器的情况下,写入每个容器标准输出的数据将被发送到Papertrail
为什么不使用Docker日志驱动程序
Docker 1.6及更高版本允许开发人员定义其他日志驱动程序,以记录在每个容器中写入的stdout/stderr 消息。其中一个日志记录驱动程序是 syslog 驱动程序,它可用于将消息写入远程syslog监听器。
为什么我会选择Logspout而不是使用标准的 Docker 日志驱动程序?主要原因是灵活性。Logspout提供了定制日志数据发送到日志聚合平台的功能。Logspout提供的功能有以下几个。
能够一次将日志数据发送到多个端点。许多公司都希望将自己的日志数据发送到一个日志聚合平台,同时还需要安全监控工具,用于监控生成的日志中的敏感数据。
在一个集中的位置过滤哪些容器将发送它们的日志数据。使用Docker驱动程序,开发人员需要在docker-compose.yml文件中为每个容器手动设置日志驱动程序,而Logspout则允许开发人员在集中式配置中定义特定容器甚至特定字符串模式的过滤器。
自定义HTTP路由,允许应用程序通过特定的HTTP端点来写入日志信息。这个特性允许开发人员完成一些事情,例如将特定的日志消息写入特定的下游日志聚合平台。举个例子,开发人员可能会将一般的日志消息从stdout/stderr转到Papertrail,与此同时,可能会希望将特定应用程序审核信息发送到内部的Elasticsearch服务器。
与syslog以外的协议集成。Logspout可以通过UDP和TCP协议发送消息。此外,Logspout还具有第三方模块,可以将Docker的stdout/stderr整合到Elasticsearch中。
9.2.4 在Papertrail中搜索Spring Cloud Sleuth的跟踪ID
现在,日志正在流向Papertrail,我们可以真正开始感激Spring Cloud Sleuth将跟踪ID添加到所有日志条目中。要查询与单个事务相关的所有日志条目,只需在Papertrail的事件界面的查询框中输入跟踪ID并进行查询即可。图9-9展示了如何使用在9.1.2节中使用的Spring Cloud Sleuth 跟踪ID a9e3e1786b74d302来执行查询。
图9-9 跟踪ID可用于筛选与单个事务相关的所有日志条目
统一日志记录和对平凡的赞美
不要低估拥有一个统一的日志架构和服务关联策略的重要性。这似乎是一项平凡的任务,但在我撰写这一章的时候,我使用了类似于Papertrail的日志聚合工具为我正在开发的一个项目跟踪3个不同服务之间的竞态条件。事实表明,这个竞态条件已经存在了一年多时间了,但处于竞态条件下的服务一直运行良好,直到我们增加了一点儿负载并加入另一个参与者才导致问题出现。
我们用了1.5周的时间进行日志查询,并遍历了几十个独特场景的跟踪输出之后才发现了这个问题。如果没有聚合的日志记录平台,我们也就不会发现这个问题。这次经历再次肯定了以下几件事。
(1)确保在服务开发的早期定义和实现日志策略——一旦项目开展起来,实现日志基础设施会是一项冗长的、有时很困难的工作并且还会耗费大量时间。
(2)日志记录是微服务基础设施的一个关键部分——在实现你自己的日志记录方案或是尝试实现内部部署的日志记录方案之前,一定要再三考虑清楚。花在基于云的日志记录平台上的钱是值得的。
(3)学习日志记录工具——几乎每个日志平台都有一个查询语言来查询合并的日志。日志是信息和度量的一个极其重要的来源。它们本质上是另一种类型的数据库,花在学习查询上的时间将会带来巨大的回报。