From 750225775b8ab37567fbe2addcfb0157c53773e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Mon, 10 Jul 2023 01:56:17 +0200 Subject: [PATCH 01/13] Integrate perflib MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan-Otto Kröpke --- collector/collector.go | 2 +- collector/perflib.go | 10 +- collector/perflib_test.go | 15 +- go.mod | 1 - go.sum | 65 ----- wmi/perflib/const.go | 10 + wmi/perflib/nametable.go | 75 ++++++ wmi/perflib/perflib.go | 473 ++++++++++++++++++++++++++++++++++++ wmi/perflib/perflib_test.go | 41 ++++ wmi/perflib/raw_types.go | 180 ++++++++++++++ wmi/perflib/utf16.go | 49 ++++ 11 files changed, 841 insertions(+), 80 deletions(-) create mode 100644 wmi/perflib/const.go create mode 100644 wmi/perflib/nametable.go create mode 100644 wmi/perflib/perflib.go create mode 100644 wmi/perflib/perflib_test.go create mode 100644 wmi/perflib/raw_types.go create mode 100644 wmi/perflib/utf16.go diff --git a/collector/collector.go b/collector/collector.go index e6f545fc..358179f5 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -9,7 +9,7 @@ import ( "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/leoluk/perflib_exporter/perflib" + "github.com/prometheus-community/windows_exporter/wmi/perflib" "github.com/prometheus/client_golang/prometheus" "golang.org/x/sys/windows/registry" ) diff --git a/collector/perflib.go b/collector/perflib.go index 6a728834..ab646480 100644 --- a/collector/perflib.go +++ b/collector/perflib.go @@ -6,13 +6,13 @@ import ( "strconv" "strings" + "github.com/prometheus-community/windows_exporter/wmi/perflib" + "github.com/go-kit/log" "github.com/go-kit/log/level" - perflibCollector "github.com/leoluk/perflib_exporter/collector" - "github.com/leoluk/perflib_exporter/perflib" ) -var nametable = perflib.QueryNameTable("Counter 009") // Reads the names in English TODO: validate that the English names are always present +var nametable = perflib.CounterNameTable func MapCounterToIndex(name string) string { return strconv.Itoa(int(nametable.LookupIndex(name))) @@ -101,9 +101,9 @@ func unmarshalObject(obj *perflib.PerfObject, vs interface{}, logger log.Logger) } switch ctr.Def.CounterType { - case perflibCollector.PERF_ELAPSED_TIME: + case perflib.PERF_ELAPSED_TIME: target.Field(i).SetFloat(float64(ctr.Value-windowsEpoch) / float64(obj.Frequency)) - case perflibCollector.PERF_100NSEC_TIMER, perflibCollector.PERF_PRECISION_100NS_TIMER: + case perflib.PERF_100NSEC_TIMER, perflib.PERF_PRECISION_100NS_TIMER: target.Field(i).SetFloat(float64(ctr.Value) * ticksToSecondsScaleFactor) default: target.Field(i).SetFloat(float64(ctr.Value)) diff --git a/collector/perflib_test.go b/collector/perflib_test.go index 47ba46a2..6126c648 100644 --- a/collector/perflib_test.go +++ b/collector/perflib_test.go @@ -4,10 +4,9 @@ import ( "reflect" "testing" - "github.com/go-kit/log" + "github.com/prometheus-community/windows_exporter/wmi/perflib" - perflibCollector "github.com/leoluk/perflib_exporter/collector" - "github.com/leoluk/perflib_exporter/perflib" + "github.com/go-kit/log" ) type simple struct { @@ -39,7 +38,7 @@ func TestUnmarshalPerflib(t *testing.T) { { Def: &perflib.PerfCounterDef{ Name: "Something", - CounterType: perflibCollector.PERF_COUNTER_COUNTER, + CounterType: perflib.PERF_COUNTER_COUNTER, }, Value: 123, }, @@ -59,14 +58,14 @@ func TestUnmarshalPerflib(t *testing.T) { { Def: &perflib.PerfCounterDef{ Name: "Something", - CounterType: perflibCollector.PERF_COUNTER_COUNTER, + CounterType: perflib.PERF_COUNTER_COUNTER, }, Value: 123, }, { Def: &perflib.PerfCounterDef{ Name: "Something Else", - CounterType: perflibCollector.PERF_COUNTER_COUNTER, + CounterType: perflib.PERF_COUNTER_COUNTER, HasSecondValue: true, }, Value: 256, @@ -88,7 +87,7 @@ func TestUnmarshalPerflib(t *testing.T) { { Def: &perflib.PerfCounterDef{ Name: "Something", - CounterType: perflibCollector.PERF_COUNTER_COUNTER, + CounterType: perflib.PERF_COUNTER_COUNTER, }, Value: 321, }, @@ -99,7 +98,7 @@ func TestUnmarshalPerflib(t *testing.T) { { Def: &perflib.PerfCounterDef{ Name: "Something", - CounterType: perflibCollector.PERF_COUNTER_COUNTER, + CounterType: perflib.PERF_COUNTER_COUNTER, }, Value: 231, }, diff --git a/go.mod b/go.mod index 570b91f3..ffa38d29 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,6 @@ require ( github.com/dimchansky/utfbom v1.1.1 github.com/go-kit/log v0.2.1 github.com/go-ole/go-ole v1.2.6 - github.com/leoluk/perflib_exporter v0.2.1 github.com/prometheus/client_golang v1.16.0 github.com/prometheus/client_model v0.4.0 github.com/prometheus/common v0.44.0 diff --git a/go.sum b/go.sum index dea7288d..20772b33 100644 --- a/go.sum +++ b/go.sum @@ -10,27 +10,18 @@ cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6T cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= @@ -80,7 +71,6 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= @@ -288,12 +278,10 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= @@ -339,7 +327,6 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -364,7 +351,6 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -377,14 +363,12 @@ github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYV github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -432,12 +416,10 @@ github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -457,8 +439,6 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leoluk/perflib_exporter v0.2.1 h1:/3/ut1k/jFt5p4ypjLZKDHDqlXAK6ERZPVWtwdI389I= -github.com/leoluk/perflib_exporter v0.2.1/go.mod h1:MinSWm88jguXFFrGsP56PtleUb4Qtm4tNRH/wXNXRTI= github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -559,7 +539,6 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -575,8 +554,6 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.31.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/exporter-toolkit v0.10.0 h1:yOAzZTi4M22ZzVxD+fhy1URTuNRj/36uQJJ5S8IPza8= @@ -671,9 +648,7 @@ github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8 github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= @@ -691,7 +666,6 @@ go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= @@ -775,10 +749,6 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -787,7 +757,6 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= @@ -796,7 +765,6 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -857,16 +825,10 @@ golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -884,7 +846,6 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= @@ -941,20 +902,11 @@ golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= @@ -972,13 +924,8 @@ google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1007,20 +954,11 @@ google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1034,10 +972,8 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= @@ -1098,7 +1034,6 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= diff --git a/wmi/perflib/const.go b/wmi/perflib/const.go new file mode 100644 index 00000000..12f1f219 --- /dev/null +++ b/wmi/perflib/const.go @@ -0,0 +1,10 @@ +package perflib + +// Based on https://github.com/leoluk/perflib_exporter/blob/master/collector/mapper.go + +const ( + PERF_COUNTER_COUNTER = 0x10410400 + PERF_100NSEC_TIMER = 0x20510500 + PERF_PRECISION_100NS_TIMER = 0x20570500 + PERF_ELAPSED_TIME = 0x30240500 +) diff --git a/wmi/perflib/nametable.go b/wmi/perflib/nametable.go new file mode 100644 index 00000000..cdeceaeb --- /dev/null +++ b/wmi/perflib/nametable.go @@ -0,0 +1,75 @@ +package perflib + +import ( + "bytes" + "fmt" + "strconv" +) + +type nameTableLookuper interface { + LookupName() string + LookupHelp() string +} + +func (p *perfObjectType) LookupName() string { + return CounterNameTable.LookupString(p.ObjectNameTitleIndex) +} + +func (p *perfObjectType) LookupHelp() string { + return HelpNameTable.LookupString(p.ObjectHelpTitleIndex) +} + +type NameTable struct { + byIndex map[uint32]string + byString map[string]uint32 +} + +func (t *NameTable) LookupString(index uint32) string { + return t.byIndex[index] +} + +func (t *NameTable) LookupIndex(str string) uint32 { + return t.byString[str] +} + +// Query a perflib name table from the registry. Specify the type and the language +// code (i.e. "Counter 009" or "Help 009") for English language. +func QueryNameTable(tableName string) *NameTable { + nameTable := new(NameTable) + nameTable.byIndex = make(map[uint32]string) + + buffer, err := queryRawData(tableName) + if err != nil { + panic(err) + } + r := bytes.NewReader(buffer) + for { + index, err := readUTF16String(r) + + if err != nil { + break + } + + desc, err := readUTF16String(r) + + if err != nil { + break + } + + indexInt, _ := strconv.Atoi(index) + + if err != nil { + panic(fmt.Sprint("Invalid index ", index)) + } + + nameTable.byIndex[uint32(indexInt)] = desc + } + + nameTable.byString = make(map[string]uint32) + + for k, v := range nameTable.byIndex { + nameTable.byString[v] = k + } + + return nameTable +} diff --git a/wmi/perflib/perflib.go b/wmi/perflib/perflib.go new file mode 100644 index 00000000..1aadd292 --- /dev/null +++ b/wmi/perflib/perflib.go @@ -0,0 +1,473 @@ +/* +Go bindings for the HKEY_PERFORMANCE_DATA perflib / Performance Counters interface. + +# Overview + +HKEY_PERFORMANCE_DATA is a low-level alternative to the higher-level PDH library and WMI. +It operates on blocks of counters and only returns raw values without calculating rates +or formatting them, which is exactly what you want for, say, a Prometheus exporter +(not so much for a GUI like Windows Performance Monitor). + +Its overhead is much lower than the high-level libraries. + +It operates on the same set of perflib providers as PDH and WMI. See this document +for more details on the relationship between the different libraries: +https://msdn.microsoft.com/en-us/library/windows/desktop/aa371643(v=vs.85).aspx + +Example C++ source code: +https://msdn.microsoft.com/de-de/library/windows/desktop/aa372138(v=vs.85).aspx + +For now, the API is not stable and is probably going to change in future +perflib_exporter releases. If you want to use this library, send the author an email +so we can discuss your requirements and stabilize the API. + +# Names + +Counter names and help texts are resolved by looking up an index in a name table. +Since Microsoft loves internalization, both names and help texts can be requested +any locally available language. + +The library automatically loads the name tables and resolves all identifiers +in English ("Name" and "HelpText" struct members). You can manually resolve +identifiers in a different language by using the NameTable API. + +# Performance Counters intro + +Windows has a system-wide performance counter mechanism. Most performance counters +are stored as actual counters, not gauges (with some exceptions). +There's additional metadata which defines how the counter should be presented to the user +(for example, as a calculated rate). This library disregards all of the display metadata. + +At the top level, there's a number of performance counter objects. +Each object has counter definitions, which contain the metadata for a particular +counter, and either zero or multiple instances. We hide the fact that there are +objects with no instances, and simply return a single null instance. + +There's one counter per counter definition and instance (or the object itself, if +there are no instances). + +Behind the scenes, every perflib DLL provides one or more objects. +Perflib has a registry where DLLs are dynamically registered and +unregistered. Some third party applications like VMWare provide their own counters, +but this is, sadly, a rare occurrence. + +Different Windows releases have different numbers of counters. + +Objects and counters are identified by well-known indices. + +Here's an example object with one instance: + + 4320 WSMan Quota Statistics [7 counters, 1 instance(s)] + `-- "WinRMService" + `-- Total Requests/Second [4322] = 59 + `-- User Quota Violations/Second [4324] = 0 + `-- System Quota Violations/Second [4326] = 0 + `-- Active Shells [4328] = 0 + `-- Active Operations [4330] = 0 + `-- Active Users [4332] = 0 + `-- Process ID [4334] = 928 + +All "per second" metrics are counters, the rest are gauges. + +Another example, with no instance: + + 4600 Network QoS Policy [6 counters, 1 instance(s)] + `-- (default) + `-- Packets transmitted [4602] = 1744 + `-- Packets transmitted/sec [4604] = 4852 + `-- Bytes transmitted [4606] = 4853 + `-- Bytes transmitted/sec [4608] = 180388626632 + `-- Packets dropped [4610] = 0 + `-- Packets dropped/sec [4612] = 0 + +You can access the same values using PowerShell's Get-Counter cmdlet +or the Performance Monitor. + + > Get-Counter '\WSMan Quota Statistics(WinRMService)\Process ID' + + Timestamp CounterSamples + --------- -------------- + 1/28/2018 10:18:00 PM \\DEV\wsman quota statistics(winrmservice)\process id : + 928 + + > (Get-Counter '\Process(Idle)\% Processor Time').CounterSamples[0] | Format-List * + [..detailed output...] + +Data for some of the objects is also available through WMI: + + > Get-CimInstance Win32_PerfRawData_Counters_WSManQuotaStatistics + + Name : WinRMService + [...] + ActiveOperations : 0 + ActiveShells : 0 + ActiveUsers : 0 + ProcessID : 928 + SystemQuotaViolationsPerSecond : 0 + TotalRequestsPerSecond : 59 + UserQuotaViolationsPerSecond : 0 +*/ +package perflib + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "sort" + "strings" + "syscall" + "unsafe" +) + +// TODO: There's a LittleEndian field in the PERF header - we ought to check it +var bo = binary.LittleEndian + +var CounterNameTable NameTable +var HelpNameTable NameTable + +const averageCount64Type = 1073874176 + +// Top-level performance object (like "Process"). +type PerfObject struct { + Name string + // Same index you pass to QueryPerformanceData + NameIndex uint + HelpText string + HelpTextIndex uint + Instances []*PerfInstance + CounterDefs []*PerfCounterDef + + Frequency int64 + + rawData *perfObjectType +} + +// Each object can have multiple instances. For example, +// In case the object has no instances, we return one single PerfInstance with an empty name. +type PerfInstance struct { + // *not* resolved using a name table + Name string + Counters []*PerfCounter + + rawData *perfInstanceDefinition + rawCounterBlock *perfCounterBlock +} + +type PerfCounterDef struct { + Name string + NameIndex uint + HelpText string + HelpTextIndex uint + + // For debugging - subject to removal. CounterType is a perflib + // implementation detail (see perflib.h) and should not be used outside + // of this package. We export it so we can show it on /dump. + CounterType uint32 + + // PERF_TYPE_COUNTER (otherwise, it's a gauge) + IsCounter bool + // PERF_COUNTER_BASE (base value of a multi-value fraction) + IsBaseValue bool + // PERF_TIMER_100NS + IsNanosecondCounter bool + HasSecondValue bool + + rawData *perfCounterDefinition +} + +type PerfCounter struct { + Value int64 + Def *PerfCounterDef + SecondValue int64 +} + +// Error value returned by RegQueryValueEx if the buffer isn't sufficiently large +const errorMoreData = syscall.Errno(234) + +var ( + bufLenGlobal = uint32(400000) + bufLenCostly = uint32(2000000) +) + +// Queries the performance counter buffer using RegQueryValueEx, returning raw bytes. See: +// https://msdn.microsoft.com/de-de/library/windows/desktop/aa373219(v=vs.85).aspx +func queryRawData(query string) ([]byte, error) { + var ( + valType uint32 + buffer []byte + bufLen uint32 + ) + + switch query { + case "Global": + bufLen = bufLenGlobal + case "Costly": + bufLen = bufLenCostly + default: + // TODO: depends on the number of values requested + // need make an educated guess + numCounters := len(strings.Split(query, " ")) + bufLen = uint32(150000 * numCounters) + } + + buffer = make([]byte, bufLen) + + name, err := syscall.UTF16PtrFromString(query) + + if err != nil { + return nil, fmt.Errorf("failed to encode query string: %v", err) + } + + defer syscall.RegCloseKey(syscall.HKEY_PERFORMANCE_DATA) + + for { + bufLen := uint32(len(buffer)) + + err := syscall.RegQueryValueEx( + syscall.HKEY_PERFORMANCE_DATA, + name, + nil, + &valType, + (*byte)(unsafe.Pointer(&buffer[0])), + &bufLen) + + if err == errorMoreData { + newBuffer := make([]byte, len(buffer)+16384) + copy(newBuffer, buffer) + buffer = newBuffer + syscall.RegCloseKey(syscall.HKEY_PERFORMANCE_DATA) + continue + } else if err != nil { + if errno, ok := err.(syscall.Errno); ok { + return nil, fmt.Errorf("ReqQueryValueEx failed: %v errno %d", err, uint(errno)) + } + + return nil, err + } + + buffer = buffer[:bufLen] + + switch query { + case "Global": + if bufLen > bufLenGlobal { + bufLenGlobal = bufLen + } + case "Costly": + if bufLen > bufLenCostly { + bufLenCostly = bufLen + } + } + + return buffer, nil + } +} + +func init() { + // Initialize global name tables + // TODO: profiling, add option to disable name tables if necessary + // Not sure if we should resolve the names at all or just have the caller do it on demand + // (for many use cases the index is sufficient) + + CounterNameTable = *QueryNameTable("Counter 009") + HelpNameTable = *QueryNameTable("Help 009") +} + +/* +Query all performance counters that match a given query. + +The query can be any of the following: + +- "Global" (all performance counters except those Windows marked as costly) + +- "Costly" (only the costly ones) + +- One or more object indices, separated by spaces ("238 2 5") + +Many objects have dependencies - if you query one of them, you often get back +more than you asked for. +*/ +func QueryPerformanceData(query string) ([]*PerfObject, error) { + buffer, err := queryRawData(query) + + if err != nil { + return nil, err + } + + r := bytes.NewReader(buffer) + + // Read global header + + header := new(perfDataBlock) + err = header.BinaryReadFrom(r) + + if err != nil { + return nil, err + } + + // Check for "PERF" signature + if header.Signature != [4]uint16{80, 69, 82, 70} { + panic("Invalid performance block header") + } + + // Parse the performance data + + numObjects := int(header.NumObjectTypes) + objects := make([]*PerfObject, numObjects) + + objOffset := int64(header.HeaderLength) + + for i := 0; i < numObjects; i++ { + r.Seek(objOffset, io.SeekStart) + + obj := new(perfObjectType) + obj.BinaryReadFrom(r) + + numCounterDefs := int(obj.NumCounters) + numInstances := int(obj.NumInstances) + + // Perf objects can have no instances. The perflib differentiates + // between objects with instances and without, but we just create + // an empty instance in order to simplify the interface. + if numInstances <= 0 { + numInstances = 1 + } + + instances := make([]*PerfInstance, numInstances) + counterDefs := make([]*PerfCounterDef, numCounterDefs) + + objects[i] = &PerfObject{ + Name: obj.LookupName(), + NameIndex: uint(obj.ObjectNameTitleIndex), + HelpText: obj.LookupHelp(), + HelpTextIndex: uint(obj.ObjectHelpTitleIndex), + Instances: instances, + CounterDefs: counterDefs, + Frequency: obj.PerfFreq, + rawData: obj, + } + + for i := 0; i < numCounterDefs; i++ { + def := new(perfCounterDefinition) + def.BinaryReadFrom(r) + + counterDefs[i] = &PerfCounterDef{ + Name: def.LookupName(), + NameIndex: uint(def.CounterNameTitleIndex), + HelpText: def.LookupHelp(), + HelpTextIndex: uint(def.CounterHelpTitleIndex), + rawData: def, + + CounterType: def.CounterType, + + IsCounter: def.CounterType&0x400 == 0x400, + IsBaseValue: def.CounterType&0x00030000 == 0x00030000, + IsNanosecondCounter: def.CounterType&0x00100000 == 0x00100000, + HasSecondValue: def.CounterType == averageCount64Type, + } + } + + if obj.NumInstances <= 0 { + blockOffset := objOffset + int64(obj.DefinitionLength) + r.Seek(blockOffset, io.SeekStart) + + _, counters := parseCounterBlock(buffer, r, blockOffset, counterDefs) + + instances[0] = &PerfInstance{ + Name: "", + Counters: counters, + rawData: nil, + rawCounterBlock: nil, + } + } else { + instOffset := objOffset + int64(obj.DefinitionLength) + + for i := 0; i < numInstances; i++ { + r.Seek(instOffset, io.SeekStart) + + inst := new(perfInstanceDefinition) + inst.BinaryReadFrom(r) + + name, _ := readUTF16StringAtPos(r, instOffset+int64(inst.NameOffset), inst.NameLength) + pos := instOffset + int64(inst.ByteLength) + offset, counters := parseCounterBlock(buffer, r, pos, counterDefs) + + instances[i] = &PerfInstance{ + Name: name, + Counters: counters, + rawData: inst, + } + + instOffset = pos + offset + } + } + + // Next perfObjectType + objOffset += int64(obj.TotalByteLength) + } + + return objects, nil +} + +func parseCounterBlock(b []byte, r io.ReadSeeker, pos int64, defs []*PerfCounterDef) (int64, []*PerfCounter) { + r.Seek(pos, io.SeekStart) + block := new(perfCounterBlock) + block.BinaryReadFrom(r) + + counters := make([]*PerfCounter, len(defs)) + + for i, def := range defs { + valueOffset := pos + int64(def.rawData.CounterOffset) + value := convertCounterValue(def.rawData, b, valueOffset) + secondValue := int64(0) + + if def.HasSecondValue { + secondValue = convertCounterValue(def.rawData, b, valueOffset+8) + } + + counters[i] = &PerfCounter{ + Value: value, + Def: def, + SecondValue: secondValue, + } + } + + return int64(block.ByteLength), counters +} + +func convertCounterValue(counterDef *perfCounterDefinition, buffer []byte, valueOffset int64) (value int64) { + /* + We can safely ignore the type since we're not interested in anything except the raw value. + We also ignore all of the other attributes (timestamp, presentation, multi counter values...) + + See also: winperf.h. + + Here's the most common value for CounterType: + + 65536 32bit counter + 65792 64bit counter + 272696320 32bit rate + 272696576 64bit rate + + */ + + switch counterDef.CounterSize { + case 4: + value = int64(bo.Uint32(buffer[valueOffset:(valueOffset + 4)])) + case 8: + value = int64(bo.Uint64(buffer[valueOffset:(valueOffset + 8)])) + default: + value = int64(bo.Uint32(buffer[valueOffset:(valueOffset + 4)])) + } + + return +} + +// Sort slice of objects by index. This is useful for displaying +// a human-readable list or dump, but unnecessary otherwise. +func SortObjects(p []*PerfObject) { + sort.Slice(p, func(i, j int) bool { + return p[i].NameIndex < p[j].NameIndex + }) + +} diff --git a/wmi/perflib/perflib_test.go b/wmi/perflib/perflib_test.go new file mode 100644 index 00000000..0c66dbd1 --- /dev/null +++ b/wmi/perflib/perflib_test.go @@ -0,0 +1,41 @@ +package perflib + +import ( + "fmt" + "testing" +) + +func ExampleQueryPerformanceData() { + objects, err := QueryPerformanceData("2") + + if err != nil { + panic(err) + } + + for _, object := range objects { + fmt.Printf("%d %s [%d counters, %d instances]\n", + object.NameIndex, object.Name, len(object.CounterDefs), len(object.Instances)) + + for _, instance := range object.Instances { + if !((instance.Name == "_Total") || (instance.Name == "")) { + continue + } + + if instance.Name == "" { + fmt.Println("No instance.", instance.Name) + } else { + fmt.Println("Instance:", instance.Name) + } + + for _, counter := range instance.Counters { + fmt.Printf(" -> %s %d\n", counter.Def.Name, counter.Def.NameIndex) + } + } + } +} + +func BenchmarkQueryPerformanceData(b *testing.B) { + for n := 0; n < b.N; n++ { + _, _ = QueryPerformanceData("Global") + } +} diff --git a/wmi/perflib/raw_types.go b/wmi/perflib/raw_types.go new file mode 100644 index 00000000..0baab304 --- /dev/null +++ b/wmi/perflib/raw_types.go @@ -0,0 +1,180 @@ +package perflib + +import ( + "encoding/binary" + "io" + "syscall" +) + +type binaryReaderFrom interface { + BinaryReadFrom(r io.Reader) error +} + +/* +https://msdn.microsoft.com/de-de/library/windows/desktop/aa373157(v=vs.85).aspx + +typedef struct _PERF_DATA_BLOCK { + WCHAR Signature[4]; + DWORD LittleEndian; + DWORD Version; + DWORD Revision; + DWORD TotalByteLength; + DWORD HeaderLength; + DWORD NumObjectTypes; + DWORD DefaultObject; + SYSTEMTIME SystemTime; + LARGE_INTEGER PerfTime; + LARGE_INTEGER PerfFreq; + LARGE_INTEGER PerfTime100nSec; + DWORD SystemNameLength; + DWORD SystemNameOffset; +} PERF_DATA_BLOCK; +*/ + +type perfDataBlock struct { + Signature [4]uint16 + LittleEndian uint32 + Version uint32 + Revision uint32 + TotalByteLength uint32 + HeaderLength uint32 + NumObjectTypes uint32 + DefaultObject int32 + SystemTime syscall.Systemtime + _ uint32 // TODO + PerfTime int64 + PerfFreq int64 + PerfTime100nSec int64 + SystemNameLength uint32 + SystemNameOffset uint32 +} + +func (p *perfDataBlock) BinaryReadFrom(r io.Reader) error { + return binary.Read(r, bo, p) +} + +/* +https://msdn.microsoft.com/en-us/library/windows/desktop/aa373160(v=vs.85).aspx + +typedef struct _PERF_OBJECT_TYPE { + DWORD TotalByteLength; + DWORD DefinitionLength; + DWORD HeaderLength; + DWORD ObjectNameTitleIndex; + LPWSTR ObjectNameTitle; + DWORD ObjectHelpTitleIndex; + LPWSTR ObjectHelpTitle; + DWORD DetailLevel; + DWORD NumCounters; + DWORD DefaultCounter; + DWORD NumInstances; + DWORD CodePage; + LARGE_INTEGER PerfTime; + LARGE_INTEGER PerfFreq; +} PERF_OBJECT_TYPE; +*/ + +type perfObjectType struct { + TotalByteLength uint32 + DefinitionLength uint32 + HeaderLength uint32 + ObjectNameTitleIndex uint32 + ObjectNameTitle uint32 + ObjectHelpTitleIndex uint32 + ObjectHelpTitle uint32 + DetailLevel uint32 + NumCounters uint32 + DefaultCounter int32 + NumInstances int32 + CodePage uint32 + PerfTime int64 + PerfFreq int64 +} + +func (p *perfObjectType) BinaryReadFrom(r io.Reader) error { + return binary.Read(r, bo, p) +} + +/* +https://msdn.microsoft.com/en-us/library/windows/desktop/aa373150(v=vs.85).aspx + +typedef struct _PERF_COUNTER_DEFINITION { + DWORD ByteLength; + DWORD CounterNameTitleIndex; + LPWSTR CounterNameTitle; + DWORD CounterHelpTitleIndex; + LPWSTR CounterHelpTitle; + LONG DefaultScale; + DWORD DetailLevel; + DWORD CounterType; + DWORD CounterSize; + DWORD CounterOffset; +} PERF_COUNTER_DEFINITION; +*/ + +type perfCounterDefinition struct { + ByteLength uint32 + CounterNameTitleIndex uint32 + CounterNameTitle uint32 + CounterHelpTitleIndex uint32 + CounterHelpTitle uint32 + DefaultScale int32 + DetailLevel uint32 + CounterType uint32 + CounterSize uint32 + CounterOffset uint32 +} + +func (p *perfCounterDefinition) BinaryReadFrom(r io.Reader) error { + return binary.Read(r, bo, p) +} + +func (p *perfCounterDefinition) LookupName() string { + return CounterNameTable.LookupString(p.CounterNameTitleIndex) +} + +func (p *perfCounterDefinition) LookupHelp() string { + return HelpNameTable.LookupString(p.CounterHelpTitleIndex) +} + +/* +https://msdn.microsoft.com/en-us/library/windows/desktop/aa373147(v=vs.85).aspx + +typedef struct _PERF_COUNTER_BLOCK { + DWORD ByteLength; +} PERF_COUNTER_BLOCK; +*/ + +type perfCounterBlock struct { + ByteLength uint32 +} + +func (p *perfCounterBlock) BinaryReadFrom(r io.Reader) error { + return binary.Read(r, bo, p) +} + +/* +https://msdn.microsoft.com/en-us/library/windows/desktop/aa373159(v=vs.85).aspx + +typedef struct _PERF_INSTANCE_DEFINITION { + DWORD ByteLength; + DWORD ParentObjectTitleIndex; + DWORD ParentObjectInstance; + DWORD UniqueID; + DWORD NameOffset; + DWORD NameLength; +} PERF_INSTANCE_DEFINITION; +*/ + +type perfInstanceDefinition struct { + ByteLength uint32 + ParentObjectTitleIndex uint32 + ParentObjectInstance uint32 + UniqueID uint32 + NameOffset uint32 + NameLength uint32 +} + +func (p *perfInstanceDefinition) BinaryReadFrom(r io.Reader) error { + return binary.Read(r, bo, p) +} diff --git a/wmi/perflib/utf16.go b/wmi/perflib/utf16.go new file mode 100644 index 00000000..3b0cec9e --- /dev/null +++ b/wmi/perflib/utf16.go @@ -0,0 +1,49 @@ +package perflib + +import ( + "encoding/binary" + "io" + "syscall" +) + +// Read an unterminated UTF16 string at a given position, specifying its length +func readUTF16StringAtPos(r io.ReadSeeker, absPos int64, length uint32) (string, error) { + value := make([]uint16, length/2) + _, err := r.Seek(absPos, io.SeekStart) + + if err != nil { + return "", err + } + + err = binary.Read(r, bo, value) + + if err != nil { + return "", err + } + + return syscall.UTF16ToString(value), nil +} + +// Reads a null-terminated UTF16 string at the current offset +func readUTF16String(r io.Reader) (string, error) { + var err error + + b := make([]byte, 2) + out := make([]uint16, 0, 100) + + for i := 0; err == nil; i += 2 { + _, err = r.Read(b) + + if b[0] == 0 && b[1] == 0 { + break + } + + out = append(out, bo.Uint16(b)) + } + + if err != nil { + return "", err + } + + return syscall.UTF16ToString(out), nil +} From 4ea61a2641de00f0241ebdc5c9cdca4d8ef2486c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Mon, 10 Jul 2023 01:56:42 +0200 Subject: [PATCH 02/13] Remove unused nameTableLookuper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan-Otto Kröpke --- wmi/perflib/nametable.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/wmi/perflib/nametable.go b/wmi/perflib/nametable.go index cdeceaeb..8b7afa48 100644 --- a/wmi/perflib/nametable.go +++ b/wmi/perflib/nametable.go @@ -6,11 +6,6 @@ import ( "strconv" ) -type nameTableLookuper interface { - LookupName() string - LookupHelp() string -} - func (p *perfObjectType) LookupName() string { return CounterNameTable.LookupString(p.ObjectNameTitleIndex) } From fff737998df537dc767fdc9e09c9c578c20ac5dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Mon, 10 Jul 2023 01:58:10 +0200 Subject: [PATCH 03/13] move global Name Tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan-Otto Kröpke --- wmi/perflib/nametable.go | 10 +++++++++- wmi/perflib/perflib.go | 13 ------------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/wmi/perflib/nametable.go b/wmi/perflib/nametable.go index 8b7afa48..3bc44961 100644 --- a/wmi/perflib/nametable.go +++ b/wmi/perflib/nametable.go @@ -6,6 +6,14 @@ import ( "strconv" ) +// Initialize global name tables +// TODO: profiling, add option to disable name tables if necessary +// Not sure if we should resolve the names at all or just have the caller do it on demand +// (for many use cases the index is sufficient) + +var CounterNameTable = *QueryNameTable("Counter 009") +var HelpNameTable = *QueryNameTable("Help 009") + func (p *perfObjectType) LookupName() string { return CounterNameTable.LookupString(p.ObjectNameTitleIndex) } @@ -27,7 +35,7 @@ func (t *NameTable) LookupIndex(str string) uint32 { return t.byString[str] } -// Query a perflib name table from the registry. Specify the type and the language +// QueryNameTable Query a perflib name table from the registry. Specify the type and the language // code (i.e. "Counter 009" or "Help 009") for English language. func QueryNameTable(tableName string) *NameTable { nameTable := new(NameTable) diff --git a/wmi/perflib/perflib.go b/wmi/perflib/perflib.go index 1aadd292..3a64c27c 100644 --- a/wmi/perflib/perflib.go +++ b/wmi/perflib/perflib.go @@ -123,9 +123,6 @@ import ( // TODO: There's a LittleEndian field in the PERF header - we ought to check it var bo = binary.LittleEndian -var CounterNameTable NameTable -var HelpNameTable NameTable - const averageCount64Type = 1073874176 // Top-level performance object (like "Process"). @@ -263,16 +260,6 @@ func queryRawData(query string) ([]byte, error) { } } -func init() { - // Initialize global name tables - // TODO: profiling, add option to disable name tables if necessary - // Not sure if we should resolve the names at all or just have the caller do it on demand - // (for many use cases the index is sufficient) - - CounterNameTable = *QueryNameTable("Counter 009") - HelpNameTable = *QueryNameTable("Help 009") -} - /* Query all performance counters that match a given query. From 81745eeedf2765753a5601560c4d171d6d16d423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Mon, 10 Jul 2023 02:06:04 +0200 Subject: [PATCH 04/13] fix docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan-Otto Kröpke --- wmi/perflib/perflib.go | 11 ++-- wmi/perflib/raw_types.go | 130 +++++++++++++++++++-------------------- wmi/perflib/utf16.go | 4 +- 3 files changed, 73 insertions(+), 72 deletions(-) diff --git a/wmi/perflib/perflib.go b/wmi/perflib/perflib.go index 3a64c27c..f9d27543 100644 --- a/wmi/perflib/perflib.go +++ b/wmi/perflib/perflib.go @@ -1,3 +1,5 @@ +package perflib + /* Go bindings for the HKEY_PERFORMANCE_DATA perflib / Performance Counters interface. @@ -107,7 +109,6 @@ Data for some of the objects is also available through WMI: TotalRequestsPerSecond : 59 UserQuotaViolationsPerSecond : 0 */ -package perflib import ( "bytes" @@ -125,7 +126,7 @@ var bo = binary.LittleEndian const averageCount64Type = 1073874176 -// Top-level performance object (like "Process"). +// PerfObject Top-level performance object (like "Process"). type PerfObject struct { Name string // Same index you pass to QueryPerformanceData @@ -140,7 +141,7 @@ type PerfObject struct { rawData *perfObjectType } -// Each object can have multiple instances. For example, +// PerfInstance Each object can have multiple instances. For example, // In case the object has no instances, we return one single PerfInstance with an empty name. type PerfInstance struct { // *not* resolved using a name table @@ -187,7 +188,7 @@ var ( bufLenCostly = uint32(2000000) ) -// Queries the performance counter buffer using RegQueryValueEx, returning raw bytes. See: +// queryRawData Queries the performance counter buffer using RegQueryValueEx, returning raw bytes. See: // https://msdn.microsoft.com/de-de/library/windows/desktop/aa373219(v=vs.85).aspx func queryRawData(query string) ([]byte, error) { var ( @@ -261,7 +262,7 @@ func queryRawData(query string) ([]byte, error) { } /* -Query all performance counters that match a given query. +QueryPerformanceData Query all performance counters that match a given query. The query can be any of the following: diff --git a/wmi/perflib/raw_types.go b/wmi/perflib/raw_types.go index 0baab304..891bd8ee 100644 --- a/wmi/perflib/raw_types.go +++ b/wmi/perflib/raw_types.go @@ -11,26 +11,26 @@ type binaryReaderFrom interface { } /* -https://msdn.microsoft.com/de-de/library/windows/desktop/aa373157(v=vs.85).aspx +perfDataBlock +See: https://msdn.microsoft.com/de-de/library/windows/desktop/aa373157(v=vs.85).aspx -typedef struct _PERF_DATA_BLOCK { - WCHAR Signature[4]; - DWORD LittleEndian; - DWORD Version; - DWORD Revision; - DWORD TotalByteLength; - DWORD HeaderLength; - DWORD NumObjectTypes; - DWORD DefaultObject; - SYSTEMTIME SystemTime; - LARGE_INTEGER PerfTime; - LARGE_INTEGER PerfFreq; - LARGE_INTEGER PerfTime100nSec; - DWORD SystemNameLength; - DWORD SystemNameOffset; -} PERF_DATA_BLOCK; + typedef struct _PERF_DATA_BLOCK { + WCHAR Signature[4]; + DWORD LittleEndian; + DWORD Version; + DWORD Revision; + DWORD TotalByteLength; + DWORD HeaderLength; + DWORD NumObjectTypes; + DWORD DefaultObject; + SYSTEMTIME SystemTime; + LARGE_INTEGER PerfTime; + LARGE_INTEGER PerfFreq; + LARGE_INTEGER PerfTime100nSec; + DWORD SystemNameLength; + DWORD SystemNameOffset; + } PERF_DATA_BLOCK; */ - type perfDataBlock struct { Signature [4]uint16 LittleEndian uint32 @@ -54,26 +54,26 @@ func (p *perfDataBlock) BinaryReadFrom(r io.Reader) error { } /* -https://msdn.microsoft.com/en-us/library/windows/desktop/aa373160(v=vs.85).aspx +perfObjectType +See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa373160(v=vs.85).aspx -typedef struct _PERF_OBJECT_TYPE { - DWORD TotalByteLength; - DWORD DefinitionLength; - DWORD HeaderLength; - DWORD ObjectNameTitleIndex; - LPWSTR ObjectNameTitle; - DWORD ObjectHelpTitleIndex; - LPWSTR ObjectHelpTitle; - DWORD DetailLevel; - DWORD NumCounters; - DWORD DefaultCounter; - DWORD NumInstances; - DWORD CodePage; - LARGE_INTEGER PerfTime; - LARGE_INTEGER PerfFreq; -} PERF_OBJECT_TYPE; + typedef struct _PERF_OBJECT_TYPE { + DWORD TotalByteLength; + DWORD DefinitionLength; + DWORD HeaderLength; + DWORD ObjectNameTitleIndex; + LPWSTR ObjectNameTitle; + DWORD ObjectHelpTitleIndex; + LPWSTR ObjectHelpTitle; + DWORD DetailLevel; + DWORD NumCounters; + DWORD DefaultCounter; + DWORD NumInstances; + DWORD CodePage; + LARGE_INTEGER PerfTime; + LARGE_INTEGER PerfFreq; + } PERF_OBJECT_TYPE; */ - type perfObjectType struct { TotalByteLength uint32 DefinitionLength uint32 @@ -96,22 +96,22 @@ func (p *perfObjectType) BinaryReadFrom(r io.Reader) error { } /* -https://msdn.microsoft.com/en-us/library/windows/desktop/aa373150(v=vs.85).aspx +perfCounterDefinition +See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa373150(v=vs.85).aspx -typedef struct _PERF_COUNTER_DEFINITION { - DWORD ByteLength; - DWORD CounterNameTitleIndex; - LPWSTR CounterNameTitle; - DWORD CounterHelpTitleIndex; - LPWSTR CounterHelpTitle; - LONG DefaultScale; - DWORD DetailLevel; - DWORD CounterType; - DWORD CounterSize; - DWORD CounterOffset; -} PERF_COUNTER_DEFINITION; + typedef struct _PERF_COUNTER_DEFINITION { + DWORD ByteLength; + DWORD CounterNameTitleIndex; + LPWSTR CounterNameTitle; + DWORD CounterHelpTitleIndex; + LPWSTR CounterHelpTitle; + LONG DefaultScale; + DWORD DetailLevel; + DWORD CounterType; + DWORD CounterSize; + DWORD CounterOffset; + } PERF_COUNTER_DEFINITION; */ - type perfCounterDefinition struct { ByteLength uint32 CounterNameTitleIndex uint32 @@ -138,13 +138,13 @@ func (p *perfCounterDefinition) LookupHelp() string { } /* -https://msdn.microsoft.com/en-us/library/windows/desktop/aa373147(v=vs.85).aspx +perfCounterBlock +See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa373147(v=vs.85).aspx -typedef struct _PERF_COUNTER_BLOCK { - DWORD ByteLength; -} PERF_COUNTER_BLOCK; + typedef struct _PERF_COUNTER_BLOCK { + DWORD ByteLength; + } PERF_COUNTER_BLOCK; */ - type perfCounterBlock struct { ByteLength uint32 } @@ -154,18 +154,18 @@ func (p *perfCounterBlock) BinaryReadFrom(r io.Reader) error { } /* -https://msdn.microsoft.com/en-us/library/windows/desktop/aa373159(v=vs.85).aspx +perfInstanceDefinition +See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa373159(v=vs.85).aspx -typedef struct _PERF_INSTANCE_DEFINITION { - DWORD ByteLength; - DWORD ParentObjectTitleIndex; - DWORD ParentObjectInstance; - DWORD UniqueID; - DWORD NameOffset; - DWORD NameLength; -} PERF_INSTANCE_DEFINITION; + typedef struct _PERF_INSTANCE_DEFINITION { + DWORD ByteLength; + DWORD ParentObjectTitleIndex; + DWORD ParentObjectInstance; + DWORD UniqueID; + DWORD NameOffset; + DWORD NameLength; + } PERF_INSTANCE_DEFINITION; */ - type perfInstanceDefinition struct { ByteLength uint32 ParentObjectTitleIndex uint32 diff --git a/wmi/perflib/utf16.go b/wmi/perflib/utf16.go index 3b0cec9e..003bd620 100644 --- a/wmi/perflib/utf16.go +++ b/wmi/perflib/utf16.go @@ -6,7 +6,7 @@ import ( "syscall" ) -// Read an unterminated UTF16 string at a given position, specifying its length +// readUTF16StringAtPos Read an unterminated UTF16 string at a given position, specifying its length func readUTF16StringAtPos(r io.ReadSeeker, absPos int64, length uint32) (string, error) { value := make([]uint16, length/2) _, err := r.Seek(absPos, io.SeekStart) @@ -24,7 +24,7 @@ func readUTF16StringAtPos(r io.ReadSeeker, absPos int64, length uint32) (string, return syscall.UTF16ToString(value), nil } -// Reads a null-terminated UTF16 string at the current offset +// readUTF16String Reads a null-terminated UTF16 string at the current offset func readUTF16String(r io.Reader) (string, error) { var err error From ad1ab3539969603e469fc9cdec52ed810b3beadc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Mon, 10 Jul 2023 02:07:49 +0200 Subject: [PATCH 05/13] remove SortObjects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan-Otto Kröpke --- wmi/perflib/perflib.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/wmi/perflib/perflib.go b/wmi/perflib/perflib.go index f9d27543..74da4a72 100644 --- a/wmi/perflib/perflib.go +++ b/wmi/perflib/perflib.go @@ -115,7 +115,6 @@ import ( "encoding/binary" "fmt" "io" - "sort" "strings" "syscall" "unsafe" @@ -450,12 +449,3 @@ func convertCounterValue(counterDef *perfCounterDefinition, buffer []byte, value return } - -// Sort slice of objects by index. This is useful for displaying -// a human-readable list or dump, but unnecessary otherwise. -func SortObjects(p []*PerfObject) { - sort.Slice(p, func(i, j int) bool { - return p[i].NameIndex < p[j].NameIndex - }) - -} From 9e368d49e77504b560d3fc9eccf4d88e639efdfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Mon, 10 Jul 2023 02:12:22 +0200 Subject: [PATCH 06/13] add error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan-Otto Kröpke --- wmi/perflib/perflib.go | 54 ++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/wmi/perflib/perflib.go b/wmi/perflib/perflib.go index 74da4a72..33bf0df3 100644 --- a/wmi/perflib/perflib.go +++ b/wmi/perflib/perflib.go @@ -305,10 +305,16 @@ func QueryPerformanceData(query string) ([]*PerfObject, error) { objOffset := int64(header.HeaderLength) for i := 0; i < numObjects; i++ { - r.Seek(objOffset, io.SeekStart) + _, err := r.Seek(objOffset, io.SeekStart) + if err != nil { + return nil, err + } obj := new(perfObjectType) - obj.BinaryReadFrom(r) + err = obj.BinaryReadFrom(r) + if err != nil { + return nil, err + } numCounterDefs := int(obj.NumCounters) numInstances := int(obj.NumInstances) @@ -336,7 +342,10 @@ func QueryPerformanceData(query string) ([]*PerfObject, error) { for i := 0; i < numCounterDefs; i++ { def := new(perfCounterDefinition) - def.BinaryReadFrom(r) + err := def.BinaryReadFrom(r) + if err != nil { + return nil, err + } counterDefs[i] = &PerfCounterDef{ Name: def.LookupName(), @@ -356,9 +365,15 @@ func QueryPerformanceData(query string) ([]*PerfObject, error) { if obj.NumInstances <= 0 { blockOffset := objOffset + int64(obj.DefinitionLength) - r.Seek(blockOffset, io.SeekStart) + _, err := r.Seek(blockOffset, io.SeekStart) + if err != nil { + return nil, err + } - _, counters := parseCounterBlock(buffer, r, blockOffset, counterDefs) + _, counters, err := parseCounterBlock(buffer, r, blockOffset, counterDefs) + if err != nil { + return nil, err + } instances[0] = &PerfInstance{ Name: "", @@ -370,14 +385,23 @@ func QueryPerformanceData(query string) ([]*PerfObject, error) { instOffset := objOffset + int64(obj.DefinitionLength) for i := 0; i < numInstances; i++ { - r.Seek(instOffset, io.SeekStart) + _, err := r.Seek(instOffset, io.SeekStart) + if err != nil { + return nil, err + } inst := new(perfInstanceDefinition) - inst.BinaryReadFrom(r) + err = inst.BinaryReadFrom(r) + if err != nil { + return nil, err + } name, _ := readUTF16StringAtPos(r, instOffset+int64(inst.NameOffset), inst.NameLength) pos := instOffset + int64(inst.ByteLength) - offset, counters := parseCounterBlock(buffer, r, pos, counterDefs) + offset, counters, err := parseCounterBlock(buffer, r, pos, counterDefs) + if err != nil { + return nil, err + } instances[i] = &PerfInstance{ Name: name, @@ -396,10 +420,16 @@ func QueryPerformanceData(query string) ([]*PerfObject, error) { return objects, nil } -func parseCounterBlock(b []byte, r io.ReadSeeker, pos int64, defs []*PerfCounterDef) (int64, []*PerfCounter) { - r.Seek(pos, io.SeekStart) +func parseCounterBlock(b []byte, r io.ReadSeeker, pos int64, defs []*PerfCounterDef) (int64, []*PerfCounter, error) { + _, err := r.Seek(pos, io.SeekStart) + if err != nil { + return 0, nil, err + } block := new(perfCounterBlock) - block.BinaryReadFrom(r) + err = block.BinaryReadFrom(r) + if err != nil { + return 0, nil, err + } counters := make([]*PerfCounter, len(defs)) @@ -419,7 +449,7 @@ func parseCounterBlock(b []byte, r io.ReadSeeker, pos int64, defs []*PerfCounter } } - return int64(block.ByteLength), counters + return int64(block.ByteLength), counters, nil } func convertCounterValue(counterDef *perfCounterDefinition, buffer []byte, valueOffset int64) (value int64) { From 976e055252cb1fdf1e7355d669ca4c7cfe055fe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Mon, 10 Jul 2023 02:17:24 +0200 Subject: [PATCH 07/13] move directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan-Otto Kröpke --- collector/collector.go | 3 ++- collector/perflib_test.go | 2 +- {wmi/perflib => perflib}/const.go | 0 {wmi/perflib => perflib}/nametable.go | 2 -- {wmi/perflib => perflib}/perflib.go | 0 {wmi/perflib => perflib}/perflib_test.go | 0 {wmi/perflib => perflib}/raw_types.go | 0 {wmi/perflib => perflib}/utf16.go | 0 8 files changed, 3 insertions(+), 4 deletions(-) rename {wmi/perflib => perflib}/const.go (100%) rename {wmi/perflib => perflib}/nametable.go (99%) rename {wmi/perflib => perflib}/perflib.go (100%) rename {wmi/perflib => perflib}/perflib_test.go (100%) rename {wmi/perflib => perflib}/raw_types.go (100%) rename {wmi/perflib => perflib}/utf16.go (100%) diff --git a/collector/collector.go b/collector/collector.go index 358179f5..90d33765 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -6,10 +6,11 @@ import ( "strconv" "strings" + "github.com/prometheus-community/windows_exporter/perflib" + "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/prometheus-community/windows_exporter/wmi/perflib" "github.com/prometheus/client_golang/prometheus" "golang.org/x/sys/windows/registry" ) diff --git a/collector/perflib_test.go b/collector/perflib_test.go index 6126c648..ee5fe0db 100644 --- a/collector/perflib_test.go +++ b/collector/perflib_test.go @@ -4,7 +4,7 @@ import ( "reflect" "testing" - "github.com/prometheus-community/windows_exporter/wmi/perflib" + "github.com/prometheus-community/windows_exporter/perflib" "github.com/go-kit/log" ) diff --git a/wmi/perflib/const.go b/perflib/const.go similarity index 100% rename from wmi/perflib/const.go rename to perflib/const.go diff --git a/wmi/perflib/nametable.go b/perflib/nametable.go similarity index 99% rename from wmi/perflib/nametable.go rename to perflib/nametable.go index 3bc44961..64ca6ebd 100644 --- a/wmi/perflib/nametable.go +++ b/perflib/nametable.go @@ -48,13 +48,11 @@ func QueryNameTable(tableName string) *NameTable { r := bytes.NewReader(buffer) for { index, err := readUTF16String(r) - if err != nil { break } desc, err := readUTF16String(r) - if err != nil { break } diff --git a/wmi/perflib/perflib.go b/perflib/perflib.go similarity index 100% rename from wmi/perflib/perflib.go rename to perflib/perflib.go diff --git a/wmi/perflib/perflib_test.go b/perflib/perflib_test.go similarity index 100% rename from wmi/perflib/perflib_test.go rename to perflib/perflib_test.go diff --git a/wmi/perflib/raw_types.go b/perflib/raw_types.go similarity index 100% rename from wmi/perflib/raw_types.go rename to perflib/raw_types.go diff --git a/wmi/perflib/utf16.go b/perflib/utf16.go similarity index 100% rename from wmi/perflib/utf16.go rename to perflib/utf16.go From 8b9c9a5bd2ced7936de1f3d1eb0265850d2dee1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Mon, 10 Jul 2023 02:26:44 +0200 Subject: [PATCH 08/13] Remove HelpNameTable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan-Otto Kröpke --- perflib/nametable.go | 5 ----- perflib/perflib.go | 35 +++++++++++------------------------ perflib/raw_types.go | 4 ---- 3 files changed, 11 insertions(+), 33 deletions(-) diff --git a/perflib/nametable.go b/perflib/nametable.go index 64ca6ebd..cd717e4f 100644 --- a/perflib/nametable.go +++ b/perflib/nametable.go @@ -12,16 +12,11 @@ import ( // (for many use cases the index is sufficient) var CounterNameTable = *QueryNameTable("Counter 009") -var HelpNameTable = *QueryNameTable("Help 009") func (p *perfObjectType) LookupName() string { return CounterNameTable.LookupString(p.ObjectNameTitleIndex) } -func (p *perfObjectType) LookupHelp() string { - return HelpNameTable.LookupString(p.ObjectHelpTitleIndex) -} - type NameTable struct { byIndex map[uint32]string byString map[string]uint32 diff --git a/perflib/perflib.go b/perflib/perflib.go index 33bf0df3..2b3c462d 100644 --- a/perflib/perflib.go +++ b/perflib/perflib.go @@ -127,13 +127,9 @@ const averageCount64Type = 1073874176 // PerfObject Top-level performance object (like "Process"). type PerfObject struct { - Name string - // Same index you pass to QueryPerformanceData - NameIndex uint - HelpText string - HelpTextIndex uint - Instances []*PerfInstance - CounterDefs []*PerfCounterDef + Name string + Instances []*PerfInstance + CounterDefs []*PerfCounterDef Frequency int64 @@ -152,10 +148,7 @@ type PerfInstance struct { } type PerfCounterDef struct { - Name string - NameIndex uint - HelpText string - HelpTextIndex uint + Name string // For debugging - subject to removal. CounterType is a perflib // implementation detail (see perflib.h) and should not be used outside @@ -330,14 +323,11 @@ func QueryPerformanceData(query string) ([]*PerfObject, error) { counterDefs := make([]*PerfCounterDef, numCounterDefs) objects[i] = &PerfObject{ - Name: obj.LookupName(), - NameIndex: uint(obj.ObjectNameTitleIndex), - HelpText: obj.LookupHelp(), - HelpTextIndex: uint(obj.ObjectHelpTitleIndex), - Instances: instances, - CounterDefs: counterDefs, - Frequency: obj.PerfFreq, - rawData: obj, + Name: obj.LookupName(), + Instances: instances, + CounterDefs: counterDefs, + Frequency: obj.PerfFreq, + rawData: obj, } for i := 0; i < numCounterDefs; i++ { @@ -348,11 +338,8 @@ func QueryPerformanceData(query string) ([]*PerfObject, error) { } counterDefs[i] = &PerfCounterDef{ - Name: def.LookupName(), - NameIndex: uint(def.CounterNameTitleIndex), - HelpText: def.LookupHelp(), - HelpTextIndex: uint(def.CounterHelpTitleIndex), - rawData: def, + Name: def.LookupName(), + rawData: def, CounterType: def.CounterType, diff --git a/perflib/raw_types.go b/perflib/raw_types.go index 891bd8ee..f9d76a7d 100644 --- a/perflib/raw_types.go +++ b/perflib/raw_types.go @@ -133,10 +133,6 @@ func (p *perfCounterDefinition) LookupName() string { return CounterNameTable.LookupString(p.CounterNameTitleIndex) } -func (p *perfCounterDefinition) LookupHelp() string { - return HelpNameTable.LookupString(p.CounterHelpTitleIndex) -} - /* perfCounterBlock See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa373147(v=vs.85).aspx From 3a61935273b43c43a11421245a23ced82cb6b08e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Mon, 10 Jul 2023 02:26:53 +0200 Subject: [PATCH 09/13] Cleanup binaryReaderFrom MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan-Otto Kröpke --- perflib/perflib.go | 5 +---- perflib/raw_types.go | 4 ---- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/perflib/perflib.go b/perflib/perflib.go index 2b3c462d..399de3fd 100644 --- a/perflib/perflib.go +++ b/perflib/perflib.go @@ -173,7 +173,7 @@ type PerfCounter struct { } // Error value returned by RegQueryValueEx if the buffer isn't sufficiently large -const errorMoreData = syscall.Errno(234) +const errorMoreData = syscall.Errno(syscall.ERROR_MORE_DATA) var ( bufLenGlobal = uint32(400000) @@ -209,8 +209,6 @@ func queryRawData(query string) ([]byte, error) { return nil, fmt.Errorf("failed to encode query string: %v", err) } - defer syscall.RegCloseKey(syscall.HKEY_PERFORMANCE_DATA) - for { bufLen := uint32(len(buffer)) @@ -226,7 +224,6 @@ func queryRawData(query string) ([]byte, error) { newBuffer := make([]byte, len(buffer)+16384) copy(newBuffer, buffer) buffer = newBuffer - syscall.RegCloseKey(syscall.HKEY_PERFORMANCE_DATA) continue } else if err != nil { if errno, ok := err.(syscall.Errno); ok { diff --git a/perflib/raw_types.go b/perflib/raw_types.go index f9d76a7d..5939b7da 100644 --- a/perflib/raw_types.go +++ b/perflib/raw_types.go @@ -6,10 +6,6 @@ import ( "syscall" ) -type binaryReaderFrom interface { - BinaryReadFrom(r io.Reader) error -} - /* perfDataBlock See: https://msdn.microsoft.com/de-de/library/windows/desktop/aa373157(v=vs.85).aspx From 9ef897e07b3cb86542f263e58af02667d5bb11fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Mon, 10 Jul 2023 02:56:17 +0200 Subject: [PATCH 10/13] Add LICENSE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan-Otto Kröpke --- perflib/LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 perflib/LICENSE diff --git a/perflib/LICENSE b/perflib/LICENSE new file mode 100644 index 00000000..169f2ab9 --- /dev/null +++ b/perflib/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018 Leopold Schabel / The perflib_exporter authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 9b5bc37a42a2709d4799128a24f0ece3976bc3d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Mon, 10 Jul 2023 03:02:46 +0200 Subject: [PATCH 11/13] Re-add NameIndex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan-Otto Kröpke --- perflib/perflib.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/perflib/perflib.go b/perflib/perflib.go index 399de3fd..b4366aba 100644 --- a/perflib/perflib.go +++ b/perflib/perflib.go @@ -127,7 +127,9 @@ const averageCount64Type = 1073874176 // PerfObject Top-level performance object (like "Process"). type PerfObject struct { - Name string + Name string + // NameIndex Same index you pass to QueryPerformanceData + NameIndex uint Instances []*PerfInstance CounterDefs []*PerfCounterDef @@ -148,7 +150,8 @@ type PerfInstance struct { } type PerfCounterDef struct { - Name string + Name string + NameIndex uint // For debugging - subject to removal. CounterType is a perflib // implementation detail (see perflib.h) and should not be used outside @@ -321,6 +324,7 @@ func QueryPerformanceData(query string) ([]*PerfObject, error) { objects[i] = &PerfObject{ Name: obj.LookupName(), + NameIndex: uint(obj.ObjectNameTitleIndex), Instances: instances, CounterDefs: counterDefs, Frequency: obj.PerfFreq, @@ -335,8 +339,9 @@ func QueryPerformanceData(query string) ([]*PerfObject, error) { } counterDefs[i] = &PerfCounterDef{ - Name: def.LookupName(), - rawData: def, + Name: def.LookupName(), + NameIndex: uint(def.CounterNameTitleIndex), + rawData: def, CounterType: def.CounterType, From 11218a95d08f5f508bc27aba23278af93a56480d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Mon, 10 Jul 2023 13:59:57 +0200 Subject: [PATCH 12/13] Implement Lazy Loading of NameTable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan-Otto Kröpke --- collector/perflib.go | 4 +-- perflib/nametable.go | 86 ++++++++++++++++++++++++-------------------- perflib/perflib.go | 5 +-- 3 files changed, 50 insertions(+), 45 deletions(-) diff --git a/collector/perflib.go b/collector/perflib.go index ab646480..743c797d 100644 --- a/collector/perflib.go +++ b/collector/perflib.go @@ -12,10 +12,8 @@ import ( "github.com/go-kit/log/level" ) -var nametable = perflib.CounterNameTable - func MapCounterToIndex(name string) string { - return strconv.Itoa(int(nametable.LookupIndex(name))) + return strconv.Itoa(int(perflib.CounterNameTable.LookupIndex(name))) } func getPerflibSnapshot(objNames string) (map[string]*perflib.PerfObject, error) { diff --git a/perflib/nametable.go b/perflib/nametable.go index cd717e4f..b10a7610 100644 --- a/perflib/nametable.go +++ b/perflib/nametable.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "strconv" + "sync" ) // Initialize global name tables @@ -18,54 +19,63 @@ func (p *perfObjectType) LookupName() string { } type NameTable struct { - byIndex map[uint32]string - byString map[string]uint32 + once sync.Once + + name string + + table struct { + index map[uint32]string + string map[string]uint32 + } } func (t *NameTable) LookupString(index uint32) string { - return t.byIndex[index] + t.initialize() + return t.table.index[index] } func (t *NameTable) LookupIndex(str string) uint32 { - return t.byString[str] + t.initialize() + return t.table.string[str] } // QueryNameTable Query a perflib name table from the registry. Specify the type and the language // code (i.e. "Counter 009" or "Help 009") for English language. func QueryNameTable(tableName string) *NameTable { - nameTable := new(NameTable) - nameTable.byIndex = make(map[uint32]string) - - buffer, err := queryRawData(tableName) - if err != nil { - panic(err) + return &NameTable{ + name: tableName, } - r := bytes.NewReader(buffer) - for { - index, err := readUTF16String(r) - if err != nil { - break - } - - desc, err := readUTF16String(r) - if err != nil { - break - } - - indexInt, _ := strconv.Atoi(index) - - if err != nil { - panic(fmt.Sprint("Invalid index ", index)) - } - - nameTable.byIndex[uint32(indexInt)] = desc - } - - nameTable.byString = make(map[string]uint32) - - for k, v := range nameTable.byIndex { - nameTable.byString[v] = k - } - - return nameTable +} + +func (t *NameTable) initialize() { + t.once.Do(func() { + t.table.index = make(map[uint32]string) + t.table.string = make(map[string]uint32) + + buffer, err := queryRawData(t.name) + if err != nil { + panic(err) + } + r := bytes.NewReader(buffer) + for { + index, err := readUTF16String(r) + if err != nil { + break + } + + desc, err := readUTF16String(r) + if err != nil { + break + } + + if err != nil { + panic(fmt.Sprint("Invalid index ", index)) + } + + indexInt, _ := strconv.Atoi(index) + + t.table.index[uint32(indexInt)] = desc + t.table.string[desc] = uint32(indexInt) + } + }) } diff --git a/perflib/perflib.go b/perflib/perflib.go index b4366aba..e6e1d78c 100644 --- a/perflib/perflib.go +++ b/perflib/perflib.go @@ -175,9 +175,6 @@ type PerfCounter struct { SecondValue int64 } -// Error value returned by RegQueryValueEx if the buffer isn't sufficiently large -const errorMoreData = syscall.Errno(syscall.ERROR_MORE_DATA) - var ( bufLenGlobal = uint32(400000) bufLenCostly = uint32(2000000) @@ -223,7 +220,7 @@ func queryRawData(query string) ([]byte, error) { (*byte)(unsafe.Pointer(&buffer[0])), &bufLen) - if err == errorMoreData { + if err == error(syscall.ERROR_MORE_DATA) { newBuffer := make([]byte, len(buffer)+16384) copy(newBuffer, buffer) buffer = newBuffer From 9e59bf920fe98e0048611efa82b7c8fb66e0ee14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Sat, 15 Jul 2023 10:05:51 +0200 Subject: [PATCH 13/13] Post rebase issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan-Otto Kröpke --- collector/perflib.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collector/perflib.go b/collector/perflib.go index 743c797d..47f0d597 100644 --- a/collector/perflib.go +++ b/collector/perflib.go @@ -6,7 +6,7 @@ import ( "strconv" "strings" - "github.com/prometheus-community/windows_exporter/wmi/perflib" + "github.com/prometheus-community/windows_exporter/perflib" "github.com/go-kit/log" "github.com/go-kit/log/level"