7-《Elastic Stack应用宝典》第十五章~第十六章 Beats

第15章 Beats原理与结构

Beats在英文中有跳动的意思,而在Elastic Stack中,它指的是一种轻量级组件。Beats这个名称源于计算机领域中的“心跳(Heartbeat)”概念,即设备或服务每隔一段时间向监控服务发送一小段数据以表明自身存活。由于“心跳”只是存活标识而与业务无关,所以“心跳”本身应尽可能少地消耗计算资源。与普通的“心跳”不同,Beats组件主要的功能不是标识存活而是收集数据,所以它们一般都会安装到业务服务所在的宿主机上,并且按一定的时间间隔或周期采集特定数据。由于Beats组件会与业务服务运行在同一计算资源上,所以Beats组件必须要尽可能少地消耗计算资源,以避免由于消耗过多计算资源而导致业务服务不可用。所以Beats组件的基本特征是需要安装于数据产生的宿主机,并以一定的时间间隔或周期轻量地收集数据

Beats组件的轻量级特征是它和Logstash组件共存的一个重要原因。虽然它们都有数据收集、传输的功能,但Beats主要用于数据收集而Logstash主要用于数据传输。以Filebeat为例,它的主要作用是收集宿主机上的文件内容;而Logstash本身也包含一个文件输入类型,主要作用也是收集宿主机上的文件内容。但不同的是,Logstash本身由Java语言开发,是重量级的组件;而Filebeat则是由Go语言开发,是轻量级的组件。Logstash在启动、运行时会消耗大量内存、CPU等计算资源,如果与业务服务安装在一起就有可能会影响到业务服务的运行。但是正是由于Logstash的重量级特性,又使得Logstash运行稳定且包含完备的数据传输和数据过功能,而这又是Beats组件不具备的。Beats组件的轻量性要求,决定了它不可能具备复杂的数据加工能力,而这些就只能留给Logstash。

15.1 Beats体系结构

Elastic官方共提供了八种Beats组件,它们分别是Packetbeat、Filebeat、Metricbeat、Heartbeat、Auditbeat、Winlogbeat、Journalbeat和Functionbeat,可以收集的数据涵盖了网络数据包、文件数据、心跳数据、审计数据以及Linux/Windows系统日志等。除了这些官方支持的组件以外,还有几十种社区版本的Beats组件,几乎涵盖了所有可能的数据收集需求。即使这些组件不能满足实际业务需求,用户也可以根据Beats框架开发自定义的Beats组件。

尽管有多种类型的Beats组件,但它们都基于Libbeat框架开发,所以具有相同的体系结构。Libbeat是Beats组件的基础框架,包含了所有Beats组件共有特征。应该说,Beats组件的体系结构与Logstash有些相似,同样包含了与数据输入、过滤和输出相关的组件,只是它们在名称、结构以及实现上与Logstash存在着一些差异。

具体来说,Beats整体上是由输入组件、发布管道和输出组件三部分组成。

输入组件从不同数据源采集数据,采集进来的数据在Beats中也称为事件(Event)。Beats事件通常以JSON格式表示,为了与Elasticsearch索引字段相区别,Beats事件中的JSON属性将统称为属性。由于不同数据源采用的数据采集方法肯定不一样,所以输入组件是在具体的Beats类型中实现,它们的名称往往也是不一样的。比如,在Filebeat中输入组件是输入(Input)和模块(Module),Metricbeat是模块(Module)和指标集(Metricset),而Packetbeat则是协议分析器(Protocol Analyzer)。

发布管道(Publisher Pipeline)由多个处理器(Processor)和个队列(Queue)组成,它们会对输入组件采集进来的事件做加工处理,然后发送到队列中存。输出组件则负责将事件发送到最终的目标数据源,它会从队列中读取事件并将它们发送出去。发布管道和输出组件由Libbeat实现,它们在所有Beats类型中都是一样的。Beats组件的整体结构如下图所示

接下来,我们对这些组成部分再分别做以简单介绍。由于输入组件是Beats不同类型之间的核心区别,所以容比较多,将在下一章专门介绍。本章只介绍Libbeat中所有Beats共有的发布管道和输出组件

15.1.1 共有组件

由于发布管道由处理器和队列组成,所以由Libbeat框架实现的Beats共有组件可以细化为处理器、队列和输出组件三种。

  • 处理器负责对事件做加工处理
  • 队列负责缓存事件以提升效率
  • 输出组件负责最终的事件发送

1.处理器

处理器与Logstash中的过滤器插件类似,负责对事件做额外的加工和处理,比如向事件中添加、删除或更新属性等。Beats发布管道可以定义多个处理器,它们最终会形成一个职责链并依次对事件做处理。目前Beats支持的处理器包括13种,见下表

 

有关上述处理器详细介绍和使用方法,请参考15.2节中的介绍

2. 队列

为了提升Beats管道处理事件的性能,Beats组件会将读取到的事件缓存到队列中,队列可以是基于内存的也可以是基于文件的。默认情况下,Beats管道使用基于内存的队列缓存事件,并在队列缓存事件数量达到2048时将事件一次性传递给输出组件。如果在超过1s时事件数量仍然没有达到2048,队列也会将事件刷出到输出组件。也就是说,队列刷出事件有两个阈值,一个是事件数量,另一个是超时时间。基于内存的队列使用queue.mem参数配置,包括一组子参数见下表

内存可以缓存事件的数量毕竟有限,所以Beats还提供了基于文件实现的队列。这种队列会将事件存入硬盘文件中,文件默认大小为100MiB并按每页4KiB分页。输入组件读取到的事件会先写入到一个大小为1MB的缓冲区中,当缓冲区被写满或者事件数量超过16384时,缓冲区中的事件就会被写入到文件中。如果缓冲区超过1s没有达到缓冲区容量或数量上限,缓冲区中的事件也会被写入文件。也就是说,有三个阈值可以触发缓冲区向文件写入事件,即存储容量、事件数量和超时时间。一旦事件从缓冲区写入到文件中,输出组件就会立即从文件中读取这些事件。基于文件的队列可通过queue.spool开头的参数配置,也包括一组子参数见下表

==========查看嘉烜的例子=====

==========查看嘉烜的例子=====

==========查看嘉烜的例子=====

3. 输出组件

Beats输出组件一般由三部分组成,它们是工作队列、重试队列和一组工作线程。管道组件发布出来的事件会进入输出组件的工作队列,工作线程再从工作队列中取出事件做处理并发送。如果发送失败则事件将进入重试队列,并在一定时间间隔后再次由工作线程处理。输出组件也是所有Beats组件都具有的组件,由Libbeat实现。将这些共有组件整合起来,它们的结构和关系如下图所示。

15.1.2 Beats配置

Beats配置文件基于YAML文件格式,YAML是YAML Aren't Markup Language的首字母缩写。YAML文件借鉴了XML、JSON、Properties等多种文件格式,由于天然具有树状结构而使得其可读性更高。YAML具有非常完备的语法体系,可参考YAML官方网站https:/ /yaml.org/查看语法定义。这里对YAML的一些关键语法做简要介绍,以保证在使用YAML配置Beats时不会产生太多困难。

首先YAML文件中的字符大小写敏感,并且一般以冒号和缩进来表示层级关系。缩进空格的数量无所谓,但要保证同一级别的缩进数量是相同的。如果同一层级只有一个元素,也可以使用点“.”来分隔以缩减文件展示空间。YAML文件会在格式上会天然形成树状结构,如示例所示

在YAML文件中支持三种大的数据类型,即映射(Mapping)、序列(Sequence)和标量(Scalar)。

  • 映射也可以理解为是对象、字典,它是以冒号分隔开的、无序的键值对,其中键必须惟一。冒号后直接跟值时需要加至少一个空格,而冒号用在分级时则不需要跟空格。YAML也支持使用类似JSON的形式定义映射,例如上示例可以写成

  • 序列则是由一组同级别的以连接线“-”开头的行,连接线也算是缩进的一部分,要保证整个缩进还是对齐的。同样,序列也可以使用类似JSON数组方括号的形式定义。
  • 除了映射和序列以外,其余出现在冒号后面的都是标量,即具体的值。标量支持的数据类型包括数值、布尔、字符串、日期等几种子类型,布尔值为true和false,日期默认格式为ISO8601。字符串默认情況下不需要加引号,除非字符串中包含有空格或特殊字符。字符串还可以写成多行,但换行符会被转换为空格;如果想要保存换行符,需要在換行前加竖线"|"。

在配置文件中还可以使用环境变量,格式是"${VAR}",其中VAR是环境变量名称。如果指定的环境变量没有设置则会使用空字符串,但可以通过"{VAR: default_value}"的格式设置默认值,或者通过"{SVAR: ? error text}"格式设置错误提示信息。

Beats配置文件中有一组通用参数,它们可以在任何类型的Beats配置文件中使用。比如,可以通过fields参数向事件中添加额外的属性,或者通过tags参数向事件打标签等。这些通用参数见下表

在这些参数中,processors参数就用于配置Beats处理器。Beats处理器有多种类型,下一节就会讨论这些处理器

15.1.3 Beats与Kibana

由于同属于Elastic Stack家族,Beats与Elasticsearch、Logstas以及Kibana都存在着天然的联系。主要体现在这两者可以作为Beats的输出类型,这将在15.3节中介绍;而Beats与Kibana的关联则主要体现在Kibana的仪表盘和监控两项功能上。本节就来看看如何在Kibana 中配置并查看Beats的仪表盘,以及如何使用Kibana监控Beats,它们对于所有Beats类型都是相同的。此外,对于Metricbeat、Heartbeats等特定的Beats类型,它们还有专门的Kibana功能相对应,这些将在下一章中介绍到具体Beats类型时讲解。

