论一个优秀的日志采集系统是如何设计和实现数据处理的

news2024/12/23 6:01:51

作者 观测云 系统开发工程师 李国壮

前言

日志采集系统的执行过程,从 “定位日志” 开始,然后是 “数据采集和处理”,最后则是 “同步采集状态”。本文主要介绍第二项,即数据的采集和解析,其中包含了很多细节处理,将会影响到采集效率、解析结果等各个方面。

数据采集和解析

读取数据并分割成行

提到读取日志数据,大部分情况都会先想到类似 Readline() 这种方法函数,每次调用都会返回完整的一行日志。但是在 DataKit 没有这样实现。

为了确保更细致的操控和更高的性能,DataKit 只使用了最基础的 Read() 方法,每次读取 4KiB 数据(buff 大小是 4KiB,实际读取到可能更少),手动将这 4KiB 数据通过换行符 \n 分割成 N 份。这样会出现两种情况:

  • 这 4KiB 数据最后一个字符刚好是换行符,可以分割成 N 份,没有剩余
  • 这 4KiB 数据最后一个字符不是换行符,对比上文,本次的分割只有 N-1 份,有剩余部分,这段剩余的部分将补充到下一个 4KiB 数据的首部,依次类推

在 DataKit 的代码中,此处对同一个 buff 不断进行 update CursorPositioncopytruncate,以实现最大化的内存复用。

经过处理,读取到的数据已经变成一行一行,可以走向执行流的下一层也就是转码和特殊字符处理。

转码和特殊字符处理

转码和特殊字符的处理要在数据成型之后再进行,否则会出现从字符中间截断、对一段截断的数据做处理的情况。比如一个 UTF-8 的中文字符占 3 字节,在采集到第 1 个字节时就做转码处理,这属于 Undefined 行为。

数据转码是很常见的行为,需要指定编码类型和大端小端(如果有),本文重点讲述一下 “特殊字符处理”。

“特殊字符” 在此处代指数据中的颜色字符,比如以下命令会在命令行终端输出一个红色 rea 单词:

$ RED='\033[0;31m' && NC='\033[0m' && print "${RED}red${NC}"

