mi: replace all WMI calls with MI calls (#1714)

This commit is contained in:
Jan-Otto Kröpke 2024-11-03 17:23:26 +01:00 committed by GitHub
parent 45d3eabab9
commit bf233ad3e3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
82 changed files with 2771 additions and 738 deletions

View File

@ -51,7 +51,7 @@ linters-settings:
forbidigo: forbidigo:
forbid: forbid:
- "^(fmt\\.Print(|f|ln)|print|println)$" - "^(fmt\\.Print(|f|ln)|print|println)$"
- p: "^syscall\\..*$" - p: "^syscall\\.(.{1,7}|.{7}[^N]|.{9,})$"
msg: use golang.org/x/sys/windows instead of syscall msg: use golang.org/x/sys/windows instead of syscall
- p: "^windows\\.NewLazyDLL$" - p: "^windows\\.NewLazyDLL$"
msg: use NewLazySystemDLL instead NewLazyDLL msg: use NewLazySystemDLL instead NewLazyDLL

17
go.mod
View File

@ -14,14 +14,13 @@ require (
github.com/prometheus/common v0.60.1 github.com/prometheus/common v0.60.1
github.com/prometheus/exporter-toolkit v0.13.0 github.com/prometheus/exporter-toolkit v0.13.0
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.9.0
github.com/yusufpapurcu/wmi v1.2.4
golang.org/x/sys v0.26.0 golang.org/x/sys v0.26.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
) )
require ( require (
github.com/Microsoft/go-winio v0.6.2 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30 // indirect github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/containerd/cgroups/v3 v3.0.3 // indirect github.com/containerd/cgroups/v3 v3.0.3 // indirect
@ -31,7 +30,7 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/jpillora/backoff v1.0.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect
github.com/klauspost/compress v1.17.10 // indirect github.com/klauspost/compress v1.17.11 // indirect
github.com/mdlayher/socket v0.5.1 // indirect github.com/mdlayher/socket v0.5.1 // indirect
github.com/mdlayher/vsock v1.2.1 // indirect github.com/mdlayher/vsock v1.2.1 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
@ -42,13 +41,13 @@ require (
github.com/sirupsen/logrus v1.9.3 // indirect github.com/sirupsen/logrus v1.9.3 // indirect
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
go.opencensus.io v0.24.0 // indirect go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.27.0 // indirect golang.org/x/crypto v0.28.0 // indirect
golang.org/x/net v0.29.0 // indirect golang.org/x/net v0.30.0 // indirect
golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect
golang.org/x/sync v0.8.0 // indirect golang.org/x/sync v0.8.0 // indirect
golang.org/x/text v0.18.0 // indirect golang.org/x/text v0.19.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect
google.golang.org/grpc v1.67.0 // indirect google.golang.org/grpc v1.67.1 // indirect
google.golang.org/protobuf v1.34.2 // indirect google.golang.org/protobuf v1.35.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
) )

36
go.sum
View File

@ -6,8 +6,8 @@ github.com/Microsoft/hcsshim v0.12.8 h1:BtDWYlFMcWhorrvSSo2M7z0csPdw6t7no/C3FsSv
github.com/Microsoft/hcsshim v0.12.8/go.mod h1:cibQ4BqhJ32FXDwPdQhKhwrwophnh3FuT4nwQZF907w= github.com/Microsoft/hcsshim v0.12.8/go.mod h1:cibQ4BqhJ32FXDwPdQhKhwrwophnh3FuT4nwQZF907w=
github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY= github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY=
github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30 h1:t3eaIm0rUkzbrIewtiFmMK5RXHej2XnoXNhxVsAYUfg= github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0=
github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs= github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bmatcuk/doublestar/v4 v4.7.1 h1:fdDeAqgT47acgwd9bd9HxJRDmc9UAmPpc+2m0CXv75Q= github.com/bmatcuk/doublestar/v4 v4.7.1 h1:fdDeAqgT47acgwd9bd9HxJRDmc9UAmPpc+2m0CXv75Q=
@ -34,7 +34,6 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
@ -65,8 +64,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/klauspost/compress v1.17.10 h1:oXAz+Vh0PMUvJczoi+flxpnBEPxoER1IaAnU/NMPtT0= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.10/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@ -113,14 +112,12 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@ -131,8 +128,8 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
@ -144,7 +141,6 @@ golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -152,8 +148,8 @@ golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@ -165,15 +161,15 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 h1:N9BgCIAUvn/M+p4NJccWPWb3BWh88+zyL0ll9HgbEeM= google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@ -183,8 +179,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

View File

@ -8,10 +8,10 @@ import (
"log/slog" "log/slog"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "ad" const Name = "ad"
@ -118,7 +118,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
counters := []string{ counters := []string{
abANRPerSec, abANRPerSec,
abBrowsesPerSec, abBrowsesPerSec,

View File

@ -8,12 +8,12 @@ import (
"log/slog" "log/slog"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils" "github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "adcs" const Name = "adcs"
@ -74,7 +74,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
if utils.PDHEnabled() { if utils.PDHEnabled() {
counters := []string{ counters := []string{
requestsPerSecond, requestsPerSecond,

View File

@ -11,12 +11,12 @@ import (
"slices" "slices"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils" "github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "adfs" const Name = "adfs"
@ -107,7 +107,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
if utils.PDHEnabled() { if utils.PDHEnabled() {
counters := []string{ counters := []string{
adLoginConnectionFailures, adLoginConnectionFailures,

View File

@ -8,13 +8,13 @@ import (
"log/slog" "log/slog"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes" "github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils" "github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "cache" const Name = "cache"
@ -92,7 +92,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
if utils.PDHEnabled() { if utils.PDHEnabled() {
counters := []string{ counters := []string{
asyncCopyReadsTotal, asyncCopyReadsTotal,

View File

@ -10,10 +10,10 @@ import (
"github.com/Microsoft/hcsshim" "github.com/Microsoft/hcsshim"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes" "github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "container" const Name = "container"
@ -86,7 +86,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
c.containerAvailable = prometheus.NewDesc( c.containerAvailable = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "available"), prometheus.BuildFQName(types.Namespace, Name, "available"),
"Available", "Available",

View File

@ -8,12 +8,12 @@ import (
"strings" "strings"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils" "github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "cpu" const Name = "cpu"
@ -83,7 +83,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
if utils.PDHEnabled() { if utils.PDHEnabled() {
counters := []string{ counters := []string{
c1TimeSeconds, c1TimeSeconds,

View File

@ -4,14 +4,15 @@ package cpu_info
import ( import (
"errors" "errors"
"fmt"
"log/slog" "log/slog"
"strconv" "strconv"
"strings" "strings"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "cpu_info" const Name = "cpu_info"
@ -22,9 +23,9 @@ var ConfigDefaults = Config{}
// A Collector is a Prometheus Collector for a few WMI metrics in Win32_Processor. // A Collector is a Prometheus Collector for a few WMI metrics in Win32_Processor.
type Collector struct { type Collector struct {
config Config config Config
miSession *mi.Session
wmiClient *wmi.Client miQuery mi.Query
cpuInfo *prometheus.Desc cpuInfo *prometheus.Desc
cpuCoreCount *prometheus.Desc cpuCoreCount *prometheus.Desc
@ -63,12 +64,19 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, miSession *mi.Session) error {
if wmiClient == nil || wmiClient.SWbemServicesClient == nil { if miSession == nil {
return errors.New("wmiClient or SWbemServicesClient is nil") return errors.New("miSession is nil")
} }
c.wmiClient = wmiClient miQuery, err := mi.NewQuery("SELECT Architecture, DeviceId, Description, Family, L2CacheSize, L3CacheSize, Name, ThreadCount, NumberOfCores, NumberOfEnabledCore, NumberOfLogicalProcessors FROM Win32_Processor")
if err != nil {
return fmt.Errorf("failed to create WMI query: %w", err)
}
c.miQuery = miQuery
c.miSession = miSession
c.cpuInfo = prometheus.NewDesc( c.cpuInfo = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, "", Name), prometheus.BuildFQName(types.Namespace, "", Name),
"Labelled CPU information as provided by Win32_Processor", "Labelled CPU information as provided by Win32_Processor",
@ -133,18 +141,20 @@ func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error {
return nil return nil
} }
type win32Processor struct { type miProcessor struct {
Architecture uint32 Architecture uint32 `mi:"Architecture"`
DeviceID string DeviceID string `mi:"DeviceID"`
Description string Description string `mi:"Description"`
Family uint16 Family uint16 `mi:"Family"`
L2CacheSize uint32 L2CacheSize uint32 `mi:"L2CacheSize"`
L3CacheSize uint32 L3CacheSize uint32 `mi:"L3CacheSize"`
Name string Name string `mi:"Name"`
ThreadCount uint32 ThreadCount uint32 `mi:"ThreadCount"`
NumberOfCores uint32 NumberOfCores uint32 `mi:"NumberOfCores"`
NumberOfEnabledCore uint32 NumberOfEnabledCore uint32 `mi:"NumberOfEnabledCore"`
NumberOfLogicalProcessors uint32 NumberOfLogicalProcessors uint32 `mi:"NumberOfLogicalProcessors"`
Total int
} }
// Collect sends the metric values for each metric // Collect sends the metric values for each metric
@ -163,16 +173,9 @@ func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan
} }
func (c *Collector) collect(ch chan<- prometheus.Metric) error { func (c *Collector) collect(ch chan<- prometheus.Metric) error {
var dst []win32Processor var dst []miProcessor
// We use a static query here because the provided methods in wmi.go all issue a SELECT *; if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, c.miQuery); err != nil {
// This results in the time-consuming LoadPercentage field being read which seems to measure each CPU return fmt.Errorf("WMI query failed: %w", err)
// serially over a 1 second interval, so the scrape time is at least 1s * num_sockets
if err := c.wmiClient.Query("SELECT Architecture, DeviceId, Description, Family, L2CacheSize, L3CacheSize, Name, ThreadCount, NumberOfCores, NumberOfEnabledCore, NumberOfLogicalProcessors FROM Win32_Processor", &dst); err != nil {
return err
}
if len(dst) == 0 {
return errors.New("WMI query returned empty result set")
} }
// Some CPUs end up exposing trailing spaces for certain strings, so clean them up // Some CPUs end up exposing trailing spaces for certain strings, so clean them up

View File

@ -7,9 +7,9 @@ import (
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/headers/sysinfoapi" "github.com/prometheus-community/windows_exporter/internal/headers/sysinfoapi"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "cs" const Name = "cs"
@ -61,7 +61,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(logger *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
logger.Warn("The cs collector is deprecated and will be removed in a future release. " + logger.Warn("The cs collector is deprecated and will be removed in a future release. " +
"Logical processors has been moved to cpu_info collector. " + "Logical processors has been moved to cpu_info collector. " +
"Physical memory has been moved to memory collector. " + "Physical memory has been moved to memory collector. " +

View File

@ -10,12 +10,12 @@ import (
"strings" "strings"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils" "github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "dfsr" const Name = "dfsr"
@ -167,7 +167,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(logger *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
logger = logger.With(slog.String("collector", Name)) logger = logger.With(slog.String("collector", Name))
logger.Info("dfsr collector is in an experimental state! Metrics for this collector have not been tested.") logger.Info("dfsr collector is in an experimental state! Metrics for this collector have not been tested.")

View File

@ -8,13 +8,13 @@ import (
"log/slog" "log/slog"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes" "github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils" "github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "dhcp" const Name = "dhcp"
@ -88,7 +88,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
if utils.PDHEnabled() { if utils.PDHEnabled() {
counters := []string{ counters := []string{
acksTotal, acksTotal,

View File

@ -4,19 +4,17 @@ package diskdrive
import ( import (
"errors" "errors"
"fmt"
"log/slog" "log/slog"
"strings" "strings"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const ( const Name = "diskdrive"
Name = "diskdrive"
win32DiskQuery = "SELECT DeviceID, Model, Caption, Name, Partitions, Size, Status, Availability FROM WIN32_DiskDrive"
)
type Config struct{} type Config struct{}
@ -25,7 +23,8 @@ var ConfigDefaults = Config{}
// A Collector is a Prometheus Collector for a few WMI metrics in Win32_DiskDrive. // A Collector is a Prometheus Collector for a few WMI metrics in Win32_DiskDrive.
type Collector struct { type Collector struct {
config Config config Config
wmiClient *wmi.Client miSession *mi.Session
miQuery mi.Query
availability *prometheus.Desc availability *prometheus.Desc
diskInfo *prometheus.Desc diskInfo *prometheus.Desc
@ -62,12 +61,19 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, miSession *mi.Session) error {
if wmiClient == nil || wmiClient.SWbemServicesClient == nil { if miSession == nil {
return errors.New("wmiClient or SWbemServicesClient is nil") return errors.New("miSession is nil")
} }
c.wmiClient = wmiClient miQuery, err := mi.NewQuery("SELECT DeviceID, Model, Caption, Name, Partitions, Size, Status, Availability FROM WIN32_DiskDrive")
if err != nil {
return fmt.Errorf("failed to create WMI query: %w", err)
}
c.miQuery = miQuery
c.miSession = miSession
c.diskInfo = prometheus.NewDesc( c.diskInfo = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "info"), prometheus.BuildFQName(types.Namespace, Name, "info"),
"General drive information", "General drive information",
@ -108,14 +114,14 @@ func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error {
} }
type win32_DiskDrive struct { type win32_DiskDrive struct {
DeviceID string DeviceID string `mi:"DeviceID"`
Model string Model string `mi:"Model"`
Size uint64 Size uint64 `mi:"Size"`
Name string Name string `mi:"Name"`
Caption string Caption string `mi:"Caption"`
Partitions uint32 Partitions uint32 `mi:"Partitions"`
Status string Status string `mi:"Status"`
Availability uint16 Availability uint16 `mi:"Availability"`
} }
var ( var (
@ -175,9 +181,8 @@ func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan
func (c *Collector) collect(ch chan<- prometheus.Metric) error { func (c *Collector) collect(ch chan<- prometheus.Metric) error {
var dst []win32_DiskDrive var dst []win32_DiskDrive
if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, c.miQuery); err != nil {
if err := c.wmiClient.Query(win32DiskQuery, &dst); err != nil { return fmt.Errorf("WMI query failed: %w", err)
return err
} }
if len(dst) == 0 { if len(dst) == 0 {

View File

@ -8,11 +8,11 @@ import (
"log/slog" "log/slog"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes" "github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "dns" const Name = "dns"
@ -79,7 +79,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
counters := []string{ counters := []string{
axfrRequestReceived, axfrRequestReceived,
axfrRequestSent, axfrRequestSent,

View File

@ -10,11 +10,11 @@ import (
"strings" "strings"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils" "github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "exchange" const Name = "exchange"
@ -207,7 +207,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
if utils.PDHEnabled() { if utils.PDHEnabled() {
collectorFuncs := map[string]func() error{ collectorFuncs := map[string]func() error{
adAccessProcesses: c.buildADAccessProcesses, adAccessProcesses: c.buildADAccessProcesses,

View File

@ -12,9 +12,9 @@ import (
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/bmatcuk/doublestar/v4" "github.com/bmatcuk/doublestar/v4"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "filetime" const Name = "filetime"
@ -85,7 +85,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(logger *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
logger.Info("filetime collector is in an experimental state! It may subject to change.", logger.Info("filetime collector is in an experimental state! It may subject to change.",
slog.String("collector", Name), slog.String("collector", Name),
) )

View File

@ -4,13 +4,14 @@ package fsrmquota
import ( import (
"errors" "errors"
"fmt"
"log/slog" "log/slog"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils" "github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "fsrmquota" const Name = "fsrmquota"
@ -21,7 +22,8 @@ var ConfigDefaults = Config{}
type Collector struct { type Collector struct {
config Config config Config
wmiClient *wmi.Client miSession *mi.Session
miQuery mi.Query
quotasCount *prometheus.Desc quotasCount *prometheus.Desc
peakUsage *prometheus.Desc peakUsage *prometheus.Desc
@ -63,12 +65,18 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, miSession *mi.Session) error {
if wmiClient == nil || wmiClient.SWbemServicesClient == nil { if miSession == nil {
return errors.New("wmiClient or SWbemServicesClient is nil") return errors.New("miSession is nil")
} }
c.wmiClient = wmiClient miQuery, err := mi.NewQuery("SELECT * FROM MSFT_FSRMQuota")
if err != nil {
return fmt.Errorf("failed to create WMI query: %w", err)
}
c.miQuery = miQuery
c.miSession = miSession
c.quotasCount = prometheus.NewDesc( c.quotasCount = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "count"), prometheus.BuildFQName(types.Namespace, Name, "count"),
@ -146,29 +154,28 @@ func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan
// MSFT_FSRMQuota docs: // MSFT_FSRMQuota docs:
// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/fsrm/msft-fsrmquota // https://docs.microsoft.com/en-us/previous-versions/windows/desktop/fsrm/msft-fsrmquota
type MSFT_FSRMQuota struct { type MSFT_FSRMQuota struct {
Name string Name string `mi:"Name"`
Path string Path string `mi:"Path"`
PeakUsage uint64 PeakUsage uint64 `mi:"PeakUsage"`
Size uint64 Size uint64 `mi:"Size"`
Usage uint64 Usage uint64 `mi:"Usage"`
Description string Description string `mi:"Description"`
Template string Template string `mi:"Template"`
// Threshold string // Threshold string `mi:"Threshold"`
Disabled bool Disabled bool `mi:"Disabled"`
MatchesTemplate bool MatchesTemplate bool `mi:"MatchesTemplate"`
SoftLimit bool SoftLimit bool `mi:"SoftLimit"`
} }
func (c *Collector) collect(ch chan<- prometheus.Metric) error { func (c *Collector) collect(ch chan<- prometheus.Metric) error {
var dst []MSFT_FSRMQuota var dst []MSFT_FSRMQuota
if err := c.miSession.Query(&dst, mi.NamespaceRootWindowsFSRM, c.miQuery); err != nil {
return fmt.Errorf("WMI query failed: %w", err)
}
var count int var count int
if err := c.wmiClient.Query("SELECT * FROM MSFT_FSRMQuota", &dst, nil, "root/microsoft/windows/fsrm"); err != nil {
return err
}
for _, quota := range dst { for _, quota := range dst {
count++ count++
path := quota.Path path := quota.Path

View File

@ -9,9 +9,10 @@ import (
"strings" "strings"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "hyperv" const Name = "hyperv"
@ -23,7 +24,7 @@ var ConfigDefaults = Config{}
// Collector is a Prometheus Collector for hyper-v. // Collector is a Prometheus Collector for hyper-v.
type Collector struct { type Collector struct {
config Config config Config
wmiClient *wmi.Client miSession *mi.Session
// Win32_PerfRawData_VmmsVirtualMachineStats_HyperVVirtualMachineHealthSummary // Win32_PerfRawData_VmmsVirtualMachineStats_HyperVVirtualMachineHealthSummary
healthCritical *prometheus.Desc healthCritical *prometheus.Desc
@ -168,12 +169,12 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, miSession *mi.Session) error {
if wmiClient == nil || wmiClient.SWbemServicesClient == nil { if miSession == nil {
return errors.New("wmiClient or SWbemServicesClient is nil") return errors.New("miSession is nil")
} }
c.wmiClient = wmiClient c.miSession = miSession
buildSubsystemName := func(component string) string { return "hyperv_" + component } buildSubsystemName := func(component string) string { return "hyperv_" + component }
@ -858,14 +859,14 @@ func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan
// Win32_PerfRawData_VmmsVirtualMachineStats_HyperVVirtualMachineHealthSummary vm health status. // Win32_PerfRawData_VmmsVirtualMachineStats_HyperVVirtualMachineHealthSummary vm health status.
type Win32_PerfRawData_VmmsVirtualMachineStats_HyperVVirtualMachineHealthSummary struct { type Win32_PerfRawData_VmmsVirtualMachineStats_HyperVVirtualMachineHealthSummary struct {
HealthCritical uint32 HealthCritical uint32 `mi:"HealthCritical"`
HealthOk uint32 HealthOk uint32 `mi:"HealthOK"`
} }
func (c *Collector) collectVmHealth(ch chan<- prometheus.Metric) error { func (c *Collector) collectVmHealth(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_VmmsVirtualMachineStats_HyperVVirtualMachineHealthSummary var dst []Win32_PerfRawData_VmmsVirtualMachineStats_HyperVVirtualMachineHealthSummary
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_VmmsVirtualMachineStats_HyperVVirtualMachineHealthSummary", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * Win32_PerfRawData_VmmsVirtualMachineStats_HyperVVirtualMachineHealthSummary"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, health := range dst { for _, health := range dst {
@ -887,16 +888,16 @@ func (c *Collector) collectVmHealth(ch chan<- prometheus.Metric) error {
// Win32_PerfRawData_VidPerfProvider_HyperVVMVidPartition ..,. // Win32_PerfRawData_VidPerfProvider_HyperVVMVidPartition ..,.
type Win32_PerfRawData_VidPerfProvider_HyperVVMVidPartition struct { type Win32_PerfRawData_VidPerfProvider_HyperVVMVidPartition struct {
Name string Name string `mi:"Name"`
PhysicalPagesAllocated uint64 PhysicalPagesAllocated uint64 `mi:"PhysicalPagesAllocated"`
PreferredNUMANodeIndex uint64 PreferredNUMANodeIndex uint64 `mi:"PreferredNUMANodeIndex"`
RemotePhysicalPages uint64 RemotePhysicalPages uint64 `mi:"RemotePhysicalPages"`
} }
func (c *Collector) collectVmVid(ch chan<- prometheus.Metric) error { func (c *Collector) collectVmVid(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_VidPerfProvider_HyperVVMVidPartition var dst []Win32_PerfRawData_VidPerfProvider_HyperVVMVidPartition
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_VidPerfProvider_HyperVVMVidPartition", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * Win32_PerfRawData_VidPerfProvider_HyperVVMVidPartition"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, page := range dst { for _, page := range dst {
@ -931,34 +932,34 @@ func (c *Collector) collectVmVid(ch chan<- prometheus.Metric) error {
// Win32_PerfRawData_HvStats_HyperVHypervisorRootPartition ... // Win32_PerfRawData_HvStats_HyperVHypervisorRootPartition ...
type Win32_PerfRawData_HvStats_HyperVHypervisorRootPartition struct { type Win32_PerfRawData_HvStats_HyperVHypervisorRootPartition struct {
Name string Name string `mi:"Name"`
AddressSpaces uint64 AddressSpaces uint64 `mi:"AddressSpaces"`
AttachedDevices uint64 AttachedDevices uint64 `mi:"AttachedDevices"`
DepositedPages uint64 DepositedPages uint64 `mi:"DepositedPages"`
DeviceDMAErrors uint64 DeviceDMAErrors uint64 `mi:"DeviceDMAErrors"`
DeviceInterruptErrors uint64 DeviceInterruptErrors uint64 `mi:"DeviceInterruptErrors"`
DeviceInterruptMappings uint64 DeviceInterruptMappings uint64 `mi:"DeviceInterruptMappings"`
DeviceInterruptThrottleEvents uint64 DeviceInterruptThrottleEvents uint64 `mi:"DeviceInterruptThrottleEvents"`
GPAPages uint64 GPAPages uint64 `mi:"GPAPages"`
GPASpaceModificationsPersec uint64 GPASpaceModificationsPersec uint64 `mi:"GPASpaceModificationsPersec"`
IOTLBFlushCost uint64 IOTLBFlushCost uint64 `mi:"IOTLBFlushCost"`
IOTLBFlushesPersec uint64 IOTLBFlushesPersec uint64 `mi:"IOTLBFlushesPersec"`
RecommendedVirtualTLBSize uint64 RecommendedVirtualTLBSize uint64 `mi:"RecommendedVirtualTLBSize"`
SkippedTimerTicks uint64 SkippedTimerTicks uint64 `mi:"SkippedTimerTicks"`
Value1Gdevicepages uint64 Value1Gdevicepages uint64 `mi:"Value1Gdevicepages"`
Value1GGPApages uint64 Value1GGPApages uint64 `mi:"Value1GGPApages"`
Value2Mdevicepages uint64 Value2Mdevicepages uint64 `mi:"Value2Mdevicepages"`
Value2MGPApages uint64 Value2MGPApages uint64 `mi:"Value2MGPApages"`
Value4Kdevicepages uint64 Value4Kdevicepages uint64 `mi:"Value4Kdevicepages"`
Value4KGPApages uint64 Value4KGPApages uint64 `mi:"Value4KGPApages"`
VirtualTLBFlushEntiresPersec uint64 VirtualTLBFlushEntiresPersec uint64 `mi:"VirtualTLBFlushEntiresPersec"`
VirtualTLBPages uint64 VirtualTLBPages uint64 `mi:"VirtualTLBPages"`
} }
func (c *Collector) collectVmHv(ch chan<- prometheus.Metric) error { func (c *Collector) collectVmHv(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_HvStats_HyperVHypervisorRootPartition var dst []Win32_PerfRawData_HvStats_HyperVHypervisorRootPartition
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_HvStats_HyperVHypervisorRootPartition", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * Win32_PerfRawData_HvStats_HyperVHypervisorRootPartition"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, obj := range dst { for _, obj := range dst {
@ -1087,14 +1088,14 @@ func (c *Collector) collectVmHv(ch chan<- prometheus.Metric) error {
// Win32_PerfRawData_HvStats_HyperVHypervisor ... // Win32_PerfRawData_HvStats_HyperVHypervisor ...
type Win32_PerfRawData_HvStats_HyperVHypervisor struct { type Win32_PerfRawData_HvStats_HyperVHypervisor struct {
LogicalProcessors uint64 LogicalProcessors uint64 `mi:"LogicalProcessors"`
VirtualProcessors uint64 VirtualProcessors uint64 `mi:"VirtualProcessors"`
} }
func (c *Collector) collectVmProcessor(ch chan<- prometheus.Metric) error { func (c *Collector) collectVmProcessor(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_HvStats_HyperVHypervisor var dst []Win32_PerfRawData_HvStats_HyperVHypervisor
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_HvStats_HyperVHypervisor", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * Win32_PerfRawData_HvStats_HyperVHypervisor"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, obj := range dst { for _, obj := range dst {
@ -1116,16 +1117,16 @@ func (c *Collector) collectVmProcessor(ch chan<- prometheus.Metric) error {
// Win32_PerfRawData_HvStats_HyperVHypervisorLogicalProcessor ... // Win32_PerfRawData_HvStats_HyperVHypervisorLogicalProcessor ...
type Win32_PerfRawData_HvStats_HyperVHypervisorLogicalProcessor struct { type Win32_PerfRawData_HvStats_HyperVHypervisorLogicalProcessor struct {
Name string Name string `mi:"Name"`
PercentGuestRunTime uint64 PercentGuestRunTime uint64 `mi:"PercentGuestRunTime"`
PercentHypervisorRunTime uint64 PercentHypervisorRunTime uint64 `mi:"PercentHypervisorRunTime"`
PercentTotalRunTime uint PercentTotalRunTime uint64 `mi:"PercentTotalRunTime"`
} }
func (c *Collector) collectHostLPUsage(logger *slog.Logger, ch chan<- prometheus.Metric) error { func (c *Collector) collectHostLPUsage(logger *slog.Logger, ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_HvStats_HyperVHypervisorLogicalProcessor var dst []Win32_PerfRawData_HvStats_HyperVHypervisorLogicalProcessor
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_HvStats_HyperVHypervisorLogicalProcessor", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * Win32_PerfRawData_HvStats_HyperVHypervisorLogicalProcessor"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, obj := range dst { for _, obj := range dst {
@ -1170,18 +1171,18 @@ func (c *Collector) collectHostLPUsage(logger *slog.Logger, ch chan<- prometheus
// Win32_PerfRawData_HvStats_HyperVHypervisorRootVirtualProcessor ... // Win32_PerfRawData_HvStats_HyperVHypervisorRootVirtualProcessor ...
type Win32_PerfRawData_HvStats_HyperVHypervisorRootVirtualProcessor struct { type Win32_PerfRawData_HvStats_HyperVHypervisorRootVirtualProcessor struct {
Name string Name string `mi:"Name"`
PercentGuestRunTime uint64 PercentGuestRunTime uint64 `mi:"PercentGuestRunTime"`
PercentHypervisorRunTime uint64 PercentHypervisorRunTime uint64 `mi:"PercentHypervisorRunTime"`
PercentRemoteRunTime uint64 PercentRemoteRunTime uint64 `mi:"PercentRemoteRunTime"`
PercentTotalRunTime uint64 PercentTotalRunTime uint64 `mi:"PercentTotalRunTime"`
CPUWaitTimePerDispatch uint64 CPUWaitTimePerDispatch uint64 `mi:"CPUWaitTimePerDispatch"`
} }
func (c *Collector) collectHostCpuUsage(logger *slog.Logger, ch chan<- prometheus.Metric) error { func (c *Collector) collectHostCpuUsage(logger *slog.Logger, ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_HvStats_HyperVHypervisorRootVirtualProcessor var dst []Win32_PerfRawData_HvStats_HyperVHypervisorRootVirtualProcessor
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_HvStats_HyperVHypervisorRootVirtualProcessor", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * Win32_PerfRawData_HvStats_HyperVHypervisorRootVirtualProcessor"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, obj := range dst { for _, obj := range dst {
@ -1240,18 +1241,18 @@ func (c *Collector) collectHostCpuUsage(logger *slog.Logger, ch chan<- prometheu
// Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor ... // Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor ...
type Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor struct { type Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor struct {
Name string Name string `mi:"Name"`
PercentGuestRunTime uint64 PercentGuestRunTime uint64 `mi:"PercentGuestRunTime"`
PercentHypervisorRunTime uint64 PercentHypervisorRunTime uint64 `mi:"PercentHypervisorRunTime"`
PercentRemoteRunTime uint64 PercentRemoteRunTime uint64 `mi:"PercentRemoteRunTime"`
PercentTotalRunTime uint64 PercentTotalRunTime uint64 `mi:"PercentTotalRunTime"`
CPUWaitTimePerDispatch uint64 CPUWaitTimePerDispatch uint64 `mi:"CPUWaitTimePerDispatch"`
} }
func (c *Collector) collectVmCpuUsage(logger *slog.Logger, ch chan<- prometheus.Metric) error { func (c *Collector) collectVmCpuUsage(logger *slog.Logger, ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor var dst []Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, obj := range dst { for _, obj := range dst {
@ -1318,37 +1319,37 @@ func (c *Collector) collectVmCpuUsage(logger *slog.Logger, ch chan<- prometheus.
// Win32_PerfRawData_NvspSwitchStats_HyperVVirtualSwitch ... // Win32_PerfRawData_NvspSwitchStats_HyperVVirtualSwitch ...
type Win32_PerfRawData_NvspSwitchStats_HyperVVirtualSwitch struct { type Win32_PerfRawData_NvspSwitchStats_HyperVVirtualSwitch struct {
Name string Name string `mi:"Name"`
BroadcastPacketsReceivedPersec uint64 BroadcastPacketsReceivedPersec uint64 `mi:"BroadcastPacketsReceivedPersec"`
BroadcastPacketsSentPersec uint64 BroadcastPacketsSentPersec uint64 `mi:"BroadcastPacketsSentPersec"`
BytesPersec uint64 BytesPersec uint64 `mi:"BytesPersec"`
BytesReceivedPersec uint64 BytesReceivedPersec uint64 `mi:"BytesReceivedPersec"`
BytesSentPersec uint64 BytesSentPersec uint64 `mi:"BytesSentPersec"`
DirectedPacketsReceivedPersec uint64 DirectedPacketsReceivedPersec uint64 `mi:"DirectedPacketsReceivedPersec"`
DirectedPacketsSentPersec uint64 DirectedPacketsSentPersec uint64 `mi:"DirectedPacketsSentPersec"`
DroppedPacketsIncomingPersec uint64 DroppedPacketsIncomingPersec uint64 `mi:"DroppedPacketsIncomingPersec"`
DroppedPacketsOutgoingPersec uint64 DroppedPacketsOutgoingPersec uint64 `mi:"DroppedPacketsOutgoingPersec"`
ExtensionsDroppedPacketsIncomingPersec uint64 ExtensionsDroppedPacketsIncomingPersec uint64 `mi:"ExtensionsDroppedPacketsIncomingPersec"`
ExtensionsDroppedPacketsOutgoingPersec uint64 ExtensionsDroppedPacketsOutgoingPersec uint64 `mi:"ExtensionsDroppedPacketsOutgoingPersec"`
LearnedMacAddresses uint64 LearnedMacAddresses uint64 `mi:"LearnedMacAddresses"`
LearnedMacAddressesPersec uint64 LearnedMacAddressesPersec uint64 `mi:"LearnedMacAddressesPersec"`
MulticastPacketsReceivedPersec uint64 MulticastPacketsReceivedPersec uint64 `mi:"MulticastPacketsReceivedPersec"`
MulticastPacketsSentPersec uint64 MulticastPacketsSentPersec uint64 `mi:"MulticastPacketsSentPersec"`
NumberofSendChannelMovesPersec uint64 NumberofSendChannelMovesPersec uint64 `mi:"NumberofSendChannelMovesPersec"`
NumberofVMQMovesPersec uint64 NumberofVMQMovesPersec uint64 `mi:"NumberofVMQMovesPersec"`
PacketsFlooded uint64 PacketsFlooded uint64 `mi:"PacketsFlooded"`
PacketsFloodedPersec uint64 PacketsFloodedPersec uint64 `mi:"PacketsFloodedPersec"`
PacketsPersec uint64 PacketsPersec uint64 `mi:"PacketsPersec"`
PacketsReceivedPersec uint64 PacketsReceivedPersec uint64 `mi:"PacketsReceivedPersec"`
PacketsSentPersec uint64 PacketsSentPersec uint64 `mi:"PacketsSentPersec"`
PurgedMacAddresses uint64 PurgedMacAddresses uint64 `mi:"PurgedMacAddresses"`
PurgedMacAddressesPersec uint64 PurgedMacAddressesPersec uint64 `mi:"PurgedMacAddressesPersec"`
} }
func (c *Collector) collectVmSwitch(ch chan<- prometheus.Metric) error { func (c *Collector) collectVmSwitch(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_NvspSwitchStats_HyperVVirtualSwitch var dst []Win32_PerfRawData_NvspSwitchStats_HyperVVirtualSwitch
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_NvspSwitchStats_HyperVVirtualSwitch", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * Win32_PerfRawData_NvspSwitchStats_HyperVVirtualSwitch"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, obj := range dst { for _, obj := range dst {
@ -1500,19 +1501,19 @@ func (c *Collector) collectVmSwitch(ch chan<- prometheus.Metric) error {
// Win32_PerfRawData_EthernetPerfProvider_HyperVLegacyNetworkAdapter ... // Win32_PerfRawData_EthernetPerfProvider_HyperVLegacyNetworkAdapter ...
type Win32_PerfRawData_EthernetPerfProvider_HyperVLegacyNetworkAdapter struct { type Win32_PerfRawData_EthernetPerfProvider_HyperVLegacyNetworkAdapter struct {
Name string Name string `mi:"Name"`
BytesDropped uint64 BytesDropped uint64 `mi:"BytesDropped"`
BytesReceivedPersec uint64 BytesReceivedPersec uint64 `mi:"BytesReceivedPersec"`
BytesSentPersec uint64 BytesSentPersec uint64 `mi:"BytesSentPersec"`
FramesDropped uint64 FramesDropped uint64 `mi:"FramesDropped"`
FramesReceivedPersec uint64 FramesReceivedPersec uint64 `mi:"FramesReceivedPersec"`
FramesSentPersec uint64 FramesSentPersec uint64 `mi:"FramesSentPersec"`
} }
func (c *Collector) collectVmEthernet(ch chan<- prometheus.Metric) error { func (c *Collector) collectVmEthernet(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_EthernetPerfProvider_HyperVLegacyNetworkAdapter var dst []Win32_PerfRawData_EthernetPerfProvider_HyperVLegacyNetworkAdapter
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_EthernetPerfProvider_HyperVLegacyNetworkAdapter", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * Win32_PerfRawData_EthernetPerfProvider_HyperVLegacyNetworkAdapter"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, obj := range dst { for _, obj := range dst {
@ -1568,19 +1569,19 @@ func (c *Collector) collectVmEthernet(ch chan<- prometheus.Metric) error {
// Win32_PerfRawData_Counters_HyperVVirtualStorageDevice ... // Win32_PerfRawData_Counters_HyperVVirtualStorageDevice ...
type Win32_PerfRawData_Counters_HyperVVirtualStorageDevice struct { type Win32_PerfRawData_Counters_HyperVVirtualStorageDevice struct {
Name string Name string `mi:"Name"`
ErrorCount uint64 ErrorCount uint64 `mi:"ErrorCount"`
QueueLength uint32 QueueLength uint32 `mi:"QueueLength"`
ReadBytesPersec uint64 ReadBytesPersec uint64 `mi:"ReadBytesPersec"`
ReadOperationsPerSec uint64 ReadOperationsPerSec uint64 `mi:"ReadOperationsPerSec"`
WriteBytesPersec uint64 WriteBytesPersec uint64 `mi:"WriteBytesPersec"`
WriteOperationsPerSec uint64 WriteOperationsPerSec uint64 `mi:"WriteOperationsPerSec"`
} }
func (c *Collector) collectVmStorage(ch chan<- prometheus.Metric) error { func (c *Collector) collectVmStorage(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_Counters_HyperVVirtualStorageDevice var dst []Win32_PerfRawData_Counters_HyperVVirtualStorageDevice
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_Counters_HyperVVirtualStorageDevice", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * Win32_PerfRawData_Counters_HyperVVirtualStorageDevice"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, obj := range dst { for _, obj := range dst {
@ -1636,19 +1637,19 @@ func (c *Collector) collectVmStorage(ch chan<- prometheus.Metric) error {
// Win32_PerfRawData_NvspNicStats_HyperVVirtualNetworkAdapter ... // Win32_PerfRawData_NvspNicStats_HyperVVirtualNetworkAdapter ...
type Win32_PerfRawData_NvspNicStats_HyperVVirtualNetworkAdapter struct { type Win32_PerfRawData_NvspNicStats_HyperVVirtualNetworkAdapter struct {
Name string Name string `mi:"Name"`
BytesReceivedPersec uint64 BytesReceivedPersec uint64 `mi:"BytesReceivedPersec"`
BytesSentPersec uint64 BytesSentPersec uint64 `mi:"BytesSentPersec"`
DroppedPacketsIncomingPersec uint64 DroppedPacketsIncomingPersec uint64 `mi:"DroppedPacketsIncomingPersec"`
DroppedPacketsOutgoingPersec uint64 DroppedPacketsOutgoingPersec uint64 `mi:"DroppedPacketsOutgoingPersec"`
PacketsReceivedPersec uint64 PacketsReceivedPersec uint64 `mi:"PacketsReceivedPersec"`
PacketsSentPersec uint64 PacketsSentPersec uint64 `mi:"PacketsSentPersec"`
} }
func (c *Collector) collectVmNetwork(ch chan<- prometheus.Metric) error { func (c *Collector) collectVmNetwork(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_NvspNicStats_HyperVVirtualNetworkAdapter var dst []Win32_PerfRawData_NvspNicStats_HyperVVirtualNetworkAdapter
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_NvspNicStats_HyperVVirtualNetworkAdapter", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * Win32_PerfRawData_NvspNicStats_HyperVVirtualNetworkAdapter"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, obj := range dst { for _, obj := range dst {
@ -1704,23 +1705,23 @@ func (c *Collector) collectVmNetwork(ch chan<- prometheus.Metric) error {
// Win32_PerfRawData_BalancerStats_HyperVDynamicMemoryVM ... // Win32_PerfRawData_BalancerStats_HyperVDynamicMemoryVM ...
type Win32_PerfRawData_BalancerStats_HyperVDynamicMemoryVM struct { type Win32_PerfRawData_BalancerStats_HyperVDynamicMemoryVM struct {
Name string Name string `mi:"Name"`
AddedMemory uint64 AddedMemory uint64 `mi:"AddedMemory"`
AveragePressure uint64 AveragePressure uint64 `mi:"AveragePressure"`
CurrentPressure uint64 CurrentPressure uint64 `mi:"CurrentPressure"`
GuestVisiblePhysicalMemory uint64 GuestVisiblePhysicalMemory uint64 `mi:"GuestVisiblePhysicalMemory"`
MaximumPressure uint64 MaximumPressure uint64 `mi:"MaximumPressure"`
MemoryAddOperations uint64 MemoryAddOperations uint64 `mi:"MemoryAddOperations"`
MemoryRemoveOperations uint64 MemoryRemoveOperations uint64 `mi:"MemoryRemoveOperations"`
MinimumPressure uint64 MinimumPressure uint64 `mi:"MinimumPressure"`
PhysicalMemory uint64 PhysicalMemory uint64 `mi:"PhysicalMemory"`
RemovedMemory uint64 RemovedMemory uint64 `mi:"RemovedMemory"`
} }
func (c *Collector) collectVmMemory(ch chan<- prometheus.Metric) error { func (c *Collector) collectVmMemory(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_BalancerStats_HyperVDynamicMemoryVM var dst []Win32_PerfRawData_BalancerStats_HyperVDynamicMemoryVM
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_BalancerStats_HyperVDynamicMemoryVM", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * Win32_PerfRawData_BalancerStats_HyperVDynamicMemoryVM"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, obj := range dst { for _, obj := range dst {

View File

@ -10,10 +10,10 @@ import (
"strings" "strings"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
"golang.org/x/sys/windows/registry" "golang.org/x/sys/windows/registry"
) )
@ -262,7 +262,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(logger *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
logger = logger.With(slog.String("collector", Name)) logger = logger.With(slog.String("collector", Name))
c.iisVersion = getIISVersion(logger) c.iisVersion = getIISVersion(logger)

View File

@ -7,9 +7,9 @@ import (
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/headers/slc" "github.com/prometheus-community/windows_exporter/internal/headers/slc"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "license" const Name = "license"
@ -61,7 +61,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
c.licenseStatus = prometheus.NewDesc( c.licenseStatus = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "status"), prometheus.BuildFQName(types.Namespace, Name, "status"),
"Status of windows license", "Status of windows license",

View File

@ -13,13 +13,13 @@ import (
"strings" "strings"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes" "github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils" "github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
@ -141,7 +141,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
if utils.PDHEnabled() { if utils.PDHEnabled() {
counters := []string{ counters := []string{
currentDiskQueueLength, currentDiskQueueLength,

View File

@ -8,9 +8,9 @@ import (
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/headers/secur32" "github.com/prometheus-community/windows_exporter/internal/headers/secur32"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "logon" const Name = "logon"
@ -54,7 +54,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
c.sessionInfo = prometheus.NewDesc( c.sessionInfo = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "session_logon_timestamp_seconds"), prometheus.BuildFQName(types.Namespace, Name, "session_logon_timestamp_seconds"),
"timestamp of the logon session in seconds.", "timestamp of the logon session in seconds.",

View File

@ -12,13 +12,13 @@ import (
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/headers/sysinfoapi" "github.com/prometheus-community/windows_exporter/internal/headers/sysinfoapi"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes" "github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils" "github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "memory" const Name = "memory"
@ -105,7 +105,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
if utils.PDHEnabled() { if utils.PDHEnabled() {
counters := []string{ counters := []string{
availableBytes, availableBytes,

View File

@ -8,9 +8,9 @@ import (
"strings" "strings"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "mscluster" const Name = "mscluster"
@ -32,7 +32,7 @@ var ConfigDefaults = Config{
// A Collector is a Prometheus Collector for WMI MSCluster_Cluster metrics. // A Collector is a Prometheus Collector for WMI MSCluster_Cluster metrics.
type Collector struct { type Collector struct {
config Config config Config
wmiClient *wmi.Client miSession *mi.Session
// cluster // cluster
clusterAddEvictDelay *prometheus.Desc clusterAddEvictDelay *prometheus.Desc
@ -221,16 +221,16 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, miSession *mi.Session) error {
if len(c.config.CollectorsEnabled) == 0 { if len(c.config.CollectorsEnabled) == 0 {
return nil return nil
} }
if wmiClient == nil || wmiClient.SWbemServicesClient == nil { if miSession == nil {
return errors.New("wmiClient or SWbemServicesClient is nil") return errors.New("miSession is nil")
} }
c.wmiClient = wmiClient c.miSession = miSession
if slices.Contains(c.config.CollectorsEnabled, "cluster") { if slices.Contains(c.config.CollectorsEnabled, "cluster") {
c.buildCluster() c.buildCluster()

View File

@ -1,7 +1,11 @@
package mscluster package mscluster
import ( import (
"fmt"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@ -10,85 +14,85 @@ const nameCluster = Name + "_cluster"
// msClusterCluster represents the MSCluster_Cluster WMI class // msClusterCluster represents the MSCluster_Cluster WMI class
// - https://docs.microsoft.com/en-us/previous-versions/windows/desktop/cluswmi/mscluster-cluster // - https://docs.microsoft.com/en-us/previous-versions/windows/desktop/cluswmi/mscluster-cluster
type msClusterCluster struct { type msClusterCluster struct {
Name string Name string `mi:"Name"`
AddEvictDelay uint AddEvictDelay uint `mi:"AddEvictDelay"`
AdminAccessPoint uint AdminAccessPoint uint `mi:"AdminAccessPoint"`
AutoAssignNodeSite uint AutoAssignNodeSite uint `mi:"AutoAssignNodeSite"`
AutoBalancerLevel uint AutoBalancerLevel uint `mi:"AutoBalancerLevel"`
AutoBalancerMode uint AutoBalancerMode uint `mi:"AutoBalancerMode"`
BackupInProgress uint BackupInProgress uint `mi:"BackupInProgress"`
BlockCacheSize uint BlockCacheSize uint `mi:"BlockCacheSize"`
ClusSvcHangTimeout uint ClusSvcHangTimeout uint `mi:"ClusSvcHangTimeout"`
ClusSvcRegroupOpeningTimeout uint ClusSvcRegroupOpeningTimeout uint `mi:"ClusSvcRegroupOpeningTimeout"`
ClusSvcRegroupPruningTimeout uint ClusSvcRegroupPruningTimeout uint `mi:"ClusSvcRegroupPruningTimeout"`
ClusSvcRegroupStageTimeout uint ClusSvcRegroupStageTimeout uint `mi:"ClusSvcRegroupStageTimeout"`
ClusSvcRegroupTickInMilliseconds uint ClusSvcRegroupTickInMilliseconds uint `mi:"ClusSvcRegroupTickInMilliseconds"`
ClusterEnforcedAntiAffinity uint ClusterEnforcedAntiAffinity uint `mi:"ClusterEnforcedAntiAffinity"`
ClusterFunctionalLevel uint ClusterFunctionalLevel uint `mi:"ClusterFunctionalLevel"`
ClusterGroupWaitDelay uint ClusterGroupWaitDelay uint `mi:"ClusterGroupWaitDelay"`
ClusterLogLevel uint ClusterLogLevel uint `mi:"ClusterLogLevel"`
ClusterLogSize uint ClusterLogSize uint `mi:"ClusterLogSize"`
ClusterUpgradeVersion uint ClusterUpgradeVersion uint `mi:"ClusterUpgradeVersion"`
CrossSiteDelay uint CrossSiteDelay uint `mi:"CrossSiteDelay"`
CrossSiteThreshold uint CrossSiteThreshold uint `mi:"CrossSiteThreshold"`
CrossSubnetDelay uint CrossSubnetDelay uint `mi:"CrossSubnetDelay"`
CrossSubnetThreshold uint CrossSubnetThreshold uint `mi:"CrossSubnetThreshold"`
CsvBalancer uint CsvBalancer uint `mi:"CsvBalancer"`
DatabaseReadWriteMode uint DatabaseReadWriteMode uint `mi:"DatabaseReadWriteMode"`
DefaultNetworkRole uint DefaultNetworkRole uint `mi:"DefaultNetworkRole"`
DetectedCloudPlatform uint DetectedCloudPlatform uint `mi:"DetectedCloudPlatform"`
DetectManagedEvents uint DetectManagedEvents uint `mi:"DetectManagedEvents"`
DetectManagedEventsThreshold uint DetectManagedEventsThreshold uint `mi:"DetectManagedEventsThreshold"`
DisableGroupPreferredOwnerRandomization uint DisableGroupPreferredOwnerRandomization uint `mi:"DisableGroupPreferredOwnerRandomization"`
DrainOnShutdown uint DrainOnShutdown uint `mi:"DrainOnShutdown"`
DynamicQuorumEnabled uint DynamicQuorumEnabled uint `mi:"DynamicQuorumEnabled"`
EnableSharedVolumes uint EnableSharedVolumes uint `mi:"EnableSharedVolumes"`
FixQuorum uint FixQuorum uint `mi:"FixQuorum"`
GracePeriodEnabled uint GracePeriodEnabled uint `mi:"GracePeriodEnabled"`
GracePeriodTimeout uint GracePeriodTimeout uint `mi:"GracePeriodTimeout"`
GroupDependencyTimeout uint GroupDependencyTimeout uint `mi:"GroupDependencyTimeout"`
HangRecoveryAction uint HangRecoveryAction uint `mi:"HangRecoveryAction"`
IgnorePersistentStateOnStartup uint IgnorePersistentStateOnStartup uint `mi:"IgnorePersistentStateOnStartup"`
LogResourceControls uint LogResourceControls uint `mi:"LogResourceControls"`
LowerQuorumPriorityNodeId uint LowerQuorumPriorityNodeId uint `mi:"LowerQuorumPriorityNodeId"`
MaxNumberOfNodes uint MaxNumberOfNodes uint `mi:"MaxNumberOfNodes"`
MessageBufferLength uint MessageBufferLength uint `mi:"MessageBufferLength"`
MinimumNeverPreemptPriority uint MinimumNeverPreemptPriority uint `mi:"MinimumNeverPreemptPriority"`
MinimumPreemptorPriority uint MinimumPreemptorPriority uint `mi:"MinimumPreemptorPriority"`
NetftIPSecEnabled uint NetftIPSecEnabled uint `mi:"NetftIPSecEnabled"`
PlacementOptions uint PlacementOptions uint `mi:"PlacementOptions"`
PlumbAllCrossSubnetRoutes uint PlumbAllCrossSubnetRoutes uint `mi:"PlumbAllCrossSubnetRoutes"`
PreventQuorum uint PreventQuorum uint `mi:"PreventQuorum"`
QuarantineDuration uint QuarantineDuration uint `mi:"QuarantineDuration"`
QuarantineThreshold uint QuarantineThreshold uint `mi:"QuarantineThreshold"`
QuorumArbitrationTimeMax uint QuorumArbitrationTimeMax uint `mi:"QuorumArbitrationTimeMax"`
QuorumArbitrationTimeMin uint QuorumArbitrationTimeMin uint `mi:"QuorumArbitrationTimeMin"`
QuorumLogFileSize uint QuorumLogFileSize uint `mi:"QuorumLogFileSize"`
QuorumTypeValue uint QuorumTypeValue uint `mi:"QuorumTypeValue"`
RequestReplyTimeout uint RequestReplyTimeout uint `mi:"RequestReplyTimeout"`
ResiliencyDefaultPeriod uint ResiliencyDefaultPeriod uint `mi:"ResiliencyDefaultPeriod"`
ResiliencyLevel uint ResiliencyLevel uint `mi:"ResiliencyLevel"`
ResourceDllDeadlockPeriod uint ResourceDllDeadlockPeriod uint `mi:"ResourceDllDeadlockPeriod"`
RootMemoryReserved uint RootMemoryReserved uint `mi:"RootMemoryReserved"`
RouteHistoryLength uint RouteHistoryLength uint `mi:"RouteHistoryLength"`
S2DBusTypes uint S2DBusTypes uint `mi:"S2DBusTypes"`
S2DCacheDesiredState uint S2DCacheDesiredState uint `mi:"S2DCacheDesiredState"`
S2DCacheFlashReservePercent uint S2DCacheFlashReservePercent uint `mi:"S2DCacheFlashReservePercent"`
S2DCachePageSizeKBytes uint S2DCachePageSizeKBytes uint `mi:"S2DCachePageSizeKBytes"`
S2DEnabled uint S2DEnabled uint `mi:"S2DEnabled"`
S2DIOLatencyThreshold uint S2DIOLatencyThreshold uint `mi:"S2DIOLatencyThreshold"`
S2DOptimizations uint S2DOptimizations uint `mi:"S2DOptimizations"`
SameSubnetDelay uint SameSubnetDelay uint `mi:"SameSubnetDelay"`
SameSubnetThreshold uint SameSubnetThreshold uint `mi:"SameSubnetThreshold"`
SecurityLevel uint SecurityLevel uint `mi:"SecurityLevel"`
SecurityLevelForStorage uint SecurityLevelForStorage uint `mi:"SecurityLevelForStorage"`
SharedVolumeVssWriterOperationTimeout uint SharedVolumeVssWriterOperationTimeout uint `mi:"SharedVolumeVssWriterOperationTimeout"`
ShutdownTimeoutInMinutes uint ShutdownTimeoutInMinutes uint `mi:"ShutdownTimeoutInMinutes"`
UseClientAccessNetworksForSharedVolumes uint UseClientAccessNetworksForSharedVolumes uint `mi:"UseClientAccessNetworksForSharedVolumes"`
WitnessDatabaseWriteTimeout uint WitnessDatabaseWriteTimeout uint `mi:"WitnessDatabaseWriteTimeout"`
WitnessDynamicWeight uint WitnessDynamicWeight uint `mi:"WitnessDynamicWeight"`
WitnessRestartInterval uint WitnessRestartInterval uint `mi:"WitnessRestartInterval"`
} }
func (c *Collector) buildCluster() { func (c *Collector) buildCluster() {
@ -558,8 +562,8 @@ func (c *Collector) buildCluster() {
func (c *Collector) collectCluster(ch chan<- prometheus.Metric) error { func (c *Collector) collectCluster(ch chan<- prometheus.Metric) error {
var dst []msClusterCluster var dst []msClusterCluster
if err := c.wmiClient.Query("SELECT * FROM MSCluster_Cluster", &dst, nil, "root/MSCluster"); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, utils.Must(mi.NewQuery("SELECT * MSCluster_Cluster"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, v := range dst { for _, v := range dst {

View File

@ -1,7 +1,11 @@
package mscluster package mscluster
import ( import (
"fmt"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@ -10,13 +14,13 @@ const nameNetwork = Name + "_network"
// msClusterNetwork represents the MSCluster_Network WMI class // msClusterNetwork represents the MSCluster_Network WMI class
// - https://docs.microsoft.com/en-us/previous-versions/windows/desktop/cluswmi/mscluster-network // - https://docs.microsoft.com/en-us/previous-versions/windows/desktop/cluswmi/mscluster-network
type msClusterNetwork struct { type msClusterNetwork struct {
Name string Name string `mi:"Name"`
Characteristics uint Characteristics uint `mi:"Characteristics"`
Flags uint Flags uint `mi:"Flags"`
Metric uint Metric uint `mi:"Metric"`
Role uint Role uint `mi:"Role"`
State uint State uint `mi:"State"`
} }
func (c *Collector) buildNetwork() { func (c *Collector) buildNetwork() {
@ -57,8 +61,8 @@ func (c *Collector) buildNetwork() {
func (c *Collector) collectNetwork(ch chan<- prometheus.Metric) error { func (c *Collector) collectNetwork(ch chan<- prometheus.Metric) error {
var dst []msClusterNetwork var dst []msClusterNetwork
if err := c.wmiClient.Query("SELECT * FROM MSCluster_Network", &dst, nil, "root/MSCluster"); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, utils.Must(mi.NewQuery("SELECT * MSCluster_Node"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, v := range dst { for _, v := range dst {

View File

@ -1,7 +1,11 @@
package mscluster package mscluster
import ( import (
"fmt"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@ -10,22 +14,22 @@ const nameNode = Name + "_node"
// msClusterNode represents the MSCluster_Node WMI class // msClusterNode represents the MSCluster_Node WMI class
// - https://docs.microsoft.com/en-us/previous-versions/windows/desktop/cluswmi/mscluster-node // - https://docs.microsoft.com/en-us/previous-versions/windows/desktop/cluswmi/mscluster-node
type msClusterNode struct { type msClusterNode struct {
Name string Name string `mi:"Name"`
BuildNumber uint BuildNumber uint `mi:"BuildNumber"`
Characteristics uint Characteristics uint `mi:"Characteristics"`
DetectedCloudPlatform uint DetectedCloudPlatform uint `mi:"DetectedCloudPlatform"`
DynamicWeight uint DynamicWeight uint `mi:"DynamicWeight"`
Flags uint Flags uint `mi:"Flags"`
MajorVersion uint MajorVersion uint `mi:"MajorVersion"`
MinorVersion uint MinorVersion uint `mi:"MinorVersion"`
NeedsPreventQuorum uint NeedsPreventQuorum uint `mi:"NeedsPreventQuorum"`
NodeDrainStatus uint NodeDrainStatus uint `mi:"NodeDrainStatus"`
NodeHighestVersion uint NodeHighestVersion uint `mi:"NodeHighestVersion"`
NodeLowestVersion uint NodeLowestVersion uint `mi:"NodeLowestVersion"`
NodeWeight uint NodeWeight uint `mi:"NodeWeight"`
State uint State uint `mi:"State"`
StatusInformation uint StatusInformation uint `mi:"StatusInformation"`
} }
func (c *Collector) buildNode() { func (c *Collector) buildNode() {
@ -120,8 +124,8 @@ func (c *Collector) buildNode() {
func (c *Collector) collectNode(ch chan<- prometheus.Metric) ([]string, error) { func (c *Collector) collectNode(ch chan<- prometheus.Metric) ([]string, error) {
var dst []msClusterNode var dst []msClusterNode
if err := c.wmiClient.Query("SELECT * FROM MSCluster_Node", &dst, nil, "root/MSCluster"); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, utils.Must(mi.NewQuery("SELECT * FROM MSCluster_Node"))); err != nil {
return nil, err return nil, fmt.Errorf("WMI query failed: %w", err)
} }
nodeNames := make([]string, 0, len(dst)) nodeNames := make([]string, 0, len(dst))

View File

@ -1,7 +1,11 @@
package mscluster package mscluster
import ( import (
"fmt"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@ -10,27 +14,27 @@ const nameResource = Name + "_resource"
// msClusterResource represents the MSCluster_Resource WMI class // msClusterResource represents the MSCluster_Resource WMI class
// - https://docs.microsoft.com/en-us/previous-versions/windows/desktop/cluswmi/mscluster-resource // - https://docs.microsoft.com/en-us/previous-versions/windows/desktop/cluswmi/mscluster-resource
type msClusterResource struct { type msClusterResource struct {
Name string Name string `mi:"Name"`
Type string Type string `mi:"Type"`
OwnerGroup string OwnerGroup string `mi:"OwnerGroup"`
OwnerNode string OwnerNode string `mi:"OwnerNode"`
Characteristics uint Characteristics uint `mi:"Characteristics"`
DeadlockTimeout uint DeadlockTimeout uint `mi:"DeadlockTimeout"`
EmbeddedFailureAction uint EmbeddedFailureAction uint `mi:"EmbeddedFailureAction"`
Flags uint Flags uint `mi:"Flags"`
IsAlivePollInterval uint IsAlivePollInterval uint `mi:"IsAlivePollInterval"`
LooksAlivePollInterval uint LooksAlivePollInterval uint `mi:"LooksAlivePollInterval"`
MonitorProcessId uint MonitorProcessId uint `mi:"MonitorProcessId"`
PendingTimeout uint PendingTimeout uint `mi:"PendingTimeout"`
ResourceClass uint ResourceClass uint `mi:"ResourceClass"`
RestartAction uint RestartAction uint `mi:"RestartAction"`
RestartDelay uint RestartDelay uint `mi:"RestartDelay"`
RestartPeriod uint RestartPeriod uint `mi:"RestartPeriod"`
RestartThreshold uint RestartThreshold uint `mi:"RestartThreshold"`
RetryPeriodOnFailure uint RetryPeriodOnFailure uint `mi:"RetryPeriodOnFailure"`
State uint State uint `mi:"State"`
Subclass uint Subclass uint `mi:"Subclass"`
} }
func (c *Collector) buildResource() { func (c *Collector) buildResource() {
@ -149,8 +153,8 @@ func (c *Collector) buildResource() {
func (c *Collector) collectResource(ch chan<- prometheus.Metric, nodeNames []string) error { func (c *Collector) collectResource(ch chan<- prometheus.Metric, nodeNames []string) error {
var dst []msClusterResource var dst []msClusterResource
if err := c.wmiClient.Query("SELECT * FROM MSCluster_Resource", &dst, nil, "root/MSCluster"); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, utils.Must(mi.NewQuery("SELECT * FROM MSCluster_Resource"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, v := range dst { for _, v := range dst {

View File

@ -1,7 +1,11 @@
package mscluster package mscluster
import ( import (
"fmt"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@ -10,22 +14,22 @@ const nameResourceGroup = Name + "_resourcegroup"
// msClusterResourceGroup represents the MSCluster_ResourceGroup WMI class // msClusterResourceGroup represents the MSCluster_ResourceGroup WMI class
// - https://docs.microsoft.com/en-us/previous-versions/windows/desktop/cluswmi/mscluster-resourcegroup // - https://docs.microsoft.com/en-us/previous-versions/windows/desktop/cluswmi/mscluster-resourcegroup
type msClusterResourceGroup struct { type msClusterResourceGroup struct {
Name string Name string `mi:"Name"`
AutoFailbackType uint AutoFailbackType uint `mi:"AutoFailbackType"`
Characteristics uint Characteristics uint `mi:"Characteristics"`
ColdStartSetting uint ColdStartSetting uint `mi:"ColdStartSetting"`
DefaultOwner uint DefaultOwner uint `mi:"DefaultOwner"`
FailbackWindowEnd int FailbackWindowEnd int `mi:"FailbackWindowEnd"`
FailbackWindowStart int FailbackWindowStart int `mi:"FailbackWindowStart"`
FailoverPeriod uint FailoverPeriod uint `mi:"FailoverPeriod"`
FailoverThreshold uint FailoverThreshold uint `mi:"FailoverThreshold"`
Flags uint Flags uint `mi:"Flags"`
GroupType uint GroupType uint `mi:"GroupType"`
OwnerNode string OwnerNode string `mi:"OwnerNode"`
Priority uint Priority uint `mi:"Priority"`
ResiliencyPeriod uint ResiliencyPeriod uint `mi:"ResiliencyPeriod"`
State uint State uint `mi:"State"`
} }
func (c *Collector) buildResourceGroup() { func (c *Collector) buildResourceGroup() {
@ -126,8 +130,8 @@ func (c *Collector) buildResourceGroup() {
func (c *Collector) collectResourceGroup(ch chan<- prometheus.Metric, nodeNames []string) error { func (c *Collector) collectResourceGroup(ch chan<- prometheus.Metric, nodeNames []string) error {
var dst []msClusterResourceGroup var dst []msClusterResourceGroup
if err := c.wmiClient.Query("SELECT * FROM MSCluster_ResourceGroup", &dst, nil, "root/MSCluster"); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, utils.Must(mi.NewQuery("SELECT * FROM MSCluster_ResourceGroup"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, v := range dst { for _, v := range dst {

View File

@ -4,14 +4,15 @@ package msmq
import ( import (
"errors" "errors"
"fmt"
"log/slog" "log/slog"
"strings" "strings"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils" "github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "msmq" const Name = "msmq"
@ -27,7 +28,7 @@ var ConfigDefaults = Config{
// A Collector is a Prometheus Collector for WMI Win32_PerfRawData_MSMQ_MSMQQueue metrics. // A Collector is a Prometheus Collector for WMI Win32_PerfRawData_MSMQ_MSMQQueue metrics.
type Collector struct { type Collector struct {
config Config config Config
wmiClient *wmi.Client miSession *mi.Session
bytesInJournalQueue *prometheus.Desc bytesInJournalQueue *prometheus.Desc
bytesInQueue *prometheus.Desc bytesInQueue *prometheus.Desc
@ -75,14 +76,14 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(logger *slog.Logger, wmiClient *wmi.Client) error { func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error {
logger = logger.With(slog.String("collector", Name)) logger = logger.With(slog.String("collector", Name))
if wmiClient == nil || wmiClient.SWbemServicesClient == nil { if miSession == nil {
return errors.New("wmiClient or SWbemServicesClient is nil") return errors.New("miSession is nil")
} }
c.wmiClient = wmiClient c.miSession = miSession
if *c.config.QueryWhereClause == "" { if *c.config.QueryWhereClause == "" {
logger.Warn("No where-clause specified for msmq collector. This will generate a very large number of metrics!") logger.Warn("No where-clause specified for msmq collector. This will generate a very large number of metrics!")
@ -132,12 +133,12 @@ func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan
} }
type msmqQueue struct { type msmqQueue struct {
Name string Name string `mi:"Name"`
BytesInJournalQueue uint64 BytesInJournalQueue uint64 `mi:"BytesInJournalQueue"`
BytesInQueue uint64 BytesInQueue uint64 `mi:"BytesInQueue"`
MessagesInJournalQueue uint64 MessagesInJournalQueue uint64 `mi:"MessagesInJournalQueue"`
MessagesInQueue uint64 MessagesInQueue uint64 `mi:"MessagesInQueue"`
} }
func (c *Collector) collect(ch chan<- prometheus.Metric) error { func (c *Collector) collect(ch chan<- prometheus.Metric) error {
@ -148,8 +149,13 @@ func (c *Collector) collect(ch chan<- prometheus.Metric) error {
query += " WHERE " + *c.config.QueryWhereClause query += " WHERE " + *c.config.QueryWhereClause
} }
if err := c.wmiClient.Query(query, &dst); err != nil { queryExpression, err := mi.NewQuery(query)
return err if err != nil {
return fmt.Errorf("failed to create WMI query: %w", err)
}
if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, queryExpression); err != nil {
return fmt.Errorf("WMI query failed: %w", err)
} }
for _, msmq := range dst { for _, msmq := range dst {

View File

@ -13,10 +13,10 @@ import (
"time" "time"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
"golang.org/x/sys/windows/registry" "golang.org/x/sys/windows/registry"
) )
@ -508,7 +508,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
// Result must order, to prevent test failures. // Result must order, to prevent test failures.
sort.Strings(c.config.CollectorsEnabled) sort.Strings(c.config.CollectorsEnabled)

View File

@ -13,12 +13,12 @@ import (
"unsafe" "unsafe"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils" "github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
@ -149,7 +149,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(logger *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
if utils.PDHEnabled() { if utils.PDHEnabled() {
counters := []string{ counters := []string{
BytesReceivedPerSec, BytesReceivedPerSec,

View File

@ -9,9 +9,9 @@ import (
"slices" "slices"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "netframework" const Name = "netframework"
@ -47,7 +47,7 @@ const (
// A Collector is a Prometheus Collector for WMI Win32_PerfRawData_NETFramework_NETCLRExceptions metrics. // A Collector is a Prometheus Collector for WMI Win32_PerfRawData_NETFramework_NETCLRExceptions metrics.
type Collector struct { type Collector struct {
config Config config Config
wmiClient *wmi.Client miSession *mi.Session
// clrexceptions // clrexceptions
numberOfExceptionsThrown *prometheus.Desc numberOfExceptionsThrown *prometheus.Desc
@ -143,12 +143,12 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, miSession *mi.Session) error {
if wmiClient == nil || wmiClient.SWbemServicesClient == nil { if miSession == nil {
return errors.New("wmiClient or SWbemServicesClient is nil") return errors.New("miSession is nil")
} }
c.wmiClient = wmiClient c.miSession = miSession
if slices.Contains(c.config.CollectorsEnabled, collectorClrExceptions) { if slices.Contains(c.config.CollectorsEnabled, collectorClrExceptions) {
c.buildClrExceptions() c.buildClrExceptions()

View File

@ -3,7 +3,11 @@
package netframework package netframework
import ( import (
"fmt"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@ -35,19 +39,19 @@ func (c *Collector) buildClrExceptions() {
} }
type Win32_PerfRawData_NETFramework_NETCLRExceptions struct { type Win32_PerfRawData_NETFramework_NETCLRExceptions struct {
Name string Name string `mi:"Name"`
NumberofExcepsThrown uint32 NumberofExcepsThrown uint32 `mi:"NumberofExcepsThrown"`
NumberofExcepsThrownPersec uint32 NumberofExcepsThrownPersec uint32 `mi:"NumberofExcepsThrownPersec"`
NumberofFiltersPersec uint32 NumberofFiltersPersec uint32 `mi:"NumberofFiltersPersec"`
NumberofFinallysPersec uint32 NumberofFinallysPersec uint32 `mi:"NumberofFinallysPersec"`
ThrowToCatchDepthPersec uint32 ThrowToCatchDepthPersec uint32 `mi:"ThrowToCatchDepthPersec"`
} }
func (c *Collector) collectClrExceptions(ch chan<- prometheus.Metric) error { func (c *Collector) collectClrExceptions(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_NETFramework_NETCLRExceptions var dst []Win32_PerfRawData_NETFramework_NETCLRExceptions
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRExceptions", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * Win32_PerfRawData_NETFramework_NETCLRExceptions"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, process := range dst { for _, process := range dst {

View File

@ -3,7 +3,11 @@
package netframework package netframework
import ( import (
"fmt"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@ -29,19 +33,19 @@ func (c *Collector) buildClrInterop() {
} }
type Win32_PerfRawData_NETFramework_NETCLRInterop struct { type Win32_PerfRawData_NETFramework_NETCLRInterop struct {
Name string Name string `mi:"Name"`
NumberofCCWs uint32 NumberofCCWs uint32 `mi:"NumberofCCWs"`
Numberofmarshalling uint32 Numberofmarshalling uint32 `mi:"Numberofmarshalling"`
NumberofStubs uint32 NumberofStubs uint32 `mi:"NumberofStubs"`
NumberofTLBexportsPersec uint32 NumberofTLBexportsPersec uint32 `mi:"NumberofTLBexportsPersec"`
NumberofTLBimportsPersec uint32 NumberofTLBimportsPersec uint32 `mi:"NumberofTLBimportsPersec"`
} }
func (c *Collector) collectClrInterop(ch chan<- prometheus.Metric) error { func (c *Collector) collectClrInterop(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_NETFramework_NETCLRInterop var dst []Win32_PerfRawData_NETFramework_NETCLRInterop
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRInterop", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * Win32_PerfRawData_NETFramework_NETCLRInterop"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, process := range dst { for _, process := range dst {

View File

@ -3,7 +3,11 @@
package netframework package netframework
import ( import (
"fmt"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@ -35,21 +39,21 @@ func (c *Collector) buildClrJIT() {
} }
type Win32_PerfRawData_NETFramework_NETCLRJit struct { type Win32_PerfRawData_NETFramework_NETCLRJit struct {
Name string Name string `mi:"Name"`
Frequency_PerfTime uint32 Frequency_PerfTime uint32 `mi:"Frequency_PerfTime"`
ILBytesJittedPersec uint32 ILBytesJittedPersec uint32 `mi:"ILBytesJittedPersec"`
NumberofILBytesJitted uint32 NumberofILBytesJitted uint32 `mi:"NumberofILBytesJitted"`
NumberofMethodsJitted uint32 NumberofMethodsJitted uint32 `mi:"NumberofMethodsJitted"`
PercentTimeinJit uint32 PercentTimeinJit uint32 `mi:"PercentTimeinJit"`
StandardJitFailures uint32 StandardJitFailures uint32 `mi:"StandardJitFailures"`
TotalNumberofILBytesJitted uint32 TotalNumberofILBytesJitted uint32 `mi:"TotalNumberofILBytesJitted"`
} }
func (c *Collector) collectClrJIT(ch chan<- prometheus.Metric) error { func (c *Collector) collectClrJIT(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_NETFramework_NETCLRJit var dst []Win32_PerfRawData_NETFramework_NETCLRJit
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRJit", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * Win32_PerfRawData_NETFramework_NETCLRJit"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, process := range dst { for _, process := range dst {

View File

@ -3,7 +3,11 @@
package netframework package netframework
import ( import (
"fmt"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@ -65,30 +69,30 @@ func (c *Collector) buildClrLoading() {
} }
type Win32_PerfRawData_NETFramework_NETCLRLoading struct { type Win32_PerfRawData_NETFramework_NETCLRLoading struct {
Name string Name string `mi:"Name"`
AssemblySearchLength uint32 AssemblySearchLength uint32 `mi:"AssemblySearchLength"`
BytesinLoaderHeap uint64 BytesinLoaderHeap uint64 `mi:"BytesinLoaderHeap"`
Currentappdomains uint32 Currentappdomains uint32 `mi:"Currentappdomains"`
CurrentAssemblies uint32 CurrentAssemblies uint32 `mi:"CurrentAssemblies"`
CurrentClassesLoaded uint32 CurrentClassesLoaded uint32 `mi:"CurrentClassesLoaded"`
PercentTimeLoading uint64 PercentTimeLoading uint64 `mi:"PercentTimeLoading"`
Rateofappdomains uint32 Rateofappdomains uint32 `mi:"Rateofappdomains"`
Rateofappdomainsunloaded uint32 Rateofappdomainsunloaded uint32 `mi:"Rateofappdomainsunloaded"`
RateofAssemblies uint32 RateofAssemblies uint32 `mi:"RateofAssemblies"`
RateofClassesLoaded uint32 RateofClassesLoaded uint32 `mi:"RateofClassesLoaded"`
RateofLoadFailures uint32 RateofLoadFailures uint32 `mi:"RateofLoadFailures"`
TotalAppdomains uint32 TotalAppdomains uint32 `mi:"TotalAppdomains"`
Totalappdomainsunloaded uint32 Totalappdomainsunloaded uint32 `mi:"Totalappdomainsunloaded"`
TotalAssemblies uint32 TotalAssemblies uint32 `mi:"TotalAssemblies"`
TotalClassesLoaded uint32 TotalClassesLoaded uint32 `mi:"TotalClassesLoaded"`
TotalNumberofLoadFailures uint32 TotalNumberofLoadFailures uint32 `mi:"TotalNumberofLoadFailures"`
} }
func (c *Collector) collectClrLoading(ch chan<- prometheus.Metric) error { func (c *Collector) collectClrLoading(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_NETFramework_NETCLRLoading var dst []Win32_PerfRawData_NETFramework_NETCLRLoading
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRLoading", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * Win32_PerfRawData_NETFramework_NETCLRLoading"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, process := range dst { for _, process := range dst {

View File

@ -3,7 +3,11 @@
package netframework package netframework
import ( import (
"fmt"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@ -53,24 +57,24 @@ func (c *Collector) buildClrLocksAndThreads() {
} }
type Win32_PerfRawData_NETFramework_NETCLRLocksAndThreads struct { type Win32_PerfRawData_NETFramework_NETCLRLocksAndThreads struct {
Name string Name string `mi:"Name"`
ContentionRatePersec uint32 ContentionRatePersec uint32 `mi:"ContentionRatePersec"`
CurrentQueueLength uint32 CurrentQueueLength uint32 `mi:"CurrentQueueLength"`
NumberofcurrentlogicalThreads uint32 NumberofcurrentlogicalThreads uint32 `mi:"NumberofcurrentlogicalThreads"`
NumberofcurrentphysicalThreads uint32 NumberofcurrentphysicalThreads uint32 `mi:"NumberofcurrentphysicalThreads"`
Numberofcurrentrecognizedthreads uint32 Numberofcurrentrecognizedthreads uint32 `mi:"Numberofcurrentrecognizedthreads"`
Numberoftotalrecognizedthreads uint32 Numberoftotalrecognizedthreads uint32 `mi:"Numberoftotalrecognizedthreads"`
QueueLengthPeak uint32 QueueLengthPeak uint32 `mi:"QueueLengthPeak"`
QueueLengthPersec uint32 QueueLengthPersec uint32 `mi:"QueueLengthPersec"`
RateOfRecognizedThreadsPersec uint32 RateOfRecognizedThreadsPersec uint32 `mi:"RateOfRecognizedThreadsPersec"`
TotalNumberofContentions uint32 TotalNumberofContentions uint32 `mi:"TotalNumberofContentions"`
} }
func (c *Collector) collectClrLocksAndThreads(ch chan<- prometheus.Metric) error { func (c *Collector) collectClrLocksAndThreads(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_NETFramework_NETCLRLocksAndThreads var dst []Win32_PerfRawData_NETFramework_NETCLRLocksAndThreads
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRLocksAndThreads", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * Win32_PerfRawData_NETFramework_NETCLRLocksAndThreads"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, process := range dst { for _, process := range dst {

View File

@ -3,7 +3,11 @@
package netframework package netframework
import ( import (
"fmt"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@ -83,43 +87,43 @@ func (c *Collector) buildClrMemory() {
} }
type Win32_PerfRawData_NETFramework_NETCLRMemory struct { type Win32_PerfRawData_NETFramework_NETCLRMemory struct {
Name string Name string `mi:"Name"`
AllocatedBytesPersec uint64 AllocatedBytesPersec uint64 `mi:"AllocatedBytesPersec"`
FinalizationSurvivors uint64 FinalizationSurvivors uint64 `mi:"FinalizationSurvivors"`
Frequency_PerfTime uint64 Frequency_PerfTime uint64 `mi:"Frequency_PerfTime"`
Gen0heapsize uint64 Gen0heapsize uint64 `mi:"Gen0heapsize"`
Gen0PromotedBytesPerSec uint64 Gen0PromotedBytesPerSec uint64 `mi:"Gen0PromotedBytesPersec"`
Gen1heapsize uint64 Gen1heapsize uint64 `mi:"Gen1heapsize"`
Gen1PromotedBytesPerSec uint64 Gen1PromotedBytesPerSec uint64 `mi:"Gen1PromotedBytesPersec"`
Gen2heapsize uint64 Gen2heapsize uint64 `mi:"Gen2heapsize"`
LargeObjectHeapsize uint64 LargeObjectHeapsize uint64 `mi:"LargeObjectHeapsize"`
NumberBytesinallHeaps uint64 NumberBytesinallHeaps uint64 `mi:"NumberBytesinallHeaps"`
NumberGCHandles uint64 NumberGCHandles uint64 `mi:"NumberGCHandles"`
NumberGen0Collections uint64 NumberGen0Collections uint64 `mi:"NumberGen0Collections"`
NumberGen1Collections uint64 NumberGen1Collections uint64 `mi:"NumberGen1Collections"`
NumberGen2Collections uint64 NumberGen2Collections uint64 `mi:"NumberGen2Collections"`
NumberInducedGC uint64 NumberInducedGC uint64 `mi:"NumberInducedGC"`
NumberofPinnedObjects uint64 NumberofPinnedObjects uint64 `mi:"NumberofPinnedObjects"`
NumberofSinkBlocksinuse uint64 NumberofSinkBlocksinuse uint64 `mi:"NumberofSinkBlocksinuse"`
NumberTotalcommittedBytes uint64 NumberTotalcommittedBytes uint64 `mi:"NumberTotalcommittedBytes"`
NumberTotalreservedBytes uint64 NumberTotalreservedBytes uint64 `mi:"NumberTotalreservedBytes"`
// PercentTimeinGC has countertype=PERF_RAW_FRACTION. // PercentTimeinGC has countertype=PERF_RAW_FRACTION.
// Formula: (100 * CounterValue) / BaseValue // Formula: (100 * CounterValue) / BaseValue
// By docs https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/scripting-articles/ms974615(v=msdn.10)#perf_raw_fraction // By docs https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/scripting-articles/ms974615(v=msdn.10)#perf_raw_fraction
PercentTimeinGC uint32 PercentTimeinGC uint32 `mi:"PercentTimeinGC"`
// BaseValue is just a "magic" number used to make the calculation come out right. // BaseValue is just a "magic" number used to make the calculation come out right.
PercentTimeinGC_base uint32 PercentTimeinGC_base uint32 `mi:"PercentTimeinGC_base"`
ProcessID uint64 ProcessID uint64 `mi:"ProcessID"`
PromotedFinalizationMemoryfromGen0 uint64 PromotedFinalizationMemoryfromGen0 uint64 `mi:"PromotedFinalizationMemoryfromGen0"`
PromotedMemoryfromGen0 uint64 PromotedMemoryfromGen0 uint64 `mi:"PromotedMemoryfromGen0"`
PromotedMemoryfromGen1 uint64 PromotedMemoryfromGen1 uint64 `mi:"PromotedMemoryfromGen1"`
} }
func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric) error { func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_NETFramework_NETCLRMemory var dst []Win32_PerfRawData_NETFramework_NETCLRMemory
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRMemory", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * Win32_PerfRawData_NETFramework_NETCLRMemory"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, process := range dst { for _, process := range dst {

View File

@ -3,7 +3,11 @@
package netframework package netframework
import ( import (
"fmt"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@ -47,21 +51,21 @@ func (c *Collector) buildClrRemoting() {
} }
type Win32_PerfRawData_NETFramework_NETCLRRemoting struct { type Win32_PerfRawData_NETFramework_NETCLRRemoting struct {
Name string Name string `mi:"Name"`
Channels uint32 Channels uint32 `mi:"Channels"`
ContextBoundClassesLoaded uint32 ContextBoundClassesLoaded uint32 `mi:"ContextBoundClassesLoaded"`
ContextBoundObjectsAllocPersec uint32 ContextBoundObjectsAllocPersec uint32 `mi:"ContextBoundObjectsAllocPersec"`
ContextProxies uint32 ContextProxies uint32 `mi:"ContextProxies"`
Contexts uint32 Contexts uint32 `mi:"Contexts"`
RemoteCallsPersec uint32 RemoteCallsPersec uint32 `mi:"RemoteCallsPersec"`
TotalRemoteCalls uint32 TotalRemoteCalls uint32 `mi:"TotalRemoteCalls"`
} }
func (c *Collector) collectClrRemoting(ch chan<- prometheus.Metric) error { func (c *Collector) collectClrRemoting(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_NETFramework_NETCLRRemoting var dst []Win32_PerfRawData_NETFramework_NETCLRRemoting
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRRemoting", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * Win32_PerfRawData_NETFramework_NETCLRRemoting"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, process := range dst { for _, process := range dst {

View File

@ -3,7 +3,11 @@
package netframework package netframework
import ( import (
"fmt"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@ -35,20 +39,20 @@ func (c *Collector) buildClrSecurity() {
} }
type Win32_PerfRawData_NETFramework_NETCLRSecurity struct { type Win32_PerfRawData_NETFramework_NETCLRSecurity struct {
Name string Name string `mi:"Name"`
Frequency_PerfTime uint32 Frequency_PerfTime uint32 `mi:"Frequency_PerfTime"`
NumberLinkTimeChecks uint32 NumberLinkTimeChecks uint32 `mi:"NumberLinkTimeChecks"`
PercentTimeinRTchecks uint32 PercentTimeinRTchecks uint32 `mi:"PercentTimeinRTchecks"`
PercentTimeSigAuthenticating uint64 PercentTimeSigAuthenticating uint64 `mi:"PercentTimeSigAuthenticating"`
StackWalkDepth uint32 StackWalkDepth uint32 `mi:"StackWalkDepth"`
TotalRuntimeChecks uint32 TotalRuntimeChecks uint32 `mi:"TotalRuntimeChecks"`
} }
func (c *Collector) collectClrSecurity(ch chan<- prometheus.Metric) error { func (c *Collector) collectClrSecurity(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_NETFramework_NETCLRSecurity var dst []Win32_PerfRawData_NETFramework_NETCLRSecurity
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRSecurity", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * Win32_PerfRawData_NETFramework_NETCLRSecurity"))); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, process := range dst { for _, process := range dst {

View File

@ -6,9 +6,9 @@ import (
"log/slog" "log/slog"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "nps" const Name = "nps"
@ -20,7 +20,10 @@ var ConfigDefaults = Config{}
// Collector is a Prometheus Collector for WMI Win32_PerfRawData_IAS_NPSAuthenticationServer and Win32_PerfRawData_IAS_NPSAccountingServer metrics. // Collector is a Prometheus Collector for WMI Win32_PerfRawData_IAS_NPSAuthenticationServer and Win32_PerfRawData_IAS_NPSAccountingServer metrics.
type Collector struct { type Collector struct {
config Config config Config
wmiClient *wmi.Client miSession *mi.Session
miQueryAuthenticationServer mi.Query
miQueryAccountingServer mi.Query
accessAccepts *prometheus.Desc accessAccepts *prometheus.Desc
accessChallenges *prometheus.Desc accessChallenges *prometheus.Desc
@ -78,12 +81,26 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, miSession *mi.Session) error {
if wmiClient == nil || wmiClient.SWbemServicesClient == nil { if miSession == nil {
return errors.New("wmiClient or SWbemServicesClient is nil") return errors.New("miSession is nil")
} }
c.wmiClient = wmiClient miQuery, err := mi.NewQuery("SELECT Name, AccessAccepts, AccessChallenges, AccessRejects, AccessRequests, AccessBadAuthenticators, AccessDroppedPackets, AccessInvalidRequests, AccessMalformedPackets, AccessPacketsReceived, AccessPacketsSent, AccessServerResetTime, AccessServerUpTime, AccessUnknownType FROM Win32_PerfRawData_IAS_NPSAuthenticationServer")
if err != nil {
return fmt.Errorf("failed to create WMI query: %w", err)
}
c.miQueryAuthenticationServer = miQuery
miQuery, err = mi.NewQuery("SELECT Name, AccountingRequests, AccountingResponses, AccountingBadAuthenticators, AccountingDroppedPackets, AccountingInvalidRequests, AccountingMalformedPackets, AccountingNoRecord, AccountingPacketsReceived, AccountingPacketsSent, AccountingServerResetTime, AccountingServerUpTime, AccountingUnknownType FROM Win32_PerfRawData_IAS_NPSAccountingServer")
if err != nil {
return fmt.Errorf("failed to create WMI query: %w", err)
}
c.miQueryAccountingServer = miQuery
c.miSession = miSession
c.accessAccepts = prometheus.NewDesc( c.accessAccepts = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "access_accepts"), prometheus.BuildFQName(types.Namespace, Name, "access_accepts"),
"(AccessAccepts)", "(AccessAccepts)",
@ -261,46 +278,46 @@ func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan
// Win32_PerfRawData_IAS_NPSAuthenticationServer docs: // Win32_PerfRawData_IAS_NPSAuthenticationServer docs:
// at the moment there is no Microsoft documentation. // at the moment there is no Microsoft documentation.
type Win32_PerfRawData_IAS_NPSAuthenticationServer struct { type Win32_PerfRawData_IAS_NPSAuthenticationServer struct {
Name string Name string `mi:"Name"`
AccessAccepts uint32 AccessAccepts uint32 `mi:"AccessAccepts"`
AccessChallenges uint32 AccessChallenges uint32 `mi:"AccessChallenges"`
AccessRejects uint32 AccessRejects uint32 `mi:"AccessRejects"`
AccessRequests uint32 AccessRequests uint32 `mi:"AccessRequests"`
AccessBadAuthenticators uint32 AccessBadAuthenticators uint32 `mi:"AccessBadAuthenticators"`
AccessDroppedPackets uint32 AccessDroppedPackets uint32 `mi:"AccessDroppedPackets"`
AccessInvalidRequests uint32 AccessInvalidRequests uint32 `mi:"AccessInvalidRequests"`
AccessMalformedPackets uint32 AccessMalformedPackets uint32 `mi:"AccessMalformedPackets"`
AccessPacketsReceived uint32 AccessPacketsReceived uint32 `mi:"AccessPacketsReceived"`
AccessPacketsSent uint32 AccessPacketsSent uint32 `mi:"AccessPacketsSent"`
AccessServerResetTime uint32 AccessServerResetTime uint32 `mi:"AccessServerResetTime"`
AccessServerUpTime uint32 AccessServerUpTime uint32 `mi:"AccessServerUpTime"`
AccessUnknownType uint32 AccessUnknownType uint32 `mi:"AccessUnknownType"`
} }
type Win32_PerfRawData_IAS_NPSAccountingServer struct { type Win32_PerfRawData_IAS_NPSAccountingServer struct {
Name string Name string `mi:"Name"`
AccountingRequests uint32 AccountingRequests uint32 `mi:"AccountingRequests"`
AccountingResponses uint32 AccountingResponses uint32 `mi:"AccountingResponses"`
AccountingBadAuthenticators uint32 AccountingBadAuthenticators uint32 `mi:"AccountingBadAuthenticators"`
AccountingDroppedPackets uint32 AccountingDroppedPackets uint32 `mi:"AccountingDroppedPackets"`
AccountingInvalidRequests uint32 AccountingInvalidRequests uint32 `mi:"AccountingInvalidRequests"`
AccountingMalformedPackets uint32 AccountingMalformedPackets uint32 `mi:"AccountingMalformedPackets"`
AccountingNoRecord uint32 AccountingNoRecord uint32 `mi:"AccountingNoRecord"`
AccountingPacketsReceived uint32 AccountingPacketsReceived uint32 `mi:"AccountingPacketsReceived"`
AccountingPacketsSent uint32 AccountingPacketsSent uint32 `mi:"AccountingPacketsSent"`
AccountingServerResetTime uint32 AccountingServerResetTime uint32 `mi:"AccountingServerResetTime"`
AccountingServerUpTime uint32 AccountingServerUpTime uint32 `mi:"AccountingServerUpTime"`
AccountingUnknownType uint32 AccountingUnknownType uint32 `mi:"AccountingUnknownType"`
} }
// CollectAccept sends the metric values for each metric // CollectAccept sends the metric values for each metric
// to the provided prometheus Metric channel. // to the provided prometheus Metric channel.
func (c *Collector) CollectAccept(ch chan<- prometheus.Metric) error { func (c *Collector) CollectAccept(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_IAS_NPSAuthenticationServer var dst []Win32_PerfRawData_IAS_NPSAuthenticationServer
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_IAS_NPSAuthenticationServer", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, c.miQueryAuthenticationServer); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
@ -386,8 +403,8 @@ func (c *Collector) CollectAccept(ch chan<- prometheus.Metric) error {
func (c *Collector) CollectAccounting(ch chan<- prometheus.Metric) error { func (c *Collector) CollectAccounting(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_IAS_NPSAccountingServer var dst []Win32_PerfRawData_IAS_NPSAccountingServer
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_IAS_NPSAccountingServer", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, c.miQueryAccountingServer); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(

View File

@ -16,10 +16,10 @@ import (
"github.com/prometheus-community/windows_exporter/internal/headers/netapi32" "github.com/prometheus-community/windows_exporter/internal/headers/netapi32"
"github.com/prometheus-community/windows_exporter/internal/headers/psapi" "github.com/prometheus-community/windows_exporter/internal/headers/psapi"
"github.com/prometheus-community/windows_exporter/internal/headers/sysinfoapi" "github.com/prometheus-community/windows_exporter/internal/headers/sysinfoapi"
"github.com/prometheus-community/windows_exporter/internal/mi"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"golang.org/x/sys/windows/registry" "golang.org/x/sys/windows/registry"
) )
@ -109,9 +109,11 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(logger *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
logger.Warn("The os collect holds a number of deprecated metrics and will be removed mid 2025. " + logger.Warn("The os collect holds a number of deprecated metrics and will be removed mid 2025. "+
"See https://github.com/prometheus-community/windows_exporter/pull/1596 for more information.") "See https://github.com/prometheus-community/windows_exporter/pull/1596 for more information.",
slog.String("collector", Name),
)
workstationInfo, err := netapi32.GetWorkstationInfo() workstationInfo, err := netapi32.GetWorkstationInfo()
if err != nil { if err != nil {

View File

@ -11,11 +11,11 @@ import (
"strings" "strings"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes" "github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "perfdata" const Name = "perfdata"
@ -92,7 +92,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(logger *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
logger.Warn("The perfdata collector is in an experimental state! The configuration may change in future. Please report any issues.") logger.Warn("The perfdata collector is in an experimental state! The configuration may change in future. Please report any issues.")
for i, object := range c.config.Objects { for i, object := range c.config.Objects {

View File

@ -9,11 +9,11 @@ import (
"strings" "strings"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes" "github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "physical_disk" const Name = "physical_disk"
@ -114,7 +114,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
c.requestsQueued = prometheus.NewDesc( c.requestsQueued = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "requests_queued"), prometheus.BuildFQName(types.Namespace, Name, "requests_queued"),
"The number of requests queued to the disk (PhysicalDisk.CurrentDiskQueueLength)", "The number of requests queued to the disk (PhysicalDisk.CurrentDiskQueueLength)",

View File

@ -10,9 +10,9 @@ import (
"strings" "strings"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "printer" const Name = "printer"
@ -39,8 +39,10 @@ var ConfigDefaults = Config{
} }
type Collector struct { type Collector struct {
config Config config Config
wmiClient *wmi.Client miSession *mi.Session
miQueryPrinterJobs mi.Query
miQueryPrinter mi.Query
printerStatus *prometheus.Desc printerStatus *prometheus.Desc
printerJobStatus *prometheus.Desc printerJobStatus *prometheus.Desc
@ -107,12 +109,25 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, miSession *mi.Session) error {
if wmiClient == nil || wmiClient.SWbemServicesClient == nil { if miSession == nil {
return errors.New("wmiClient or SWbemServicesClient is nil") return errors.New("miSession is nil")
} }
c.wmiClient = wmiClient miQuery, err := mi.NewQuery("SELECT Name, Default, PrinterStatus, JobCountSinceLastReset FROM win32_Printer")
if err != nil {
return fmt.Errorf("failed to create WMI query: %w", err)
}
c.miQueryPrinter = miQuery
miQuery, err = mi.NewQuery("SELECT Name, Status FROM win32_PrintJob")
if err != nil {
return fmt.Errorf("failed to create WMI query: %w", err)
}
c.miQueryPrinterJobs = miQuery
c.miSession = miSession
c.printerJobStatus = prometheus.NewDesc( c.printerJobStatus = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "job_status"), prometheus.BuildFQName(types.Namespace, Name, "job_status"),
@ -143,42 +158,35 @@ func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
} }
type wmiPrinter struct { type wmiPrinter struct {
Name string Name string `mi:"Name"`
Default bool Default bool `mi:"Default"`
PrinterStatus uint16 PrinterStatus uint16 `mi:"PrinterStatus"`
JobCountSinceLastReset uint32 JobCountSinceLastReset uint32 `mi:"JobCountSinceLastReset"`
} }
type wmiPrintJob struct { type wmiPrintJob struct {
Name string Name string `mi:"Name"`
Status string Status string `mi:"Status"`
} }
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error { func (c *Collector) Collect(_ *types.ScrapeContext, _ *slog.Logger, ch chan<- prometheus.Metric) error {
logger = logger.With(slog.String("collector", Name)) var errs []error
if err := c.collectPrinterStatus(ch); err != nil {
logger.Error("failed to collect printer status metrics",
slog.Any("err", err),
)
return err if err := c.collectPrinterStatus(ch); err != nil {
errs = append(errs, fmt.Errorf("failed to collect printer status metrics: %w", err))
} }
if err := c.collectPrinterJobStatus(ch); err != nil { if err := c.collectPrinterJobStatus(ch); err != nil {
logger.Error("failed to collect printer job status metrics", errs = append(errs, fmt.Errorf("failed to collect printer job status metrics: %w", err))
slog.Any("err", err),
)
return err
} }
return nil return errors.Join(errs...)
} }
func (c *Collector) collectPrinterStatus(ch chan<- prometheus.Metric) error { func (c *Collector) collectPrinterStatus(ch chan<- prometheus.Metric) error {
var printers []wmiPrinter var printers []wmiPrinter
if err := c.wmiClient.Query("SELECT * FROM win32_Printer", &printers); err != nil { if err := c.miSession.Query(&printers, mi.NamespaceRootCIMv2, c.miQueryPrinter); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
for _, printer := range printers { for _, printer := range printers {
@ -215,8 +223,8 @@ func (c *Collector) collectPrinterStatus(ch chan<- prometheus.Metric) error {
func (c *Collector) collectPrinterJobStatus(ch chan<- prometheus.Metric) error { func (c *Collector) collectPrinterJobStatus(ch chan<- prometheus.Metric) error {
var printJobs []wmiPrintJob var printJobs []wmiPrintJob
if err := c.wmiClient.Query("SELECT * FROM win32_PrintJob", &printJobs); err != nil { if err := c.miSession.Query(&printJobs, mi.NamespaceRootCIMv2, c.miQueryPrinterJobs); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
groupedPrintJobs := c.groupPrintJobs(printJobs) groupedPrintJobs := c.groupPrintJobs(printJobs)

View File

@ -12,13 +12,13 @@ import (
"unsafe" "unsafe"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
v2 "github.com/prometheus-community/windows_exporter/internal/perfdata/v2" v2 "github.com/prometheus-community/windows_exporter/internal/perfdata/v2"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils" "github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
@ -38,7 +38,9 @@ var ConfigDefaults = Config{
type Collector struct { type Collector struct {
config Config config Config
wmiClient *wmi.Client miSession *mi.Session
workerProcessMIQueryQuery mi.Query
perfDataCollector perfdata.Collector perfDataCollector perfdata.Collector
@ -139,14 +141,20 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(logger *slog.Logger, wmiClient *wmi.Client) error { func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error {
logger = logger.With(slog.String("collector", Name)) logger = logger.With(slog.String("collector", Name))
if wmiClient == nil || wmiClient.SWbemServicesClient == nil { if miSession == nil {
return errors.New("wmiClient or SWbemServicesClient is nil") return errors.New("miSession is nil")
} }
c.wmiClient = wmiClient miQuery, err := mi.NewQuery("SELECT AppPoolName, ProcessId FROM WorkerProcess")
if err != nil {
return fmt.Errorf("failed to create WMI query: %w", err)
}
c.workerProcessMIQueryQuery = miQuery
c.miSession = miSession
if utils.PDHEnabled() { if utils.PDHEnabled() {
counters := []string{ counters := []string{
@ -302,8 +310,8 @@ func (c *Collector) Build(logger *slog.Logger, wmiClient *wmi.Client) error {
} }
type WorkerProcess struct { type WorkerProcess struct {
AppPoolName string AppPoolName string `mi:"AppPoolName"`
ProcessId uint64 ProcessId uint64 `mi:"ProcessId"`
} }
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error { func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
@ -333,10 +341,8 @@ func (c *Collector) collect(ctx *types.ScrapeContext, logger *slog.Logger, ch ch
var workerProcesses []WorkerProcess var workerProcesses []WorkerProcess
if c.config.EnableWorkerProcess { if c.config.EnableWorkerProcess {
if err := c.wmiClient.Query("SELECT * FROM WorkerProcess", &workerProcesses, nil, "root\\WebAdministration"); err != nil { if err := c.miSession.Query(&workerProcesses, mi.NamespaceRootWebAdministration, c.workerProcessMIQueryQuery); err != nil {
logger.Debug("Could not query WebAdministration namespace for IIS worker processes", return fmt.Errorf("WMI query failed: %w", err)
slog.Any("err", err),
)
} }
} }
@ -540,10 +546,8 @@ func (c *Collector) collectPDH(logger *slog.Logger, ch chan<- prometheus.Metric)
var workerProcesses []WorkerProcess var workerProcesses []WorkerProcess
if c.config.EnableWorkerProcess { if c.config.EnableWorkerProcess {
if err := c.wmiClient.Query("SELECT * FROM WorkerProcess", &workerProcesses, nil, "root\\WebAdministration"); err != nil { if err := c.miSession.Query(&workerProcesses, mi.NamespaceRootWebAdministration, c.workerProcessMIQueryQuery); err != nil {
logger.Debug("Could not query WebAdministration namespace for IIS worker processes", return fmt.Errorf("WMI query failed: %w", err)
slog.Any("err", err),
)
} }
} }

View File

@ -7,11 +7,11 @@ import (
"strings" "strings"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils" "github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "remote_fx" const Name = "remote_fx"
@ -81,7 +81,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(*slog.Logger, *wmi.Client) error { func (c *Collector) Build(*slog.Logger, *mi.Session) error {
// net // net
c.baseTCPRTT = prometheus.NewDesc( c.baseTCPRTT = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "net_base_tcp_rtt_seconds"), prometheus.BuildFQName(types.Namespace, Name, "net_base_tcp_rtt_seconds"),

View File

@ -13,9 +13,9 @@ import (
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/go-ole/go-ole" "github.com/go-ole/go-ole"
"github.com/go-ole/go-ole/oleutil" "github.com/go-ole/go-ole/oleutil"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "scheduled_task" const Name = "scheduled_task"
@ -148,7 +148,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
initErrCh := make(chan error) initErrCh := make(chan error)
c.scheduledTasksReqCh = make(chan struct{}) c.scheduledTasksReqCh = make(chan struct{})
c.scheduledTasksCh = make(chan *scheduledTaskResults) c.scheduledTasksCh = make(chan *scheduledTaskResults)
@ -281,7 +281,7 @@ func (c *Collector) initializeScheduleService(initErrCh chan<- error) {
if err := ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED); err != nil { if err := ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED); err != nil {
var oleCode *ole.OleError var oleCode *ole.OleError
if errors.As(err, &oleCode) && oleCode.Code() != ole.S_OK && oleCode.Code() != wmi.S_FALSE { if errors.As(err, &oleCode) && oleCode.Code() != ole.S_OK && oleCode.Code() != 0x00000001 {
initErrCh <- err initErrCh <- err
return return

View File

@ -11,9 +11,9 @@ import (
"unsafe" "unsafe"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"golang.org/x/sys/windows/svc/mgr" "golang.org/x/sys/windows/svc/mgr"
) )
@ -106,7 +106,7 @@ func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
return []string{}, nil return []string{}, nil
} }
func (c *Collector) Build(logger *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
logger = logger.With(slog.String("collector", Name)) logger = logger.With(slog.String("collector", Name))
if c.config.ServiceInclude.String() == "^(?:.*)$" && c.config.ServiceExclude.String() == "^(?:)$" { if c.config.ServiceInclude.String() == "^(?:.*)$" && c.config.ServiceExclude.String() == "^(?:)$" {

View File

@ -7,10 +7,10 @@ import (
"strings" "strings"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "smb" const Name = "smb"
@ -56,7 +56,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
// desc creates a new prometheus description // desc creates a new prometheus description
desc := func(metricName string, description string, labels ...string) *prometheus.Desc { desc := func(metricName string, description string, labels ...string) *prometheus.Desc {
return prometheus.NewDesc( return prometheus.NewDesc(

View File

@ -7,11 +7,11 @@ import (
"strings" "strings"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes" "github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const ( const (
@ -79,7 +79,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
// desc creates a new prometheus description // desc creates a new prometheus description
desc := func(metricName string, description string, labels []string) *prometheus.Desc { desc := func(metricName string, description string, labels []string) *prometheus.Desc {
return prometheus.NewDesc( return prometheus.NewDesc(

View File

@ -8,10 +8,10 @@ import (
"regexp" "regexp"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "smtp" const Name = "smtp"
@ -141,10 +141,10 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(logger *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
logger = logger.With(slog.String("collector", Name)) logger.Info("smtp collector is in an experimental state! Metrics for this collector have not been tested.",
slog.String("collector", Name),
logger.Info("smtp collector is in an experimental state! Metrics for this collector have not been tested.") )
c.badMailedMessagesBadPickupFileTotal = prometheus.NewDesc( c.badMailedMessagesBadPickupFileTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "badmailed_messages_bad_pickup_file_total"), prometheus.BuildFQName(types.Namespace, Name, "badmailed_messages_bad_pickup_file_total"),

View File

@ -7,10 +7,10 @@ import (
"log/slog" "log/slog"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "system" const Name = "system"
@ -61,7 +61,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
c.contextSwitchesTotal = prometheus.NewDesc( c.contextSwitchesTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "context_switches_total"), prometheus.BuildFQName(types.Namespace, Name, "context_switches_total"),
"Total number of context switches (WMI source: PerfOS_System.ContextSwitchesPersec)", "Total number of context switches (WMI source: PerfOS_System.ContextSwitchesPersec)",

View File

@ -10,11 +10,11 @@ import (
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/headers/iphlpapi" "github.com/prometheus-community/windows_exporter/internal/headers/iphlpapi"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes" "github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
@ -100,7 +100,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
counters := []string{ counters := []string{
connectionFailures, connectionFailures,
connectionsActive, connectionsActive,

View File

@ -11,10 +11,11 @@ import (
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/headers/wtsapi32" "github.com/prometheus-community/windows_exporter/internal/headers/wtsapi32"
"github.com/prometheus-community/windows_exporter/internal/mi"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
@ -31,9 +32,9 @@ type Win32_ServerFeature struct {
ID uint32 ID uint32
} }
func isConnectionBrokerServer(logger *slog.Logger, wmiClient *wmi.Client) bool { func isConnectionBrokerServer(logger *slog.Logger, miSession *mi.Session) bool {
var dst []Win32_ServerFeature var dst []Win32_ServerFeature
if err := wmiClient.Query("SELECT * FROM Win32_ServerFeature", &dst); err != nil { if err := miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_ServerFeature"))); err != nil {
return false return false
} }
@ -112,10 +113,14 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(logger *slog.Logger, wmiClient *wmi.Client) error { func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error {
if miSession == nil {
return errors.New("miSession is nil")
}
logger = logger.With(slog.String("collector", Name)) logger = logger.With(slog.String("collector", Name))
c.connectionBrokerEnabled = isConnectionBrokerServer(logger, wmiClient) c.connectionBrokerEnabled = isConnectionBrokerServer(logger, miSession)
c.sessionInfo = prometheus.NewDesc( c.sessionInfo = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "session_info"), prometheus.BuildFQName(types.Namespace, Name, "session_info"),

View File

@ -29,11 +29,11 @@ import (
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/dimchansky/utfbom" "github.com/dimchansky/utfbom"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go" dto "github.com/prometheus/client_model/go"
"github.com/prometheus/common/expfmt" "github.com/prometheus/common/expfmt"
"github.com/yusufpapurcu/wmi"
) )
const Name = "textfile" const Name = "textfile"
@ -104,7 +104,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(logger *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
logger.Info("textfile Collector directories: "+strings.Join(c.config.TextFileDirectories, ","), logger.Info("textfile Collector directories: "+strings.Join(c.config.TextFileDirectories, ","),
slog.String("collector", Name), slog.String("collector", Name),
) )

View File

@ -4,12 +4,13 @@ package thermalzone
import ( import (
"errors" "errors"
"fmt"
"log/slog" "log/slog"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "thermalzone" const Name = "thermalzone"
@ -21,7 +22,8 @@ var ConfigDefaults = Config{}
// A Collector is a Prometheus Collector for WMI Win32_PerfRawData_Counters_ThermalZoneInformation metrics. // A Collector is a Prometheus Collector for WMI Win32_PerfRawData_Counters_ThermalZoneInformation metrics.
type Collector struct { type Collector struct {
config Config config Config
wmiClient *wmi.Client miSession *mi.Session
miQuery mi.Query
percentPassiveLimit *prometheus.Desc percentPassiveLimit *prometheus.Desc
temperature *prometheus.Desc temperature *prometheus.Desc
@ -56,12 +58,19 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, miSession *mi.Session) error {
if wmiClient == nil || wmiClient.SWbemServicesClient == nil { if miSession == nil {
return errors.New("wmiClient or SWbemServicesClient is nil") return errors.New("miSession is nil")
} }
c.wmiClient = wmiClient miQuery, err := mi.NewQuery("SELECT Name, HighPrecisionTemperature, PercentPassiveLimit, ThrottleReasons FROM Win32_PerfRawData_Counters_ThermalZoneInformation")
if err != nil {
return fmt.Errorf("failed to create WMI query: %w", err)
}
c.miQuery = miQuery
c.miSession = miSession
c.temperature = prometheus.NewDesc( c.temperature = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "temperature_celsius"), prometheus.BuildFQName(types.Namespace, Name, "temperature_celsius"),
"(Temperature)", "(Temperature)",
@ -108,22 +117,20 @@ func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan
// Win32_PerfRawData_Counters_ThermalZoneInformation docs: // Win32_PerfRawData_Counters_ThermalZoneInformation docs:
// https://wutils.com/wmi/root/cimv2/win32_perfrawdata_counters_thermalzoneinformation/ // https://wutils.com/wmi/root/cimv2/win32_perfrawdata_counters_thermalzoneinformation/
type Win32_PerfRawData_Counters_ThermalZoneInformation struct { type Win32_PerfRawData_Counters_ThermalZoneInformation struct {
Name string Name string `mi:"Name"`
HighPrecisionTemperature uint32 `mi:"HighPrecisionTemperature"`
HighPrecisionTemperature uint32 PercentPassiveLimit uint32 `mi:"PercentPassiveLimit"`
PercentPassiveLimit uint32 ThrottleReasons uint32 `mi:"ThrottleReasons"`
ThrottleReasons uint32
} }
func (c *Collector) collect(ch chan<- prometheus.Metric) error { func (c *Collector) collect(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_Counters_ThermalZoneInformation var dst []Win32_PerfRawData_Counters_ThermalZoneInformation
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_Counters_ThermalZoneInformation", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, c.miQuery); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
// ThermalZone collector has been known to 'successfully' return an empty result.
if len(dst) == 0 { if len(dst) == 0 {
return errors.New("empty results set for collector") return errors.New("WMI query returned empty result set")
} }
for _, info := range dst { for _, info := range dst {

View File

@ -9,10 +9,10 @@ import (
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/headers/kernel32" "github.com/prometheus-community/windows_exporter/internal/headers/kernel32"
"github.com/prometheus-community/windows_exporter/internal/mi"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
@ -64,7 +64,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
c.currentTime = prometheus.NewDesc( c.currentTime = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "current_timestamp_seconds"), prometheus.BuildFQName(types.Namespace, Name, "current_timestamp_seconds"),
"OperatingSystem.LocalDateTime", "OperatingSystem.LocalDateTime",

View File

@ -15,9 +15,9 @@ import (
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/go-ole/go-ole" "github.com/go-ole/go-ole"
"github.com/go-ole/go-ole/oleutil" "github.com/go-ole/go-ole/oleutil"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "update" const Name = "update"
@ -80,7 +80,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(logger *slog.Logger, _ *wmi.Client) error { func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
logger = logger.With(slog.String("collector", Name)) logger = logger.With(slog.String("collector", Name))
logger.Info("update collector is in an experimental state! The configuration and metrics may change in future. Please report any issues.") logger.Info("update collector is in an experimental state! The configuration and metrics may change in future. Please report any issues.")
@ -147,7 +147,7 @@ func (c *Collector) scheduleUpdateStatus(logger *slog.Logger, initErrCh chan<- e
if err := ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED); err != nil { if err := ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED); err != nil {
var oleCode *ole.OleError var oleCode *ole.OleError
if errors.As(err, &oleCode) && oleCode.Code() != ole.S_OK && oleCode.Code() != wmi.S_FALSE { if errors.As(err, &oleCode) && oleCode.Code() != ole.S_OK && oleCode.Code() != 0x00000001 {
initErrCh <- fmt.Errorf("CoInitializeEx: %w", err) initErrCh <- fmt.Errorf("CoInitializeEx: %w", err)
return return

View File

@ -4,13 +4,14 @@ package vmware
import ( import (
"errors" "errors"
"fmt"
"log/slog" "log/slog"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes" "github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
const Name = "vmware" const Name = "vmware"
@ -21,8 +22,10 @@ var ConfigDefaults = Config{}
// A Collector is a Prometheus Collector for WMI Win32_PerfRawData_vmGuestLib_VMem/Win32_PerfRawData_vmGuestLib_VCPU metrics. // A Collector is a Prometheus Collector for WMI Win32_PerfRawData_vmGuestLib_VMem/Win32_PerfRawData_vmGuestLib_VCPU metrics.
type Collector struct { type Collector struct {
config Config config Config
wmiClient *wmi.Client miSession *mi.Session
miQueryCPU mi.Query
miQueryMem mi.Query
memActive *prometheus.Desc memActive *prometheus.Desc
memBallooned *prometheus.Desc memBallooned *prometheus.Desc
@ -74,12 +77,25 @@ func (c *Collector) Close(_ *slog.Logger) error {
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error { func (c *Collector) Build(_ *slog.Logger, miSession *mi.Session) error {
if wmiClient == nil || wmiClient.SWbemServicesClient == nil { if miSession == nil {
return errors.New("wmiClient or SWbemServicesClient is nil") return errors.New("miSession is nil")
} }
c.wmiClient = wmiClient miQuery, err := mi.NewQuery("SELECT * FROM Win32_PerfRawData_vmGuestLib_VCPU")
if err != nil {
return fmt.Errorf("failed to create WMI query: %w", err)
}
c.miQueryCPU = miQuery
miQuery, err = mi.NewQuery("SELECT * FROM Win32_PerfRawData_vmGuestLib_VMem")
if err != nil {
return fmt.Errorf("failed to create WMI query: %w", err)
}
c.miQueryMem = miQuery
c.miSession = miSession
c.memActive = prometheus.NewDesc( c.memActive = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_active_bytes"), prometheus.BuildFQName(types.Namespace, Name, "mem_active_bytes"),
@ -224,34 +240,34 @@ func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan
} }
type Win32_PerfRawData_vmGuestLib_VMem struct { type Win32_PerfRawData_vmGuestLib_VMem struct {
MemActiveMB uint64 MemActiveMB uint64 `mi:"MemActiveMB"`
MemBalloonedMB uint64 MemBalloonedMB uint64 `mi:"MemBalloonedMB"`
MemLimitMB uint64 MemLimitMB uint64 `mi:"MemLimitMB"`
MemMappedMB uint64 MemMappedMB uint64 `mi:"MemMappedMB"`
MemOverheadMB uint64 MemOverheadMB uint64 `mi:"MemOverheadMB"`
MemReservationMB uint64 MemReservationMB uint64 `mi:"MemReservationMB"`
MemSharedMB uint64 MemSharedMB uint64 `mi:"MemSharedMB"`
MemSharedSavedMB uint64 MemSharedSavedMB uint64 `mi:"MemSharedSavedMB"`
MemShares uint64 MemShares uint64 `mi:"MemShares"`
MemSwappedMB uint64 MemSwappedMB uint64 `mi:"MemSwappedMB"`
MemTargetSizeMB uint64 MemTargetSizeMB uint64 `mi:"MemTargetSizeMB"`
MemUsedMB uint64 MemUsedMB uint64 `mi:"MemUsedMB"`
} }
type Win32_PerfRawData_vmGuestLib_VCPU struct { type Win32_PerfRawData_vmGuestLib_VCPU struct {
CpuLimitMHz uint64 CpuLimitMHz uint64 `mi:"CpuLimitMHz"`
CpuReservationMHz uint64 CpuReservationMHz uint64 `mi:"CpuReservationMHz"`
CpuShares uint64 CpuShares uint64 `mi:"CpuShares"`
CpuStolenMs uint64 CpuStolenMs uint64 `mi:"CpuStolenMs"`
CpuTimePercents uint64 CpuTimePercents uint64 `mi:"CpuTimePercents"`
EffectiveVMSpeedMHz uint64 EffectiveVMSpeedMHz uint64 `mi:"EffectiveVMSpeedMHz"`
HostProcessorSpeedMHz uint64 HostProcessorSpeedMHz uint64 `mi:"HostProcessorSpeedMHz"`
} }
func (c *Collector) collectMem(ch chan<- prometheus.Metric) error { func (c *Collector) collectMem(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_vmGuestLib_VMem var dst []Win32_PerfRawData_vmGuestLib_VMem
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_vmGuestLib_VMem", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, c.miQueryMem); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
if len(dst) == 0 { if len(dst) == 0 {
@ -333,14 +349,15 @@ func (c *Collector) collectMem(ch chan<- prometheus.Metric) error {
return nil return nil
} }
// mbToBytes moved to utils package
func mbToBytes(mb uint64) float64 { func mbToBytes(mb uint64) float64 {
return float64(mb * 1024 * 1024) return float64(mb * 1024 * 1024)
} }
func (c *Collector) collectCpu(ch chan<- prometheus.Metric) error { func (c *Collector) collectCpu(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_vmGuestLib_VCPU var dst []Win32_PerfRawData_vmGuestLib_VCPU
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_vmGuestLib_VCPU", &dst); err != nil { if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, c.miQueryCPU); err != nil {
return err return fmt.Errorf("WMI query failed: %w", err)
} }
if len(dst) == 0 { if len(dst) == 0 {

View File

@ -129,7 +129,7 @@ func (c *MetricsHTTPHandler) handlerFactory(logger *slog.Logger, scrapeTimeout t
metricCollectors = &collector.MetricCollectors{ metricCollectors = &collector.MetricCollectors{
Collectors: filteredCollectors, Collectors: filteredCollectors,
WMIClient: c.metricCollectors.WMIClient, MISession: c.metricCollectors.MISession,
PerfCounterQuery: c.metricCollectors.PerfCounterQuery, PerfCounterQuery: c.metricCollectors.PerfCounterQuery,
} }
} }

283
internal/mi/application.go Normal file
View File

@ -0,0 +1,283 @@
//go:build windows
package mi
import (
"errors"
"fmt"
"syscall"
"time"
"unsafe"
"golang.org/x/sys/windows"
)
const (
applicationID = "windows_exporter"
LocaleEnglish = "en-us"
)
var (
// DestinationOptionsTimeout is the key for the timeout option.
//
// https://github.com/microsoft/win32metadata/blob/527806d20d83d3abd43d16cd3fa8795d8deba343/generation/WinSDK/RecompiledIdlHeaders/um/mi.h#L7830
DestinationOptionsTimeout = UTF16PtrFromString[*uint16]("__MI_DESTINATIONOPTIONS_TIMEOUT")
// DestinationOptionsUILocale is the key for the UI locale option.
//
// https://github.com/microsoft/win32metadata/blob/527806d20d83d3abd43d16cd3fa8795d8deba343/generation/WinSDK/RecompiledIdlHeaders/um/mi.h#L8248
DestinationOptionsUILocale = UTF16PtrFromString[*uint16]("__MI_DESTINATIONOPTIONS_UI_LOCALE")
)
var (
modMi = windows.NewLazySystemDLL("mi.dll")
procMIApplicationInitialize = modMi.NewProc("MI_Application_InitializeV1")
)
// Application represents the MI application.
// https://learn.microsoft.com/de-de/windows/win32/api/mi/ns-mi-mi_application
type Application struct {
reserved1 uint64
reserved2 uintptr
ft *ApplicationFT
}
// ApplicationFT represents the function table of the MI application.
// https://learn.microsoft.com/de-de/windows/win32/api/mi/ns-mi-mi_applicationft
type ApplicationFT struct {
Close uintptr
NewSession uintptr
NewHostedProvider uintptr
NewInstance uintptr
NewDestinationOptions uintptr
NewOperationOptions uintptr
NewSubscriptionDeliveryOptions uintptr
NewSerializer uintptr
NewDeserializer uintptr
NewInstanceFromClass uintptr
NewClass uintptr
}
type DestinationOptions struct {
reserved1 uint64
reserved2 uintptr
ft *DestinationOptionsFT
}
type DestinationOptionsFT struct {
Delete uintptr
SetString uintptr
SetNumber uintptr
AddCredentials uintptr
GetString uintptr
GetNumber uintptr
GetOptionCount uintptr
GetOptionAt uintptr
GetOption uintptr
GetCredentialsCount uintptr
GetCredentialsAt uintptr
GetCredentialsPasswordAt uintptr
Clone uintptr
SetInterval uintptr
GetInterval uintptr
}
// Application_Initialize initializes the MI [Application].
// It is recommended to have only one Application per process.
//
// https://learn.microsoft.com/en-us/windows/win32/api/mi/nf-mi-mi_application_initializev1
func Application_Initialize() (*Application, error) {
application := &Application{}
applicationId, err := windows.UTF16PtrFromString(applicationID)
if err != nil {
return nil, err
}
r0, _, err := procMIApplicationInitialize.Call(
0,
uintptr(unsafe.Pointer(applicationId)),
0,
uintptr(unsafe.Pointer(application)),
)
if !errors.Is(err, windows.NOERROR) {
return nil, fmt.Errorf("syscall returned: %w", err)
}
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return nil, result
}
return application, nil
}
// Close deinitializes the management infrastructure client API that was initialized through a call to Application_Initialize.
//
// https://learn.microsoft.com/en-us/windows/win32/api/mi/nf-mi-mi_application_close
func (application *Application) Close() error {
if application == nil || application.ft == nil {
return ErrNotInitialized
}
r0, _, _ := syscall.SyscallN(application.ft.Close, uintptr(unsafe.Pointer(application)))
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return result
}
return nil
}
// NewSession creates a session used to share connections for a set of operations to a single destination.
//
// https://learn.microsoft.com/en-us/windows/win32/api/mi/nf-mi-mi_application_newsession
func (application *Application) NewSession(options *DestinationOptions) (*Session, error) {
if application == nil || application.ft == nil {
return nil, ErrNotInitialized
}
session := &Session{}
r0, _, _ := syscall.SyscallN(
application.ft.NewSession,
uintptr(unsafe.Pointer(application)),
0,
0,
uintptr(unsafe.Pointer(options)),
0,
0,
uintptr(unsafe.Pointer(session)),
)
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return nil, result
}
defaultOperationOptions, err := application.NewOperationOptions()
if err != nil {
return nil, fmt.Errorf("failed to create default operation options: %w", err)
}
if err = defaultOperationOptions.SetTimeout(5 * time.Second); err != nil {
return nil, fmt.Errorf("failed to set timeout: %w", err)
}
session.defaultOperationOptions = defaultOperationOptions
return session, nil
}
// NewOperationOptions creates an OperationOptions object that can be used with the operation functions on the Session object.
//
// https://learn.microsoft.com/en-us/windows/win32/api/mi/nf-mi-mi_application_newoperationoptions
func (application *Application) NewOperationOptions() (*OperationOptions, error) {
if application == nil || application.ft == nil {
return nil, ErrNotInitialized
}
operationOptions := &OperationOptions{}
mustUnderstand := True
r0, _, _ := syscall.SyscallN(
application.ft.NewOperationOptions,
uintptr(unsafe.Pointer(application)),
uintptr(mustUnderstand),
uintptr(unsafe.Pointer(operationOptions)),
)
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return nil, result
}
return operationOptions, nil
}
// NewDestinationOptions creates an DestinationOptions object that can be used with the Application.NewSession function.
//
// https://learn.microsoft.com/en-us/windows/win32/api/mi/nf-mi-mi_application_newdestinationoptions
func (application *Application) NewDestinationOptions() (*DestinationOptions, error) {
if application == nil || application.ft == nil {
return nil, ErrNotInitialized
}
operationOptions := &DestinationOptions{}
r0, _, _ := syscall.SyscallN(
application.ft.NewDestinationOptions,
uintptr(unsafe.Pointer(application)),
uintptr(unsafe.Pointer(operationOptions)),
)
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return nil, result
}
return operationOptions, nil
}
// SetTimeout sets the timeout for the destination options.
//
// https://learn.microsoft.com/en-us/windows/win32/api/mi/nf-mi-mi_destinationoptions_settimeout
func (do *DestinationOptions) SetTimeout(timeout time.Duration) error {
if do == nil || do.ft == nil {
return ErrNotInitialized
}
r0, _, _ := syscall.SyscallN(
do.ft.SetInterval,
uintptr(unsafe.Pointer(do)),
uintptr(unsafe.Pointer(DestinationOptionsTimeout)),
uintptr(unsafe.Pointer(NewInterval(timeout))),
0,
)
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return result
}
return nil
}
// SetLocale sets the locale for the destination options.
//
// https://learn.microsoft.com/en-us/windows/win32/api/mi/nf-mi-mi_destinationoptions_setuilocale
func (do *DestinationOptions) SetLocale(locale string) error {
if do == nil || do.ft == nil {
return ErrNotInitialized
}
localeUTF16, err := windows.UTF16PtrFromString(locale)
if err != nil {
return fmt.Errorf("failed to convert locale: %w", err)
}
r0, _, _ := syscall.SyscallN(
do.ft.SetString,
uintptr(unsafe.Pointer(do)),
uintptr(unsafe.Pointer(DestinationOptionsUILocale)),
uintptr(unsafe.Pointer(localeUTF16)),
0,
)
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return result
}
return nil
}
func (do *DestinationOptions) Delete() error {
r0, _, _ := syscall.SyscallN(
do.ft.Delete,
uintptr(unsafe.Pointer(do)),
)
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return result
}
return nil
}

154
internal/mi/callbacks.go Normal file
View File

@ -0,0 +1,154 @@
//go:build windows
package mi
import (
"errors"
"fmt"
"reflect"
"sync"
"unsafe"
"golang.org/x/sys/windows"
)
// We have to registry a global callback function, since the amount of callbacks is limited.
var operationUnmarshalCallbacksInstanceResult = sync.OnceValue[uintptr](func() uintptr {
return windows.NewCallback(func(
operation *Operation,
callbacks *OperationUnmarshalCallbacks,
instance *Instance,
moreResults Boolean,
instanceResult ResultError,
errorMessageUTF16 *uint16,
errorDetails *Instance,
_ uintptr,
) uintptr {
if moreResults == False {
defer operation.Close()
}
return callbacks.InstanceResult(operation, instance, moreResults, instanceResult, errorMessageUTF16, errorDetails)
})
})
type OperationUnmarshalCallbacks struct {
dst any
dv reflect.Value
errCh chan<- error
elemType reflect.Type
elemValue reflect.Value
}
func NewUnmarshalOperationsCallbacks(dst any, errCh chan<- error) (*OperationCallbacks[OperationUnmarshalCallbacks], error) {
dv := reflect.ValueOf(dst)
if dv.Kind() != reflect.Ptr || dv.IsNil() {
return nil, ErrInvalidEntityType
}
dv = dv.Elem()
elemType := dv.Type().Elem()
elemValue := reflect.ValueOf(reflect.New(elemType).Interface()).Elem()
if dv.Kind() != reflect.Slice || elemType.Kind() != reflect.Struct {
return nil, ErrInvalidEntityType
}
dv.Set(reflect.MakeSlice(dv.Type(), 0, 0))
return &OperationCallbacks[OperationUnmarshalCallbacks]{
CallbackContext: &OperationUnmarshalCallbacks{
errCh: errCh,
dst: dst,
dv: dv,
elemType: elemType,
elemValue: elemValue,
},
InstanceResult: operationUnmarshalCallbacksInstanceResult(),
}, nil
}
func (o *OperationUnmarshalCallbacks) InstanceResult(
_ *Operation,
instance *Instance,
moreResults Boolean,
instanceResult ResultError,
errorMessageUTF16 *uint16,
_ *Instance,
) uintptr {
defer func() {
if moreResults == False {
close(o.errCh)
}
}()
if !errors.Is(instanceResult, MI_RESULT_OK) {
o.errCh <- fmt.Errorf("%w: %s", instanceResult, windows.UTF16PtrToString(errorMessageUTF16))
return 0
}
if instance == nil {
return 0
}
counter, err := instance.GetElementCount()
if err != nil {
o.errCh <- fmt.Errorf("failed to get element count: %w", err)
return 0
}
if counter == 0 {
return 0
}
for i := range o.elemType.NumField() {
field := o.elemValue.Field(i)
// Check if the field has an `mi` tag
miTag := o.elemType.Field(i).Tag.Get("mi")
if miTag == "" {
continue
}
element, err := instance.GetElement(miTag)
if err != nil {
o.errCh <- fmt.Errorf("failed to get element: %w", err)
return 0
}
switch element.valueType {
case ValueTypeBOOLEAN:
field.SetBool(element.value == 1)
case ValueTypeUINT8, ValueTypeUINT16, ValueTypeUINT32, ValueTypeUINT64:
field.SetUint(uint64(element.value))
case ValueTypeSINT8, ValueTypeSINT16, ValueTypeSINT32, ValueTypeSINT64:
field.SetInt(int64(element.value))
case ValueTypeSTRING:
if element.value == 0 {
o.errCh <- fmt.Errorf("%s: invalid pointer: value is nil", miTag)
return 0
}
// Convert the UTF-16 string to a Go string
stringValue := windows.UTF16PtrToString((*uint16)(unsafe.Pointer(element.value)))
field.SetString(stringValue)
case ValueTypeREAL32, ValueTypeREAL64:
field.SetFloat(float64(element.value))
default:
o.errCh <- fmt.Errorf("unsupported value type: %d", element.valueType)
return 0
}
}
o.dv.Set(reflect.Append(o.dv, o.elemValue))
return 0
}

7
internal/mi/doc.go Normal file
View File

@ -0,0 +1,7 @@
//go:build windows
// mi is a package that provides a Go API for Windows Management Infrastructure (MI) functions.
// It requires Windows Management Framework 3.0 or later.
//
// https://learn.microsoft.com/de-de/previous-versions/windows/desktop/wmi_v2/why-use-mi-
package mi

10
internal/mi/errors.go Normal file
View File

@ -0,0 +1,10 @@
//go:build windows
package mi
import "errors"
var (
ErrNotInitialized = errors.New("not initialized")
ErrInvalidEntityType = errors.New("invalid entity type")
)

179
internal/mi/instance.go Normal file
View File

@ -0,0 +1,179 @@
//go:build windows
package mi
import (
"errors"
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
type Instance struct {
ft *InstanceFT
classDecl *ClassDecl
serverName *uint16
nameSpace *uint16
_ [4]uintptr
}
type InstanceFT struct {
Clone uintptr
Destruct uintptr
Delete uintptr
IsA uintptr
GetClassName uintptr
SetNameSpace uintptr
GetNameSpace uintptr
GetElementCount uintptr
AddElement uintptr
SetElement uintptr
SetElementAt uintptr
GetElement uintptr
GetElementAt uintptr
ClearElement uintptr
ClearElementAt uintptr
GetServerName uintptr
SetServerName uintptr
GetClass uintptr
}
type ClassDecl struct {
Flags uint32
Code uint32
Name *uint16
Mqualifiers uintptr
NumQualifiers uint32
Mproperties uintptr
NumProperties uint32
Size uint32
SuperClass *uint16
SuperClassDecl uintptr
Methods uintptr
NumMethods uint32
Schema uintptr
ProviderFT uintptr
OwningClass uintptr
}
func (instance *Instance) Delete() error {
if instance == nil || instance.ft == nil {
return ErrNotInitialized
}
r0, _, _ := syscall.SyscallN(instance.ft.Delete, uintptr(unsafe.Pointer(instance)))
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return result
}
return nil
}
func (instance *Instance) GetElement(elementName string) (*Element, error) {
if instance == nil || instance.ft == nil {
return nil, ErrNotInitialized
}
elementNameUTF16, err := windows.UTF16PtrFromString(elementName)
if err != nil {
return nil, fmt.Errorf("failed to convert element name %s to UTF-16: %w", elementName, err)
}
var (
value uintptr
valueType ValueType
)
r0, _, _ := syscall.SyscallN(
instance.ft.GetElement,
uintptr(unsafe.Pointer(instance)),
uintptr(unsafe.Pointer(elementNameUTF16)),
uintptr(unsafe.Pointer(&value)),
uintptr(unsafe.Pointer(&valueType)),
0,
0,
)
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return nil, result
}
return &Element{
value: value,
valueType: valueType,
}, nil
}
func (instance *Instance) GetElementCount() (uint32, error) {
if instance == nil || instance.ft == nil {
return 0, ErrNotInitialized
}
var count uint32
r0, _, _ := syscall.SyscallN(
instance.ft.GetElementCount,
uintptr(unsafe.Pointer(instance)),
uintptr(unsafe.Pointer(&count)),
)
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return 0, result
}
return count, nil
}
func (instance *Instance) GetClassName() (string, error) {
if instance == nil || instance.ft == nil {
return "", ErrNotInitialized
}
var classNameUTF16 *uint16
r0, _, _ := syscall.SyscallN(
instance.ft.GetClassName,
uintptr(unsafe.Pointer(instance)),
uintptr(unsafe.Pointer(&classNameUTF16)),
)
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return "", result
}
if classNameUTF16 == nil {
return "", errors.New("class name is nil")
}
return windows.UTF16PtrToString(classNameUTF16), nil
}
func Instance_Print(instance *Instance) (string, error) {
elementMap := map[string]any{}
properties := instance.classDecl.Properties()
count, err := instance.GetElementCount()
if err != nil {
return "", err
}
if count == 0 {
return "", nil
}
for _, property := range properties {
name := windows.UTF16PtrToString(property.Name)
element, _ := instance.GetElement(name)
value, _ := element.GetValue()
elementMap[windows.UTF16PtrToString(property.Name)] = value
}
return fmt.Sprintf("%v", elementMap), nil
}

View File

@ -0,0 +1,43 @@
//go:build windows
package mi_test
import (
"testing"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/stretchr/testify/require"
)
func Benchmark_MI_Query_Unmarshal(b *testing.B) {
application, err := mi.Application_Initialize()
require.NoError(b, err)
require.NotEmpty(b, application)
session, err := application.NewSession(nil)
require.NoError(b, err)
require.NotEmpty(b, session)
b.ResetTimer()
var processes []win32Process
query, err := mi.NewQuery("SELECT Name FROM Win32_Process WHERE Handle = 0 OR Handle = 4")
require.NoError(b, err)
for i := 0; i < b.N; i++ {
err := session.QueryUnmarshal(&processes, mi.OperationFlagsStandardRTTI, nil, mi.NamespaceRootCIMv2, mi.QueryDialectWQL, query)
require.NoError(b, err)
require.Equal(b, []win32Process{{Name: "System Idle Process"}, {Name: "System"}}, processes)
}
b.StopTimer()
err = session.Close()
require.NoError(b, err)
err = application.Close()
require.NoError(b, err)
b.ReportAllocs()
}

294
internal/mi/mi_test.go Normal file
View File

@ -0,0 +1,294 @@
//go:build windows
package mi_test
import (
"testing"
"time"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/testutils"
"github.com/stretchr/testify/require"
"golang.org/x/sys/windows"
)
type win32Process struct {
Name string `mi:"Name"`
}
type wmiPrinter struct {
Name string `mi:"Name"`
Default bool `mi:"Default"`
PrinterStatus uint16 `mi:"PrinterStatus"`
JobCountSinceLastReset uint32 `mi:"JobCountSinceLastReset"`
}
type wmiPrintJob struct {
Name string `mi:"Name"`
Status string `mi:"Status"`
}
func Test_MI_Application_Initialize(t *testing.T) {
application, err := mi.Application_Initialize()
require.NoError(t, err)
require.NotEmpty(t, application)
err = application.Close()
require.NoError(t, err)
}
func Test_MI_Application_TestConnection(t *testing.T) {
application, err := mi.Application_Initialize()
require.NoError(t, err)
require.NotEmpty(t, application)
destinationOptions, err := application.NewDestinationOptions()
require.NoError(t, err)
require.NotEmpty(t, destinationOptions)
err = destinationOptions.SetTimeout(1 * time.Second)
require.NoError(t, err)
err = destinationOptions.SetLocale(mi.LocaleEnglish)
require.NoError(t, err)
session, err := application.NewSession(destinationOptions)
require.NoError(t, err)
require.NotEmpty(t, session)
err = session.TestConnection()
require.NoError(t, err)
require.NotEmpty(t, session)
err = session.Close()
require.NoError(t, err)
err = application.Close()
require.NoError(t, err)
}
func Test_MI_Query(t *testing.T) {
application, err := mi.Application_Initialize()
require.NoError(t, err)
require.NotEmpty(t, application)
destinationOptions, err := application.NewDestinationOptions()
require.NoError(t, err)
require.NotEmpty(t, destinationOptions)
err = destinationOptions.SetTimeout(1 * time.Second)
require.NoError(t, err)
err = destinationOptions.SetLocale(mi.LocaleEnglish)
require.NoError(t, err)
session, err := application.NewSession(destinationOptions)
require.NoError(t, err)
require.NotEmpty(t, session)
operation, err := session.QueryInstances(mi.OperationFlagsStandardRTTI, nil, mi.NamespaceRootCIMv2, mi.QueryDialectWQL, "select Name from win32_process where handle = 0")
require.NoError(t, err)
require.NotEmpty(t, operation)
instance, moreResults, err := operation.GetInstance()
require.NoError(t, err)
require.NotEmpty(t, instance)
count, err := instance.GetElementCount()
require.NoError(t, err)
require.NotZero(t, count)
element, err := instance.GetElement("Name")
require.NoError(t, err)
require.NotEmpty(t, element)
value, err := element.GetValue()
require.NoError(t, err)
require.Equal(t, "System Idle Process", value)
require.NotEmpty(t, value)
require.False(t, moreResults)
err = operation.Close()
require.NoError(t, err)
err = session.Close()
require.NoError(t, err)
err = application.Close()
require.NoError(t, err)
}
func Test_MI_QueryUnmarshal(t *testing.T) {
application, err := mi.Application_Initialize()
require.NoError(t, err)
require.NotEmpty(t, application)
destinationOptions, err := application.NewDestinationOptions()
require.NoError(t, err)
require.NotEmpty(t, destinationOptions)
err = destinationOptions.SetTimeout(1 * time.Second)
require.NoError(t, err)
err = destinationOptions.SetLocale(mi.LocaleEnglish)
require.NoError(t, err)
session, err := application.NewSession(destinationOptions)
require.NoError(t, err)
require.NotEmpty(t, session)
var processes []win32Process
queryProcess, err := mi.NewQuery("select Name from win32_process where handle = 0")
require.NoError(t, err)
err = session.QueryUnmarshal(&processes, mi.OperationFlagsStandardRTTI, nil, mi.NamespaceRootCIMv2, mi.QueryDialectWQL, queryProcess)
require.NoError(t, err)
require.Equal(t, []win32Process{{Name: "System Idle Process"}}, processes)
err = session.Close()
require.NoError(t, err)
err = application.Close()
require.NoError(t, err)
}
func Test_MI_EmptyQuery(t *testing.T) {
application, err := mi.Application_Initialize()
require.NoError(t, err)
require.NotEmpty(t, application)
destinationOptions, err := application.NewDestinationOptions()
require.NoError(t, err)
require.NotEmpty(t, destinationOptions)
err = destinationOptions.SetTimeout(1 * time.Second)
require.NoError(t, err)
err = destinationOptions.SetLocale(mi.LocaleEnglish)
require.NoError(t, err)
session, err := application.NewSession(destinationOptions)
require.NoError(t, err)
require.NotEmpty(t, session)
operation, err := session.QueryInstances(mi.OperationFlagsStandardRTTI, nil, mi.NamespaceRootCIMv2, mi.QueryDialectWQL, "SELECT Name, Status FROM win32_PrintJob")
require.NoError(t, err)
require.NotEmpty(t, operation)
instance, moreResults, err := operation.GetInstance()
require.NoError(t, err)
require.Empty(t, instance)
require.False(t, moreResults)
err = operation.Close()
require.NoError(t, err)
err = session.Close()
require.NoError(t, err)
err = application.Close()
require.NoError(t, err)
}
func Test_MI_Query_Unmarshal(t *testing.T) {
application, err := mi.Application_Initialize()
require.NoError(t, err)
require.NotEmpty(t, application)
destinationOptions, err := application.NewDestinationOptions()
require.NoError(t, err)
require.NotEmpty(t, destinationOptions)
err = destinationOptions.SetTimeout(1 * time.Second)
require.NoError(t, err)
err = destinationOptions.SetLocale(mi.LocaleEnglish)
require.NoError(t, err)
session, err := application.NewSession(destinationOptions)
require.NoError(t, err)
require.NotEmpty(t, session)
operation, err := session.QueryInstances(mi.OperationFlagsStandardRTTI, nil, mi.NamespaceRootCIMv2, mi.QueryDialectWQL, "SELECT Name FROM Win32_Process WHERE Handle = 0 OR Handle = 4")
require.NoError(t, err)
require.NotEmpty(t, operation)
var processes []win32Process
err = operation.Unmarshal(&processes)
require.NoError(t, err)
require.Equal(t, []win32Process{{Name: "System Idle Process"}, {Name: "System"}}, processes)
err = operation.Close()
require.NoError(t, err)
err = session.Close()
require.NoError(t, err)
err = application.Close()
require.NoError(t, err)
}
func Test_MI_FD_Leak(t *testing.T) {
t.Skip("This test is disabled because it is not deterministic and may fail on some systems.")
application, err := mi.Application_Initialize()
require.NoError(t, err)
require.NotEmpty(t, application)
session, err := application.NewSession(nil)
require.NoError(t, err)
require.NotEmpty(t, session)
currentFileHandle, err := testutils.GetProcessHandleCount(windows.CurrentProcess())
require.NoError(t, err)
t.Log("Current File Handle Count: ", currentFileHandle)
queryPrinter, err := mi.NewQuery("SELECT Name, Default, PrinterStatus, JobCountSinceLastReset FROM win32_Printer")
require.NoError(t, err)
queryPrinterJob, err := mi.NewQuery("SELECT Name, Status FROM win32_PrintJob")
require.NoError(t, err)
for range 1000 {
var wmiPrinters []wmiPrinter
err := session.Query(&wmiPrinters, mi.NamespaceRootCIMv2, queryPrinter)
require.NoError(t, err)
var wmiPrintJobs []wmiPrintJob
err = session.Query(&wmiPrintJobs, mi.NamespaceRootCIMv2, queryPrinterJob)
require.NoError(t, err)
currentFileHandle, err = testutils.GetProcessHandleCount(windows.CurrentProcess())
require.NoError(t, err)
t.Log("Current File Handle Count: ", currentFileHandle)
}
currentFileHandle, err = testutils.GetProcessHandleCount(windows.CurrentProcess())
require.NoError(t, err)
t.Log("Current File Handle Count: ", currentFileHandle)
err = session.Close()
require.NoError(t, err)
currentFileHandle, err = testutils.GetProcessHandleCount(windows.CurrentProcess())
require.NoError(t, err)
t.Log("Current File Handle Count: ", currentFileHandle)
err = application.Close()
require.NoError(t, err)
currentFileHandle, err = testutils.GetProcessHandleCount(windows.CurrentProcess())
require.NoError(t, err)
t.Log("Current File Handle Count: ", currentFileHandle)
}

272
internal/mi/operation.go Normal file
View File

@ -0,0 +1,272 @@
//go:build windows
package mi
import (
"errors"
"fmt"
"reflect"
"syscall"
"time"
"unsafe"
"golang.org/x/sys/windows"
)
// OperationOptionsTimeout is the key for the timeout option.
//
// https://github.com/microsoft/win32metadata/blob/527806d20d83d3abd43d16cd3fa8795d8deba343/generation/WinSDK/RecompiledIdlHeaders/um/mi.h#L9240
var OperationOptionsTimeout = UTF16PtrFromString[*uint16]("__MI_OPERATIONOPTIONS_TIMEOUT")
// OperationFlags represents the flags for an operation.
//
// https://learn.microsoft.com/en-us/previous-versions/windows/desktop/wmi_v2/mi-flags
type OperationFlags uint32
const (
OperationFlagsDefaultRTTI OperationFlags = 0x0000
OperationFlagsBasicRTTI OperationFlags = 0x0002
OperationFlagsNoRTTI OperationFlags = 0x0400
OperationFlagsStandardRTTI OperationFlags = 0x0800
OperationFlagsFullRTTI OperationFlags = 0x0004
)
// Operation represents an operation.
// https://learn.microsoft.com/en-us/windows/win32/api/mi/ns-mi-mi_operation
type Operation struct {
reserved1 uint64
reserved2 uintptr
ft *OperationFT
}
// OperationFT represents the function table for Operation.
// https://learn.microsoft.com/en-us/windows/win32/api/mi/ns-mi-mi_operationft
type OperationFT struct {
Close uintptr
Cancel uintptr
GetSession uintptr
GetInstance uintptr
GetIndication uintptr
GetClass uintptr
}
type OperationOptions struct {
reserved1 uint64
reserved2 uintptr
ft *OperationOptionsFT
}
type OperationOptionsFT struct {
Delete uintptr
SetString uintptr
SetNumber uintptr
SetCustomOption uintptr
GetString uintptr
GetNumber uintptr
GetOptionCount uintptr
GetOptionAt uintptr
GetOption uintptr
GetEnabledChannels uintptr
Clone uintptr
SetInterval uintptr
GetInterval uintptr
}
type OperationCallbacks[T any] struct {
CallbackContext *T
PromptUser uintptr
WriteError uintptr
WriteMessage uintptr
WriteProgress uintptr
InstanceResult uintptr
IndicationResult uintptr
ClassResult uintptr
StreamedParameterResult uintptr
}
// Close closes an operation handle.
//
// https://learn.microsoft.com/en-us/windows/win32/api/mi/nf-mi-mi_operation_close
func (o *Operation) Close() error {
if o == nil || o.ft == nil {
return ErrNotInitialized
}
r0, _, _ := syscall.SyscallN(o.ft.Close, uintptr(unsafe.Pointer(o)))
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return result
}
return nil
}
func (o *Operation) Cancel() error {
if o == nil || o.ft == nil {
return ErrNotInitialized
}
r0, _, _ := syscall.SyscallN(o.ft.Close, uintptr(unsafe.Pointer(o)), 0)
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return result
}
return nil
}
func (o *Operation) GetInstance() (*Instance, bool, error) {
if o == nil || o.ft == nil {
return nil, false, ErrNotInitialized
}
var (
instance *Instance
errorDetails *Instance
moreResults Boolean
instanceResult ResultError
errorMessageUTF16 *uint16
)
r0, _, _ := syscall.SyscallN(
o.ft.GetInstance,
uintptr(unsafe.Pointer(o)),
uintptr(unsafe.Pointer(&instance)),
uintptr(unsafe.Pointer(&moreResults)),
uintptr(unsafe.Pointer(&instanceResult)),
uintptr(unsafe.Pointer(&errorMessageUTF16)),
uintptr(unsafe.Pointer(&errorDetails)),
)
if !errors.Is(instanceResult, MI_RESULT_OK) {
return nil, false, fmt.Errorf("instance result: %w (%s)", instanceResult, windows.UTF16PtrToString(errorMessageUTF16))
}
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return nil, false, result
}
return instance, moreResults == True, nil
}
func (o *Operation) Unmarshal(dst any) error {
if o == nil || o.ft == nil {
return ErrNotInitialized
}
dv := reflect.ValueOf(dst)
if dv.Kind() != reflect.Ptr || dv.IsNil() {
return ErrInvalidEntityType
}
dv = dv.Elem()
elemType := dv.Type().Elem()
elemValue := reflect.ValueOf(reflect.New(elemType).Interface()).Elem()
if dv.Kind() != reflect.Slice || elemType.Kind() != reflect.Struct {
return ErrInvalidEntityType
}
dv.Set(reflect.MakeSlice(dv.Type(), 0, 0))
for {
instance, moreResults, err := o.GetInstance()
if err != nil {
return fmt.Errorf("failed to get instance: %w", err)
}
// If WMI returns nil, it means there are no more results.
if instance == nil {
break
}
counter, err := instance.GetElementCount()
if err != nil {
return fmt.Errorf("failed to get element count: %w", err)
}
if counter == 0 {
break
}
for i := range elemType.NumField() {
field := elemValue.Field(i)
// Check if the field has an `mi` tag
miTag := elemType.Field(i).Tag.Get("mi")
if miTag == "" {
continue
}
element, err := instance.GetElement(miTag)
if err != nil {
return fmt.Errorf("failed to get element: %w", err)
}
switch element.valueType {
case ValueTypeBOOLEAN:
field.SetBool(element.value == 1)
case ValueTypeUINT8, ValueTypeUINT16, ValueTypeUINT32, ValueTypeUINT64:
field.SetUint(uint64(element.value))
case ValueTypeSINT8, ValueTypeSINT16, ValueTypeSINT32, ValueTypeSINT64:
field.SetInt(int64(element.value))
case ValueTypeSTRING:
if element.value == 0 {
return fmt.Errorf("%s: invalid pointer: value is nil", miTag)
}
// Convert the UTF-16 string to a Go string
stringValue := windows.UTF16PtrToString((*uint16)(unsafe.Pointer(element.value)))
field.SetString(stringValue)
case ValueTypeREAL32, ValueTypeREAL64:
field.SetFloat(float64(element.value))
default:
return fmt.Errorf("unsupported value type: %d", element.valueType)
}
}
dv.Set(reflect.Append(dv, elemValue))
if !moreResults {
break
}
}
return nil
}
func (o *OperationOptions) SetTimeout(timeout time.Duration) error {
if o == nil || o.ft == nil {
return ErrNotInitialized
}
r0, _, _ := syscall.SyscallN(
o.ft.SetInterval,
uintptr(unsafe.Pointer(o)),
uintptr(unsafe.Pointer(OperationOptionsTimeout)),
uintptr(unsafe.Pointer(NewInterval(timeout))),
0,
)
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return result
}
return nil
}
func (o *OperationOptions) Delete() error {
if o == nil || o.ft == nil {
return ErrNotInitialized
}
r0, _, _ := syscall.SyscallN(o.ft.Delete, uintptr(unsafe.Pointer(o)))
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return result
}
return nil
}

102
internal/mi/result.go Normal file
View File

@ -0,0 +1,102 @@
//go:build windows
package mi
import "errors"
type ResultError uint32
const (
MI_RESULT_OK ResultError = iota
MI_RESULT_FAILED
MI_RESULT_ACCESS_DENIED
MI_RESULT_INVALID_NAMESPACE
MI_RESULT_INVALID_PARAMETER
MI_RESULT_INVALID_CLASS
MI_RESULT_NOT_FOUND
MI_RESULT_NOT_SUPPORTED
MI_RESULT_CLASS_HAS_CHILDREN
MI_RESULT_CLASS_HAS_INSTANCES
MI_RESULT_INVALID_SUPERCLASS
MI_RESULT_ALREADY_EXISTS
MI_RESULT_NO_SUCH_PROPERTY
MI_RESULT_TYPE_MISMATCH
MI_RESULT_QUERY_LANGUAGE_NOT_SUPPORTED
MI_RESULT_INVALID_QUERY
MI_RESULT_METHOD_NOT_AVAILABLE
MI_RESULT_METHOD_NOT_FOUND
MI_RESULT_NAMESPACE_NOT_EMPTY
MI_RESULT_INVALID_ENUMERATION_CONTEXT
MI_RESULT_INVALID_OPERATION_TIMEOUT
MI_RESULT_PULL_HAS_BEEN_ABANDONED
MI_RESULT_PULL_CANNOT_BE_ABANDONED
MI_RESULT_FILTERED_ENUMERATION_NOT_SUPPORTED
MI_RESULT_CONTINUATION_ON_ERROR_NOT_SUPPORTED
MI_RESULT_SERVER_LIMITS_EXCEEDED
MI_RESULT_SERVER_IS_SHUTTING_DOWN
)
func (r ResultError) Error() string {
return r.String()
}
func (r ResultError) String() string {
switch {
case errors.Is(r, MI_RESULT_OK):
return "MI_RESULT_OK"
case errors.Is(r, MI_RESULT_FAILED):
return "MI_RESULT_FAILED"
case errors.Is(r, MI_RESULT_ACCESS_DENIED):
return "MI_RESULT_ACCESS_DENIED"
case errors.Is(r, MI_RESULT_INVALID_NAMESPACE):
return "MI_RESULT_INVALID_NAMESPACE"
case errors.Is(r, MI_RESULT_INVALID_PARAMETER):
return "MI_RESULT_INVALID_PARAMETER"
case errors.Is(r, MI_RESULT_INVALID_CLASS):
return "MI_RESULT_INVALID_CLASS"
case errors.Is(r, MI_RESULT_NOT_FOUND):
return "MI_RESULT_NOT_FOUND"
case errors.Is(r, MI_RESULT_NOT_SUPPORTED):
return "MI_RESULT_NOT_SUPPORTED"
case errors.Is(r, MI_RESULT_CLASS_HAS_CHILDREN):
return "MI_RESULT_CLASS_HAS_CHILDREN"
case errors.Is(r, MI_RESULT_CLASS_HAS_INSTANCES):
return "MI_RESULT_CLASS_HAS_INSTANCES"
case errors.Is(r, MI_RESULT_INVALID_SUPERCLASS):
return "MI_RESULT_INVALID_SUPERCLASS"
case errors.Is(r, MI_RESULT_ALREADY_EXISTS):
return "MI_RESULT_ALREADY_EXISTS"
case errors.Is(r, MI_RESULT_NO_SUCH_PROPERTY):
return "MI_RESULT_NO_SUCH_PROPERTY"
case errors.Is(r, MI_RESULT_TYPE_MISMATCH):
return "MI_RESULT_TYPE_MISMATCH"
case errors.Is(r, MI_RESULT_QUERY_LANGUAGE_NOT_SUPPORTED):
return "MI_RESULT_QUERY_LANGUAGE_NOT_SUPPORTED"
case errors.Is(r, MI_RESULT_INVALID_QUERY):
return "MI_RESULT_INVALID_QUERY"
case errors.Is(r, MI_RESULT_METHOD_NOT_AVAILABLE):
return "MI_RESULT_METHOD_NOT_AVAILABLE"
case errors.Is(r, MI_RESULT_METHOD_NOT_FOUND):
return "MI_RESULT_METHOD_NOT_FOUND"
case errors.Is(r, MI_RESULT_NAMESPACE_NOT_EMPTY):
return "MI_RESULT_NAMESPACE_NOT_EMPTY"
case errors.Is(r, MI_RESULT_INVALID_ENUMERATION_CONTEXT):
return "MI_RESULT_INVALID_ENUMERATION_CONTEXT"
case errors.Is(r, MI_RESULT_INVALID_OPERATION_TIMEOUT):
return "MI_RESULT_INVALID_OPERATION_TIMEOUT"
case errors.Is(r, MI_RESULT_PULL_HAS_BEEN_ABANDONED):
return "MI_RESULT_PULL_HAS_BEEN_ABANDONED"
case errors.Is(r, MI_RESULT_PULL_CANNOT_BE_ABANDONED):
return "MI_RESULT_PULL_CANNOT_BE_ABANDONED"
case errors.Is(r, MI_RESULT_FILTERED_ENUMERATION_NOT_SUPPORTED):
return "MI_RESULT_FILTERED_ENUMERATION_NOT_SUPPORTED"
case errors.Is(r, MI_RESULT_CONTINUATION_ON_ERROR_NOT_SUPPORTED):
return "MI_RESULT_CONTINUATION_ON_ERROR_NOT_SUPPORTED"
case errors.Is(r, MI_RESULT_SERVER_LIMITS_EXCEEDED):
return "MI_RESULT_SERVER_LIMITS_EXCEEDED"
case errors.Is(r, MI_RESULT_SERVER_IS_SHUTTING_DOWN):
return "MI_RESULT_SERVER_IS_SHUTTING_DOWN"
default:
return "MI_RESULT_UNKNOWN"
}
}

235
internal/mi/session.go Normal file
View File

@ -0,0 +1,235 @@
//go:build windows
package mi
import (
"errors"
"fmt"
"runtime"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
// Session represents a session.
//
// https://learn.microsoft.com/en-us/windows/win32/api/mi/ns-mi-mi_session
type Session struct {
reserved1 uint64
reserved2 uintptr
ft *SessionFT
defaultOperationOptions *OperationOptions
}
// SessionFT represents the function table for Session.
//
// https://learn.microsoft.com/en-us/windows/win32/api/mi/ns-mi-mi_session
type SessionFT struct {
Close uintptr
GetApplication uintptr
GetInstance uintptr
ModifyInstance uintptr
CreateInstance uintptr
DeleteInstance uintptr
Invoke uintptr
EnumerateInstances uintptr
QueryInstances uintptr
AssociatorInstances uintptr
ReferenceInstances uintptr
Subscribe uintptr
GetClass uintptr
EnumerateClasses uintptr
TestConnection uintptr
}
// Close closes a session and releases all associated memory.
//
// https://learn.microsoft.com/en-us/windows/win32/api/mi/nf-mi-mi_session_close
func (s *Session) Close() error {
if s == nil || s.ft == nil {
return ErrNotInitialized
}
if s.defaultOperationOptions != nil {
_ = s.defaultOperationOptions.Delete()
}
r0, _, _ := syscall.SyscallN(s.ft.Close,
uintptr(unsafe.Pointer(s)),
0,
0,
)
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return result
}
return nil
}
// TestConnection queries instances. It is used to test the connection.
// The function returns an operation that can be used to retrieve the result with [Operation.GetInstance]. The operation must be closed with [Operation.Close].
// The instance returned by [Operation.GetInstance] is always nil.
//
// https://learn.microsoft.com/en-us/windows/win32/api/mi/nf-mi-mi_session_testconnection
func (s *Session) TestConnection() error {
if s == nil || s.ft == nil {
return ErrNotInitialized
}
operation := &Operation{}
// ref: https://github.com/KurtDeGreeff/omi/blob/9caa55032a1070a665e14fd282a091f6247d13c3/Unix/scriptext/py/PMI_Session.c#L92-L105
r0, _, _ := syscall.SyscallN(
s.ft.TestConnection,
uintptr(unsafe.Pointer(s)),
0,
0,
uintptr(unsafe.Pointer(operation)),
)
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return result
}
var err error
if _, _, err = operation.GetInstance(); err != nil {
return fmt.Errorf("failed to get instance: %w", err)
}
if err = operation.Close(); err != nil {
return fmt.Errorf("failed to close operation: %w", err)
}
return nil
}
// GetApplication gets the Application handle that was used to create the specified session.
//
// https://learn.microsoft.com/en-us/windows/win32/api/mi/nf-mi-mi_session_getapplication
func (s *Session) GetApplication() (*Application, error) {
if s == nil || s.ft == nil {
return nil, ErrNotInitialized
}
application := &Application{}
r0, _, _ := syscall.SyscallN(
s.ft.GetApplication,
uintptr(unsafe.Pointer(s)),
uintptr(unsafe.Pointer(application)),
)
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return nil, result
}
return application, nil
}
// QueryInstances queries for a set of instances based on a query expression.
//
// https://learn.microsoft.com/en-us/windows/win32/api/mi/nf-mi-mi_session_queryinstances
func (s *Session) QueryInstances(flags OperationFlags, operationOptions *OperationOptions, namespaceName Namespace,
queryDialect QueryDialect, queryExpression string,
) (*Operation, error) {
if s == nil || s.ft == nil {
return nil, ErrNotInitialized
}
queryExpressionUTF16, err := windows.UTF16PtrFromString(queryExpression)
if err != nil {
return nil, err
}
operation := &Operation{}
if operationOptions == nil {
operationOptions = s.defaultOperationOptions
}
r0, _, _ := syscall.SyscallN(
s.ft.QueryInstances,
uintptr(unsafe.Pointer(s)),
uintptr(flags),
uintptr(unsafe.Pointer(operationOptions)),
uintptr(unsafe.Pointer(namespaceName)),
uintptr(unsafe.Pointer(queryDialect)),
uintptr(unsafe.Pointer(queryExpressionUTF16)),
0,
uintptr(unsafe.Pointer(operation)),
)
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return nil, result
}
return operation, nil
}
// QueryUnmarshal queries for a set of instances based on a query expression.
//
// https://learn.microsoft.com/en-us/windows/win32/api/mi/nf-mi-mi_session_queryinstances
func (s *Session) QueryUnmarshal(dst any,
flags OperationFlags, operationOptions *OperationOptions,
namespaceName Namespace, queryDialect QueryDialect, queryExpression Query,
) error {
if s == nil || s.ft == nil {
return ErrNotInitialized
}
operation := &Operation{}
if operationOptions == nil {
operationOptions = s.defaultOperationOptions
}
errCh := make(chan error, 1)
operationCallbacks, err := NewUnmarshalOperationsCallbacks(dst, errCh)
if err != nil {
return err
}
r0, _, _ := syscall.SyscallN(
s.ft.QueryInstances,
uintptr(unsafe.Pointer(s)),
uintptr(flags),
uintptr(unsafe.Pointer(operationOptions)),
uintptr(unsafe.Pointer(namespaceName)),
uintptr(unsafe.Pointer(queryDialect)),
uintptr(unsafe.Pointer(queryExpression)),
uintptr(unsafe.Pointer(operationCallbacks)),
uintptr(unsafe.Pointer(operation)),
)
if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) {
return result
}
errs := make([]error, 0)
for err := range errCh {
if err != nil {
errs = append(errs, err)
}
}
// KeepAlive is used to ensure that the callbacks are not garbage collected before the operation is closed.
runtime.KeepAlive(operationCallbacks.CallbackContext)
return errors.Join(errs...)
}
// Query queries for a set of instances based on a query expression.
func (s *Session) Query(dst any, namespaceName Namespace, queryExpression Query) error {
err := s.QueryUnmarshal(dst, OperationFlagsStandardRTTI, nil, namespaceName, QueryDialectWQL, queryExpression)
if err != nil {
return fmt.Errorf("WMI query failed: %w", err)
}
return nil
}

137
internal/mi/types.go Normal file
View File

@ -0,0 +1,137 @@
//go:build windows
package mi
import (
"time"
"unsafe"
"github.com/prometheus-community/windows_exporter/internal/utils"
"golang.org/x/sys/windows"
)
type Boolean uint8
const (
False Boolean = 0
True Boolean = 1
)
type QueryDialect *uint16
func NewQueryDialect(queryDialect string) (QueryDialect, error) {
return windows.UTF16PtrFromString(queryDialect)
}
var (
QueryDialectWQL = utils.Must(NewQueryDialect("WQL"))
QueryDialectCQL = utils.Must(NewQueryDialect("CQL"))
)
type Namespace *uint16
func NewNamespace(namespace string) (Namespace, error) {
return windows.UTF16PtrFromString(namespace)
}
var (
NamespaceRootCIMv2 = utils.Must(NewNamespace("root/CIMv2"))
NamespaceRootWindowsFSRM = utils.Must(NewNamespace("root/microsoft/windows/fsrm"))
NamespaceRootWebAdministration = utils.Must(NewNamespace("root/WebAdministration"))
NamespaceRootMSCluster = utils.Must(NewNamespace("root/MSCluster"))
)
type Query *uint16
func NewQuery(query string) (Query, error) {
return windows.UTF16PtrFromString(query)
}
// UTF16PtrFromString converts a string to a UTF-16 pointer at initialization time.
//
//nolint:ireturn
func UTF16PtrFromString[T *uint16](s string) T {
val, err := windows.UTF16PtrFromString(s)
if err != nil {
panic(err)
}
return val
}
type Timestamp struct {
Year uint32
Month uint32
Day uint32
Hour uint32
Minute uint32
Second uint32
Microseconds uint32
UTC int32
}
type Interval struct {
Days uint32
Hours uint32
Minutes uint32
Seconds uint32
Microseconds uint32
Padding1 uint32
Padding2 uint32
Padding3 uint32
}
func NewInterval(interval time.Duration) *Interval {
// Convert the duration to a number of microseconds
microseconds := interval.Microseconds()
// Create a new interval with the microseconds
return &Interval{
Days: uint32(microseconds / (24 * 60 * 60 * 1000000)),
Hours: uint32(microseconds / (60 * 60 * 1000000)),
Minutes: uint32(microseconds / (60 * 1000000)),
Seconds: uint32(microseconds / 1000000),
Microseconds: uint32(microseconds % 1000000),
}
}
type Datetime struct {
IsTimestamp bool
Timestamp *Timestamp // Used when IsTimestamp is true
Interval *Interval // Used when IsTimestamp is false
}
type PropertyDecl struct {
Flags uint32
Code uint32
Name *uint16
Mqualifiers uintptr
NumQualifiers uint32
PropertyType ValueType
ClassName *uint16
Subscript uint32
Offset uint32
Origin *uint16
Propagator *uint16
Value uintptr
}
func (c *ClassDecl) Properties() []*PropertyDecl {
// Create a slice to hold the properties
properties := make([]*PropertyDecl, c.NumProperties)
// Mproperties is a pointer to an array of pointers to PropertyDecl
propertiesArray := (**PropertyDecl)(unsafe.Pointer(c.Mproperties))
// Iterate over the number of properties and fetch each property
for i := range c.NumProperties {
// Get the property pointer at index i
propertyPtr := *(**PropertyDecl)(unsafe.Pointer(uintptr(unsafe.Pointer(propertiesArray)) + uintptr(i)*unsafe.Sizeof(uintptr(0))))
// Append the property to the slice
properties[i] = propertyPtr
}
// Return the slice of properties
return properties
}

112
internal/mi/value.go Normal file
View File

@ -0,0 +1,112 @@
//go:build windows
package mi
import (
"errors"
"fmt"
"unsafe"
"golang.org/x/sys/windows"
)
type ValueType int
const (
ValueTypeBOOLEAN ValueType = iota
ValueTypeUINT8
ValueTypeSINT8
ValueTypeUINT16
ValueTypeSINT16
ValueTypeUINT32
ValueTypeSINT32
ValueTypeUINT64
ValueTypeSINT64
ValueTypeREAL32
ValueTypeREAL64
ValueTypeCHAR16
ValueTypeDATETIME
ValueTypeSTRING
ValueTypeREFERENCE
ValueTypeINSTANCE
ValueTypeBOOLEANA
ValueTypeUINT8A
ValueTypeSINT8A
ValueTypeUINT16A
ValueTypeSINT16A
ValueTypeUINT32A
ValueTypeSINT32A
ValueTypeUINT64A
ValueTypeSINT64A
ValueTypeREAL32A
ValueTypeREAL64A
ValueTypeCHAR16A
ValueTypeDATETIMEA
ValueTypeSTRINGA
ValueTypeREFERENCEA
ValueTypeINSTANCEA
ValueTypeARRAY ValueType = 16
)
type Element struct {
value uintptr
valueType ValueType
}
func (e *Element) GetValue() (any, error) {
switch e.valueType {
case ValueTypeBOOLEAN:
return e.value == 1, nil
case ValueTypeUINT8:
return uint8(e.value), nil
case ValueTypeSINT8:
return int8(e.value), nil
case ValueTypeUINT16:
return uint16(e.value), nil
case ValueTypeSINT16:
return int16(e.value), nil
case ValueTypeUINT32:
return uint32(e.value), nil
case ValueTypeSINT32:
return int32(e.value), nil
case ValueTypeUINT64:
return uint64(e.value), nil
case ValueTypeSINT64:
return int64(e.value), nil
case ValueTypeREAL32:
return float32(e.value), nil
case ValueTypeREAL64:
return float64(e.value), nil
case ValueTypeCHAR16:
return uint16(e.value), nil
case ValueTypeDATETIME:
if e.value == 0 {
return nil, errors.New("invalid pointer: value is nil")
}
return *(*Datetime)(unsafe.Pointer(e.value)), nil
case ValueTypeSTRING:
if e.value == 0 {
return nil, errors.New("invalid pointer: value is nil")
}
// Convert the UTF-16 string to a Go string
return windows.UTF16PtrToString((*uint16)(unsafe.Pointer(e.value))), nil
case ValueTypeSTRINGA:
if e.value == 0 {
return nil, errors.New("invalid pointer: value is nil")
}
// Assuming array of pointers to UTF-16 strings
ptrArray := *(*[]*uint16)(unsafe.Pointer(e.value))
strArray := make([]string, len(ptrArray))
for i, ptr := range ptrArray {
strArray[i] = windows.UTF16PtrToString(ptr)
}
return strArray, nil
default:
return nil, fmt.Errorf("unsupported value type: %d", e.valueType)
}
}

View File

@ -0,0 +1,28 @@
package testutils
import (
"unsafe"
"golang.org/x/sys/windows"
)
var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
procGetProcessHandleCount = modkernel32.NewProc("GetProcessHandleCount")
)
func GetProcessHandleCount(handle windows.Handle) (uint32, error) {
var count uint32
r1, _, err := procGetProcessHandleCount.Call(
uintptr(handle),
uintptr(unsafe.Pointer(&count)),
)
if r1 != 1 {
return 0, err
}
return count, nil
}

View File

@ -10,10 +10,10 @@ import (
"time" "time"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/pkg/collector" "github.com/prometheus-community/windows_exporter/pkg/collector"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/yusufpapurcu/wmi"
) )
func FuncBenchmarkCollector[C collector.Collector](b *testing.B, name string, collectFunc collector.BuilderWithFlags[C]) { func FuncBenchmarkCollector[C collector.Collector](b *testing.B, name string, collectFunc collector.BuilderWithFlags[C]) {
@ -57,14 +57,16 @@ func TestCollector[C collector.Collector, V interface{}](t *testing.T, fn func(*
c := fn(conf) c := fn(conf)
ch := make(chan prometheus.Metric, 10000) ch := make(chan prometheus.Metric, 10000)
wmiClient := &wmi.Client{ miApp, err := mi.Application_Initialize()
AllowMissingFields: true, require.NoError(t, err)
}
wmiClient.SWbemServicesClient, err = wmi.InitializeSWbemServices(wmiClient) miSession, err := miApp.NewSession(nil)
require.NoError(t, err) require.NoError(t, err)
t.Cleanup(func() { t.Cleanup(func() {
require.NoError(t, c.Close(logger)) require.NoError(t, c.Close(logger))
require.NoError(t, miSession.Close())
require.NoError(t, miApp.Close())
}) })
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
@ -78,7 +80,7 @@ func TestCollector[C collector.Collector, V interface{}](t *testing.T, fn func(*
} }
}() }()
require.NoError(t, c.Build(logger, wmiClient)) require.NoError(t, c.Build(logger, miSession))
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)

View File

@ -35,3 +35,11 @@ func PDHEnabled() bool {
return false return false
} }
func MIEnabled() bool {
if v, ok := os.LookupEnv("WINDOWS_EXPORTER_WMI_ENGINE"); ok && v == "mi" {
return true
}
return false
}

View File

@ -17,3 +17,14 @@ func BoolToFloat(b bool) float64 {
func ToPTR[t any](v t) *t { func ToPTR[t any](v t) *t {
return &v return &v
} }
// Must panics if the error is not nil.
//
//nolint:ireturn
func Must[T any](v T, err error) T {
if err != nil {
panic(err)
}
return v
}

1
main.go Normal file
View File

@ -0,0 +1 @@
package main

View File

@ -57,9 +57,9 @@ import (
"github.com/prometheus-community/windows_exporter/internal/collector/time" "github.com/prometheus-community/windows_exporter/internal/collector/time"
"github.com/prometheus-community/windows_exporter/internal/collector/update" "github.com/prometheus-community/windows_exporter/internal/collector/update"
"github.com/prometheus-community/windows_exporter/internal/collector/vmware" "github.com/prometheus-community/windows_exporter/internal/collector/vmware"
"github.com/prometheus-community/windows_exporter/internal/mi"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/yusufpapurcu/wmi"
) )
// NewWithFlags To be called by the exporter for collector initialization before running kingpin.Parse. // NewWithFlags To be called by the exporter for collector initialization before running kingpin.Parse.
@ -132,9 +132,6 @@ func NewWithConfig(config Config) *MetricCollectors {
func New(collectors Map) *MetricCollectors { func New(collectors Map) *MetricCollectors {
return &MetricCollectors{ return &MetricCollectors{
Collectors: collectors, Collectors: collectors,
WMIClient: &wmi.Client{
AllowMissingFields: true,
},
} }
} }
@ -186,11 +183,9 @@ func (c *MetricCollectors) Enable(enabledCollectors []string) error {
// Build To be called by the exporter for collector initialization. // Build To be called by the exporter for collector initialization.
func (c *MetricCollectors) Build(logger *slog.Logger) error { func (c *MetricCollectors) Build(logger *slog.Logger) error {
var err error err := c.initMI()
c.WMIClient.SWbemServicesClient, err = wmi.InitializeSWbemServices(c.WMIClient)
if err != nil { if err != nil {
return fmt.Errorf("initialize SWbemServices: %w", err) return fmt.Errorf("error from initialize MI: %w", err)
} }
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
@ -203,7 +198,7 @@ func (c *MetricCollectors) Build(logger *slog.Logger) error {
go func() { go func() {
defer wg.Done() defer wg.Done()
if err = collector.Build(logger, c.WMIClient); err != nil { if err = collector.Build(logger, c.MISession); err != nil {
errCh <- fmt.Errorf("error build collector %s: %w", collector.GetName(), err) errCh <- fmt.Errorf("error build collector %s: %w", collector.GetName(), err)
} }
}() }()
@ -245,11 +240,42 @@ func (c *MetricCollectors) Close(logger *slog.Logger) error {
} }
} }
if c.WMIClient != nil && c.WMIClient.SWbemServicesClient != nil { app, err := c.MISession.GetApplication()
if err := c.WMIClient.SWbemServicesClient.Close(); err != nil { if err != nil && !errors.Is(err, mi.ErrNotInitialized) {
errs = append(errs, err) errs = append(errs, err)
} }
if err := c.MISession.Close(); err != nil && !errors.Is(err, mi.ErrNotInitialized) {
errs = append(errs, err)
}
if err := app.Close(); err != nil && !errors.Is(err, mi.ErrNotInitialized) {
errs = append(errs, err)
} }
return errors.Join(errs...) return errors.Join(errs...)
} }
// Close To be called by the exporter for collector cleanup.
func (c *MetricCollectors) initMI() error {
app, err := mi.Application_Initialize()
if err != nil {
return fmt.Errorf("error from initialize MI application: %w", err)
}
destinationOptions, err := app.NewDestinationOptions()
if err != nil {
return fmt.Errorf("error from create NewDestinationOptions: %w", err)
}
if err = destinationOptions.SetLocale(mi.LocaleEnglish); err != nil {
return fmt.Errorf("error from set locale: %w", err)
}
c.MISession, err = app.NewSession(destinationOptions)
if err != nil {
return fmt.Errorf("error from create NewSession: %w", err)
}
return nil
}

View File

@ -4,14 +4,14 @@ import (
"log/slog" "log/slog"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/yusufpapurcu/wmi"
) )
type MetricCollectors struct { type MetricCollectors struct {
Collectors Map Collectors Map
WMIClient *wmi.Client MISession *mi.Session
PerfCounterQuery string PerfCounterQuery string
} }
@ -22,7 +22,7 @@ type (
// Collector interface that a collector has to implement. // Collector interface that a collector has to implement.
type Collector interface { type Collector interface {
Build(logger *slog.Logger, wmiClient *wmi.Client) error Build(logger *slog.Logger, miSession *mi.Session) error
// Close closes the collector // Close closes the collector
Close(logger *slog.Logger) error Close(logger *slog.Logger) error
// GetName get the name of the collector // GetName get the name of the collector