1. 仪表盘

每种Beats组件都自了一组Kibana仪表盘,它们可以快速实现Beats采集数据的可视化。但在使用这些Kibana对象之前,需要先将Beats组件对应这些Kibana对象导入到Kibana中。在Beats组件安装路径下有一个kibana目录,这个目录中存储了与当前Beats组件对应的Kibana仪表盘对象。由于Kibana仪表盘由可视化对象和查询对象组成,所以导入了仪表盘也就导入了可视化对象和查询对象。如果仪表盘存储在其他路径中,或者希望使用自定义的仪表盘对象,可通过setup.dashboards.directory修改加载路径。

不仅如此,Kibana对象在使用之前还需要先定义索引模式。不同的Beats组件使用的索引模式并不相同,但它们基本的模式为 xbeat-*,其中的xbeat代表具体Beats类型名称。举例来说,Filebeat创建的索引模式是filebeat-*,它会匹配所有以filebeat-开头的索引;而Metricbeat创建的索引模式则是metricbeat-*,它匹配所有以metricbeat-开头的索引。所以如果Beats采集进来的数据并没有存储在默认的索引中,则需要通过setup.dashboards.index参数修改索引模式。

Beats组件导入Kibana表盘有两种方式,一种是通过Beats组件自动完成仪表盘导入,另一种则是通过命令手工完成仪表盘导入。这两种方式在导入仪表盘时,都要求Kibana已经启动并且可通过网络访问。第一种方式需要先修改Beatst配置文件,然后Beats组件重启时就会自动将仪表盘对象导入。以Packetbeat为例,它的配置文件是位于安装目录中的packetbeat.yml,在配置文件中找到如下参数并按下面的例子修改它们:

参数setup.dashboards.enabled开启了Packetbeat的Kibana仪表盘导入,它的默认值是false。参数setup.kibana.host指定了Kibana访问地址和端口,而参数output.Elasticsearch则将Packetbeate的输出指定为Elasticsearch。由于Kibana仪表盘数据来源是Elasticsearch,所以如果想要查看Packetbeat导入的似表盘效果,就需要将它的输出设置为Elasticsearch,否则仪表盘中的数据都将为空。重启Packetbeat后,在Kibana管理功能中通过Saved Obiects查看索引模式,就会发现多了ー个packetbeat-*索引模式,而在仪表盘、可视化对象和查询对象中则多出了许多名称中带[Packetbeat]标识的对象。在Kibana仪表盘中搜索packetbeat,打开[Packetbeat] Overview ECS 仪表盘像模像样的网络流量监控仪表盘就呈现出来,如下图所示

这真是一种完美的结合,要知道这仅仅是修改了Packetbeate的几配置而已,那些复杂的网络流量数据就変成了非常直观的图表。在Beats家族中,只有Functionbeat和Heartbeat没有默认的仪表盘。其中,Heartbeat虽然没有仪表盘,但它与Kibana中另一项功能Uptime相关联。有关Heartbeat与Uptime的使用,请参考16.3节

2. 监控Beats

在本书11.3节介绍了如何通过Kibana监控Elasticsearch和Kibana自身,在12.1.4节又介绍了如何监控Logstash。事实上对Beats组件的监控可能比对上述三种组件的监控还要重要。因为Beats组件需要与产生数据的业务应用安装在一起,所以它一定是分布在集群的各个节点上而且数量众多。如果没有合适的监控和报警机制,有可能会出现Beats组件崩溃而没人知道的情况。Elastic  Stack提供了对Beats组件的监控机制,所有Beats组件都可以借助Elasticsearch和Kibana轻松实现监控。从监控机制来看,Beats组件的监控与其他组件的监控并无区别,都是将自身监控数据发送给Elasticsearch,然后由Kibana将它们以图表的形式展示出来。Elasticsearch在监控中处于核心地位,需要按11.3.1节中介绍的方法开启收集组件监控数据。如果希望Beats组件被监控,需要在Beats组件的配置文件中做相应的开启并指明 Elasticsearch节点地址,例如:

Beats组件开启监控后,进入Kibana中查看监控功能就会看到Beats监控的卡片。以Filebeat为例,开启监控后的界面如下图所示

对于Elasticsearch的配置中,除了hosts以外还有一些额外的参数。这些参数大多数与Beats的Elasticsearch输出类型相同,但它们都以xpack.monitoring.elasticsearch开头的,所以在表中将它们省略以节省空间。此外它们的默认值与Elasticsearch输出也不完全相同,具体请参见下表。

15.2 Beats处理器

每一个Beats处理器都有一个惟一标识处理器的名称,比如add_fields用于向事件中添加属性,而rename则用于修改属性名称。它们通过配置文件的processors参数设置并开启。所以在processors参数下就是一组处理器名称,而在每个处理器中又包含了处理器应用的条件和处理器本身的配置参数。处理器配置格式如示例所示:

processors参数可以设置全局处理器,也可以设置局部处理器局部处理器只在某一特定输入中有效。换句话说,processors参数可以直接定义在配置文件的根元素上,也可以定义在特定输入元素下面,具体取決于Beats组件的类型。比如对于Filebeat来说,processors可以定义在filebeat_inputs的列表中;而对于Packetbeat则可以定义在packeted.protocols的列表中,这些处理器将只在这个输入类型的范围内有效。

处理器都包含一个when参数,用于定义处理器的执行条件。有些处理器的执行条件是可选的,如果没有定义执行条件则处理器总会执行。另外一些处理器的执行条件则是必须的,处理器仅在满足执行条件的情况下才会执行。处理器执行条件可以根据事件某一属性做比较运算,比较结果可以再与其他条件通过逻辑运算组合起来。

例如在下面示例中,处理器的执行条件使用了逻辑与运算,而参与逻辑与运算的两个条件分别是正则表达式和等于。它们结合在一起的含义是当message属性以"["开头并以"]"结尾,并且input.type属性为stdin时,向事件添加formattedMsg属性

在上面示例中,and、regexp和equals就是在when参数中可以使用的执行条件,下表列出了所有可以使用的执行条件,它们的使用方法与示例中展示的三个执行条件类似。

在这些处理器执行条件中,or、and、not属于逻辑运算,所以参与运算的都是其他执行条件。在使用上,or、and需要使用YAML列表提供各个执行条件,而not则直接定义其他执行条件即可。下面按处理器的功能分门别类对它们做简要介绍。

15.2.1 添加逻辑信息

这一类处理器用于向事件添加用户自定义的信息,这些信息都与具体业务逻辑相关联,并通过新的属性(Field)、标签(Tag)、标注(Label)体现出来。实现这些功能的处理器是add_fields、 add_tags和add_abels,它们是在Beats版本7之后被加入到处理器家族中。

1. add_fields

add_fields处理器可以向事件添加额外的属性,它们默认会被添加到fields属性下,也可以通过target参数来配置添加位置。如果想要将属性添加到根元素下,则将target参数设置为空,即target:""。向事件中添加的额外属性可通过add_fields.fields参数来配置,可按键值对的形式设置多个,如示例所示:

示例中定义了两个add_fields处理器,第一个处理器添加了一个log属性到事件根元素上,而第二个处理器同样也添加了log属性,但这个属性会被到添加到fields属性下。第二处理器添加的另属性是service,这个属性最终会以JSON对象的形式添加到fields属性中。需要特别注意的是,如果新添加的属性在事件中已经存在,那么add_fields将覆盖原来的属性值。比如在上述示例中,第一个处理器的log在事件中就已经存在,那么原事件中的log属性就会被覆盖。

事实上,Beats组件还有另外两个更为通用的配置项fields和fields_under_root,它们也可以用于向事件中添加属性。例如

示例中,fields参数用于设置需要添加的属性,而fields_under_root参数则用于指定是否将属性添加到事件的根元素上。与add_fields处理器相比,上述示例中配置的属性是在读取时就添加到事件中,所以如果add_fields处理器中添加了同名的属性会覆盖这里设置的值。另外一点区别就是使用fields参数添加进来的属性要么添加到fields属性中,要么添加到根元素中,而不能通过设置target参数指定添加到其他属性中。

所以总的来说,使用fields添加的属性应该是一些基础的、通用的属性,它在读取事件时就添加到事件中。而使用add_fields处理器添加进来的属性应该是一些定制化的特殊属性,它在事件读取完成后在处理器组件中完成

2. add tags

add_tags处理器用于向事件添加标签(Tag),标签是一组字符串,代表了事件的某一种特征。默认情况下标签会被添加到事件的tags属性中,tags属性是一个包含了多个字符串的数组。标签添加的属性可通过target参数来设置,而需要添加的标签则通过tags参数设置,例如

需要注意的是,标签只能被添加到某一属性中,而不要指望通过target的形式将它们添加到事件的根元素上。另外,与add_field处理器类似,Beats组件也包含一个通用的tags参数用于添加通用的标签。tags参数设置的标签内容只能添加到tags属性中,add_tags设置标签最终会与tegs参数设置的标签合并起来。

3. add_labels

add_labels处理器用于向事件添加标注(Label),标注与标签的区别在于标注是一组键值对而标签只是一组字符串。标注只能被添加到事件的labels属性中,这是add_labels处理器与add_fields、add_tags处理器的一个显著区别。add_labels处理器只有一个参数labels,用于设置希望向事件中添加的标注,例如