如果不进行处理,不删除颜色字符,那么最终日志数据也会带有 \033[0;31m,不仅缺乏美观、占用存储,而且可能对后续的数据处理产生负影响。所以要在此处筛除特殊颜色字符。

开源社区有许多案例,大部分都使用正则表达式进行实现,性能不是很出色。

但是对于一个成熟的日志输出框架,一定有关闭颜色字符的方法,DataKit 更推荐这种做法,由日志产生端从避免打印颜色字符。

解析行数据

“解析行数据” 主要是针对容器 Stdout/Stderr 日志。容器 runtime 管理和落盘日志时会添加一些额外的信息字段,比如产生时间,来源是 stdout 还是 stderr,本条日志是否被截断等等。DataKit 需要对这种数据做解析,提取对应字段。

  • Docker json-file 日志单条格式如下,是 JSON 格式,正文在 log 字段中。如果 log 内容的结尾是 \n 表示这一行数据是完整的,没有被截断;如果不是 \n,则表明数据太长超过 16KB 被截断了,其剩余部分在下一个 JSON 中。

    {"log":"2022/09/14 15:11:11 Bash For Loop Examples. Hello, world! Testing output.\n","stream":"stdout","time":"2022-09-14T15:11:11.125641305Z"}
    
  • Containerd(CRI)单条日志格式如下,各项字段以空格分割。和 Docker 相同的是,Containerd(CRI)也有日志截断的标记,即第三个字段 P,此外还有 FP 表示 Partial,即不完整的、被截断的;F 表示 Full

    2016-10-06T00:17:09.669794202Z stdout P log content 1
    2016-10-06T00:17:09.669794202Z stdout F log content 2
    

    拼接之后的日志数据是 log content 1 log content 2

通过解析行数据,可以获得日志正文、stdout/sterr 等信息,根据标记确定是否是不完整的截断日志,要进行日志拼接。在普通日志文件中不存在截断,文件中的单行数据理论上可以无限长。

此外,日志单行被截断,拼接之后也属于一行日志,而不是下文要提到的多行日志,这是两个不同的概念。

数据处理

上文描述的过程,是将数据从文件中读取,并通过解码和解析,组织成一行可读的文本。从现在开始讲针对这一行文本做各种处理,包括多行拼接、字段切割。

多行数据

多行处理是日志采集非常重要的一项,它将一些不符合特征的数据,在不丢失数据的前提下变得符合特征。比如日志文件中有以下数据,这是一段常见的 Python 栈打印:

2020-10-23 06:41:56,688 INFO demo.py 1.0
2020-10-23 06:54:20,164 ERROR /usr/local/lib/python3.6/dist-packages/flask/app.py Exception on /0 [GET]
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
2020-10-23 06:41:56,688 INFO demo.py 5.0

如果没有多行处理,那么最终数据就是以上 7 行,和原文一模一样。这不利于后续的 Pipeline 切割,因为像第 3 行的 Traceback (most recent call last): 或 第 4 行的 File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 2447, in wsgi_app 都不是固定格式。

如果经过有效的多行处理,这 7 行数据会变成 3 行,结果如下:

2020-10-23 06:41:56,688 INFO demo.py 1.0
2020-10-23 06:54:20,164 ERROR /usr/local/lib/python3.6/dist-packages/flask/app.py Exception on /0 [GET]\nTraceback (most recent call last):\n  File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 2447, in wsgi_app\n    response = self.full_dispatch_request()
2020-10-23 06:41:56,688 INFO demo.py 5.0

可以看到,现在每行日志数据都以 2020-10-23 这样的特征字符串开头,原文中不符合特征的第 3、4、5 行被追加到第 2 行的末尾。这样看起来要美观很多,而且有利于后续的 Pipeline 字段切割。

这一功能并不复杂,只需要指定特征字符串的正则表达式即可。

在 DataKit logging 采集器配置有 multiline_match 项,以上文的例子,该项的配置应该是 ^\d{4}-\d{2}-\d{2},即匹配形如 2020-10-23 这样的行首。

具体实现上类似一个数据结构中的栈(stack)结构,符合特征就将前一条出栈并再把自己入栈进去,不符合特征就只将自己入栈追加到前一条末尾,这样从外面收到的出栈数据都是符合特征的。

此外,DataKit 还支持自动多行,在 logging 采集器的配置项中是 auto_multiline_detectionauto_multiline_extra_patterns,它的逻辑非常简单,就是提供一组的 multiline_match,根据原文遍历匹配所有规则,匹配成功就提高它的权重以便下次优先选择它。

自动多行是简化配置的一种方式,除了用户配置外,还提供 “默认自动多行规则列表”,详情链接见文章末尾。

Pipeline 切割和日志 status

Pipeline 是一种简单的脚本语言,提供各种函数和语法,用以编写对一段文本数据的执行规则,主要用于切割非结构化的文本数据,例如把一行字符串文本切割出多个有意义的字段,或者用于从结构化的文本中(如 JSON)提取部分信息。

Pipeline 的实现比较复杂,它由抽象语法树(AST)和一系列内部状态机、功能纯函数组成,此处不过多描述。

只看使用场景,举个简单的例子,原文如下:

2020-10-23 06:41:56,688 INFO demo.py 1.0

pipeline 脚本:

grok(_, "%{date:time} %{NOTSPACE:status} %{GREEDYDATA:msg}")
default_time(time)

最终结果:

{
    "message": "2020-10-23 06:41:56,688 INFO demo.py 1.0",
    "msg": "demo.py 1.0",
    "status": "info",
    "time": 1603435316688000000
}

注意:Pipeline 切割后的 status 字段是 INFO,但是 DataKit 有做映射处理,所以严谨起见显示为小写的 info

Pipeline 是日志数据处理最后一步,DataKit 会使用 Pipeline 的结果构建行协议,序列化对象并准备打包发送给 Dataway。

结尾

日志数据处理的细节又多又杂,在此只简单描述了一些基础的执行策略,后续会再进行内容补全。
图片

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1015978.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows10关闭自动更新

0 前言 从Windows Update服务、组策略、计划任务、注册表四个方面入手,目前我这边改完后是可以停止更新的,修改过程中也没遇到其他问题 1 禁用Windows Update服务 ① winR,输入services.msc打开服务 ② 双击打开Windows Update ③ 常规&a…

基于springboot+vue的药店管理系统

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

微信开放平台第三方开发,实现代小程序备案申请

大家好,我是小悟 微信小程序备案整体流程总共分为五个环节:备案信息填写、平台初审、工信部短信核验、通管局审核和备案成功。 服务商可以代小程序发起备案申请。在申请小程序备案之前,需要确保小程序基本信息已填写完成、小程序至少存在一个…

银河麒麟安装Docker-国产化-九五小庞

银河麒麟高级服务器操作系统 V10 是针对企业级关键业务,适应虚拟化、 云计算、大数据、工业互联网时代对主机系统可靠性、安全性、性能、扩展性和 实时性的需求,依据 CMMI 5 级标准研制的提供内生安全、云原生支持、国产 平台深入优化、高性能、易管理的…

vue基础知识十二:双向数据绑定是什么

一、什么是双向绑定 我们先从单向绑定切入单向绑定非常简单,就是把Model绑定到View,当我们用JavaScript代码更新Model时,View就会自动更新双向绑定就很容易联想到了,在单向绑定的基础上,用户更新了View,Mo…

【基于优化算法的光伏系统】基于光伏系统(由光伏、电池、转换器、PI 控制器、逆变器和充电控制器组成)的 Simulink 模型

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

BF算法(C++)简单讲解

BF算法匹配过程易理解,若匹配,子串和主串都往下移一位。不匹配时,主串回溯至本次匹配开始下标的下一位。例:图中第三趟匹配时,主串到第七位时与子串不匹配,这次匹配主串是从第三位开始的,所以下…

大数据技术准备

Hbase:HBase 底层原理详解(深度好文,建议收藏) - 腾讯云开发者社区-腾讯云 Hbase架构图 同一个列族如果有多个store,那么这些store在不同的region Hbase写流程(读比写慢) MemStore Flush Hbas…

有名管道实现简易版聊天功能

简单的代码&#xff0c;只能你写一句 我回一句 依次循环 //chat A#include<stdio.h> #include<unistd.h> #include <sys/types.h> #include <sys/stat.h> #include<fcntl.h> #include<string.h> #include<stdlib.h> int main() {//…

SocketTool V4.0 使用说明

TCP/UDP Socket 调 试 工 具 提 供 了 TCP Server,TCP Client,UDP Server,UDP Client,UDP Group 五种 Socket 调试方案。 下面是一份简要的使用流程&#xff1a; TCP 通信测试&#xff1a; 1) 创建 TCP Server 选中左方的 TCP Server, 然后点击 ”创建 ”按钮&#xff0c;软件弹…

临时工说: 云原生数据库别整新名词,bypass ,不就是旁路吗

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&#xff08;共…

有史以来最香的日志收集平台是怎样练成的

作者 观测云 系统开发工程师 李国壮 前言 日志采集&#xff08;logging&#xff09;是观测云 DataKit 重要的一项&#xff0c;它将主动采集或被动接收的日志数据加以处理&#xff0c;最终上传到观测云中心。 日志采集的执行过程可大致分为三段&#xff0c;分别是“定位日志”…

听GPT 讲Istio源代码--pilot

File: istio/operator/pkg/translate/translate.go 在Istio项目中&#xff0c;istio/operator/pkg/translate/translate.go文件的作用是处理Istio Operator的配置信息和Kubernetes的资源对象之间的翻译和转换。 首先&#xff0c;scope和componentToAutoScaleEnabledPath是用于记…

趣谈网络协议_1

趣谈网络协议_1 第1讲 | 为什么要学习网络协议&#xff1f;第4讲 | DHCP与PXE&#xff1a;IP是怎么来的&#xff0c;又是怎么没的&#xff1f;动态主机配置协议&#xff08;DHCP&#xff09; 第5讲 | 从物理层到MAC层&#xff1a;如何在宿舍里自己组网玩联机游戏&#xff1f;第…

WPF 如何让xmal的属性换行显示 格式化

WPF 如何让UI的xmal 按照下面的格式化显示 首先格式化显示在VS中的快捷键是 Ctrl &#xff2b;D 然后需要配置&#xff0c;工具 选项 -文本编辑器 -xmal -格式化-间距 更改成如下就可以了

分布式锁的三种实现方式!

分布式锁是一种用于保证分布式系统中多个进程或线程同步访问共享资源的技术。同时它又是面试中的常见问题&#xff0c;所以我们本文就重点来看分布式锁的具体实现&#xff08;含实现代码&#xff09;。 在分布式系统中&#xff0c;由于各个节点之间的网络通信延迟、故障等原因…

基于java求长方形的周长和面积详细方法

一、方法 要使用Java求长方形的周长和面积&#xff0c;可以通过定义长方形的长度和宽度&#xff0c;然后使用相应的公式进行计算。 首先&#xff0c;定义长方形的长度和宽度&#xff1a; double length 10.0; double width 5.0;然后&#xff0c;使用以下公式计算长方形的周…

RK3588 添加I2C模拟芯片CH423

一.简介 有时候会遇到IO不够用的情况&#xff0c;例如说驱动LED灯&#xff0c;那么有没有什么便宜的&#xff0c;容易买到的芯片&#xff1f;我这次就考虑使用WCH的CH423S&#xff0c;这是一个比较新的IO扩展芯片。 二.硬件原理图 使用gpio来模拟IIC&#xff0c;飞线处理&…

2020-2023中国高等级自动驾驶产业发展趋势研究-概念界定

1.1 概念界定 自动驾驶发展过程中&#xff0c;中国出现了诸多专注于研发L3级以上自动驾驶的公司&#xff0c;其在业界地位也越来越重要。本报告围绕“高等级自动驾驶” 展开&#xff0c;并聚焦于该技术2020-2023年在中国市场的变化趋势进行研究。 1.1.1 什么是自动驾驶 自动驾驶…

发现matplotlib的一个问题

今天在做需求的时候发现一个问题&#xff0c;就是当传一个‘o’时&#xff0c;调用plt.plot画图会自动成为散点图&#xff0c;而不是折线图&#xff0c;代码如下&#xff1a; import pandas as pd import numpy as np import matplotlib.pyplot as plt ds pd.date_range(star…