Telegraf win_services 插件详解:在 Windows 上监控系统服务运行状态与启动模式
【免费下载链接】telegrafAgent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.项目地址: https://gitcode.com/GitHub_Trending/te/telegraf
Telegraf 的win_services输入插件用于采集 Windows 系统上服务的运行状态(state)与启动类型(startup_mode),支持通过通配符按服务名筛选采集范围。本篇围绕官方插件文档展开,结合插件源码解析其服务枚举、过滤匹配与错误处理的完整实现机制,帮助你在 Windows 主机上落地一套完整的服务状态监控方案。
插件定位与平台限制
根据插件文档,win_services用于收集 Windows 服务的状态信息,并且仅支持 Windows 平台。文档同时特别提示:
监控某些服务可能需要以管理员权限运行 Telegraf。
从源码结构可以印证这一点。真实实现文件 win_services.go 顶部带有//go:build windows构建标签,而 win_services_notwindows.go 为非 Windows 平台提供了一个空实现(stub),其Init()仅输出一条 "Current platform is not supported" 警告,Gather不做任何采集。这意味着在 Linux/macOS 上配置该插件不会报错,但也不会产生任何指标。
配置说明
插件的完整配置示例如下(来自 sample.conf,该文件通过//go:embed内嵌进二进制,可直接由telegraf --usage查看):
# Input plugin to report Windows services info. # This plugin ONLY supports Windows [[inputs.win_services]] ## Names of the services to monitor. Leave empty to monitor all the available ## services on the host. Globs accepted. Case insensitive. service_names = [ "LanmanServer", "TermService", "Win*", ] # optional, list of service names to exclude excluded_service_names = ['WinRM']配置参数与源码中的结构体一一对应:
| 配置项 | 源码字段 | 说明 |
|---|---|---|
service_names | ServiceNames []string | 要监控的服务名列表,支持通配符(glob)且不区分大小写;留空则监控主机上所有服务 |
excluded_service_names | ServiceNamesExcluded []string | 可选的排除列表,同样支持通配符,用于从采集结果中剔除指定服务 |
此外,插件还支持 Telegraf 的全局插件配置选项(如alias、tags、ignore_empty等),详见 CONFIGURATION.md。
大小写不敏感的匹配实现
service_names的"不区分大小写"并非简单注释,而是有明确的源码依据。在 win_services.go 的Init()中,插件将 include 与 exclude 列表中的每个名称统一转换为小写:
func (m *WinServices) Init() error { // For case insensitive comparison (see issue #8796) we need to transform the services // to lowercase servicesInclude := make([]string, 0, len(m.ServiceNames)) for _, s := range m.ServiceNames { servicesInclude = append(servicesInclude, strings.ToLower(s)) } servicesExclude := make([]string, 0, len(m.ServiceNamesExcluded)) for _, s := range m.ServiceNamesExcluded { servicesExclude = append(servicesExclude, strings.ToLower(s)) } f, err := filter.NewIncludeExcludeFilter(servicesInclude, servicesExclude) if err != nil { return err } m.servicesFilter = f return nil }对应的匹配逻辑在listServices中:枚举出的每个服务名同样转小写后再交给过滤器判断——
func (m *WinServices) listServices(scmgr winServiceManager) ([]string, error) { names, err := scmgr.listServices() if err != nil { return nil, fmt.Errorf("could not list services: %w", err) } var services []string for _, name := range names { // Compare case-insensitive. Use lowercase as we already converted the filter to use it. n := strings.ToLower(name) if m.servicesFilter.Match(n) { services = append(services, name) } } return services, nil }底层过滤器是 Telegraf 的通用filter包。filter.NewIncludeExcludeFilter默认以includeDefault=true, excludeDefault=false构造IncludeExcludeFilter(见 filter.go),其Match语义为:include 列表为空时默认放行一切;非空则必须命中,且命中 exclude 的服务始终被剔除。这解释了为什么留空service_names会采集全部服务,而同时配置两者时excluded_service_names具有更高优先级。通配符(如Win*)的匹配由 implementations.go 中的filterGlobMultiple基于 glob 编译模式实现;若全部模式均不含 glob 字符,则退化为基于哈希集合的精确匹配,性能更优。
采集流程与底层实现
每次采集(Gather)的核心调用链如下,全部封装在 win_services.go 中:
- 连接服务控制管理器:
mgProvider.connect()调用windows.OpenSCManager(nil, nil, windows.GENERIC_READ)以只读权限打开 SCManager,并包装为mgr.Mgr。只读权限意味着该插件只能查询、不会修改任何服务。 - 枚举服务:
listServices()通过mgr.Mgr.ListServices()拿到系统服务名列表,再经servicesFilter过滤。 - 逐服务查询:对每个候选服务执行
openService(windows.OpenService,GENERIC_READ句柄)→Query()获取运行时状态 →Config()获取服务配置,最后通过acc.AddFields("win_services", fields, tags)输出指标。
这里有一个值得注意的实现细节:display_name标签是条件性添加的——
tags := map[string]string{ "service_name": service.ServiceName, } // display name could be empty, but still valid service if len(service.DisplayName) > 0 { tags["display_name"] = service.DisplayName }即服务没有显示名时该标签不会出现,而不是写入空值。在下游做 tag 基数分析或告警规则匹配时需要注意这一点。
错误处理与权限行为
Gather对错误采取了"整体失败与单项跳过"分离的策略:
- SCManager 连接失败或服务列表获取失败:直接返回错误,整轮采集失败。这一点被单元测试 win_services_test.go 中的
TestMgrErrors覆盖(通过FakeMgProvider注入mgrConnectError、mgrListServicesError验证错误向上传播)。 - 单个服务的打开/查询/配置失败:仅记录日志并
continue,不影响其他服务的采集。其中权限错误(fs.ErrPermission,即ERROR_ACCESS_DENIED一类错误)通过isPermission判定后降级为Debug 级别日志,其他错误才记Error 级别——因为非管理员运行时对部分服务无访问权是常见且可预期的情况,不应产生大量告警日志。
TestServiceErrors测试用例通过fakeWinSvc分别注入serviceOpenError、serviceQueryError、serviceConfigError三种故障,验证了上述"记日志但不中断"的行为。
测试与验证方式
- 单元测试(win_services_test.go):基于接口抽象
winServiceManager/managerProvider,用假实现模拟服务管理器,验证了 glob 包含匹配(TestGatherContainsTag)、glob 排除匹配(TestExcludingNamesTag)以及各种错误路径。 - 集成测试(win_services_integration_test.go):文件头明确注明 "these tests must be run under administrator account",即需要管理员权限的 Windows 环境运行。
TestListIntegration验证LanmanServer、TermService两个已知服务能被精确过滤出,TestEmptyListIntegration验证空配置能枚举出 20 个以上服务,TestGatherErrorsIntegration则用不存在的非法服务名验证错误计数。
如果你需要按自定义构建裁剪 Telegraf(只编译所需插件),该插件的注册入口为 win_services.go,构建标签为inputs.win_services。
指标说明
插件输出单一指标名win_services,其结构与取值范围如下:
Tags:
| 标签 | 说明 |
|---|---|
service_name | 服务名(SCManager 内部名称),始终存在 |
display_name | 服务显示名,可能为空(为空时该标签不输出) |
Fields:
| 字段 | 类型 | 说明 |
|---|---|---|
state | integer | 服务运行状态 |
startup_mode | integer | 服务启动类型 |
state的取值(对应svc.Status.State):
1- stopped(已停止)2- start pending(正在启动)3- stop pending(正在停止)4- running(运行中)5- continue pending(正在继续)6- pause pending(正在暂停)7- paused(已暂停)
startup_mode的取值(对应mgr.Config.StartType):
0- boot start(启动时启动)1- system start(系统启动时启动)2- auto start(自动启动)3- demand start(手动/按需启动)4- disabled(禁用)
示例输出(来自插件文档):
win_services,host=WIN2008R2H401,display_name=Server,service_name=LanmanServer state=4i,startup_mode=2i 1500040669000000000 win_services,display_name=Remote\ Desktop\ Services,service_name=TermService,host=WIN2008R2H401 state=1i,startup_mode=3i 1500040669000000000可以直观看出:LanmanServer(Server 服务)处于运行中(state=4i)、自动启动(startup_mode=2i);而TermService(远程桌面服务)处于停止(state=1i)、手动启动(startup_mode=3i)。由于display_name中可能含空格与反斜杠转义(如Remote\ Desktop\ Services),后续解析需按 InfluxDB Line Protocol 规则处理。
实战配置建议
结合文档与源码行为,一个典型的监控"关键服务是否停止"的配置可以这样写:
[[inputs.win_services]] ## 只关注关键服务,通配符覆盖所有 Windows Update 相关服务 service_names = [ "LanmanServer", "TermService", "Wuauserv", "W32Time", ] ## 排除不需要纳入采集范围的服务 excluded_service_names = ["WinRM"]使用时的几个要点:
- 权限:以普通用户运行时,无权限的服务会以 Debug 日志静默跳过,指标会缺失但进程不报错。为保证指标完整,建议以管理员权限运行(Windows 服务方式部署 Telegraf 时通常满足此条件)。
- 状态判断:
state是瞬态枚举值,2/3/5/6属于过渡态,做"服务已停止"告警时应重点判断state == 1且持续若干个采集周期,避免把正在重启的服务误报。 - 启动模式告警:
startup_mode可用于发现配置漂移,例如核心服务startup_mode从2(auto)变为3(demand)或4(disabled)时可触发通知。 - 平台前提:该插件只在实际编译目标为 Windows 时生效;在 Linux 上运行同一配置只会收到一条 "Current platform is not supported" 警告,不会报错也不会采集。
小结
win_services插件以只读权限连接 Windows SCManager,枚举服务后按 glob 过滤,输出state与startup_mode两个整型字段。其源码通过接口抽象(winServiceManager/managerProvider)实现了对服务管理器的解耦,使单元测试无需真实系统依赖;对权限错误的降级处理则保证了非管理员场景下的日志安静。相关实现与测试可分别在 win_services.go、win_services_test.go 与 win_services_integration_test.go 中查阅。
【免费下载链接】telegrafAgent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.项目地址: https://gitcode.com/GitHub_Trending/te/telegraf
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考