Vector File Descriptor 源:从已有文件描述符读取日志数据的完整解析
【免费下载链接】vectorA high-performance observability data pipeline.项目地址: https://gitcode.com/GitHub_Trending/vect/vector
本文以 Vector 的file_descriptor数据源为对象,系统讲解其配置参数(fd、max_length、host_key、framing、decoding)、行分隔与解码机制、事件输出结构,并结合 源码实现 与 测试用例 说明该组件从裸 fd 读取字节、切帧解码并注入元数据的完整调用链,读完即可掌握在 sidecar 场景中复用宿主机已有管道(pipe)文件描述符采集日志的实战方法。
组件定位与核心能力
file_descriptor是 Vector 的一个source(数据源)组件,用于从一个已经存在的文件描述符(file descriptor)编号中读取日志数据。其官方文档页 file_descriptor.md 的定位即"Collect logs from a file descriptor",组件的详细元数据则维护在 CUE 文件 file_descriptor.cue 中。
与stdin源固定绑定标准输入不同,file_descriptor源让你通过配置直接指定任意已打开的 fd 编号(例如通过pipe()系统调用获得并传递给 Vector 进程的管道读端)。根据组件元数据(classes与features段),该组件具备如下特性:
| 特性 | 取值 | 说明 |
|---|---|---|
| 投递语义(delivery) | at_least_once | 至少一次投递 |
| 部署角色(deployment_roles) | sidecar | 定位为 sidecar 场景 |
| 开发状态(development) | stable | 稳定版本 |
| 数据出方式(egress_method) | stream | 流式输出 |
| 是否有状态(stateful) | false | 无状态组件 |
| 确认机制(acknowledgements) | 不支持 | can_acknowledge返回false |
| 多行日志(multiline) | 不支持 | 仅按行处理 |
| 编解码(codecs) | 支持 | 默认帧分隔为newline_delimited(native编解码器除外,其为length_delimited) |
| 接收来源 | stdin 服务接口 | 从标准输入服务接口接收 |
| TLS | 不支持 | 无网络接收面 |
从源码结构看,该组件仅在Unix 平台且启用sources-file_descriptorfeature 时编译(见 mod.rs 中的#[cfg(all(unix, feature = "sources-file_descriptor"))]),它和stdin源共用同一套FileDescriptorConfigtrait 与流处理逻辑。
配置参数详解
组件的完整配置 schema 由代码宏生成并同步到 generated/file_descriptor.cue,对应的 Rust 配置结构体为 FileDescriptorSourceConfig。字段如下:
fd(必填)
# 要从中读取的文件描述符编号 fd = 10- 类型:
uint(Rust 中为u32); - 含义:要读取的文件描述符编号("The file descriptor number to read from");
- 示例值:
10。
在 SourceConfig 实现 中,build()方法通过File::from_raw_fd(self.fd as i32)将裸 fd 包装为File,再套上io::BufReader进行缓冲读取。这里使用了unsafe代码块——fd 的所有权由外部(通常是父进程或容器运行时)负责管理,Vector 只是"借用"这个编号来读,因此必须确保配置中的 fd 在本进程内处于打开状态且可读,否则会读到 "Bad file descriptor" 错误(这一点被测试用例专门验证,见下文)。
此外,该组件通过resources()方法将Resource::Fd(self.fd)声明为自身占用的系统资源,Vector 在组件管理(如优雅关闭)时会感知这一 fd 依赖。
max_length(选填)
# 接收消息的最大缓冲区大小(字节),超过该长度的消息将被截断 max_length = 102400- 默认值:
102400字节(约 100 KB),由crate::serde::default_max_length提供默认值; - 单位:bytes;
- 行为:超过该大小的消息会被截断而非丢弃整个事件。
host_key(选填)
# 覆盖用于向每个事件添加当前主机名的日志字段名 # 默认使用全局 log_schema.host_key 选项 host_key = "host"- 类型:字符串路径(
OptionalValuePath); - 默认使用全局
log_schema.host_key配置;若未设置全局值,则回退到log_schema().host_key()的默认值; - 在 source() 构建逻辑 中,可以推断其解析优先级为:
组件级 host_key → 全局 host_key → 默认值,最终将主机名插入日志事件的host字段(在 legacy 命名空间下为日志字段,在 vector 命名空间下为元数据)。
framing(选填)
# 帧(framing)配置:定义原始字节流中每个事件(帧)如何分隔 framing = { method = "newline_delimited" }- 含义:帧处理了原始字节形式下事件的分界方式——每个事件是一个帧,必须以某种前缀或分隔符标记事件的起止边界;
- 若不显式配置,则取
decoding.default_stream_framing(),即默认编解码器对应的newline_delimited(native编解码器为length_delimited)。
decoding(选填)
# 配置如何从原始字节解码事件;部分解码器还能决定事件输出类型(log/metric/trace) decoding = { codec = "plain" }- 类型:
DeserializerConfig,默认值为plain(default_decoding()); - 部分解码器(如
json、native)能同时决定输出事件的类型,这也是为什么该源虽然主要输出日志,但 schema 上仍保留了 metrics/traces 的输出声明(见下文"输出结构")。
完整配置示例
[sources.file_descriptor_logs] type = "file_descriptor" # 组件类型 fd = 10 # 读取的文件描述符编号(必填) max_length = 102400 # 可选,默认 102400 字节 # host_key = "host" # 可选,覆盖全局 host_key # framing = { method = "newline_delimited" } # 可选 # decoding = { codec = "plain" } # 可选,默认 plain工作机制:行分隔与解码管线
行分隔符
组件元数据中的 "Line Delimiters" 一节说明:每一行读取到0xA字节(换行符)为止。即默认按\n切分行,写入端每写一行(以\n结尾)就会产生一个候选事件,再经framing/decoding配置进一步解析。
从 fd 到事件的完整调用链
核心流处理逻辑集中在 src/sources/file_descriptors/mod.rs,调用链如下:
- 包装 fd 并启动后台读取线程(
source()方法,L41-L88):- 解析
host_key与当前主机名; - 构建
DecodingConfig(framing + decoding + log_namespace)得到Decoder; - 创建一个容量为 1024 的
futures::channel::mpsc通道; std::thread::spawn启动一个阻塞 I/O 线程调用read_from_fd()。源码注释明确指出这是 Tokio 的推荐做法——否则进程在收到换行前无法干净退出;
- 解析
- 阻塞读取循环(
read_from_fd(),L92-L111):- 循环调用
reader.fill_buf():读到空(EOF)时退出循环;Interrupted错误则继续;其他错误连同错误值一起发给通道; - 每次将缓冲区内容拷贝为
Bytes通过通道发出,接收端关闭即退出;
- 循环调用
- 异步解码与事件加工(
process_stream(),L116-L199):- 用
StreamReader+DecoderFramedRead将字节流按帧切分并解码为事件; - 读取错误会触发内部事件
FileDescriptorReadError(定义于 internal_events/file_descriptor.rs),解码不可恢复错误(!error.can_continue())则终止流; - 对每个
Log事件,按log_namespace注入标准 Vector 源元数据(source_type、ingest_timestamp等),并通过host_key插入主机名; - 下游接收端关闭时发出
StreamClosedError并记录未发送事件数(定义于 internal_events/common.rs); - 全程发出
BytesReceived与EventsReceived内部遥测事件,供内部监控指标使用。
- 用
这一设计与stdin源完全同构——两者共用outputs()辅助函数(L203-L227),其文档注释也明确写着"Builds theOutputsfor stdin and file_descriptor sources"。
输出结构
组件输出的字段结构由 CUE 元数据的output段定义:
| 数据面 | 事件 | 说明 |
|---|---|---|
| logs | line(逐行事件) | 单个来自该文件描述符的事件,包含host(主机名)、message(原始行)、timestamp(当前时间戳)三个字段 |
| metrics | 无专属事件 | 仅可能由解码器顺带产生 |
| traces | 无专属事件 | 仅可能由解码器顺带产生 |
以line输出为例,给定输入行:
2019-02-13T19:48:34+00:00 [info] Started GET "/" for 127.0.0.1配置fd = 10后,输出的 log 事件为:
{ "timestamp": "<current_timestamp>", "message": "2019-02-13T19:48:34+00:00 [info] Started GET \"/\" for 127.0.0.1", "host": "<local_host>" }这正是 CUE 元数据examples段中 "Line sent over pipe" 示例所描述的输入→输出映射。
源码与测试印证的行为细节
该组件的行为有大量内联测试支撑,位于 file_descriptor.rs 测试模块,覆盖了三个关键场景:
- 正常解码(
file_descriptor_decodes_line):测试通过nix::unistd::pipe()创建匿名管道,将读端 fd 写入配置,向写端写入"hello world\nhello world again\n"后关闭写端。断言事件流依次产出message = "hello world"、"hello world again",随后 EOF 结束——印证了"按\n分行、EOF 时流结束"的行为。 - Vector 命名空间元数据(
file_descriptor_decodes_line_vector_namespace):开启log_namespace = true后,日志值本身为纯行内容,而vector.source_type = "file_descriptor"、vector.ingest_timestamp等元数据挂在事件 metadata 上——对应process_stream中insert_standard_vector_source_metadata的调用。 - 无效 fd 的容错(
file_descriptor_handles_invalid_fd):故意给源一个写端 fd(write-only),源在首次读取时记录 "Bad file descriptor" 错误日志,事件流安静结束而不 panic——印证了read_from_fd将 I/O 错误经通道转发、由FileDescriptorReadError内部事件上报的设计。
另外,GenerateConfig实现(L71-L91)揭示了生成默认配置时的一个细节:由于测试环境没有真实可读管道,generate_config()会通过null_fd()打开/dev/null(Windows 下为C:\NUL)取一个合法 fd 填充fd字段,保证生成的示例配置语法可解析。
适用前提与限制
- 平台限制:该源依赖
FromRawFd/IntoRawFd,仅在 Unix 系平台编译启用;fd必须是当前 Vector 进程内处于打开状态的文件描述符,常见做法是父进程创建管道并将读端 fd 通过环境变量/约定编号传给 Vector 子进程; - 无确认、无多行:不支持端到端 ack,也不做跨行的多行日志聚合,日志切割逻辑必须在上游完成或依靠下游 transform;
- 截断策略:单条消息超过
max_length(默认 102400 字节)时截断而非丢弃; - 无状态、至少一次:组件不持久化任何读取进度,进程重启后从 fd 的当前位置(而非历史)继续读,可能漏掉上游重发窗口外的数据。
小结
file_descriptor源是 Vector 面向 sidecar/容器化场景的一个轻量入口:以fd一个必填参数为锚点,复用stdin源成熟的"阻塞线程读取 + 通道 + 帧解码"管线,按0xA行分隔符切分事件,并注入host/时间戳/源类型等标准元数据。配置侧仅需理解fd、max_length、host_key、framing、decoding五个参数;实现侧的关键文件为 src/sources/file_descriptors/file_descriptor.rs 与 src/sources/file_descriptors/mod.rs,行为边界可参照其内联测试与 文档元数据 交叉验证。
【免费下载链接】vectorA high-performance observability data pipeline.项目地址: https://gitcode.com/GitHub_Trending/vect/vector
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考