示例中,add_labels处理器向事件添加了log和service两个标注。需要特别注意的是,serice属性在配置时虽然使用对象的形式,但它们在添加到labels属性后会被平铺为serice.name和serice.author两个属性。这是add_labels处理器与add_fields处理器的另一个区别。

15.2.2 添加基础信息

这一类处理器用于向事件添加与业务逻辑无关的基础信息,这包括Beats组件运行的主机、进程、时间等等信息。

1. add_host_metadata

add_host_metadata处理器用于向事件添加Beats组件运行主机的信息,包括主机名称、操作系统、网络信息等。add_host_metadata处理器中可用的参数见下表

add_host_metadata处理器默认情况下会被添加到处理器链表中,读者可自行查询默认配置文件

2. add_process_metadata

add_process_metadata处理器用于向事件中添加某一进程的相关信息,这包括进程的名称、ID、参数等。add_process_metadata处理器通过match_pids参数定义的属性列表来査找进程PID,然后再根据PID将其对应的进程信息添加到事件的process属性中。默认情況下, process属性会被添加到事件的根元素下,但可以通过target参数设置添加到其他元素下。例如:

示例配置的add_process_metadata处理器会从message中获取PID,然后根据PID査询进程信息,最后将进程相关信息保存在details.process属性中。返回结果如下所示:

add_process_metadata处理器可用参数见下表

3. add_locale

add_locale处理器用于向事件中添加时区信息,时区信息最终会被添加到event.timezone属性中。add_locale处理器只有一个参数format,用于设置时区名称的格式。format参数支持offset和abbreviation两个可选值,默认值offset以类似“+08:00”的偏移量形式显示时区,而abbreviation则以时区简称显示时区。

15.2.3 添加云信息

这一类处理器也用于向事件添加与业务逻辑无关的基础信息,但这一部分信息主要是Beats组件运行的云、Kubernetes、Dockers等环境信息。

1. add_cloud_metadata

add_cloud_metadata处理器用于向事件中添加云服务的元数据,这些有关云的元数据将会存储在事件的cloud属性上。 add_cloud_metadata处理器会在Beats组件启动会检测所在云主机的基本信息,然后将这些信息缓存起来并在后续处理事件时使用。目前支持包括亚马逊AWS、阿里云、谷歌云腾讯云、微软云Azure、Openstack、Digital Ocean等7种云服务。

add_cloud_metadata处理器支持timeout和overwrite两个参数,前者用于设置获取云主机信息的超时时间,而后者则用于设置是否覆盖已经存在的coud属性。例如:

示例中,通过两个参数设置了超时时间为3s,并且不覆盖coud中已经存在的属性值,这两个值也是它们的默认值。

2. add_kubemetes_metadata

add_kubemetes_metadata处理器用于向事件添加Kubernetes中Pod相关信息,Kubernetes是一套由Google开源的容器管理与编排弓擎,而Pod则是Kubernetes可以创建和管理的最小可部暑单元。目前无论是在国外还是在国内,Kubernetes都得到了极为广泛的应用,它是使用第三方云服务之外的一种替代方案。

add_kubemetes_metadata处理器会将所在Pod的名称、UID、名字空间和标签都添加到事件中。add_kubemetes_metadata处理器可用参数见下表

3. add_docker_metadata

add_docker_metadata处理器用于向事件添加Docker容器相关信息,包括容器ID、名称、镜像和标签等。例如

15.2.4 删除数据

Beats还提供了一组可以用于数据清洗的处理器,它们可以删除事件中的属性,或者在条件满足时除整个事件。

1. drop_fields

drop_fields处理器用于从事件中删除一个或多个属性,需要删除的属性通过该处理器的fields参数定义。fields参数的数据类型为字符串类型的数组,其中每个元素为一个属性的名称。

例如下面示例定义的drop_fields处理器,将事件中的beat.version和message两个属性删除了:

有两个属性不能通过drop_fields处理器删除,它们是@timestamp和type,即使它们明确地出现在fields参数中。

2. include_fields

drop_fields处理器通过直接指定需要删除的属性,将不需要的属性从事件中删除;include_fields处理器则刚好相反,它通过定义需要输出的属性来排除其他属性。这个处理器也是使用fields参数设置需要输出的属性,同样的,@timestamp和type属性无论是否出现在fields 参数中都会被输出。例如示例中的输出事件中,除了@timestamp和type属性以外,将只包含message属性

3. drop_event

drop_event处理器用于在满足一定条件的情况下删除整个事件,所以定义drop_ event时必须要定义删除条件。

例如在示例中当事件的level属性为debug时,执行drop_event将事件删除

15.2.5 转换数据

除了可以向事件中添加属性、除属性以外,Beats还有一组可以修改属性的处理器。它们是rename、dissect、decode_json_fields和dns。

1. rename

rename处理器用于修改属性名称,需要修改名称的属性在fields参数中定义。fields参数为列表类型,其中包含from和to两个子参数。前者用于指定需要属性的原始名称,而后者则用于指定属性修改后的名称。

例如在示例中定义的rename处理器会将message属性更名为originMsg:

除了fields参数以外,rename处理器还支持ignore_missing和fail_on_error两个参数。这两个参数都是布尔类型的,前者用于设置是否忽略属性缺失,默认值为false;而后者则用于设置在重命令失败时是否报错,默认值为true。

2. dissect

dissect处理器用于根据定义的模式对文本内容做拆解,拆解出来的字符串会根据模式定义的名称存储到相应的属性上。dissect拆解字符串使用的模式由tokenizer参数定,在模式中可以使用%{field name}的格式定义拆解字符串的单元。

例如在示例定义的模式中,message属性将以空格为分隔符拆解,提取出来的字符串最终会存在在事件根元素下的command、action和argument三个属性上

除了使用tokenizer字义拆解模式以外,field参数用于定义需要拆解字符串来自哪一个属性,而target_prefix则定义了拆解后属性的前缀。如果dissect处理器不能按模式拆解字符串,则模式中定义的属性将不会被添加到事件中。

3. decode_son_fields

decode_json_fields处理器用于解析JSON字符串,并将JSON字符串转换为事件的JSON对象。decode_json_fields处理器从fields参数指定的属性中读取JSON字符串,然后将它们解析成JSON对象后存储在target参数指定的属性上。

例如示例定义的处理器会将message属性解析为JSON对象,并将JSON对象存储在事件的根元素

 

如果输入为"{"name": "tom", "age":12}",那么事件message属性的值将是"{\"name\": \"tom\", \"age\":12}", 是一段未被识别为JSON对象的纯文本字符串。但经过示例中的decode_json_fields处理器解析后,将会在事件中添加user属性,如下所示 

除了fields、target参数以外,decode_json_fields处理器还有一些其他参数,这些参数中fields参数是必须要设置的。见下表

4. dns

dns处理器根据IP地址通过DNS反查域名,需要询的IP地址通过fields参数来定义。fields参数定义了一组键值对的映射,键是需要反查域名的属性,值则是反查结果存储的属性。dns处理器反查域名时使用的服务器由nameserers定义,nameservers在Windows环境下必须要设置,而在Linux环境下会默认使用/etc/resolv.conf文件中定义的域名服务器列表。认情况下,dns处理器会忽略反查域名时出现的错误,但也可通过tag_on_failure配置在错误时为事件添加标签。具体如下所示:

在示例中,type参数用于指定DNS查询类型,目前仅支持reverse,是dns处理器必须要配置的参数。下表列出了dns处理器支持的所有参数。

由于查询DNS存在网络开销,所以如果每个事件都连接DNS做查询会大大降低事件处理效率。为了提升性能,dns处理器会将每一次查询结果绶存起来。对于成功的DNS查询,查询结果会依据询响应TTL定义的周期缓存。而对于失败的DNS查询,查询结果也会缓存起来,但存有效期由failure_cache.ttl定义,默认值为1min。成功存和失败缓存是分开存储的,它们容量的定义可以参见上表中的相关参数。 

15.3 Beats输出组件

Beats输出组件由Libbeat框架实现,所以它们的类型、配置对所有Beats组件也都相同。由于同属Elastic家族,Elasticsearch(elasticsearch)和Logstash(logstash)是Beats输出的主要类型。除此之外还支持Kafka消息中间件(kafka)、Rediss缓存(redis)、文件(ile)、控制台(console)、Elastic云服务(cloud)等几种输出的类型。上述输出类型后面的括号中,是Beats配置这些输出类型时使用的关键字。此外Functionbeat比较特殊,它仅支持Elasticsearch和Coud两种输出组件。

从配置的角度来看,输出组件都是通过配置文件中的output参数开启,output参数后接输出组件的关键字。每种输出组件的配置中还包含一些参数,其中enabled参数是所有输出组件都具有的一个参数,用于开启或关闭当前的输出类型,这个参数的默认值都是true。所以,如果接受输出类型的所有默认配置,开启一个输出类型最简单的方式就是直接在配置文件中添加output.<类型关键字>。

由于Elasticsearch、Logstash和Coud输出类型同属Elastic Stack家族,所以它们在输出格式上都是一致和固定的。但对于其他Beats输出组件来说,它们的输出格式则可以定制,这种定制通过输出类型的codec参数定义。codec参数的默认值为json,即Beats组件认都会以 JSON格式输出事件。json输出格式有两个布尔类型的参数pretty和escape_html, pretty用于设置是否将JSON输出格式化,认值为false;而escape_html则用于设置是否将HTML标签转义,默认值也是false。

除了json以外,codec参数另一个可选值为format。format有一个名称为string的参数,可以设置以"%{}"为基础的输出格式。

