Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Metricbeat] Windows Module add wmi metricset #42017

Open
wants to merge 55 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
5aff55e
Add stub for wmi module
herrBez Dec 3, 2024
60dfc6d
Execute mage update
herrBez Dec 3, 2024
4c6334f
Add first draft of wmi metricset
herrBez Dec 3, 2024
e5e45a5
Merge branch 'main' of https://github.com/elastic/beats into wmi
herrBez Dec 12, 2024
880a7ef
Merge branch 'main' of https://github.com/elastic/beats into wmi
herrBez Dec 12, 2024
ebc8ceb
Add first draft of wmi windows module
herrBez Dec 12, 2024
6198252
Add config unit test
herrBez Dec 12, 2024
98357b7
Add unit test for the config class
herrBez Dec 12, 2024
70abaef
Add license notice mage fmt
herrBez Dec 12, 2024
0349726
Add License to wmi/wmi.go
herrBez Dec 12, 2024
65d594f
Update example
herrBez Dec 12, 2024
aface56
Use wrapping fromat verb for fmt.Errorf
herrBez Dec 13, 2024
b833f93
Fix mispelled comment
herrBez Dec 13, 2024
a5e69f2
Add first draft of the documentation
herrBez Dec 13, 2024
18ba51d
Add the config reference and config file
herrBez Dec 13, 2024
dfb1338
Bump microsfot/wmi to 0.25.1
herrBez Dec 13, 2024
aa6b937
Make sure the wmi metricset is only used on windows
herrBez Dec 13, 2024
de36999
Run mage update
herrBez Dec 13, 2024
64201dc
Add License for microsoft/wmi library in Notice.txt
herrBez Dec 13, 2024
c5adc90
Add Timeout configuration
herrBez Dec 16, 2024
d706121
Introduce the ExecuteGuardedQueryInstances to wait for at most a time…
herrBez Dec 16, 2024
e0477e5
Merge branch 'wmi' of github.com:herrBez/beats into wmi
herrBez Dec 16, 2024
59b625c
Add invokation of CloseAllInstances() to make sure to free resources …
herrBez Dec 21, 2024
f01ba97
Add license header to utils.go
herrBez Dec 23, 2024
0a6c670
Rename timeout to warning_threshold to conceive the message that the …
herrBez Dec 24, 2024
06ae564
Refactor the ExecuteGuardedQueryInstances to use the context.WithTimeout
herrBez Dec 24, 2024
c1c956b
Add unit test for ExecuteGuardedQueryInstances
herrBez Dec 24, 2024
b29f5c7
Add parameter IncludeEmptyString. Create function to check skip condi…
herrBez Dec 24, 2024
bf9c088
Add namespace at the query level and add a structure to index queries…
herrBez Dec 24, 2024
c54eca0
Rename the config method to be more explicit
herrBez Dec 24, 2024
3e232f2
Add Primitives to deal with the type convrsion for strings
herrBez Dec 24, 2024
7ff8b88
Add unit test for the conversion function
herrBez Dec 24, 2024
f1e67e4
Add heuristic to determine if fetching the CIMType is needed
herrBez Dec 24, 2024
c4f7101
Add type conversion
herrBez Dec 24, 2024
1e00ac9
Improve comments to explicitly state what are the config parameters u…
herrBez Dec 24, 2024
54e6642
Add license header to wmi and utils test
herrBez Dec 24, 2024
0cced56
Run mage fmt
herrBez Dec 24, 2024
9661c45
Update the reference config after the final implementation
herrBez Dec 24, 2024
ab3c5e6
Remove the dummy field definition
herrBez Dec 24, 2024
6c3c55f
Add sample data in the data.json file
herrBez Dec 24, 2024
969b7cc
Fix go.mod and change NOTICE.txt to reflect the fact that go-ole is n…
herrBez Dec 24, 2024
be95605
Make sure that the wmi tests run only on windows
herrBez Dec 24, 2024
9a8b9b8
Improve the error message to prepare a Troubleshooting Guide
herrBez Dec 24, 2024
082873a
Merge branch 'wmi' of github.com:herrBez/beats into wmi
herrBez Dec 24, 2024
e7fcdd4
Merge remote-tracking branch 'upstream/main' into wmi
herrBez Jan 15, 2025
4882238
Fix test to use right function
herrBez Jan 15, 2025
213d92e
Add doc.go file
herrBez Jan 15, 2025
83e2627
Add pragma to avoid compiling utils.go on platforms other than windows
herrBez Jan 15, 2025
f7b4865
Run make update BEATS=metricbeat
herrBez Jan 15, 2025
8ff47b4
Use Metricset Logger instead of generic one in wmi.go
herrBez Jan 16, 2025
cd513ef
Make sure that we are using the Metricset logger everywhere. Address …
herrBez Jan 16, 2025
f4c0c7d
Merge branch 'wmi' of github.com:herrBez/beats into wmi
herrBez Jan 16, 2025
8ccb2dc
Merge branch 'main' into wmi
herrBez Jan 16, 2025
df56ec6
Run make updates BEATS=metricbeat
herrBez Jan 16, 2025
cf9b2f6
Get rid of duplicated rawResult.Clear()
herrBez Jan 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add first draft of wmi metricset
  • Loading branch information
