From f9b62e05eb015d41d212a6b63f0ded703b21b00b Mon Sep 17 00:00:00 2001 From: shalper2 Date: Mon, 23 Sep 2024 09:28:31 -0500 Subject: [PATCH] first pass --- receiver/windowsservicereceiver/factory.go | 22 ++++++ receiver/windowsservicereceiver/go.mod | 7 +- receiver/windowsservicereceiver/receiver.go | 4 - receiver/windowsservicereceiver/scraper.go | 25 +++++++ .../{receiver_test.go => scraper_test.go} | 0 .../windowsservicereceiver/windowsservice.go | 73 +++++++++++++++++++ 6 files changed, 124 insertions(+), 7 deletions(-) delete mode 100644 receiver/windowsservicereceiver/receiver.go create mode 100644 receiver/windowsservicereceiver/scraper.go rename receiver/windowsservicereceiver/{receiver_test.go => scraper_test.go} (100%) diff --git a/receiver/windowsservicereceiver/factory.go b/receiver/windowsservicereceiver/factory.go index 3ffbb3937079..b19b36bdc86c 100644 --- a/receiver/windowsservicereceiver/factory.go +++ b/receiver/windowsservicereceiver/factory.go @@ -2,3 +2,25 @@ // SPDX-License-Identifier: Apache-2.0 package windowsservicereceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/windowsservicereceiver" + +import ( + "time" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/receiver/scraperhelper" +) + +const ( + defaultInterval = 5 * time.Minute +) + +func createDefaultConfig() component.Config { + scfg := scraperhelper.NewDefaultControllerConfig() + scfg.CollectionInterval = defaultInterval + + return &Config{ + ControllerConfig: scfg, + Services: nil, + MonitorAll: false, + } +} diff --git a/receiver/windowsservicereceiver/go.mod b/receiver/windowsservicereceiver/go.mod index 109d0eeb483d..89aee6f6c4fe 100644 --- a/receiver/windowsservicereceiver/go.mod +++ b/receiver/windowsservicereceiver/go.mod @@ -3,12 +3,16 @@ module github.com/open-telemetry/opentelemetry-collector-contrib/receiver/window go 1.23.1 require ( + github.com/google/go-cmp v0.6.0 github.com/stretchr/testify v1.9.0 go.opentelemetry.io/collector/component v0.109.0 go.opentelemetry.io/collector/confmap v1.15.0 go.opentelemetry.io/collector/consumer/consumertest v0.109.0 + go.opentelemetry.io/collector/pdata v1.15.0 go.opentelemetry.io/collector/receiver v0.109.0 go.uber.org/goleak v1.3.0 + go.uber.org/zap v1.27.0 + golang.org/x/sys v0.24.0 ) require ( @@ -39,7 +43,6 @@ require ( go.opentelemetry.io/collector/config/configtelemetry v0.109.0 // indirect go.opentelemetry.io/collector/consumer v0.109.0 // indirect go.opentelemetry.io/collector/consumer/consumerprofiles v0.109.0 // indirect - go.opentelemetry.io/collector/pdata v1.15.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.109.0 // indirect go.opentelemetry.io/collector/receiver/receiverprofiles v0.109.0 // indirect go.opentelemetry.io/otel v1.29.0 // indirect @@ -49,9 +52,7 @@ require ( go.opentelemetry.io/otel/sdk/metric v1.29.0 // indirect go.opentelemetry.io/otel/trace v1.29.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect golang.org/x/text v0.17.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect google.golang.org/grpc v1.66.0 // indirect diff --git a/receiver/windowsservicereceiver/receiver.go b/receiver/windowsservicereceiver/receiver.go deleted file mode 100644 index 3ffbb3937079..000000000000 --- a/receiver/windowsservicereceiver/receiver.go +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package windowsservicereceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/windowsservicereceiver" diff --git a/receiver/windowsservicereceiver/scraper.go b/receiver/windowsservicereceiver/scraper.go new file mode 100644 index 000000000000..e6acf798b668 --- /dev/null +++ b/receiver/windowsservicereceiver/scraper.go @@ -0,0 +1,25 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package windowsservicereceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/windowsservicereceiver" + +import ( + "context" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/receiver" +) + +type windowsServiceScraper struct { + cfg *Config + settings *receiver.Settings +} + +func (wss *windowsServiceScraper) Start(ctx context.Context, _ component.Host) error { + + return nil +} + +func (wss *windowsServiceScraper) Shutdown(_ context.Context) error { + return nil +} diff --git a/receiver/windowsservicereceiver/receiver_test.go b/receiver/windowsservicereceiver/scraper_test.go similarity index 100% rename from receiver/windowsservicereceiver/receiver_test.go rename to receiver/windowsservicereceiver/scraper_test.go diff --git a/receiver/windowsservicereceiver/windowsservice.go b/receiver/windowsservicereceiver/windowsservice.go index 3ffbb3937079..c854b0983b71 100644 --- a/receiver/windowsservicereceiver/windowsservice.go +++ b/receiver/windowsservicereceiver/windowsservice.go @@ -1,4 +1,77 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +//go:build windows package windowsservicereceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/windowsservicereceiver" + +import ( + "unsafe" + + "golang.org/x/sys/windows" + "golang.org/x/sys/windows/svc/mgr" +) + +// represents the service struct before we have converted it into a metric +type Service struct { + ServiceStatus uint32 + StartType uint32 + Name string + service *mgr.Service +} + +func GetService(sname string) (*Service, error) { + manager, err := mgr.Connect() + defer manager.Disconnect() + if err != nil { + return nil, err + } + + service, err := manager.OpenService(sname) + if err != nil { + return nil, err + } + + s := Service{ + Name: sname, + service: service, + } + + return &s, nil +} + +// populates fields from service status query +// +// docs for the functions used are found here +// https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-queryservicestatusex +func (s *Service) getStatus() error { + // we need to do this in order to get the size of the buffer we need to actually read the status + var bytesNeeded uint32 + + if err := windows.QueryServiceStatusEx(s.service.Handle, windows.SC_STATUS_PROCESS_INFO, nil, 0, &bytesNeeded); err != windows.ERROR_INSUFFICIENT_BUFFER { + return err + } + + // allocate our buffer with this fun little trick + buf := make([]byte, bytesNeeded) // make an empty buffer of the required size + // remember: unsafe.Pointer() is basically like void * in C, so this is probably pretty sketchy. + lp := (*windows.SERVICE_STATUS_PROCESS)(unsafe.Pointer(&buf[0])) + + // the second time around we know our required buffer (bytesRemaining is set to [bytes needed to read status] - [bytes of buffer supplied]) + if err := windows.QueryServiceStatusEx(s.service.Handle, windows.SC_STATUS_PROCESS_INFO, &buf[0], uint32(len(buf)), &bytesNeeded); err != nil { + return err + } + + s.ServiceStatus = lp.CurrentState + return nil +} + +// popualtes fields from service config query +func (s *Service) getConfig() error { + c, err := s.service.Config() + if err != nil { + return err + } + + s.StartType = c.StartType + return nil +}