例如,为Beats组件添加控制台输出类型,并将输出编码格式定义为format

示例中,codec.format.string将事件的@timestamp和message属性按一定格式组织起来作为输出。console输出组件会将事件输出到控制台,这在测试Beats组件时查看输出结果还是比较有用的,但很少会用于生产环境。console输出组件还支持pretty和bulk_max_size两个参数。前者用于设置是否格式化输出结果,而后者则用于设置发布前缓存事件的数量。

15.3.1 输出到Elasticsearch

由于elasticsearch输出组件可用参数非常多,所以下面分几个部分介绍它们。

1. 连接 Elasticsearch

如果希望将Beats组件收集到的数据发送到Elasticsearch,首先要定义连接Elasticsearch的方式和地址。output.elasticsearch包括 hosts、protocol、path、proxy_url等几个用于设置连接的参数,其中hosts参数接收一组Elasticsearch节点访问地址,地址格式可以是标准的URL,也可以是IP: PORT格式的地址。hosts接收参数的类型为list,当指定多个节点时Beats会轮询Elasticsearch以实现负载均衡。Beats组件会为每一个Easticsearch节点创建一个独立的线程,也可以通过worker参数加大线程数量以增加吞吐量。其他与连接Elasticsearch相关的参数,请参考下表

2. 索引名称

在默认情况下,Beatse的elasticsearch输出组件会将事件编入名称为Xbeat-%{ [agent.version%]}-%{+yyyy.MM.dd}的索引,其中XBeat代表某一Beats类型的名称。例如,对于Filebeat来说,索引名称可能为filebeat-7.0.0-2019-07-07。

自定义索引名称有两种方式,一种是直接通过index参数更改索引认名称,另一种方式是使用indices参数设置规则,将输入的数据编入不同的索引中。通常可以使用indices的子参数when设置不同的条件以对应不同的索引

例如根据message属性包含的日志级别,将日志数据编入不同的索引中,则其配置如下示例所示

在示例中使用了when.contains定义匹配规则,它代表的是包含关系,即属性内容是否包含某一字符串。如果message属性中包含有ERROR,则日志将被编入error-%{+yyyy.MM.dd}索引中;如果包含INFO则编入info-%{+yyyy.MM.dd}索引中;而如果两者都不包含则会编入index参数设置的索引中。when 参数可以使用的条件关键字与处理器中可用条件完全一致,具体请参考15.2节中的表格。

除了使用when指定不同的条件外,还可以使用mappings参数将索引名称做固定的映射转换。如果在mappings中没有定义相应的规则,则可以使用default子参数定义默认索引名,这非常像编程语言中的switch case语句。

例如同样是根据日志级别将日志分别记录到不同文件,也可以使用如下的配

在示例中,首先从事件中取出level属性作为index参数的值,然后再根据mappings配置的映射关系将index参数的值转换为最终的索引名称。在示例中 mappings将 error、info分别与error-logs、info-logs对应起来,所以当日志级别为error、info时,日志将会被编入error-logs、info-logs 索引中。下表列出index和indices两个参数的详细信息

3. 索引模板

在确定了编入索引名称之后,当文档数据首次编入索引时会动态创建索引,这时就需要使用Elasticsearch的索引模板了。索引模板根据预定义的名称规则匹配索引,然后将索引模板中定义的配置和映射规则应用到新创建的索引中。在认情况下,Beats组件索引模板定义的名称规则是XBeat-*。同样,Xbeat也是代表了具体Beats类型的名称。例如,对于Filebeat来说模板名称规则为filebeat-*,匹配所有以filebeat-开头的索引。Beat组件会在与Elasticsearch连接上之后,将Beats索引模板添加到Elasticsearch中;如果Elasticsearch中已经存在了相同的索引模板,Beats会延用之前的模板而并不是覆盖它。显然,如果想让Beats创建索引时应用上索引模板,索引名称与索引模板定义的名称规则必须要协调一致,修改其中任何一个的同时要更新其余所有相关联的配置。

如果想要修改索引模板的默认设置,可以在配置文件中修改相关配置,这些配置都以setup.template开头。下表列出了与索引模板相关的所有配置,为了节省空间略去了参数前缀setup.template

默认情况下,在每种Beats组件的安装路径下都有个fields.yml文件,这个文件就用于导入索引模板。同时由于这个文件定义了Beats组件输出的所有属性,并且多数都添加了注释说明,所以也是在学习和使用Beats组件时的重要参考资料。 

15.3.2 输出到Logstash

如果希望将Logstash添加为Beats的输出,需要在配置文件中将配置项outpu.logstash开启。与Elasticsearch类似,output.logstash也包含一个hosts参数可以设置多个Logstash节点。但在认情况下Filebeat并不会对多个Logstash节点做负载均衡,而是从 Logstash节点是任意选择一个节点做输出。只有当loadbalance参数设置为true时Beats组件才会在多个Logstash节点做负载均衡。Beats连接Logstash其他相关参数见下表

 

 

所有Beats组件都会向Logstash输入事件的metadata属性添加beat、version、type三个子属性,它们一般是提供给Logstash用于定义向Elasticsearch输出时的索引名称。其中,version属性保存着Beats组件的版本,beat属性默认则会保存Beats组件的具体类型名称,比如 Filebeat保存的beat属性值就是filebeat,而Packetbeat保存的则是packetbeat。但也可以通过index参数修改它的默认值,例如在示例中将index参数设置为mybeat, 则输出到Logstash时@metadata.beat就会跟着一起发生变化

 

@metadata.type属性保存的是Elasticsearch索引的映射类型,由于映射类型已经在Elasticsearchk版本7中废止,所以type只是为了与之前的版本兼容,它的值是固定值_doc。Beats组件向Logstash输出的其他相关参数见下表

  

15.3.3 输出到Kafka

Kafka是一种性能很好的消息中间件,在生产环境中可以用来应对突发流量,以实现削峰填谷、保护后台应用的效果。Beats连接Kafka时需要通过hosts参数指定Kafka连接地址,还可以通过version参数指定Kafka版本号。目前Beats支持Kafka版本号为0.0.8.2.0至2.1.0, 默认值为1.0.0。如果Kafka 开启了身份认证,则可以通过username和password 两个参数设置认证的用户名和密码。Beats 组件与连接 Kaka 相关的参数见下表

除了连接 Kafka 的一些必要参数以外,另一个需要设置的参数是topic,用于指定事件发送到Kafka的哪一个主题中。所以一个最简单的连接Kafka配置如下:

除了使用topic设置惟一主题以外,还可以使用topics将不同的事件根据条件发送到不同的主题中,这与elasticsearch输出组件的index和indices的关系类似。另外,partition参数可用于设置Kafka的分区规则。这些参数具体见下表

补充:线上Service_Live filebeat.yaml配置示例如下

######################## Filebeat Configuration ############################
##
##
###=========================== Filebeat prospectors ============================