herrBez committed Dec 3, 2024
commit 4c6334fe32e441ad48ae428b52154fc54b52f165
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ require (
github.com/mattn/go-ieproxy v0.0.1 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/microsoft/wmi v0.24.5 // indirect
github.com/mileusna/useragent v1.3.4 // indirect
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 // indirect
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,8 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/microsoft/go-mssqldb v1.7.2 h1:CHkFJiObW7ItKTJfHo1QX7QBBD1iV+mn1eOyRP3b/PA=
github.com/microsoft/go-mssqldb v1.7.2/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA=
github.com/microsoft/wmi v0.24.5 h1:NT+WqhjKbEcg3ldmDsRMarWgHGkpeW+gMopSCfON0kM=
github.com/microsoft/wmi v0.24.5/go.mod h1:1zbdSF0A+5OwTUII5p3hN7/K6KF2m3o27pSG6Y51VU8=
github.com/miekg/dns v1.1.22/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs=
github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ=
Expand Down
37 changes: 37 additions & 0 deletions metricbeat/module/windows/wmi/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Config is put into a different package to prevent cyclic imports in case
// it is needed in several locations

package wmi

import (
"time"

wmiquery "github.com/microsoft/wmi/pkg/base/query"
)

type WmibeatConfig struct {
Period time.Duration `config:"period"`
IncludeQueries bool `config:"include_queries"` // Whether to include the query in the document
IncludeNull bool `config:"include_null"` // Whether to include or not nil properties
Host string `config:"host"`
User string `config:"username"`
Password string `config:"password"`
Namespace string `config:"namespace"` // Namespace for the queries
Queries []QueryConfig `config:"queries"`
}

type QueryConfig struct {
Query *wmiquery.WmiQuery
Class string `config:"class"`
Fields []string `config:"fields"`
Where []string `config:"where"`
}

func NewDefaultConfig() WmibeatConfig {
return WmibeatConfig{
Period: 10 * time.Second,
IncludeQueries: false,
IncludeNull: false,
Namespace: WMIDefaultNamespace,
}
}
94 changes: 82 additions & 12 deletions metricbeat/module/windows/wmi/wmi.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package wmi

import (
"github.com/elastic/elastic-agent-libs/mapstr"
"fmt"

"github.com/elastic/beats/v7/libbeat/common/cfgwarn"
"github.com/elastic/beats/v7/metricbeat/mb"
"github.com/elastic/elastic-agent-libs/logp"
"github.com/elastic/elastic-agent-libs/mapstr"

wmiquery "github.com/microsoft/wmi/pkg/base/query"
wmi "github.com/microsoft/wmi/pkg/wmiinstance"
)

// init registers the MetricSet with the central registry as soon as the program
Expand All @@ -20,35 +26,99 @@ func init() {
// interface methods except for Fetch.
type MetricSet struct {
mb.BaseMetricSet
counter int
config WmibeatConfig
}

const WMIDefaultNamespace = "root\\cimv2"

// New creates a new instance of the MetricSet. New is responsible for unpacking
// any MetricSet specific configuration options if there are any.
func New(base mb.BaseMetricSet) (mb.MetricSet, error) {
cfgwarn.Beta("The windows wmi metricset is beta.")

config := struct{}{}
config := NewDefaultConfig()
if err := base.Module().UnpackConfig(&config); err != nil {
return nil, err
}

return &MetricSet{
m := &MetricSet{
BaseMetricSet: base,
counter: 1,
}, nil
config: config,
}

// Compiling the Query once
for i := range m.config.Queries {
q := m.config.Queries[i]
m.config.Queries[i].Query = wmiquery.NewWmiQueryWithSelectList(q.Class, q.Fields, q.Where...)
}

return m, nil
}

// Fetch method implements the data gathering and data conversion to the right
// format. It publishes the event which is then forwarded to the output. In case
// of an error set the Error field of mb.Event or simply call report.Error().
func (m *MetricSet) Fetch(report mb.ReporterV2) error {
report.Event(mb.Event{
MetricSetFields: mapstr.M{
"counter": m.counter,
},
})
m.counter++

var err error

sm := wmi.NewWmiSessionManager()
defer sm.Dispose()

session, err := sm.GetSession(m.config.Namespace, m.config.Host, "", m.config.User, m.config.Password)

if err != nil {
return fmt.Errorf("could not initialize session %v", err)
}
_, err = session.Connect()
if err != nil {
return fmt.Errorf("could not connect session %v", err)
}
defer session.Dispose()

for _, queryConfig := range m.config.Queries {

rows, err := session.QueryInstances(queryConfig.Query.String())
if err != nil {
logp.Warn("Could not execute query %v", err)
continue
}

for _, instance := range rows {
event := mb.Event{
MetricSetFields: mapstr.M{
"class": queryConfig.Class,
"namespace": m.config.Namespace,
},
}

if m.config.IncludeQueries {
event.MetricSetFields.Put(".query", queryConfig.Query)
}

// Get only the required properites
properties := queryConfig.Fields

// With special array, we retrive all properties
if len(queryConfig.Fields) == 1 && queryConfig.Fields[0] == "*" {
properties = instance.GetClass().GetPropertiesNames()
}

for _, fieldName := range properties {
fieldValue, err := instance.GetProperty(fieldName)
if err != nil {
logp.Err("Unable to get propery by name: %v", err)
continue
}

if !m.config.IncludeNull && fieldValue == nil {
continue
}

event.MetricSetFields.Put(fieldName, fieldValue)
}
report.Event(event)
}
}
return nil
}