@@ -4,32 +4,52 @@ package win_services
44
55import (
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
1434type 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
2646type 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
3353type 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
4969type 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
7292type WinServices struct {
7393 ServiceNames []string `toml:"service_names"`
74- mgrProvider WinServiceManagerProvider
94+ mgrProvider ManagerProvider
7595}
7696
7797type ServiceInfo struct {
7898 ServiceName string
7999 DisplayName string
80100 State int
81101 StartUpMode int
82- Error error
83102}
84103
85104func (m * WinServices ) Description () string {
@@ -91,93 +110,102 @@ func (m *WinServices) SampleConfig() string {
91110}
92111
93112func (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
181205func 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