filebeat.prospectors:
#------------------------------ Log prospector --------------------------------
#
- input_type: log
  paths:
    - /data1/www/applogs/service.live.xxx.com/logs/*log
  exclude_files: ['\.gz$']
  ignore_older: 25h
  close_inactive: 24h
  tail_files: true
  document_type: service_live_applog_log

- input_type: log
  paths:
    - /data1/www/logs/service.live.xxx.com-access_log
  ignore_older: 25h
  close_inactive: 24h
  tail_files: true
  document_type: service_live_access_log

- input_type: log
  paths:
    - /data1/www/logs/live.xxx.com-access_log
  ignore_older: 25h
  close_inactive: 24h
  tail_files: true
  document_type: live_access_log

output.kafka:
  hosts: ["yz-re009.kafka.xxxx.com:9110","yz-re006.kafka.xxx.com:9110","yz-re002.kafka.xxx.com:9110","yz-re005.kafka.xxx.com"]
  topic: '%{[type]}'
  username: 'xxxx-dpool'
  password: 'xxxxxxxxx'
  version: 0.10.0.0

  partition.round_robin:
     reachable_only: false
  compression: gzip
  timeout: 10
  max_message_bytes: 1000000
  codec.format:
        string: '%{[message]}'
#================================= Paths ======================================
path.home: /usr/share/filebeat/
path.config: /data1/filebeat/conf/
path.data: /data1/filebeat/data/
path.logs: /data1/filebeat/logs/

#================================ Logging ======================================
#
logging.to_files: true
logging.files:
  path: /data1/filebeat/logs/

  keepfiles: 7

15.3.4 输出到Redis

Redisz是一种应用比较广泛的分布式缓存中间件,由于它既可以基于内存也可以持久化,所以在很多文献中也把它归类为是一种基于键值对的NoSQL数据库。Beats连接Redis是通过hosts参数指明一个或多个Redis实例地址和端口,如果配置了多个Redis实例地址同时又将 loadbalance参数设置为true, Beats将在多个Redis实例中做负载均衡。下表列出了其他与连接Redis相关的参数。

尽管Redis在多数情况下被认为是一种缓存或数据库,但在很多场景下也可以被当作MQ来使用。例如,Redis支持的List数据类型或发布订阅机制都可以当成MQ来使用。事实上,Beats组件在连接Redis时也是只支持这两种方式发送事件,要么使用List数据类型的RPUSH命令将事件添加到List中,要么使用发送订阅机制的PUBLSH命令将事件发送到管道中。可见,Beats是将Redis当成与Kafka类似的分布式MQ来使用默认情況下,事件将会被发送到以Beats类型名称为键的List中。如果不想使用List,则可以通过配置参数datatype来修改,它的可选值包括list和channel两种

示例中使用的key参数定义了使用List的键名,而db则定义了使用的是Redis中的哪一个库。除了使用key参数定义Redis键名以外,还可以使用keys参数以类似Elasticsearch输出参数indices的方式,根据条件动态确定Redis键名。有关这些参数的说明见下表

 

15.3.5 输出到文件

与控制台输出类型类似,文件输出类型一般也用于测试场景,在生产环境中使用的也不多。文件输出类型的配置也不复杂,但必须要指定输出文件的路径,例如 

 

示例中,Beats会将事件输出到/tmp/beatout路径下名为out的文件中。如果文件大小超过rotate_every_kb参数设置的10000kb,Beats则会将文件命名为out.1并创建一个空白的out文件继续写入。如果新的out文件也超过了上限,将会以滚动方式将文件命名为out.1、out.2但滚动文件的数量是有上限的,number_of_files参数设置了它的最大数量,超过了这个上限后旧文件将会被删除。文件输出类型配置参数具体见下表

15.4 本章小结

本章介绍了Beats整体的体系结构,它与Logstash极为相似,大体上是由输入组件、发布管道、输出组件三部分组成。发布管道主要是用于处理事件的处理器,它的职责与Logstash过器相同。同时为了提升性能,发布管道中也包含有队列,只是这些组件相Logstash要轻量得多。

所有Beats类型都是在Libbeat框架上开发出来的,因此由Libbeat框架中的组件对于所以Beats类型都是有效的。Beats中的输入组件由各种Beats类型单独实现,而发布管道和输出组件则由Libbeat框架现。本章主要就是介绍了这些公共组件中的处理器和输出组件。

一个Beats实例中可以配置多个处理器组件,它们会组成处理器的职责链,按顺序依次对事件做预处理。这些处理器可以向事件中添加数据、除数据或是对数据做一些简单的变換,以保证事件在发送出去之前数据的完整性。

一个Beats实例也可以配置多个输出组件,Beats可以输出的目标数据源包括Elasticsearch、Logstash、Kafka、Redis、File和Console。如果希望输出到其他数据源,可以使用Loastash做进一步的适配。

在介绍了Beats共有组件后,下一章开始将介绍Beats不同类型之间的核心区别,即它们的输入组件。

第16章 Beats采集数据

Beats处理器组件、输出组件由Libbeat实现,所以在所有Beats组件中基本上都是通用的。但Beats输入组件由具体Beats实例单独实现,它们之间存在着巨大差异,也是不同种类Beats之间的核心区别。

本章就来介绍这些输入组件的使用方法。

16.1 网络通信

Packetbeat是Beats家族中的第一个成员,可通过轻量的方式采集网络数据包。正是它的设计思想启发了Elastic Stack,并由此开启了Beats家族的兴盛之旅。

Packetbeat监控的对象是网络流量,它监听特定网络端并抓取网络数据包,最后将这些网络流量数据汇总后发送出来。

Packetbeat可以直接安装到业务服务器上,也可以安装在另一台专用服务器上,然后从镜像端口或使用TAP设备获取业务服务器的网络数据包。显然将Packetbeat安装在专用服务器上更为理想,因为这样Packetbeat的运行不会对业务产生影响。但由于需要专用网络设备,所以也限制了这种方式的具体应用。比如在一般情况下,云服务就不会提供这样的设备服务。在实际应用中,用户可以根据实际业务情况和部暑环境选择最合适的安装方式。

Packetbeat有三种监听网络数据包的形式:

第一种是通过通信协议并指定具体监听的端口

第二种是监听整个网络通信的过程

第三种是监听本机进程之间的通信

默认情况下,前两种监听方式都会被Packetbeat打开。但无论使用哪一种监听方式,首先都必须先要通过一些基本安装和配置,让Packetbeate组件正确地运行起来。

16.1.1 安装配置

Packetbeat安装后可能无法直接运行,这是因为Packetbeat在运行时需要第三方抓包工具,所以在未安装抓包工具的操作系统上运行Packetbeat会报错。Packetbeat支持两种抓包方式,可通过packetbea.interfaces.type参数来设置。

第一种:使用libpcap库抓取,相应的参数值为pcap。这种抓包方式在Linux中需要安装libpcap,而在Windows中则需要安装Winpcap。具体来说,Ubuntu系列的Linux可执行“sudo apt install libpcap0.8”安装;而Centos系列的Linux 则可执行“sudo yum install libpcap”。在Windows环境下,则需要先到Winpcap官网下载安装包,安装时需要以管理员身份运行安装程序,否则将无法抓取网络数据包。此外,由于 Winpcap 存在安全隐患,读者可根据WinPcap官网介绍以兼容Winpcap的方式安装Npcap。

第二种:使用af_packet,它使用Linux特有的特性,以内存映射的方式来获取网络数据包。这个选项比使用libpcap快,但由于使用了Linux特性,所以只能在Linux下使用。af_packet的工作方式是将内核态与用户态的不同应用映射到相同的内存区域,并且在这个内存区域中创建循环冲区,内核向循环缓冲区写入网络数据包而用户程序则从缓冲区中将它们读取出来。缓冲区的默认大小是30MB,缓冲区越大所需的系统调用就越少,可以通过packetbeat.interfaces.buffer_size_mb参数修改。

安装好抓包工具后,还需要指定嗅探网络设备的编号。在packetbeat.yml 文件中,配置网络设备的参数为packetbeat.interfaces.device,默认值0代表编号为0的设备。如果想要查看网络设备,可在命令行运行"packetbeat devices"命令,该令会列出主机上所有网络设备及其编号。在返回结果中找到想要监控的网卡,然后将它的编号设置到上述配置参数中。如果是在Linux系统上,可以将该配置项设置为any, 将嗅探所有网络设备。为了能够让packetbeat运行起来,本小节已经介绍了三个packetbea.interfaces相关的参数devices、type和buffer_size_mb。但packetbeat.interfaces可用参数还有一些,它们具体含义列在下表中。

 

16.1.2 通信协议

Packetbeat抓取网络数据包是以不同的通信协议为单元做区分,针对不同协议Packetbeat的配置和抓取数据会有一些不同。 Packetbeate目前支持14种通信协议,可通过packetbeat.protocols参数添加,它们是ICMP (v4和v6)、DHCP (v4)、DNS、HTTP、 AMQP 0.9.1、Cassandra、Mysql、Postgresql、Redis、Thrift RPC、MongoDB、Memcache、NFS和TLS。默认情况下,这些通信协议都会被监控,并且配置了一些默认的监听端口。用户可根据实际需要开启或关闭这些协议,如下所示

上述示例中,packetbeat.protocols开启了HTTP、Mysql和TLS协议的网络数据抓包,它们均使用ports参数来配置抓取数据的端口。除了ports以外,packetbeat.protocols还有一些与具体协议无关的通用参数,见下表

在表中,fields、fields_under_root、tags和processors与15.1.2节中介绍的通用参数用法和含义完全相同,区别在于此处的参数设置仅针对当前通信协议有效。除了这些通用参数以外,每种协议还有一些只在当前协议中有效的配置参数,这些参数按协议分别在下表中

16.1.3 通信流程

Packetbeat可以配置为收集一个完整网络通信流程的数据包,这里所说的通信流程(Fow)是指在同一时间段内发送或接收的具有相同属性的所有网络数据包,比如在HTTP协议下请求和响应就形成个完整的通信流程。Packetbeat识网络数据包是否属于同一个流程,主要是看网络数据包是否同属一种协议、是否具有相同的发送端和接收端等等。在默认情况下,当接收端在30s之内没有再接收到新的网络数据包,Packetbeat就认为一个通信流程结束了。此外,为了提升性能,还设置了发送通信流程数据的时间间隔。默认每隔10s发送一次通信流程数据。

Packetbeat通信流程主要通过packetbeat.flows参数配置,刚刚提到的通信流程超时时间和发送时间间隔就是通过timeout和period参数设置。例如:

上例展示的配置实际上是Packetbeate的默认配置,其中通过enabled开启了通信流程监控,而timeou和period参数则设置了通信流程超时时间和上报时间间隔。下表列出了packetbea.flows的主要参数,其中fields、fields_under_root、tags和processors也是仅在当前配置的流程中有效。

对于每个流程,Packetbeat会收集从源主机发送到目标主机的包数量和字节总数,并将这些信息存储在network属性中。相同流程的数据包具有相同的id属性,同时还有一个final属性来标识当前数据包是否为最后一个数据包,这两个信息会存在在flow属性中。其余与流程相关的属性主要是source标识的源主机信息,以destination标识的目标主机信息。下例展示了一段网络流程监控的返回结果,可比照上述说明查看其中的属性信息

 

 

16.1.4 本地进程

在默认情况下,Packetbeat收集的网络数据是在不同物理节点之间传输。在有些情况下,单个服务器有可能会部暑多个应用,如果想收集这些应用之间的网络数据传输,就需要开启Packetbeat对进程之间网络数据的收集。这可以通过packetbeat.procs开启,它包括  enabled和monitored两个参数。其中enabled接收boolean类型的值且默认值为false,用来标识是否开启进程间网络数据包监控。当开启进程间网络数据包监控后,在输出中会添加cmdline和client_cmdline属性,用于标识通信双方的本地进程。另一个参数monitored用于配置要监控的进程有哪些,它包括process、cmdline_grep、 shutdown_timeout三个子配置项。其中,process是在输出中显示的名称,而cmdline_grep则是要监控的进程,shutdown_timeout则是超时时间。

16.1.5 事件属性

无论是通过哪一种方式监听网络数据包,它们最终都会以事件的形式输出。不同种类的协议或配置方式输出的事件属性有很大差异,许多属性都是与具体通信协议相关的信息。限于篇幅本书不太可能将每一种协议输出的属性全部讲解,但在Packetbeatz安装路径下有一个 fields.yml的文件,这个文件其实是导入Elasticsearch的索引模板,其中定义了每一种协议对应事件的全部属性及其说明。这个文件以YAML列表格式保存每种事件的格式,列表的每一个事件以key属性开头定义,通过它就可以知道当前事件是哪一种事件。例如要想查看 HTTP协议事件的属性,可以通过搜索功能查找"key: http"就可以找到所有事件及其属性说明。更为详细的说明还可以到Elastic官网査找。fields.yml文件在其他Beats类型中也有,在学习后面小节内容时同样可以参考它们的fields.yml文件

16.2 文件数据

Filebeat一般用于采集宿主机本地保存的文件,然后将它们发送到指定的目的地,以实现对文件内容的收集、归档和分析等。最典型的应用场景是收集日志文件,能够在不侵入现有业务系统的情况下实现日志收集,比如将日志收集到Elasticsearch中以供检索分析使用。这对于采集第三方应用产生的日志来说尤为重要,因为多数第三方应用的日志只提供了本地文件日志。比如MYSQL、Tomcat等第三方应用,它们一般只会在指定的目录中保存日志文件,而没有提供将日志写到其他地方的功能。所以如果想对它们的日志做统一分析和处理,就必须在日志文件所在主机安装采集日志的Agent。能够实现这种功能的组件除了Filebeat以外还有很多,比如Flume、Scribe等。

Filebeatt 输入组件的配置相对其他 Beats:来说更为灵活,可以通过两种方式实现,它们对于学习后面的 Beats 组件配置也有一定的借鉴意义。第一种方式是通过输入类型指定输入组件,另一种则是通过开启模块指定输入组件。前者根据输入类型和用户自定义的配置收集数据,数据从哪里收集以及如何展示都需要用户自定义;而后者则预先定义了一组通用系统的日志收集配置,每一组配置就是一个模块并针对一种第三方应用。所以相对来说,输入类型在配置上更自由更灵活,而模块则更简便更快捷。下面就来看看这两种方式是如何配置和使用的

16.2.1 输入类型

尽管大多数系统的日志都写到文件中,但依然有一些系统的日志并不是以文件的形式存在。比如Redis的慢查询日志就不是存储在文件中,而是以Redis5列表的形式保存在内存中。还有通过Syslog协议传输的日志数据也不是以文件形式存在,而是通过UDP或TCP协议传输。为了能够处理这些类型的日志数据,Filebeath提供了对8种输入来源类型的支持,对应着八种输入类型

输入类型通过filebeat.inputs参数开启,它是list类型的参数,可以接收多个相同或不同类型的输入组件。每个输入组件都有一个type参数用于设置输入组件的类型,每种类型的输入组件都有特定的配置参数。例如,在下面的示例16-4中就开启了log和docker两种类型的输入

在示例16-4中,log输入类型通过paths参数设置了日志文件的路径,而docker输入类型则通过containers.ids参数设置了容器ID。

使用这些输入类型的关键是了解它们的可用参数,接下来就来逐一介绍这些输入类型的可用参数。

1. log输入类型

log输入类型主要用于收集文件中的日志数据,这是Filebeat支持的最主要输入类型。log输入类型必须要配置的参数是paths,用于设置日志文件所在路径。参数类型为list,可以接收以Glob模式定义的路径。log输入类型支持的参数很多,具体见下表

虽然log输入类型可选参数非常多,但它们大多不需要配置。最简单的形式就是类似示例16-4中那样,只配置paths参数即可使用。16.2.3节还将对上表中的部分参数做更详细的介绍。

2. docker输入类型

一种办法是将日志从Docker容器中映射到宿主机上,而Filebeat则直接部署于宿主机上收集这些映射出来的日志文件。

另一种办法是将Filebeat与业务应用部署在同Docker容器中,这样也可以将Docker中的日志收集出来。

补充:现在公司的方法是,将日志从Docker映射到宿主机上,再启动一个Filebeat容器,将宿主机上的日志挂载进Filebeat Docker容器中实现收集

除此之外,Filebeat还提供了一种docker输入类型,专门用于收集Docker容器标准输出stdout和标准错误输出stderr产生的日志信息。默认情況下,Docker容器标准输出和标准错误输出产生的日志会映射到宿主机的"/var/lib/docker/containers"目录中,每个容器都会在这目录中使用容器ID创建一个容器专属目录用于存储容器日志。 docker输入类型会根据容器ID,到它们的日志目录中读取输出的日志信息。容器ID可通过docker输入类型的containers.ids参数设置,而日志所在的宿主机目录则可以通过containers.path来设置。 containers.ids 参数类型为list,所以可以设置多个容器同时监控,也可以将containersds参数设置为“*”以监控所有容器。docker输入类型支持的与容器相关的参数见下表

由于docker输入类型本质上也是收集文件,所以log输入类型中的参数除了paths和recursive_glob.enabled以外,其余在dockers输入类型中也都是有效的。这些参数一般只需要配置containers.ids参数,如示例16-4所示。

3. redis输入类型

redis输入类型用于从Redis的慢查询日志中读取数据,它会按照定的时间间隔向Redis发送slowlog指令以获取慢査询日志。Redis所在主机地址和端口由hosts参数定义,可以通过数组形式定义多个Redis实例地址。下表列出了redis输入类型可用参数。

4. syslog输入类型

syslog输入类型用于读取基于Syslog协议的日志数据,它将通过TCP或UDP读取数据并依据RFC3164解析读取到的数据。下表列出了syslog输入类型可用参数。

5. netflow输入类型

netflow输入类型用于读取Cisco Netflow或IETF IPFIXE的数据,它们主要应用于网络流量监控,相当于网络流量的日志信息。下表列出了netflow输入类型可用参数。

6. tcp输入类型

tcp输入类型用于通过TCP协议读取数据,在使用上一般只需要通过host参数设置其监听主机和端口即可。下表列出了tcp输入类型可用参数。

7. udp输入类型

udp输入类型用于通过UDP读取数据,在使用上与tcp类似,也是需要通过host参数设置其监听主机和端口。下表列出了udp输入类型可用参数。

 

8. stdin输入类型

stdin输入类型用于从标准输入中读取数据,这种输入类型具有排他性,不能与其他输入类型同时使用。下表列出了stdin输入类型可用参数。

 

16.2.2 模块

Filebeat模块(Module)是一组预定义的输入配置,主要针对些常见的应用系统实现快速配置。当Filebeate的一个模块被开启后, Filebeat启动后就会针对这个模块对应的系统收集日志,同时还会生成与该应用相关的Kibana仪表盘。例如,当开启了mysql模块Filebeat启动后就会到Mysql默认日志路径中收集日志,同时会在Kibana中部署表盘。Filebeat提供了3种方式开启和关闭模块

Filebeat针对模块提供了专门的命令"filebeat modules",可通过命令实现对模板的査看、开启和关闭。在命令行键入"filebeat modules list"可以查看Filebeat支持的所有模块,返回结果分为Enabled和Disabled两部分,分别列出Filebeatr中开启和关闭的模块名称。类似地,如果想要开启mysql模块,可以使用enable和disable命令,如下所示

实际上,开启和关闭模块的命令的业务逻辑非常简单,它们只是修改了modules.d目录中相关模块配置文件的扩展名。modules.d目录位于Filebeat安装路径中,其中包含了若干配置文件,每一个配置文件对应一个模块。这些配置文件最开始时都是以.disable为扩展名,而当模块开启后模块对应配置文件的扩展名会被修改为.yml。还是以mysql模块为例,它对应的配置文件黙认为mysql.yml.disabled,而当模块开启后文件名称会被修改为mysql.yml。Filebeat在启动后会加载modules.d目录中的.yml文件,这样模块对应的功能也就开启了。事实上,模块配置文件的目录并不一定在modules.d目录中,可以通过filebeat.yml文件指向其他目录。

 

上面展示的就是filebeat.yml文件中有关模块路径的配置,其中path 参数定义了模块配置文件路径。reload.enabled定义了模块配置文件是否动态加载,reload.period则定义了动态加载的时间间隔。如果开启了动态加载模块配置文件,则通过命令关闭模块时将不需要重新启动Filebeat。

在Filebeat安装路径下还有一个modulel目录,其中包含了很多子目录,每一个子目录都对应一个模块。在每一个子目录中,都包含了这个模块的一些认配置文件。以mysql模块为例,打开mysql目录下的error目录,其中的manifest.yml文件中就包含了Error日志的默认存储路径及其他配置,如下所示

如果Mysql的Error日志并不存储在这个路径中,可以修改这个文件。但一般不建议直接修改这个文件,而应该修改modules.d目录中的YAML文件。例如,mysql.yml文件中包含的var.paths就是用来覆盖默认日志路径的,如示例16-8所示:

 

每一种模块都有一些可以覆盖默认值的变量,它们可以在模块的配置文件中找到,限于篇幅就不ーー介绍了。

除了可以通过命令开启模块以外,还可以在filebeat.yml文件中开启模块。同样是开启mysql模块,在filebeat.yml文件中的配置方式为

上例中,filebeat.modules参数下的所有内容,与在示例16-8中模块配置文件完全一样。事实上,Filebeat在加载模块配置文件后也会以这样的方式跟filebeat.yml文件做整合。只是将模块配置文件独立出来后变得更灵活,可以在运行时通过命令开启或关闭模块。而如果按示例的方式修改模块,不仅每次都要修改filebeat.yml配置文件,还必须要重新启动Filebeat

上述两种开启模块的方法实际上都是通过修改配置文件实现的,它们在Filebeatb重启后还会一直有效。但在某些情下可能只希望临时开启某一模块,这时可以使用命令行参数在运行Filebeat时动态开启模块,如下所示

上例中使用了--modules参数指定了要开启的模块,可以指定一个也可以指定多个。参数-M设置了那些需要覆盖的变量,在上例中通过mysql.error.var.paths覆盖了Error日志文件的默认路径

尽管本小节花费了不少篇幅介绍模块,但由于Filebeat支持的模块种类很多,本小节并没有涵盖所有模块配置信息。但module和moulds.d目录中的模块配置文件本身就是很好的学习材料,尤其是modules.d目录中的配置文件还给出了模块文档的链接地址,可以根据这些链接地址进一步学习模块。 

16.2.3 文件读取

虽然Filebeat支持多种输入类型和多种模块,但Filebeat最原始目的还是要收集日志文件。所以下面专门针对Filebeat读取文件时一些细节做讨论,这对于理解Filebeate的配置参数非常有帮助,它们主要适用于log和docker输入类型。

1. 资源管理

Filebeat采集数据的功能由两类组件构成,它们是输入组件(Input)和收集组件(Harvester)。输入组件负责管理一个或多个收集组件,它会根据配置找到所有要收集的文件并创建专门的收集组件。每个收集组件对应一个要处理的文件,除了负责从文件中收集数据以外,它还要负责文件的打开与关闭以保证文件被合理使用和释放。

Filebeat输入组件通过扫描文件感知文件变化,扫描的时间间隔由scan_frequency参数设置,它的默认值为10s。在扫描过程中,输入组件除了要感知是否有新文件加入被监控路径以外,还要感知没有被收集的旧文件是否发生了化。如果发现有新文件加入,或是旧文件发生了变化则会为它们创建新的收集组件以收集数据。在扫描文件变化时,Filebeat输入组件会按文件在操作系统中的顺序依次扫描,但可以通过scan.sort和scan.order两个参数自定义扫描文件的次序。 scan.sort参数的可选值为modtime和filename,前者定义扫描时按文件的修改时间顺序扫描,后者则是按文件名称排序。scan.order参数定义扫描排序是升序还是降序,所以可选值为asc和desc。

默认情况下,如果收集组件在5min内没有从文件中收集到数据,收集组件就会被关闭以释放资源,这是Filebeat释放收集组件和文件的最主要方式。如果文件在收集组件关闭后又发生了变化,输入组件会再次创建新的收集组件来收集数据。但由于输入组件默认情况下每隔 10sオ扫描一次文件变化,所以在最坏情况下Filebeat要在10s以后才能收集到变化的数据。所以为了保证收集文件数据的实时性,应尽量将关闭收集组件的时间间隔设置得高于文件更新的频率。比如日志文件更新频度如果是秒级别的,则应该通过close_inactive参数将关闭文件的时间间隔设置为分钟级别,以保证日志在持续更新时不会关闭文件。

除了close_inactive以外,log输入类型还提供了close_removed、close_renamed、close_eof和close_timeout几个参数用于控制对收集组件的关闭时机。

close_removed:默认情况下开启,输入组件会在文件被删除时关闭对应的收集组件

close_renamed:默认情况下关闭,会在文件重命名时关闭收集组件

close_eof: 默认情况下关闭,在读取到文件结尾时关闭收集组件

close_timeout:比较特殊,它给每个收集组件定义了一个生存周期。超过生存周期时,不管收集组件是否已经收集结束都会被关闭。默认情况下close_timeout值为0, 也就是没有给收集组件定义生存周期。

2. 读取状态

Filebeat通过注册文件(Registry File)保存收集组件读取每个文件的状态,具体来说就是收集组件读取文件的偏移量。注册文件保存的读取状态可以保证文件中所有的内容都可以被读取出来,这与Logstash中文件输入插件SinceDB的作用类似。默认情况下,注册文件会被保存到Filebeat数据路径下的registry目录中,而Filebeat数据路径一般位于Filebeat安装路径下的data目录。注册文件存储路径可以通过filebeat.registry.path参数来修改,它的默认值为${path.data}/registry。如果设置了新的注册文件目录并重启Filebeat,那么已经保存的读取状态将全部丢失。

当Filebeate因意外崩溃,重启后会通过注册文件获取文件的读取状态以保证不会重复读取数据。同时由于只有事件被发送后偏移量才会保存到注册文件中,所以Filebeat可以保证收集的数据至少被发送一次。比如当事件发送的目的地不可用,Filebeat除了会尝试重新发送事件以外,读取状态的偏移量也不会更新到注册文件中。显然,如果Filebeat发送成功而偏移量不能及时更新到注册文件时,有可能会导致数据被重复发送。在默认情况下,Filebeat会在发送成功后立即更新注册文件,更新的时间间隔可通过filebeat.registry.flush参数设置默认值为0s。

如果Filebeath监控的文件非常多,那么注册文件要保存的条目也就非常多,这将导致注册文件变得越来越大。log输入类型提供了clean_inactive参数,可以将超过该参数指定时限的注册条目删除。另一个参数clean_removed参数,可以将已经删除文件的注册条目删除。这个参数与close_removed参数相关联,如果close_removed没有开启,则clean_removed也必须要关闭。

16.3 指标数据 

Beats组件设计的初衷是采集数据,但如果采集上来的数据是系统运行状态的数据,那么这样的组件就可以用来对系统运行状态做监控。Beats组件中可以采集系运行状态的组件有两个,它们是Metricbeat和Heartbeat。前者用来收集指标数据,而后者则以“心跳”的方式反映某一系统是否可达。

16.3.1 Metricbeat

指标(Metric)是监控领域中十分重要的概念,一般是一组与业务逻辑无关的数值,通常包括CPU、内存、硬盘等资源使用的情。指标可以从系统层面反映一个应用在运行时的健康状态,但需要有工具能够在运行时定期收集它,而Metricbeat就是这样的工具,会根据配置定期收集系统或应用的指标数据,然后再将这些指标数据发送到指定地点分析处理。

现在统一通过Metricbeat完成指标数据收集,而不同的系统或应用则是Metricbeat中的一个模块。比如Metricbeat默认开启的system模块,用于收集Beats所在主机的系统信息。与Filebeat不同,Metricbeat只能通过开启模块来定义指标数据的收集,而没有提供用户自定义收集指标的方式。

1. 模块与指标集

在配置Metricbeat收集指标时,除了通过模块指定要收集的系统或应用,还要定义模块对应的指标集(Metricset)。模块一般会定义如何连接系统或应用,以及访问系统或应用的周期;而指标集则定义了如何收集指标以及收集哪些指标。每个模块可以定义个或多个指标集,而指标集对于不同种类的模块来说又各不相同。以收集Mysql指标数据为例,mysql模块的定义如下16-11所示:

在示例中,module参数声明了当前模块为mysql, metricsets参数则定义了mysql模块的指标集只有一个status。另外两个参数中,period参数定义了收集指标的度为每10秒一次,而hosts则定义了连接Mysql的用户名、密码、主机地址和端口。

从实现的角度来说,Metricbeat并不会为了获取单个指标就连接次系统或应用,而是利用系统或应用提供的接口在一次访问中获取全部指标值。所以在Metricbeat中,指标集的名字往往就是收集指标时要执行的命令,或者是收集指标的一种方式。例如在示例16-11中,mysq 指标值status对应的就是Mysql数据库的“show global status”命令。Metricbeat会将命令返回的结果组装成事件,事件的格式如示例16-12所示

所有模块收集指标后返回的事件格式与示例16-12所示都差不多,其中事件最后一个属性mysql是模收集到的具体指标值。mysql属性会包含很多子属性,它们的具体含义可以查看fields.yml文件。

2. 开启模块

开启Metricbeat模块有两种方式:一种方式是使用命令开启模块的默认配置,另一种则是直接在metricbeat.yml文件中配置。开启模块的命令为metricbeat modules,它包括list、enable、disable三个子命令,如示例所示:

 

与Filebeat 类似,Iist命令会列出所有可选模块,并将它们按Enabled和Disabled分别展示;enable和disable命令分别用于开启和关模块,可以一次指定多个模块并用空格分开。与Filebeat相同, metricbeat modules命令操作的也是modules.d目录下的一组配置文件,可以通过metricbeat.config.modules.path修改这个路径,并且可开启动态加载功能。具体请参考16.2.2 节。

这些配置文件包含了模块和指标集的信息,开启后还需要找到相应模块的配置文件,并将其中有关连接应用、指标集等根据实际需要做修改。示例16-11就是在开启mysql后,根据MYSQL实际配置做的修改示例,读者可根据实验环境自行修改。

另一种方式是在metricbeat.yml文件中直接配置模块,配置项为metricbeat.modules,它接收列表类型的配置数据,列表中的每一项为一个模块及其指标集的相关配置。metricbeat.modules下的内容与模块配置文件中的内容也是完全相同,可以直接将示例16-11的内容添加到metricbeat.yml文件中。与Filebeat类似,使用这种方式开启模块的不利之处也是降低了灵活性,开启或关闭模块必须要修改配置文件并且需要重新启动Metricbeat。可见,无论使用哪一种方式开启模块,模块的配置基本都是相同的,可用于配置模块的参数具体见下表

更为具体的配置参数,请参考 modules.d中的配置文件。每个模块对应的配置文件中都列出了该模块适用的参数,并且还包含有文档链接可供参考。 

16.3.2 Heartbeat

Heartbeat用于监控远程服务是否可达,它通过某种通信协议定期访问服务地址以确定服务是否可达,所以在配置Heartbeat时主要就是要指定被监控服务的访问协议、访问地址和访问周期。它们在Heartbeat中被称为监视器(Monitor),可通过heartbeat.monitors配置项设置。例如Hearbeat默认监控的服务是Elasticsearch,其配置如示例,如下所示

 

在示例中,type指定了访问Elasticsearch的通信协议是HTTP; urls指定了访问Elasticsearch的地址,它接收地址的列表可以指定多个;schedule则指定了访问 Elasticsearch的周期为每10秒访问次,其中@every为关键字,代表每隔一定时间访问一次,它还可以按CRON格式定义执行周期。总的来说,示例的配置代表每隔10s对本机9200端口上的服务做一次访问,以确定该服务是否可达。Heartbeat协议相关的参数见下表

Heartbeat目前支持三种通信协议ICMP、TCP和HTP,不同通信协议下的配置参数也不尽相同。下表列出与这些通信协议相关的参数。

16.3.3 Uptime

15.1.3节曾经介绍过,在所有Beats组件中Heartbeat没有自己的Kibana仪表盘,而与Kibana另一种称为Uptime的功能相关联。Uptime可以将Heartbeat采集上来的心跳数据绘制成直观的视图,并以类似柱状图、面积图或表格等形式展示出来。Uptime会在Elasticsearch中找heartbeat-7开头的索引读取心跳数据,heartbeat后面的数字取决于Kibana版本。Uptime以监视器监听的服务为单位分析心跳数据,如果监听的服务可达就将其标识为Up,反之则标识为Down。当Heartbeat采取上来的数据编入索引后,点击导航栏上的Uptime按钮就可以直接看到视图了,如下所示。

 

Uptime界面中,最上面是一些可供设置查询条件的功能区域,可根据时间范围、服务状态(Up 或 Down)以及监视器属性(ID、Name、URL、Port和Scheme)检索心跳数据。展示区域分为四部分:

左上角是Endpoint status,它展示了被监听服务的总体情况。其中,Up是可达服务的总量,Down是不可达服务的总量,Total则是两者的总和。

右上角是Status over time,它以柱状图的形式展示了在指定时间范围內被监听服务的可达情況。红色代表不可达,蓝色则代表可达。

中间区域为Monitor status,它以监视器的视角展示被监听服务的总体情况。

最下面的是Error List,展示了在监听中发生的错误。

点击Monitor status列表中ID列中的链接,或是点击Error List列表中Monitor ID列中的链接,都可以进入监视器界面,如下所示。

在监视器界面中,Monitor Duration以类似面积图的形式展示了请求时间的范围和平均值,而Check status则展示了监听服务的检查状态。最下面的Check History则以列表形式将心跳数据展示出来了。

16.4 操作系统信息

Beats家族的其余4个组件都针对特定的操作系统或云收集数据。其中,Auditbeat主要用于收集操作系统中与审计相关的信息  Winlogbeat和Journalbeat分别用于收集Windows和Linux中的日志信息。由于Functionbeat主要用于收集AWS相关信息,本书将不对该组件做更多介绍。

16.4.1 Auditbeat

Auditbeat主要针对Linux操作系统的安全审计框架,同时也部分地支持Mac和Windows操作系统。Auditbeat主要收集操作系统密码修改、用户变更等与安全相关的信息,还可以收集主机、进程及文件完整性等信息。

Auditbeat配置也基于模块,但它不能像Filebeata和Metricbeat一样通过命令开启模块,而只能在它的配置文件auditbeat.xml中配置。 Auditbeat支持 auditd、file_integrity和system三个模块,分别对应Linux审计框架、文件完整性和系统基础信息等审计内容。

1. auditd模块

auditd模块通过与Linux内核建立订阅关系接收审计事件,所以只支持Linux操作系统。Linux审计框架对于ー个审计事件可能会发送多条消息,Auditbeat会将同一审计事件的消息存起来并最终生成完整的独立事件。审计规则可以在Auditbeat文件中通过audit_rules定义,Auditbeat在应用这些规则之前会将已有审计规则全部删除,然后再根据这些配置向内核安装新的审计规则。审计规则的定义与audits使用的语法格式一致,比如使用-w代表监控文件系统行为,-a代表监控系统调用行为等。例如在示例16-15中定义了一组监控文件和系统调用的审计规划

除了使用audit_rules直接定义审计规则以外,还可以将审计规则定义在单独的文件中,然后通过audit_rule_files参数指向该文件。 Auditbeat可使用的参数除了这两个以外还有不少,表16-16列出了这些可用参数

Auditbeat 还提供了查看审计规则和审计状态的命令,它们分别是auditbeat show audit-rules 和 auditbeat show audit-status。前者会将有审计规则全部列出来,与auditctl -l命令的作用相同;后者则用于查看审计规则状态,与 auditctl -s命令的作用相同。

最后需要注意,因为auditd模块是直接向Linux内核订阅审计信息,所以使用该模块并不需要事先安装和启动Linux的auditd服务。相反,由于auditd也会从内核中订阅审计信息,如果启动了auditd反而有可能会影响Auditbeat收集审计信息,所以在使用前应该先将auditd服务停用。

2. file_integrity模块

file_integrity模块用于监听文件变化,包括文件创建、更新和删除等等事件,支持Linux、macos (Darwin)和Windows三种操作系统。Auditbeat在不同操作系统上使用了不同的接口来监听文件,比如在Linux中使用inotify,而在macos中则使用FSEvents接口。在模块配置中,通过paths参数设置要监听文件或文件路径,如示例16-16所示

除了paths参数设置路径以外,还可以使用正则表达式通过exclude_files和include_files两个参数设置排除和包含的文件模式。下表列出了file_integrity模块中所有可用参数

3. system模块

system模块收集操作系统中与安全相关的信息,这些安全信息以数据集(Dataset)为单元组织起来,反映了有关系统安全的一个面。数据集包括状态和事件两组信息,状态信息按固定的周期更新,而事件信息仅在事件发生时才发送。system模块定义了6组数据集,但并不支持所有操作系统,见下表

在定义system模块时,最主要的配置工作就是通过datasets参数设置system模块需要的数据集有哪些。datasets参数为list类型,接收表所示的数据集,如示例所示 

不同数据集收集出来的事件属性各不相同,具体属性请参考Elastic官方网站或者在配置路径下的fields.yml文件中查找。  

16.4.2 Journalbeat

Journalbeat用于收集Linux系统中systemd-journald产生的数据, systemd-journald是systemd中的一个模块,主要用于收集操作系统产生的事件日志。默认情况下,Journalbeat通过systemd-journald默认路径收集日志,也可以通过paths参数指定其他joumal日志的路径。 Journalbeat会根据seek参数设置的位置开始读取日志,可选值包括head、tail和cursor。其中,head代表从日志文件开始读取,tail代表从日志文件结尾读取,而cursory则会保留已经读取位置。默认情况下Journalbeat会将所有Journal日志全部读取出来,但可以通过 include_matches参数定义匹配模式以筛选日志。例如示例16-18就是将根据process.name 属性,将进程名称为nm-dispatcher的日志筛选出来

include_matches参数接收模式的列表,模式格式为 feld=value。其中,field为输出事件的属性,它们可以在从fields.yml文件中查询到;value则是属性的具体值。为了方便使用, Journalbeat还为每个属性定义了简写名称,例如在示例中使用的process.name简写名称为 _COMM。由于Journalbeata基本上为每个属性都定义了简写名称,所以要将这些简写列举出来会占用大量篇幅,本书在这里就不ー列举了,读者可在需要时到Elastic官方网站查询。除了上述参数以外,Journalbeat输入组件可用参数见表 16-19。

16.4.3 Winlogbeat

Winlogbeat用于收集 Windows 事件日志。

16.5 本章小结

本章介绍了Pakcetbeat、Filebeat、Metricbeat、Heartbeat Auditbeat、Journalbeat和Winlogbeat七种 Beats 类型。

从它们采集的数据来分类:

Packetbeat用于采集网络通信数据,所以它的配置一般是基于某一种通信协议。

Filebeat用于采集文本文件,它的配置主要是通过输入类型和模块两种方式。

Metricbeat和Hearbeat可以采集指标数据,这些数据可以用于监控系统或应用的运行状态。其中Metricbeat在配置时主要使用模块和指标集,而Heartbeat则使用监视器以ICMP、TCP和HTTP三种协议接收心跳数据。

其余三种Beats都是针对操作系统,Auditbeats采集审计相关数据,可以用于安全监控;而Jouralbeat和Winlogbeat则是分别针对Linux和Window的日志收集工具

另外还有两种未介绍的Beats类型,它们是Functionbeat和Topbeat。

Funtionbeat:未介绍是因为它用于收集云服务生成的事件,目前版本仅支持将Functionbeat部署为AWS Lambda服务,可收集AWS Cloudwatch Logs和Amazon SQS生成的数据。

而Topbeat则属于老版本遗留下来的Beats类型,新版本中已经合并到Metricbeat 中,相当于Metricbeath中的system模块。

 

posted @ 2021-01-12 16:00  番茄土豆西红柿  阅读(2)  评论(0)    收藏  举报
TOP