Skip to content

Commit 3cf08be

Browse files
danielnelsonMathieu Lecarme
authored and
Mathieu Lecarme
committed
Log access denied opening a service at debug level (influxdata#4674)
1 parent 2cd5b99 commit 3cf08be

File tree

3 files changed

+121
-152
lines changed

3 files changed

+121
-152
lines changed

plugins/inputs/win_services/README.md

+10-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
# Telegraf Plugin: win_services
2-
Input plugin to report Windows services info.
1+
# Windows Services Input Plugin
2+
3+
Reports information about Windows service status.
4+
5+
Monitoring some services may require running Telegraf with administrator privileges.
36

4-
It requires that Telegraf must be running under the administrator privileges.
57
### Configuration:
68

79
```toml
@@ -25,15 +27,15 @@ The `state` field can have the following values:
2527
- 3 - stop pending
2628
- 4 - running
2729
- 5 - continue pending
28-
- 6 - pause pending
30+
- 6 - pause pending
2931
- 7 - paused
3032

3133
The `startup_mode` field can have the following values:
3234
- 0 - boot start
3335
- 1 - system start
3436
- 2 - auto start
3537
- 3 - demand start
36-
- 4 - disabled
38+
- 4 - disabled
3739

3840
### Tags:
3941

@@ -43,14 +45,13 @@ The `startup_mode` field can have the following values:
4345

4446
### Example Output:
4547
```
46-
* Plugin: inputs.win_services, Collection 1
47-
> win_services,host=WIN2008R2H401,display_name=Server,service_name=LanmanServer state=4i,startup_mode=2i 1500040669000000000
48-
> win_services,display_name=Remote\ Desktop\ Services,service_name=TermService,host=WIN2008R2H401 state=1i,startup_mode=3i 1500040669000000000
48+
win_services,host=WIN2008R2H401,display_name=Server,service_name=LanmanServer state=4i,startup_mode=2i 1500040669000000000
49+
win_services,display_name=Remote\ Desktop\ Services,service_name=TermService,host=WIN2008R2H401 state=1i,startup_mode=3i 1500040669000000000
4950
```
5051
### TICK Scripts
5152

5253
A sample TICK script for a notification about a not running service.
53-
It sends a notification whenever any service changes its state to be not _running_ and when it changes that state back to _running_.
54+
It sends a notification whenever any service changes its state to be not _running_ and when it changes that state back to _running_.
5455
The notification is sent via an HTTP POST call.
5556

5657
```

plugins/inputs/win_services/win_services.go

+93-65
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,52 @@ package win_services
44

55
import (
66
"fmt"
7+
"log"
8+
"os"
9+
710
"github.com/influxdata/telegraf"
811
"github.com/influxdata/telegraf/plugins/inputs"
912
"golang.org/x/sys/windows/svc"
1013
"golang.org/x/sys/windows/svc/mgr"
1114
)
1215

13-
//WinService provides interface for svc.Service
16+
type ServiceErr struct {
17+
Message string
18+
Service string
19+
Err error
20+
}
21+
22+
func (e *ServiceErr) Error() string {
23+
return fmt.Sprintf("%s: '%s': %v", e.Message, e.Service, e.Err)
24+
}
25+
26+
func IsPermission(err error) bool {
27+
if err, ok := err.(*ServiceErr); ok {
28+
return os.IsPermission(err.Err)
29+
}
30+
return false
31+
}
32+
33+
// WinService provides interface for svc.Service
1434
type WinService interface {
1535
Close() error
1636
Config() (mgr.Config, error)
1737
Query() (svc.Status, error)
1838
}
1939

20-
//WinServiceManagerProvider sets interface for acquiring manager instance, like mgr.Mgr
21-
type WinServiceManagerProvider interface {
40+
// ManagerProvider sets interface for acquiring manager instance, like mgr.Mgr
41+
type ManagerProvider interface {
2242
Connect() (WinServiceManager, error)
2343
}
2444

25-
//WinServiceManager provides interface for mgr.Mgr
45+
// WinServiceManager provides interface for mgr.Mgr
2646
type WinServiceManager interface {
2747
Disconnect() error
2848
OpenService(name string) (WinService, error)
2949
ListServices() ([]string, error)
3050
}
3151

32-
//WinSvcMgr is wrapper for mgr.Mgr implementing WinServiceManager interface
52+
// WinSvcMgr is wrapper for mgr.Mgr implementing WinServiceManager interface
3353
type WinSvcMgr struct {
3454
realMgr *mgr.Mgr
3555
}
@@ -45,7 +65,7 @@ func (m *WinSvcMgr) ListServices() ([]string, error) {
4565
return m.realMgr.ListServices()
4666
}
4767

48-
//MgProvider is an implementation of WinServiceManagerProvider interface returning WinSvcMgr
68+
// MgProvider is an implementation of WinServiceManagerProvider interface returning WinSvcMgr
4969
type MgProvider struct {
5070
}
5171

@@ -71,15 +91,14 @@ var description = "Input plugin to report Windows services info."
7191
//WinServices is an implementation if telegraf.Input interface, providing info about Windows Services
7292
type WinServices struct {
7393
ServiceNames []string `toml:"service_names"`
74-
mgrProvider WinServiceManagerProvider
94+
mgrProvider ManagerProvider
7595
}
7696

7797
type ServiceInfo struct {
7898
ServiceName string
7999
DisplayName string
80100
State int
81101
StartUpMode int
82-
Error error
83102
}
84103

85104
func (m *WinServices) Description() string {
@@ -91,93 +110,102 @@ func (m *WinServices) SampleConfig() string {
91110
}
92111

93112
func (m *WinServices) Gather(acc telegraf.Accumulator) error {
113+
scmgr, err := m.mgrProvider.Connect()
114+
if err != nil {
115+
return fmt.Errorf("Could not open service manager: %s", err)
116+
}
117+
defer scmgr.Disconnect()
94118

95-
serviceInfos, err := listServices(m.mgrProvider, m.ServiceNames)
96-
119+
serviceNames, err := listServices(scmgr, m.ServiceNames)
97120
if err != nil {
98121
return err
99122
}
100123

101-
for _, service := range serviceInfos {
102-
if service.Error == nil {
103-
fields := make(map[string]interface{})
104-
tags := make(map[string]string)
105-
106-
//display name could be empty, but still valid service
107-
if len(service.DisplayName) > 0 {
108-
tags["display_name"] = service.DisplayName
124+
for _, srvName := range serviceNames {
125+
service, err := collectServiceInfo(scmgr, srvName)
126+
if err != nil {
127+
if IsPermission(err) {
128+
log.Printf("D! Error in plugin [inputs.win_services]: %v", err)
129+
} else {
130+
acc.AddError(err)
109131
}
110-
tags["service_name"] = service.ServiceName
132+
continue
133+
}
111134

112-
fields["state"] = service.State
113-
fields["startup_mode"] = service.StartUpMode
135+
tags := map[string]string{
136+
"service_name": service.ServiceName,
137+
}
138+
//display name could be empty, but still valid service
139+
if len(service.DisplayName) > 0 {
140+
tags["display_name"] = service.DisplayName
141+
}
114142

115-
acc.AddFields("win_services", fields, tags)
116-
} else {
117-
acc.AddError(service.Error)
143+
fields := map[string]interface{}{
144+
"state": service.State,
145+
"startup_mode": service.StartUpMode,
118146
}
147+
acc.AddFields("win_services", fields, tags)
119148
}
120149

121150
return nil
122151
}
123152

124-
//listServices gathers info about given services. If userServices is empty, it return info about all services on current Windows host. Any a critical error is returned.
125-
func listServices(mgrProv WinServiceManagerProvider, userServices []string) ([]ServiceInfo, error) {
126-
scmgr, err := mgrProv.Connect()
127-
if err != nil {
128-
return nil, fmt.Errorf("Could not open service manager: %s", err)
153+
// listServices returns a list of services to gather.
154+
func listServices(scmgr WinServiceManager, userServices []string) ([]string, error) {
155+
if len(userServices) != 0 {
156+
return userServices, nil
129157
}
130-
defer scmgr.Disconnect()
131158

132-
var serviceNames []string
133-
if len(userServices) == 0 {
134-
//Listing service names from system
135-
serviceNames, err = scmgr.ListServices()
136-
if err != nil {
137-
return nil, fmt.Errorf("Could not list services: %s", err)
138-
}
139-
} else {
140-
serviceNames = userServices
141-
}
142-
serviceInfos := make([]ServiceInfo, len(serviceNames))
143-
144-
for i, srvName := range serviceNames {
145-
serviceInfos[i] = collectServiceInfo(scmgr, srvName)
159+
names, err := scmgr.ListServices()
160+
if err != nil {
161+
return nil, fmt.Errorf("Could not list services: %s", err)
146162
}
147-
148-
return serviceInfos, nil
163+
return names, nil
149164
}
150165

151-
//collectServiceInfo gathers info about a service from WindowsAPI
152-
func collectServiceInfo(scmgr WinServiceManager, serviceName string) (serviceInfo ServiceInfo) {
153-
154-
serviceInfo.ServiceName = serviceName
166+
// collectServiceInfo gathers info about a service.
167+
func collectServiceInfo(scmgr WinServiceManager, serviceName string) (*ServiceInfo, error) {
155168
srv, err := scmgr.OpenService(serviceName)
156169
if err != nil {
157-
serviceInfo.Error = fmt.Errorf("Could not open service '%s': %s", serviceName, err)
158-
return
170+
return nil, &ServiceErr{
171+
Message: "could not open service",
172+
Service: serviceName,
173+
Err: err,
174+
}
159175
}
160176
defer srv.Close()
161177

162178
srvStatus, err := srv.Query()
163-
if err == nil {
164-
serviceInfo.State = int(srvStatus.State)
165-
} else {
166-
serviceInfo.Error = fmt.Errorf("Could not query service '%s': %s", serviceName, err)
167-
//finish collecting info on first found error
168-
return
179+
if err != nil {
180+
return nil, &ServiceErr{
181+
Message: "could not query service",
182+
Service: serviceName,
183+
Err: err,
184+
}
169185
}
170186

171187
srvCfg, err := srv.Config()
172-
if err == nil {
173-
serviceInfo.DisplayName = srvCfg.DisplayName
174-
serviceInfo.StartUpMode = int(srvCfg.StartType)
175-
} else {
176-
serviceInfo.Error = fmt.Errorf("Could not get config of service '%s': %s", serviceName, err)
188+
if err != nil {
189+
return nil, &ServiceErr{
190+
Message: "could not get config of service",
191+
Service: serviceName,
192+
Err: err,
193+
}
194+
}
195+
196+
serviceInfo := &ServiceInfo{
197+
ServiceName: serviceName,
198+
DisplayName: srvCfg.DisplayName,
199+
StartUpMode: int(srvCfg.StartType),
200+
State: int(srvStatus.State),
177201
}
178-
return
202+
return serviceInfo, nil
179203
}
180204

181205
func init() {
182-
inputs.Add("win_services", func() telegraf.Input { return &WinServices{mgrProvider: &MgProvider{}} })
206+
inputs.Add("win_services", func() telegraf.Input {
207+
return &WinServices{
208+
mgrProvider: &MgProvider{},
209+
}
210+
})
183211
}

0 commit comments

Comments
 (0)