From cc974cab3b06419c417259c44b1ba8536b4f36ff Mon Sep 17 00:00:00 2001 From: Yuri Shkuro Date: Tue, 21 Jun 2022 17:17:32 -0400 Subject: [PATCH] Copy expvar metrics implementation from jaeger-lib (#3772) Signed-off-by: Albert Teoh --- go.mod | 4 +- go.sum | 19 +++ internal/metrics/expvar/adapter.go | 84 -------------- internal/metrics/expvar/adapter_test.go | 33 ------ internal/metrics/expvar/cache.go | 83 ++++++++++++++ internal/metrics/expvar/cache_test.go | 54 +++++++++ internal/metrics/expvar/factory.go | 114 +++++++++++++++++- internal/metrics/expvar/factory_test.go | 146 ++++++++++++++++++++++++ internal/metrics/expvar/metrics.go | 82 +++++++++++++ internal/metrics/expvar/metrics_test.go | 54 +++++++++ 10 files changed, 551 insertions(+), 122 deletions(-) delete mode 100644 internal/metrics/expvar/adapter.go delete mode 100644 internal/metrics/expvar/adapter_test.go create mode 100644 internal/metrics/expvar/cache.go create mode 100644 internal/metrics/expvar/cache_test.go create mode 100644 internal/metrics/expvar/factory_test.go create mode 100644 internal/metrics/expvar/metrics.go create mode 100644 internal/metrics/expvar/metrics_test.go diff --git a/go.mod b/go.mod index fb27d687d7f..ecdb9b43f69 100644 --- a/go.mod +++ b/go.mod @@ -59,7 +59,7 @@ require ( ) require ( - github.com/HdrHistogram/hdrhistogram-go v1.0.1 // indirect + github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect github.com/VividCortex/gohistogram v1.0.0 // indirect github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect github.com/benbjohnson/clock v1.3.0 // indirect @@ -75,7 +75,7 @@ require ( github.com/eapache/queue v1.1.0 // indirect github.com/fatih/color v1.13.0 // indirect github.com/felixge/httpsnoop v1.0.2 // indirect - github.com/go-kit/kit v0.11.0 // indirect + github.com/go-kit/kit v0.12.0 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.21.2 // indirect diff --git a/go.sum b/go.sum index 58e28938455..2215925eabf 100644 --- a/go.sum +++ b/go.sum @@ -43,6 +43,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/HdrHistogram/hdrhistogram-go v1.0.1 h1:GX8GAYDuhlFQnI2fRDHQhTlkHMz8bEn0jTI6LJU0mpw= github.com/HdrHistogram/hdrhistogram-go v1.0.1/go.mod h1:BWJ+nMSHY3L41Zj7CA3uXnloDp7xxV0YvstAE7nKTaM= +github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= +github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -58,6 +60,7 @@ github.com/Shopify/toxiproxy/v2 v2.3.0/go.mod h1:KvQTtB6RjCJY4zqNJn7C7JDFgsG5uoH github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 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= @@ -174,6 +177,7 @@ github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o= github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= @@ -194,6 +198,8 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.11.0 h1:IGmIEl7aHTYh6E2HlT+ptILBotjo4xl8PMDl852etiI= github.com/go-kit/kit v0.11.0/go.mod h1:73/6Ixaufkvb5Osvkls8C79vuQ49Ba1rUEUYNSf+FUw= +github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= +github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= @@ -274,6 +280,7 @@ github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6x github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -449,6 +456,7 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X 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/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -801,7 +809,10 @@ golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= @@ -811,6 +822,7 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1002,8 +1014,10 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/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-20190206041539-40960b6deb8e/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-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -1064,6 +1078,10 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -1216,6 +1234,7 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt 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= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/internal/metrics/expvar/adapter.go b/internal/metrics/expvar/adapter.go deleted file mode 100644 index 5baa587d54a..00000000000 --- a/internal/metrics/expvar/adapter.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2022 The Jaeger Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package expvar - -import ( - jlibmetrics "github.com/uber/jaeger-lib/metrics" - - "github.com/jaegertracing/jaeger/pkg/metrics" -) - -// adapter is temporary type used to bridge metrics API in this package -// with that of jaeger-lib. -type adapter struct { - f jlibmetrics.Factory -} - -var _ metrics.Factory = (*adapter)(nil) - -func newAdapter(f jlibmetrics.Factory) *adapter { - return &adapter{f: f} -} - -// Counter creates a Counter. -func (a *adapter) Counter(opts metrics.Options) metrics.Counter { - return a.f.Counter(jlibmetrics.Options{ - Name: opts.Name, - Tags: opts.Tags, - Help: opts.Help, - }) -} - -// Timer creates a Timer. -func (a *adapter) Timer(opts metrics.TimerOptions) metrics.Timer { - return a.f.Timer(jlibmetrics.TimerOptions{ - Name: opts.Name, - Tags: opts.Tags, - Help: opts.Help, - Buckets: opts.Buckets, - }) -} - -// Gauge creates a Gauge. -func (a *adapter) Gauge(opts metrics.Options) metrics.Gauge { - return a.f.Gauge(jlibmetrics.Options{ - Name: opts.Name, - Tags: opts.Tags, - Help: opts.Help, - }) -} - -// Histogram creates a Histogram. -func (a *adapter) Histogram(opts metrics.HistogramOptions) metrics.Histogram { - return a.f.Histogram(jlibmetrics.HistogramOptions{ - Name: opts.Name, - Tags: opts.Tags, - Help: opts.Help, - Buckets: opts.Buckets, - }) -} - -// Namespace creates a Namespace. -func (a *adapter) Namespace(opts metrics.NSOptions) metrics.Factory { - return &adapter{f: a.f.Namespace(jlibmetrics.NSOptions{ - Name: opts.Name, - Tags: opts.Tags, - })} -} - -// Unwrap returns underlying jaeger-lib factory. -func (a *adapter) Unwrap() jlibmetrics.Factory { - return a.f -} diff --git a/internal/metrics/expvar/adapter_test.go b/internal/metrics/expvar/adapter_test.go deleted file mode 100644 index cf2ffeb5835..00000000000 --- a/internal/metrics/expvar/adapter_test.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2022 The Jaeger Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package expvar - -import ( - "testing" - - jlibmetrics "github.com/uber/jaeger-lib/metrics" - - "github.com/jaegertracing/jaeger/pkg/metrics" -) - -func TestAdapter(t *testing.T) { - f := newAdapter(jlibmetrics.NullFactory) - f.Counter(metrics.Options{}) - f.Timer(metrics.TimerOptions{}) - f.Gauge(metrics.Options{}) - f.Histogram(metrics.HistogramOptions{}) - f.Namespace(metrics.NSOptions{}) - f.Unwrap() -} diff --git a/internal/metrics/expvar/cache.go b/internal/metrics/expvar/cache.go new file mode 100644 index 00000000000..f25ddba563b --- /dev/null +++ b/internal/metrics/expvar/cache.go @@ -0,0 +1,83 @@ +// Copyright (c) 2022 The Jaeger Authors. +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package expvar + +import ( + "sync" + + "github.com/jaegertracing/jaeger/pkg/metrics" +) + +type cache struct { + lock sync.Mutex + counters map[string]metrics.Counter + gauges map[string]metrics.Gauge + timers map[string]metrics.Timer + histograms map[string]metrics.Histogram +} + +func newCache() *cache { + return &cache{ + counters: make(map[string]metrics.Counter), + gauges: make(map[string]metrics.Gauge), + timers: make(map[string]metrics.Timer), + histograms: make(map[string]metrics.Histogram), + } +} + +func (r *cache) getOrSetCounter(name string, create func() metrics.Counter) metrics.Counter { + r.lock.Lock() + defer r.lock.Unlock() + c, ok := r.counters[name] + if !ok { + c = create() + r.counters[name] = c + } + return c +} + +func (r *cache) getOrSetGauge(name string, create func() metrics.Gauge) metrics.Gauge { + r.lock.Lock() + defer r.lock.Unlock() + g, ok := r.gauges[name] + if !ok { + g = create() + r.gauges[name] = g + } + return g +} + +func (r *cache) getOrSetTimer(name string, create func() metrics.Timer) metrics.Timer { + r.lock.Lock() + defer r.lock.Unlock() + t, ok := r.timers[name] + if !ok { + t = create() + r.timers[name] = t + } + return t +} + +func (r *cache) getOrSetHistogram(name string, create func() metrics.Histogram) metrics.Histogram { + r.lock.Lock() + defer r.lock.Unlock() + t, ok := r.histograms[name] + if !ok { + t = create() + r.histograms[name] = t + } + return t +} diff --git a/internal/metrics/expvar/cache_test.go b/internal/metrics/expvar/cache_test.go new file mode 100644 index 00000000000..bfdee81a864 --- /dev/null +++ b/internal/metrics/expvar/cache_test.go @@ -0,0 +1,54 @@ +// Copyright (c) 2022 The Jaeger Authors. +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package expvar + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/jaegertracing/jaeger/internal/metricstest" + "github.com/jaegertracing/jaeger/pkg/metrics" +) + +func TestCache(t *testing.T) { + f := metricstest.NewFactory(100 * time.Second) + c1 := f.Counter(metrics.Options{Name: "x"}) + g1 := f.Gauge(metrics.Options{Name: "y"}) + t1 := f.Timer(metrics.TimerOptions{Name: "z"}) + h1 := f.Histogram(metrics.HistogramOptions{Name: "h"}) + + c := newCache() + + c2 := c.getOrSetCounter("x", func() metrics.Counter { return c1 }) + assert.Equal(t, c1, c2) + g2 := c.getOrSetGauge("y", func() metrics.Gauge { return g1 }) + assert.Equal(t, g1, g2) + t2 := c.getOrSetTimer("z", func() metrics.Timer { return t1 }) + assert.Equal(t, t1, t2) + h2 := c.getOrSetHistogram("h", func() metrics.Histogram { return h1 }) + assert.Equal(t, h1, h2) + + c3 := c.getOrSetCounter("x", func() metrics.Counter { panic("c1") }) + assert.Equal(t, c1, c3) + g3 := c.getOrSetGauge("y", func() metrics.Gauge { panic("g1") }) + assert.Equal(t, g1, g3) + t3 := c.getOrSetTimer("z", func() metrics.Timer { panic("t1") }) + assert.Equal(t, t1, t3) + h3 := c.getOrSetHistogram("h", func() metrics.Histogram { panic("h1") }) + assert.Equal(t, h1, h3) +} diff --git a/internal/metrics/expvar/factory.go b/internal/metrics/expvar/factory.go index aca574a0cfc..6ce562e5ef1 100644 --- a/internal/metrics/expvar/factory.go +++ b/internal/metrics/expvar/factory.go @@ -1,4 +1,5 @@ // Copyright (c) 2022 The Jaeger Authors. +// Copyright (c) 2018 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,12 +16,119 @@ package expvar import ( - "github.com/uber/jaeger-lib/metrics/expvar" + "sort" + + kexpvar "github.com/go-kit/kit/metrics/expvar" "github.com/jaegertracing/jaeger/pkg/metrics" ) -// NewFactory creates metrics.Factory for expvar. +// NewFactory creates a new metrics factory using go-kit expvar package. +// buckets is the number of buckets to be used in histograms. +// Custom buckets passed via options are not supported. func NewFactory(buckets int) metrics.Factory { - return newAdapter(expvar.NewFactory(buckets)) + return &factory{ + buckets: buckets, + scope: "", + scopeSep: ".", + tagsSep: ".", + tagKVSep: "_", + cache: newCache(), + } +} + +type factory struct { + buckets int + + scope string + tags map[string]string + scopeSep string + tagsSep string + tagKVSep string + cache *cache +} + +var _ metrics.Factory = (*factory)(nil) + +func (f *factory) subScope(name string) string { + if f.scope == "" { + return name + } + if name == "" { + return f.scope + } + return f.scope + f.scopeSep + name +} + +func (f *factory) mergeTags(tags map[string]string) map[string]string { + ret := make(map[string]string, len(f.tags)+len(tags)) + for k, v := range f.tags { + ret[k] = v + } + for k, v := range tags { + ret[k] = v + } + return ret +} + +func (f *factory) getKey(name string, tags map[string]string) string { + fullName := f.subScope(name) + fullTags := f.mergeTags(tags) + return makeKey(fullName, fullTags, f.tagsSep, f.tagKVSep) +} + +// getKey converts name+tags into a single string of the form +// "name|tag1=value1|...|tagN=valueN", where tag names are +// sorted alphabetically. +func makeKey(name string, tags map[string]string, tagsSep string, tagKVSep string) string { + keys := make([]string, 0, len(tags)) + for k := range tags { + keys = append(keys, k) + } + sort.Strings(keys) + key := name + for _, k := range keys { + key = key + tagsSep + k + tagKVSep + tags[k] + } + return key +} + +func (f *factory) Counter(options metrics.Options) metrics.Counter { + key := f.getKey(options.Name, options.Tags) + return f.cache.getOrSetCounter(key, func() metrics.Counter { + return NewCounter(kexpvar.NewCounter(key)) + }) +} + +func (f *factory) Gauge(options metrics.Options) metrics.Gauge { + key := f.getKey(options.Name, options.Tags) + return f.cache.getOrSetGauge(key, func() metrics.Gauge { + return NewGauge(kexpvar.NewGauge(key)) + }) +} + +func (f *factory) Timer(options metrics.TimerOptions) metrics.Timer { + key := f.getKey(options.Name, options.Tags) + return f.cache.getOrSetTimer(key, func() metrics.Timer { + return NewTimer(kexpvar.NewHistogram(key, f.buckets)) + }) +} + +func (f *factory) Histogram(options metrics.HistogramOptions) metrics.Histogram { + key := f.getKey(options.Name, options.Tags) + return f.cache.getOrSetHistogram(key, func() metrics.Histogram { + return NewHistogram(kexpvar.NewHistogram(key, f.buckets)) + }) +} + +func (f *factory) Namespace(options metrics.NSOptions) metrics.Factory { + return &factory{ + buckets: f.buckets, + scope: f.subScope(options.Name), + tags: f.mergeTags(options.Tags), + scopeSep: f.scopeSep, + tagsSep: f.tagsSep, + tagKVSep: f.tagKVSep, + cache: f.cache, + } } diff --git a/internal/metrics/expvar/factory_test.go b/internal/metrics/expvar/factory_test.go new file mode 100644 index 00000000000..5486a6ac81f --- /dev/null +++ b/internal/metrics/expvar/factory_test.go @@ -0,0 +1,146 @@ +// Copyright (c) 2022 The Jaeger Authors. +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package expvar + +import ( + "expvar" + "fmt" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/jaegertracing/jaeger/pkg/metrics" +) + +var ( + id = time.Now().UnixNano() + prefix = fmt.Sprintf("test_%d", id) + counterPrefix = prefix + "_counter_" + gaugePrefix = prefix + "_gauge_" + timerPrefix = prefix + "_timer_" + histogramPrefix = prefix + "_histogram_" + + tagsA = map[string]string{"a": "b"} + tagsX = map[string]string{"x": "y"} +) + +func TestFactory(t *testing.T) { + buckets := []float64{10, 20, 30, 40, 50, 60} + testCases := []struct { + name string + tags map[string]string + buckets []float64 + durationBuckets []time.Duration + namespace string + nsTags map[string]string + fullName string + expectedCounter string + }{ + {name: "x", fullName: "%sx", buckets: buckets}, + {tags: tagsX, fullName: "%s.x_y", buckets: buckets}, + {name: "x", tags: tagsA, fullName: "%sx.a_b", buckets: buckets}, + {namespace: "y", fullName: "y.%s", buckets: buckets}, + {nsTags: tagsA, fullName: "%s.a_b", buckets: buckets}, + {namespace: "y", nsTags: tagsX, fullName: "y.%s.x_y", buckets: buckets}, + {name: "x", namespace: "y", nsTags: tagsX, fullName: "y.%sx.x_y", buckets: buckets}, + {name: "x", tags: tagsX, namespace: "y", nsTags: tagsX, fullName: "y.%sx.x_y", expectedCounter: "84", buckets: buckets}, + {name: "x", tags: tagsA, namespace: "y", nsTags: tagsX, fullName: "y.%sx.a_b.x_y", buckets: buckets}, + {name: "x", tags: tagsX, namespace: "y", nsTags: tagsA, fullName: "y.%sx.a_b.x_y", expectedCounter: "84", buckets: buckets}, + } + f := NewFactory(2) + for _, testCase := range testCases { + t.Run("", func(t *testing.T) { + if testCase.expectedCounter == "" { + testCase.expectedCounter = "42" + } + ff := f + if testCase.namespace != "" || testCase.nsTags != nil { + ff = f.Namespace(metrics.NSOptions{ + Name: testCase.namespace, + Tags: testCase.nsTags, + }) + } + counter := ff.Counter(metrics.Options{ + Name: counterPrefix + testCase.name, + Tags: testCase.tags, + }) + gauge := ff.Gauge(metrics.Options{ + Name: gaugePrefix + testCase.name, + Tags: testCase.tags, + }) + timer := ff.Timer(metrics.TimerOptions{ + Name: timerPrefix + testCase.name, + Tags: testCase.tags, + Buckets: testCase.durationBuckets, + }) + histogram := ff.Histogram(metrics.HistogramOptions{ + Name: histogramPrefix + testCase.name, + Tags: testCase.tags, + Buckets: testCase.buckets, + }) + + // register second time, should not panic + ff.Counter(metrics.Options{ + Name: counterPrefix + testCase.name, + Tags: testCase.tags, + }) + ff.Gauge(metrics.Options{ + Name: gaugePrefix + testCase.name, + Tags: testCase.tags, + }) + ff.Timer(metrics.TimerOptions{ + Name: timerPrefix + testCase.name, + Tags: testCase.tags, + Buckets: testCase.durationBuckets, + }) + ff.Histogram(metrics.HistogramOptions{ + Name: histogramPrefix + testCase.name, + Tags: testCase.tags, + Buckets: testCase.buckets, + }) + + counter.Inc(42) + gauge.Update(42) + timer.Record(42 * time.Millisecond) + histogram.Record(42) + + assertExpvar(t, fmt.Sprintf(testCase.fullName, counterPrefix), testCase.expectedCounter) + assertExpvar(t, fmt.Sprintf(testCase.fullName, gaugePrefix), "42") + assertExpvar(t, fmt.Sprintf(testCase.fullName, timerPrefix)+".p99", "0.042") + assertExpvar(t, fmt.Sprintf(testCase.fullName, histogramPrefix)+".p99", "42") + }) + } +} + +func assertExpvar(t *testing.T, fullName string, value string) { + var found expvar.KeyValue + expvar.Do(func(kv expvar.KeyValue) { + if kv.Key == fullName { + found = kv + } + }) + if !assert.Equal(t, fullName, found.Key) { + expvar.Do(func(kv expvar.KeyValue) { + if strings.HasPrefix(kv.Key, prefix) { + t.Log(kv) + } + }) + return + } + assert.Equal(t, value, found.Value.String(), fullName) +} diff --git a/internal/metrics/expvar/metrics.go b/internal/metrics/expvar/metrics.go new file mode 100644 index 00000000000..f3cbf740b1a --- /dev/null +++ b/internal/metrics/expvar/metrics.go @@ -0,0 +1,82 @@ +// Copyright (c) 2022 The Jaeger Authors. +// Copyright (c) 2017 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package expvar + +import ( + "time" + + kit "github.com/go-kit/kit/metrics" +) + +// Counter is an adapter from go-kit Counter to jaeger-lib Counter +type Counter struct { + counter kit.Counter +} + +// NewCounter creates a new Counter +func NewCounter(counter kit.Counter) *Counter { + return &Counter{counter: counter} +} + +// Inc adds the given value to the counter. +func (c *Counter) Inc(delta int64) { + c.counter.Add(float64(delta)) +} + +// Gauge is an adapter from go-kit Gauge to jaeger-lib Gauge +type Gauge struct { + gauge kit.Gauge +} + +// NewGauge creates a new Gauge +func NewGauge(gauge kit.Gauge) *Gauge { + return &Gauge{gauge: gauge} +} + +// Update the gauge to the value passed in. +func (g *Gauge) Update(value int64) { + g.gauge.Set(float64(value)) +} + +// Timer is an adapter from go-kit Histogram to jaeger-lib Timer +type Timer struct { + hist kit.Histogram +} + +// NewTimer creates a new Timer +func NewTimer(hist kit.Histogram) *Timer { + return &Timer{hist: hist} +} + +// Record saves the time passed in. +func (t *Timer) Record(delta time.Duration) { + t.hist.Observe(delta.Seconds()) +} + +// Histogram is an adapter from go-kit Histogram to jaeger-lib Histogram +type Histogram struct { + hist kit.Histogram +} + +// NewHistogram creates a new Histogram +func NewHistogram(hist kit.Histogram) *Histogram { + return &Histogram{hist: hist} +} + +// Record saves the value passed in. +func (t *Histogram) Record(value float64) { + t.hist.Observe(value) +} diff --git a/internal/metrics/expvar/metrics_test.go b/internal/metrics/expvar/metrics_test.go new file mode 100644 index 00000000000..9beb9c31ed6 --- /dev/null +++ b/internal/metrics/expvar/metrics_test.go @@ -0,0 +1,54 @@ +// Copyright (c) 2022 The Jaeger Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package expvar_test + +import ( + "testing" + "time" + + "github.com/go-kit/kit/metrics/generic" + "github.com/stretchr/testify/assert" + "github.com/uber/jaeger-lib/metrics" + + "github.com/jaegertracing/jaeger/internal/metrics/expvar" +) + +func TestCounter(t *testing.T) { + kitCounter := generic.NewCounter("abc") + var counter metrics.Counter = expvar.NewCounter(kitCounter) + counter.Inc(123) + assert.EqualValues(t, 123, kitCounter.Value()) +} + +func TestGauge(t *testing.T) { + kitGauge := generic.NewGauge("abc") + var gauge metrics.Gauge = expvar.NewGauge(kitGauge) + gauge.Update(123) + assert.EqualValues(t, 123, kitGauge.Value()) +} + +func TestTimer(t *testing.T) { + kitHist := generic.NewHistogram("abc", 10) + var timer metrics.Timer = expvar.NewTimer(kitHist) + timer.Record(100*time.Millisecond + 500*time.Microsecond) // 100.5 milliseconds + assert.EqualValues(t, 0.1005, kitHist.Quantile(0.9)) +} + +func TestHistogram(t *testing.T) { + kitHist := generic.NewHistogram("abc", 10) + var histogram metrics.Histogram = expvar.NewHistogram(kitHist) + histogram.Record(100) + assert.EqualValues(t, 100, kitHist.Quantile(0.9)) +}