Skip to content

Commit fbde2fd

Browse files
authored
Merge branch 'master' into check_size
Signed-off-by: Jan-Otto Kröpke <[email protected]>
2 parents 2603b2c + 71cedbc commit fbde2fd

File tree

8 files changed

+232
-222
lines changed

8 files changed

+232
-222
lines changed

.idea/dictionaries/project.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/collector/mssql/mssql_instance.go

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,34 +18,63 @@
1818
package mssql
1919

2020
import (
21+
"fmt"
22+
"log/slog"
23+
2124
"github.com/prometheus-community/windows_exporter/internal/types"
2225
"github.com/prometheus/client_golang/prometheus"
26+
"golang.org/x/sys/windows/registry"
2327
)
2428

2529
type collectorInstance struct {
26-
instances *prometheus.GaugeVec
30+
instances *prometheus.Desc
2731
}
2832

2933
func (c *Collector) buildInstance() error {
30-
c.instances = prometheus.NewGaugeVec(
31-
prometheus.GaugeOpts{
32-
Namespace: types.Namespace,
33-
Subsystem: Name,
34-
Name: "instance_info",
35-
Help: "A metric with a constant '1' value labeled with mssql instance information",
36-
},
34+
c.instances = prometheus.NewDesc(
35+
prometheus.BuildFQName(types.Namespace, Name, "instance_info"),
36+
"A metric with a constant '1' value labeled with mssql instance information",
3737
[]string{"edition", "mssql_instance", "patch", "version"},
38+
nil,
3839
)
3940

40-
for _, instance := range c.mssqlInstances {
41-
c.instances.WithLabelValues(instance.edition, instance.name, instance.patchVersion, instance.majorVersion.String()).Set(1)
42-
}
43-
4441
return nil
4542
}
4643

4744
func (c *Collector) collectInstance(ch chan<- prometheus.Metric) error {
48-
c.instances.Collect(ch)
45+
for _, instance := range c.mssqlInstances {
46+
regKeyName := fmt.Sprintf(`Software\Microsoft\Microsoft SQL Server\%s\Setup`, instance.instanceName)
47+
48+
regKey, err := registry.OpenKey(registry.LOCAL_MACHINE, regKeyName, registry.QUERY_VALUE)
49+
if err != nil {
50+
c.logger.Debug(fmt.Sprintf("couldn't open registry %s:", regKeyName),
51+
slog.Any("err", err),
52+
)
53+
54+
continue
55+
}
56+
57+
patchVersion, _, err := regKey.GetStringValue("PatchLevel")
58+
_ = regKey.Close()
59+
60+
if err != nil {
61+
c.logger.Debug("couldn't get version from registry",
62+
slog.Any("err", err),
63+
)
64+
65+
continue
66+
}
67+
68+
ch <- prometheus.MustNewConstMetric(
69+
c.instances,
70+
prometheus.GaugeValue,
71+
1,
72+
instance.edition,
73+
instance.name,
74+
patchVersion,
75+
instance.majorVersion.String(),
76+
)
77+
}
4978

5079
return nil
5180
}

internal/collector/mssql/types.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ import (
2626

2727
type mssqlInstance struct {
2828
name string
29+
instanceName string
2930
majorVersion mssqlServerMajorVersion
30-
patchVersion string
3131
edition string
3232
isFirstInstance bool
3333
}
@@ -54,14 +54,15 @@ func newMssqlInstance(key, name string) (mssqlInstance, error) {
5454
return mssqlInstance{}, fmt.Errorf("couldn't get version from registry: %w", err)
5555
}
5656

57+
instanceName := name
5758
_, name, _ = strings.Cut(name, ".")
5859

5960
return mssqlInstance{
6061
edition: edition,
6162
name: name,
6263
majorVersion: newMajorVersion(patchVersion),
63-
patchVersion: patchVersion,
6464
isFirstInstance: key == "MSSQLSERVER",
65+
instanceName: instanceName,
6566
}, nil
6667
}
6768

internal/mi/callbacks.go

Lines changed: 0 additions & 181 deletions
This file was deleted.

internal/mi/mi_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ import (
2222
"time"
2323

2424
"github.com/prometheus-community/windows_exporter/internal/mi"
25+
"github.com/prometheus-community/windows_exporter/internal/utils/testutils"
2526
"github.com/stretchr/testify/require"
27+
"golang.org/x/sys/windows"
2628
)
2729

2830
type win32Process struct {
@@ -234,3 +236,54 @@ func Test_MI_Query_Unmarshal(t *testing.T) {
234236
err = application.Close()
235237
require.NoError(t, err)
236238
}
239+
240+
func Test_MI_FD_Leak(t *testing.T) {
241+
application, err := mi.ApplicationInitialize()
242+
require.NoError(t, err)
243+
require.NotEmpty(t, application)
244+
245+
session, err := application.NewSession(nil)
246+
require.NoError(t, err)
247+
require.NotEmpty(t, session)
248+
249+
currentFileHandle, err := testutils.GetProcessHandleCount(windows.CurrentProcess())
250+
require.NoError(t, err)
251+
252+
t.Log("Current File Handle Count: ", currentFileHandle)
253+
254+
queryPrinter, err := mi.NewQuery("SELECT Name FROM Win32_Process")
255+
require.NoError(t, err)
256+
257+
for range 300 {
258+
var processes []win32Process
259+
260+
err := session.Query(&processes, mi.NamespaceRootCIMv2, queryPrinter)
261+
require.NoError(t, err)
262+
263+
currentFileHandle, err = testutils.GetProcessHandleCount(windows.CurrentProcess())
264+
require.NoError(t, err)
265+
266+
t.Log("Current File Handle Count: ", currentFileHandle)
267+
}
268+
269+
currentFileHandle, err = testutils.GetProcessHandleCount(windows.CurrentProcess())
270+
require.NoError(t, err)
271+
272+
t.Log("Current File Handle Count: ", currentFileHandle)
273+
274+
err = session.Close()
275+
require.NoError(t, err)
276+
277+
currentFileHandle, err = testutils.GetProcessHandleCount(windows.CurrentProcess())
278+
require.NoError(t, err)
279+
280+
t.Log("Current File Handle Count: ", currentFileHandle)
281+
282+
err = application.Close()
283+
require.NoError(t, err)
284+
285+
currentFileHandle, err = testutils.GetProcessHandleCount(windows.CurrentProcess())
286+
require.NoError(t, err)
287+
288+
t.Log("Current File Handle Count: ", currentFileHandle)
289+
}

internal/mi/operation.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,7 @@ var OperationOptionsTimeout = UTF16PtrFromString[*uint16]("__MI_OPERATIONOPTIONS
4141
type OperationFlags uint32
4242

4343
const (
44-
OperationFlagsDefaultRTTI OperationFlags = 0x0000
45-
OperationFlagsBasicRTTI OperationFlags = 0x0002
46-
OperationFlagsNoRTTI OperationFlags = 0x0400
4744
OperationFlagsStandardRTTI OperationFlags = 0x0800
48-
OperationFlagsFullRTTI OperationFlags = 0x0004
4945
)
5046

5147
// Operation represents an operation.
@@ -123,7 +119,7 @@ func (o *Operation) Cancel() error {
123119
return ErrNotInitialized
124120
}
125121

126-
r0, _, _ := syscall.SyscallN(o.ft.Close, uintptr(unsafe.Pointer(o)), 0)
122+
r0, _, _ := syscall.SyscallN(o.ft.Cancel, uintptr(unsafe.Pointer(o)), 0)
127123

128124
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
129125
return result
@@ -229,10 +225,14 @@ func (o *Operation) Unmarshal(dst any) error {
229225
field.SetInt(int64(element.value))
230226
case ValueTypeSTRING:
231227
if element.value == 0 {
232-
return fmt.Errorf("%s: invalid pointer: value is nil", miTag)
228+
field.SetString("") // Set empty string for nil values
229+
230+
continue
233231
}
234232

235-
// Convert the UTF-16 string to a Go string
233+
// Convert uintptr to *uint16 for Windows UTF-16 string
234+
// This is safe because element.value comes directly from Windows MI API
235+
//goland:noinspection GoVetUnsafePointer
236236
stringValue := windows.UTF16PtrToString((*uint16)(unsafe.Pointer(element.value)))
237237

238238
field.SetString(stringValue)

0 commit comments

Comments
 (0)