From 3ee4b3c13cd902d366369e19ff1698b9fabf2913 Mon Sep 17 00:00:00 2001 From: AH-dark Date: Tue, 12 Sep 2023 18:52:26 +0800 Subject: [PATCH 1/6] feat: tracer configuration using options --- options.go | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ tracer.go | 41 +++++++++++++++++++++--------- 2 files changed, 102 insertions(+), 12 deletions(-) create mode 100644 options.go diff --git a/options.go b/options.go new file mode 100644 index 0000000..c3ac98a --- /dev/null +++ b/options.go @@ -0,0 +1,73 @@ +/* + * Copyright 2022 CloudWeGo 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 prometheus + +import ( + prom "github.com/prometheus/client_golang/prometheus" +) + +var defaultBuckets = []float64{5000, 10000, 25000, 50000, 100000, 250000, 500000, 1000000} + +// Option opts for monitor prometheus +type Option interface { + apply(cfg *config) +} + +type option func(cfg *config) + +func (fn option) apply(cfg *config) { + fn(cfg) +} + +type config struct { + buckets []float64 + enableGoCollector bool + registry *prom.Registry +} + +func defaultConfig() *config { + return &config{ + buckets: defaultBuckets, + enableGoCollector: false, + registry: prom.NewRegistry(), + } +} + +// WithEnableGoCollector enable go collector +func WithEnableGoCollector(enable bool) Option { + return option(func(cfg *config) { + cfg.enableGoCollector = enable + }) +} + +// WithHistogramBuckets define your custom histogram buckets base on your biz +func WithHistogramBuckets(buckets []float64) Option { + return option(func(cfg *config) { + if len(buckets) > 0 { + cfg.buckets = buckets + } + }) +} + +// WithRegistry define your custom registry +func WithRegistry(registry *prom.Registry) Option { + return option(func(cfg *config) { + if registry != nil { + cfg.registry = registry + } + }) +} diff --git a/tracer.go b/tracer.go index 350122d..15fd5c5 100644 --- a/tracer.go +++ b/tracer.go @@ -23,6 +23,7 @@ import ( "net/http" prom "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/cloudwego/kitex/pkg/rpcinfo" @@ -100,9 +101,13 @@ func (c *clientTracer) Finish(ctx context.Context) { } // NewClientTracer provide tracer for client call, addr and path is the scrape_configs for prometheus server. -func NewClientTracer(addr, path string) stats.Tracer { - registry := prom.NewRegistry() - http.Handle(path, promhttp.HandlerFor(registry, promhttp.HandlerOpts{ErrorHandling: promhttp.ContinueOnError})) +func NewClientTracer(addr, path string, options ...Option) stats.Tracer { + cfg := defaultConfig() + for _, opt := range options { + opt.apply(cfg) + } + + http.Handle(path, promhttp.HandlerFor(cfg.registry, promhttp.HandlerOpts{ErrorHandling: promhttp.ContinueOnError})) go func() { if err := http.ListenAndServe(addr, nil); err != nil { log.Fatal("Unable to start a promhttp server, err: " + err.Error()) @@ -116,17 +121,21 @@ func NewClientTracer(addr, path string) stats.Tracer { }, []string{labelKeyCaller, labelKeyCallee, labelKeyMethod, labelKeyStatus, labelKeyRetry}, ) - registry.MustRegister(clientHandledCounter) + cfg.registry.MustRegister(clientHandledCounter) clientHandledHistogram := prom.NewHistogramVec( prom.HistogramOpts{ Name: "kitex_client_latency_us", Help: "Latency (microseconds) of the RPC until it is finished.", - Buckets: []float64{5000, 10000, 25000, 50000, 100000, 250000, 500000, 1000000}, + Buckets: cfg.buckets, }, []string{labelKeyCaller, labelKeyCallee, labelKeyMethod, labelKeyStatus, labelKeyRetry}, ) - registry.MustRegister(clientHandledHistogram) + cfg.registry.MustRegister(clientHandledHistogram) + + if cfg.enableGoCollector { + cfg.registry.MustRegister(collectors.NewGoCollector()) + } return &clientTracer{ clientHandledCounter: clientHandledCounter, @@ -166,9 +175,13 @@ func (c *serverTracer) Finish(ctx context.Context) { } // NewServerTracer provides tracer for server access, addr and path is the scrape_configs for prometheus server. -func NewServerTracer(addr, path string) stats.Tracer { - registry := prom.NewRegistry() - http.Handle(path, promhttp.HandlerFor(registry, promhttp.HandlerOpts{ErrorHandling: promhttp.ContinueOnError})) +func NewServerTracer(addr, path string, options ...Option) stats.Tracer { + cfg := defaultConfig() + for _, opt := range options { + opt.apply(cfg) + } + + http.Handle(path, promhttp.HandlerFor(cfg.registry, promhttp.HandlerOpts{ErrorHandling: promhttp.ContinueOnError})) go func() { if err := http.ListenAndServe(addr, nil); err != nil { log.Fatal("Unable to start a promhttp server, err: " + err.Error()) @@ -182,17 +195,21 @@ func NewServerTracer(addr, path string) stats.Tracer { }, []string{labelKeyCaller, labelKeyCallee, labelKeyMethod, labelKeyStatus, labelKeyRetry}, ) - registry.MustRegister(serverHandledCounter) + cfg.registry.MustRegister(serverHandledCounter) serverHandledHistogram := prom.NewHistogramVec( prom.HistogramOpts{ Name: "kitex_server_latency_us", Help: "Latency (microseconds) of RPC that had been application-level handled by the server.", - Buckets: []float64{5000, 10000, 25000, 50000, 100000, 250000, 500000, 1000000}, + Buckets: cfg.buckets, }, []string{labelKeyCaller, labelKeyCallee, labelKeyMethod, labelKeyStatus, labelKeyRetry}, ) - registry.MustRegister(serverHandledHistogram) + cfg.registry.MustRegister(serverHandledHistogram) + + if cfg.enableGoCollector { + cfg.registry.MustRegister(collectors.NewGoCollector()) + } return &serverTracer{ serverHandledCounter: serverHandledCounter, From e9260a5a7207cde2eb932420e9fce2b7fde8f4bb Mon Sep 17 00:00:00 2001 From: AH-dark Date: Thu, 14 Sep 2023 22:35:24 +0800 Subject: [PATCH 2/6] feat: allow configuration of http serveMux --- options.go | 29 +++++++++++++---------------- tracer.go | 14 ++++++++++---- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/options.go b/options.go index c3ac98a..372bab9 100644 --- a/options.go +++ b/options.go @@ -1,22 +1,8 @@ -/* - * Copyright 2022 CloudWeGo 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 prometheus import ( + "net/http" + prom "github.com/prometheus/client_golang/prometheus" ) @@ -37,6 +23,7 @@ type config struct { buckets []float64 enableGoCollector bool registry *prom.Registry + serveMux *http.ServeMux } func defaultConfig() *config { @@ -44,6 +31,7 @@ func defaultConfig() *config { buckets: defaultBuckets, enableGoCollector: false, registry: prom.NewRegistry(), + serveMux: http.DefaultServeMux, } } @@ -71,3 +59,12 @@ func WithRegistry(registry *prom.Registry) Option { } }) } + +// WithServeMux define your custom serve mux +func WithServeMux(serveMux *http.ServeMux) Option { + return option(func(cfg *config) { + if serveMux != nil { + cfg.serveMux = serveMux + } + }) +} diff --git a/tracer.go b/tracer.go index 15fd5c5..9e3ec72 100644 --- a/tracer.go +++ b/tracer.go @@ -107,9 +107,12 @@ func NewClientTracer(addr, path string, options ...Option) stats.Tracer { opt.apply(cfg) } - http.Handle(path, promhttp.HandlerFor(cfg.registry, promhttp.HandlerOpts{ErrorHandling: promhttp.ContinueOnError})) + cfg.serveMux.Handle(path, promhttp.HandlerFor(cfg.registry, promhttp.HandlerOpts{ + ErrorHandling: promhttp.ContinueOnError, + Registry: cfg.registry, + })) go func() { - if err := http.ListenAndServe(addr, nil); err != nil { + if err := http.ListenAndServe(addr, cfg.serveMux); err != nil { log.Fatal("Unable to start a promhttp server, err: " + err.Error()) } }() @@ -181,9 +184,12 @@ func NewServerTracer(addr, path string, options ...Option) stats.Tracer { opt.apply(cfg) } - http.Handle(path, promhttp.HandlerFor(cfg.registry, promhttp.HandlerOpts{ErrorHandling: promhttp.ContinueOnError})) + cfg.serveMux.Handle(path, promhttp.HandlerFor(cfg.registry, promhttp.HandlerOpts{ + ErrorHandling: promhttp.ContinueOnError, + Registry: cfg.registry, + })) go func() { - if err := http.ListenAndServe(addr, nil); err != nil { + if err := http.ListenAndServe(addr, cfg.serveMux); err != nil { log.Fatal("Unable to start a promhttp server, err: " + err.Error()) } }() From aabb60e6c11644fcecb85e9969b2cc917103fddb Mon Sep 17 00:00:00 2001 From: AH-dark Date: Sun, 17 Sep 2023 02:18:50 +0800 Subject: [PATCH 3/6] feat: allow to set runtime metrics rules --- options.go | 26 ++++++++++++++++++-------- tracer.go | 4 ++-- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/options.go b/options.go index 372bab9..f50e52c 100644 --- a/options.go +++ b/options.go @@ -4,6 +4,7 @@ import ( "net/http" prom "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/collectors" ) var defaultBuckets = []float64{5000, 10000, 25000, 50000, 100000, 250000, 500000, 1000000} @@ -20,18 +21,20 @@ func (fn option) apply(cfg *config) { } type config struct { - buckets []float64 - enableGoCollector bool - registry *prom.Registry - serveMux *http.ServeMux + buckets []float64 + enableGoCollector bool + runtimeMetricRules []collectors.GoRuntimeMetricsRule + registry *prom.Registry + serveMux *http.ServeMux } func defaultConfig() *config { return &config{ - buckets: defaultBuckets, - enableGoCollector: false, - registry: prom.NewRegistry(), - serveMux: http.DefaultServeMux, + buckets: defaultBuckets, + enableGoCollector: false, + runtimeMetricRules: []collectors.GoRuntimeMetricsRule{}, + registry: prom.NewRegistry(), + serveMux: http.DefaultServeMux, } } @@ -42,6 +45,13 @@ func WithEnableGoCollector(enable bool) Option { }) } +// WithGoCollectorRule define your custom go collector rule +func WithGoCollectorRule(rules ...collectors.GoRuntimeMetricsRule) Option { + return option(func(cfg *config) { + cfg.runtimeMetricRules = rules + }) +} + // WithHistogramBuckets define your custom histogram buckets base on your biz func WithHistogramBuckets(buckets []float64) Option { return option(func(cfg *config) { diff --git a/tracer.go b/tracer.go index 9e3ec72..46309ff 100644 --- a/tracer.go +++ b/tracer.go @@ -137,7 +137,7 @@ func NewClientTracer(addr, path string, options ...Option) stats.Tracer { cfg.registry.MustRegister(clientHandledHistogram) if cfg.enableGoCollector { - cfg.registry.MustRegister(collectors.NewGoCollector()) + cfg.registry.MustRegister(collectors.NewGoCollector(collectors.WithGoCollectorRuntimeMetrics(cfg.runtimeMetricRules...))) } return &clientTracer{ @@ -214,7 +214,7 @@ func NewServerTracer(addr, path string, options ...Option) stats.Tracer { cfg.registry.MustRegister(serverHandledHistogram) if cfg.enableGoCollector { - cfg.registry.MustRegister(collectors.NewGoCollector()) + cfg.registry.MustRegister(collectors.NewGoCollector(collectors.WithGoCollectorRuntimeMetrics(cfg.runtimeMetricRules...))) } return &serverTracer{ From d2fd28f2c2c125b309c09e2069f1bba823ed612c Mon Sep 17 00:00:00 2001 From: AH-dark Date: Sat, 23 Sep 2023 19:17:16 +0800 Subject: [PATCH 4/6] feat: allow to disable http server --- options.go | 9 +++++++++ tracer.go | 20 +++++++++++--------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/options.go b/options.go index f50e52c..9d1e4a1 100644 --- a/options.go +++ b/options.go @@ -26,6 +26,7 @@ type config struct { runtimeMetricRules []collectors.GoRuntimeMetricsRule registry *prom.Registry serveMux *http.ServeMux + disableServer bool } func defaultConfig() *config { @@ -35,6 +36,7 @@ func defaultConfig() *config { runtimeMetricRules: []collectors.GoRuntimeMetricsRule{}, registry: prom.NewRegistry(), serveMux: http.DefaultServeMux, + disableServer: false, } } @@ -78,3 +80,10 @@ func WithServeMux(serveMux *http.ServeMux) Option { } }) } + +// WithDisableServer disable prometheus server +func WithDisableServer(disable bool) Option { + return option(func(cfg *config) { + cfg.disableServer = disable + }) +} diff --git a/tracer.go b/tracer.go index 46309ff..55a7788 100644 --- a/tracer.go +++ b/tracer.go @@ -107,15 +107,17 @@ func NewClientTracer(addr, path string, options ...Option) stats.Tracer { opt.apply(cfg) } - cfg.serveMux.Handle(path, promhttp.HandlerFor(cfg.registry, promhttp.HandlerOpts{ - ErrorHandling: promhttp.ContinueOnError, - Registry: cfg.registry, - })) - go func() { - if err := http.ListenAndServe(addr, cfg.serveMux); err != nil { - log.Fatal("Unable to start a promhttp server, err: " + err.Error()) - } - }() + if !cfg.disableServer { + cfg.serveMux.Handle(path, promhttp.HandlerFor(cfg.registry, promhttp.HandlerOpts{ + ErrorHandling: promhttp.ContinueOnError, + Registry: cfg.registry, + })) + go func() { + if err := http.ListenAndServe(addr, cfg.serveMux); err != nil { + log.Fatal("Unable to start a promhttp server, err: " + err.Error()) + } + }() + } clientHandledCounter := prom.NewCounterVec( prom.CounterOpts{ From a78448652d1ba75bc576efe09ff1fe4c65ddb195 Mon Sep 17 00:00:00 2001 From: AH-dark Date: Fri, 29 Sep 2023 20:17:20 +0800 Subject: [PATCH 5/6] chore: added license header --- options.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/options.go b/options.go index 9d1e4a1..f466a1b 100644 --- a/options.go +++ b/options.go @@ -1,3 +1,19 @@ +/* + * Copyright 2021 CloudWeGo 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 prometheus import ( From c6f3c751a9c53ea9931ecbed74e78df170b68961 Mon Sep 17 00:00:00 2001 From: AH-dark Date: Fri, 29 Sep 2023 20:18:48 +0800 Subject: [PATCH 6/6] fix: adapted disableServer config in server tracer --- tracer.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/tracer.go b/tracer.go index 55a7788..7e92e04 100644 --- a/tracer.go +++ b/tracer.go @@ -186,15 +186,17 @@ func NewServerTracer(addr, path string, options ...Option) stats.Tracer { opt.apply(cfg) } - cfg.serveMux.Handle(path, promhttp.HandlerFor(cfg.registry, promhttp.HandlerOpts{ - ErrorHandling: promhttp.ContinueOnError, - Registry: cfg.registry, - })) - go func() { - if err := http.ListenAndServe(addr, cfg.serveMux); err != nil { - log.Fatal("Unable to start a promhttp server, err: " + err.Error()) - } - }() + if !cfg.disableServer { + cfg.serveMux.Handle(path, promhttp.HandlerFor(cfg.registry, promhttp.HandlerOpts{ + ErrorHandling: promhttp.ContinueOnError, + Registry: cfg.registry, + })) + go func() { + if err := http.ListenAndServe(addr, cfg.serveMux); err != nil { + log.Fatal("Unable to start a promhttp server, err: " + err.Error()) + } + }() + } serverHandledCounter := prom.NewCounterVec( prom.CounterOpts{