@@ -4,32 +4,52 @@ package win_services
4
4
5
5
import (
6
6
"fmt"
7
+ "log"
8
+ "os"
9
+
7
10
"github.com/influxdata/telegraf"
8
11
"github.com/influxdata/telegraf/plugins/inputs"
9
12
"golang.org/x/sys/windows/svc"
10
13
"golang.org/x/sys/windows/svc/mgr"
11
14
)
12
15
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
14
34
type WinService interface {
15
35
Close () error
16
36
Config () (mgr.Config , error )
17
37
Query () (svc.Status , error )
18
38
}
19
39
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 {
22
42
Connect () (WinServiceManager , error )
23
43
}
24
44
25
- //WinServiceManager provides interface for mgr.Mgr
45
+ // WinServiceManager provides interface for mgr.Mgr
26
46
type WinServiceManager interface {
27
47
Disconnect () error
28
48
OpenService (name string ) (WinService , error )
29
49
ListServices () ([]string , error )
30
50
}
31
51
32
- //WinSvcMgr is wrapper for mgr.Mgr implementing WinServiceManager interface
52
+ // WinSvcMgr is wrapper for mgr.Mgr implementing WinServiceManager interface
33
53
type WinSvcMgr struct {
34
54
realMgr * mgr.Mgr
35
55
}
@@ -45,7 +65,7 @@ func (m *WinSvcMgr) ListServices() ([]string, error) {
45
65
return m .realMgr .ListServices ()
46
66
}
47
67
48
- //MgProvider is an implementation of WinServiceManagerProvider interface returning WinSvcMgr
68
+ // MgProvider is an implementation of WinServiceManagerProvider interface returning WinSvcMgr
49
69
type MgProvider struct {
50
70
}
51
71
@@ -71,15 +91,14 @@ var description = "Input plugin to report Windows services info."
71
91
//WinServices is an implementation if telegraf.Input interface, providing info about Windows Services
72
92
type WinServices struct {
73
93
ServiceNames []string `toml:"service_names"`
74
- mgrProvider WinServiceManagerProvider
94
+ mgrProvider ManagerProvider
75
95
}
76
96
77
97
type ServiceInfo struct {
78
98
ServiceName string
79
99
DisplayName string
80
100
State int
81
101
StartUpMode int
82
- Error error
83
102
}
84
103
85
104
func (m * WinServices ) Description () string {
@@ -91,93 +110,102 @@ func (m *WinServices) SampleConfig() string {
91
110
}
92
111
93
112
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 ()
94
118
95
- serviceInfos , err := listServices (m .mgrProvider , m .ServiceNames )
96
-
119
+ serviceNames , err := listServices (scmgr , m .ServiceNames )
97
120
if err != nil {
98
121
return err
99
122
}
100
123
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 )
109
131
}
110
- tags ["service_name" ] = service .ServiceName
132
+ continue
133
+ }
111
134
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
+ }
114
142
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 ,
118
146
}
147
+ acc .AddFields ("win_services" , fields , tags )
119
148
}
120
149
121
150
return nil
122
151
}
123
152
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
129
157
}
130
- defer scmgr .Disconnect ()
131
158
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 )
146
162
}
147
-
148
- return serviceInfos , nil
163
+ return names , nil
149
164
}
150
165
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 ) {
155
168
srv , err := scmgr .OpenService (serviceName )
156
169
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
+ }
159
175
}
160
176
defer srv .Close ()
161
177
162
178
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
+ }
169
185
}
170
186
171
187
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 ),
177
201
}
178
- return
202
+ return serviceInfo , nil
179
203
}
180
204
181
205
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
+ })
183
211
}
0 commit comments