拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Telegraf 插件内部统计(internal plugin statistics):基于 selfstat.Collector 的插件级指标采集规范与实践

Telegraf 插件内部统计internal plugin statistics基于 selfstat.Collector 的插件级指标采集规范与实践【免费下载链接】telegrafAgent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.项目地址: https://gitcode.com/GitHub_Trending/te/telegraf本篇文章围绕 Telegraf 仓库中的设计规范文档 tsd-011-internal-plugin-statistics.md 展开系统讲解如何让插件上报只有插件实例自身才知道的内部统计指标例如输出插件实际写入的字节数、特定错误类型等并通过internal输入插件对外暴露。文中将结合selfstat包源码、models层的自动注入机制以及真实插件如influxdb输出插件的落地实现说明从定义一个Statistics字段到指标进入常规采集管线的完整链路帮助读者掌握编写或扩展带内部统计能力的 Telegraf 插件的方法。一、为什么需要插件级内部统计Telegraf 通过 internal 输入插件 提供对运行中插件的统计能力这些指标是运维与调优 Telegraf 部署、定位问题的重要依据。从源码实现看该插件定义了三类采集内容见 plugins/inputs/internal/internal.gointernal_memstatsGo 运行时内存统计默认开启collect_memstats trueinternal_gostatsGoruntime/metrics暴露的指标默认关闭collect_gostats false插件统计通过selfstat.Metrics()汇聚所有已注册的自统计指标默认按插件类型聚合输出也可通过per_instance true改为逐实例输出。其中插件统计又分为两类模型层model-level统计由models包中的各 Running 类如running_input.go、running_output.go负责注册覆盖采集时长、写入时长、错误次数等通用维度插件内部plugin-internal统计只有插件实例自身知道的信息例如向输出目标实际写入的字节数、特定协议错误、请求计数等无法在模型层获知。问题在于插件若绕过模型层直接调用selfstat.Register注册统计对象将无法获得全局tags配置与alias别名设置——这些信息只在模型层掌握。tsd-011 规范的初衷正是解决这一缺陷定义一个框架把携带了alias与 tags 信息的统计收集器statistics collector注入插件让插件通过它注册内部统计。相关背景可追溯至仓库历史中的 issue #4889InfluxDB 输出插件内部统计、#6965Kafka 输出插件内部统计与 #17275InfluxDB v2 输出插件内部统计。二、总体机制注入一个统计收集器规范提出的核心设计包含三个环节插件侧插件结构体导出Statistics成员类型必须为指针*selfstat.Collector强烈建议为其声明-的 TOML tag避免用户配置与内部成员冲突模型层注入Telegraf 模型代码在实例化插件之后、调用插件Init函数之前将selfstat.Collector实例注入Statistics成员注入时携带模型层已知的alias、tags等全部信息插件使用插件必须通过该 collector 作为代理来完成统计的注册register、注销unregister、重置reset与访问access而不是直接调用全局的selfstat.Register。2.1 注入的源码实现注入逻辑位于 models/common.go 的SetStatisticsOnPlugin函数func SetStatisticsOnPlugin(plugin interface{}, logger telegraf.Logger, tags map[string]string) { // Find the statistics collector instance : reflect.Indirect(reflect.ValueOf(plugin)) field : instance.FieldByName(Statistics) if !field.IsValid() { return } // Validate the type and make sure we can actually set the struct field if field.Type().String() ! *selfstat.Collector || !field.CanSet() { logger.Debugf( Plugin %q defines a Statistics field on its struct of an unexpected type %q. Expected *selfstat.Collector, instance.Type().Name(), field.Type().String(), ) return } // Create a new collector and set it collector : selfstat.NewCollector(tags) field.Set(reflect.ValueOf(collector)) }该函数使用反射定位插件结构体上的Statistics字段字段不存在!field.IsValid()时静默返回保证未实现内部统计的插件不受影响字段类型不是*selfstat.Collector或不可写时仅输出 Debug 日志并跳过避免破坏插件启动校验通过后以模型层构造的tags创建新的 collector 并写入字段。这里传入的tags已经包含了模型层信息。以输出插件为例models/running_output.go 中构造的 tags 为tags : map[string]string{ output: config.Name, _id: config.ID, } if config.Alias ! { tags[alias] config.Alias } errorLogRegister : selfstat.Register(write, errors, tags) logger : logging.New(outputs, config.Name, config.Alias) logger.RegisterErrorCallback(func() { errorLogRegister.Incr(1) }) if err : logger.SetLogLevel(config.LogLevel); err ! nil { logger.Error(err) } SetLoggerOnPlugin(output, logger) SetStatisticsOnPlugin(output, logger, tags)可见output插件名、_id插件实例 ID、可选的alias别名在模型层被统一封装进 collector随后通过SetStatisticsOnPlugin注入插件。2.2 Collector 的职责与能力selfstat.Collector定义在 selfstat/collector.gotype Collector struct { tags map[string]string statistics map[string]Stat }它持有一份收集器级的 tags即模型层注入的 alias/tags并缓存本收集器注册过的统计对象。其对外方法完整对应规范要求的四种能力Register(measurement, field string, tags map[string]string) Statcollector.go注册普通统计内部先把传入 tags 与收集器自身 tags合并再调用全局selfstat.Register并缓存 key 避免重复注册RegisterTiming(measurement, field string, tags map[string]string) Statcollector.go注册耗时类统计语义与Register相同但底层使用RegisterTiming见下文普通统计与计时统计Unregister(measurement, field string, tags map[string]string)collector.go注销指定统计并从缓存删除另有UnregisterAll()批量注销全部统计Get(measurement, field string, tags map[string]string) Stat与Reset(measurement, field string, tags map[string]string)collector.go按 key 读取统计对象或将指定统计的值重置为 0。由此插件侧拿到的是已预先绑定了模型层 tags 的代理注册的每个统计都会自动带上alias、插件名等模型层标签从根上解决了直接调用全局selfstat.Register丢失 tags 的问题。2.3 全局注册表collector 的底层支撑collector 最终仍委托给selfstat包的全局注册表完成实际登记。selfstat/selfstat.go 暴露了核心 APIRegister(measurement, field string, tags map[string]string) Stat注册普通统计测量名会被自动加上internal_前缀RegisterTiming(measurement, field string, tags map[string]string) Stat注册计时统计同样带internal_前缀Unregister(...)从注册表移除统计Metrics() []telegraf.Metric把注册表中所有统计转换为 Telegraf 指标供internal插件采集。注册表内部以map[uint64]map[string]Stat组织selfstat.go外层 key 由测量名 排序后的 tags经 FNV-1a 哈希生成key函数selfstat.go内层再按字段名索引并发安全由sync.Mutex保证。Stat接口selfstat.go定义了指标对象的核心操作Name()/FieldName()/Tags()返回测量名、字段名与 tags每次调用返回新 mapIncr(v int64)普通统计累加计时统计则将本次耗时加入缓存Set(v int64)普通统计直接赋值计时统计同样写入缓存Get()读取当前值计时统计返回自上次Get()以来所有计时的平均值无新计时则沿用上次值Unregister()从注册表移除。一个典型输出后立刻见到的现象是插件统计在internal_plugin_name测量下按 measurement 聚合多个字段配合internal插件默认的per_instance false按插件类型聚合或per_instance true按实例输出保留_idtag两种模式对外呈现。三、插件侧落地步骤与完整示例按规范落地一个带内部统计的插件需要三步声明字段 → 在Init中注册统计 → 在运行路径上更新统计。3.1 声明Statistics成员在插件结构体中增加指针类型的Statistics *selfstat.Collector字段并打上toml:-标签type InfluxDB struct { // ... 既有配置字段 ... Statistics *selfstat.Collector toml:- // 插件自己的统计句柄 bytesWritten selfstat.Stat }toml:-的作用是防止用户在配置文件中通过同名键覆盖该成员。这正是规范中强烈建议定义-TOML tag的落地形态可在 plugins/outputs/influxdb/influxdb.go 看到真实样例。3.2 在Init中通过 collector 注册统计Init是注入完成的保证点模型层在实例化之后、调用Init之前注入 collector因此Init内可以安全使用i.Statistics。参考 plugins/outputs/influxdb/influxdb.gofunc (i *InfluxDB) Init() error { // ... 既有默认值与序列化器初始化 ... // Register internal metrics i.bytesWritten i.Statistics.Register(write, bytes_written, nil) return nil }这里以 measurementwrite、字段bytes_written注册统计collector 会拼接internal_前缀最终测量名为internal_writetags 传nil表示只使用收集器自身携带的模型层 tags。3.3 在写入路径上更新统计注册得到的selfstat.Stat句柄保存在插件字段中之后在每次成功写入后更新例如httpClient/udpClient会把BytesWritten: i.bytesWritten传入客户端由客户端在写出字节后调用Incr(n)见 plugins/outputs/influxdb/influxdb.go。这样internal_write测量中就会实时反映该输出实例累计写入的字节数且天然带上了output、_id、alias等模型层标签。除influxdb外仓库中已按同一模式实现的插件还包括 plugins/inputs/prometheus/prometheus.go 与 plugins/inputs/influxdb_v2_listener/influxdb_v2_listener.go可作为多类型插件输入与服务输入的对照参考。四、统计在internal插件中的呈现启用internal输入插件后插件内部统计与模型层统计一起进入常规采集管线。该插件的完整配置如下plugins/inputs/internal/README.md# Collect statistics about itself [[inputs.internal]] ## If true, collect telegraf memory stats. # collect_memstats true ## If true, collect metrics from Gos runtime.metrics. For a full list see: ## https://pkg.go.dev/runtime/metrics # collect_gostats false ## Collect statistics per plugin instance and not per plugin type # per_instance false采集逻辑见 plugins/inputs/internal/internal.goPerInstance为false默认时调用collectAccumulatedPluginStat以测量名 tags剔除_id为 key 将同类型插件的统计聚合累加为一条指标模拟按插件类型统计的旧行为PerInstance为true时调用collectIndividualPluginStat直接逐条输出每个实例的统计保留_id标签无论哪种模式internal_agent测量都会被补上go_version标签所有测量统一附加versiontelegraf 版本internal.go。结合内部统计后典型输出节选自 plugins/inputs/internal/README.md形如internal_write,outputfile,hosttyrion,version1.99.0 buffer_limit10000i,buffer_size0i,errors0i,metrics_added18i,metrics_dropped0i,metrics_filtered0i,metrics_rejected0i,metrics_written18i,startup_errors1i,write_errors0i,write_time_ns636609i 1480682800000000000 internal_gather,inputinternal,hosttyrion,version1.99.0 errors2i,gather_errors1i,gather_time_ns442114i,gather_timeouts0i,metrics_gathered19i,startup_errors0i 1480682800000000000 internal_http_listener,address:8186,hosttyrion,version1.99.0 queries_received0i,writes_received0i,requests_received0i,buffers_created0i,requests_served0i,pings_received0i,bytes_received0i,not_founds_served0i,pings_served0i,queries_served0i,writes_served0i 1480682800000000000 internal_mqtt_consumer,hosttyrion,version1.99.0 messages_received622i,payload_size37942i 1657282270000000000其中internal_http_listener、internal_mqtt_consumer即为各自插件通过 collector 注册的内部统计测量字段如requests_served、messages_received、payload_size正是那些只有插件实例才知道的数据点。五、模型层统计与内部统计的边界为帮助读者区分两类统计的职责这里汇总模型层各 Running 类已注册的通用统计全部通过selfstat完成tags 由模型层构造模型类测量名统计字段节选源码位置RunningInputinternal_gathermetrics_gathered、gather_time_ns、gather_timeouts、gather_errors、startup_errors、errorsmodels/running_input.goRunningOutputinternal_writemetrics_written、write_time_ns、write_errors、startup_errors、metrics_filtered、errorsmodels/running_output.goRunningAggregatorinternal_aggregatemetrics_pushed、metrics_filtered、metrics_dropped、push_time_nsmodels/running_aggregator.goBufferinternal_writemetrics_added、metrics_written、metrics_rejected、metrics_dropped、buffer_size、buffer_limitmodels/buffer.goRunningParserinternal_parsermetrics_parsed、parse_time_nsmodels/running_parsers.goRunningSerializerinternal_serializermetrics_serialized、bytes_serialized、serialization_time_nsmodels/running_serializer.go这些统计由模型层在构造 Running 对象时注册任何插件都会自动获得而 tsd-011 定义的内部统计则是插件按需自主注册、补充模型层覆盖不到的指标。模型层与插件内部统计共用同一个selfstat注册表因此internal插件无需区分来源即可统一采集。此外internal插件对外暴露的字段名称与internal测量下各字段的完整语义可对照 plugins/inputs/internal/README.md 中internal_agent、internal_gather、internal_write的逐字段说明查阅。六、相关规范与测试验证tsd-011 属于 Telegraf 的 TSDTelegraf Specification Document体系规范文件统一以tsd-前缀 递增编号命名如tsd-001-deprecation、tsd-010-labels-and-selectors写作要求至少包含 Objective 与 Overview 两部分参见 docs/specs/README.md 与 docs/specs/template.md。tsd-011 即通过 Objective、Overview、Related Issues 三部分完整描述了内部统计框架的动机与设计。实现层面可进一步通过仓库测试验证行为models目录下的running_input_test.go如TestRunningInputStatisticsErrorsCount、running_output_test.go如TestRunningOutputStatisticsErrorsCount、TestRunningOutputStatisticsWriteErrorsCount均直接调用selfstat.Register构造相同 tags 的统计并断言计数行为可作为理解模型层统计注册与聚合语义的参考selfstat包的collector_test.go、selfstat_test.go则覆盖了 collector 与全局注册表的注册、去重与清理逻辑。七、编写新插件的检查清单基于上述规范与实现为自研插件接入内部统计时可遵循如下清单导入依赖import github.com/influxdata/telegraf/selfstat声明字段在插件结构体中添加Statistics *selfstat.Collector \toml:-注册统计在Init中使用s.Statistics.Register(measurement, field, nil)或RegisterTiming(...)获取selfstat.Stat句柄并保存到插件字段更新统计在采集/写入/请求等业务路径上调用Incr(v)或Set(v)计时类调用RegisterTiming并按需Incr单次耗时清理统计若插件生命周期内需要释放统计可调用 collector 的Unregister/UnregisterAll验证输出启用[[inputs.internal]]并设置per_instance true可逐实例观察带_id标签的内部统计per_instance false则观察按类型聚合后的结果。遵循该模式插件即可在保证tags 与 alias 不丢失的前提下把自身最关键的运行数据通过标准的internal采集管线暴露给监控系统为部署调优与故障定位提供数据支撑。八、总结tsd-011 规范为 Telegraf 的插件内部统计建立了一套标准机制插件声明*selfstat.Collector类型的Statistics成员模型层在Init之前把携带 alias 与 tags 的 collector 注入插件插件经由 collector 注册、更新、注销自身指标最终由internal输入插件以internal_plugin_name测量统一对外输出。整条链路以selfstat全局注册表为底座以 models/common.go 的SetStatisticsOnPlugin为注入枢纽以influxdb等真实插件为范例——理解这一设计就能为任何 Telegraf 插件低成本地补充可观测性也为阅读和评审其他插件实现提供了清晰的切入点。【免费下载链接】telegrafAgent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.项目地址: https://gitcode.com/GitHub_Trending/te/telegraf创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门