Skip to content

Commit

Permalink
coremain: add metrics support
Browse files Browse the repository at this point in the history
  • Loading branch information
IrineSistiana committed Jun 24, 2022
1 parent d393fb4 commit 561508c
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 1 deletion.
20 changes: 20 additions & 0 deletions coremain/mosdns.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ import (
"github.com/IrineSistiana/mosdns/v4/mlog"
"github.com/IrineSistiana/mosdns/v4/pkg/data_provider"
"github.com/IrineSistiana/mosdns/v4/pkg/executable_seq"
"github.com/IrineSistiana/mosdns/v4/pkg/metrics"
"github.com/IrineSistiana/mosdns/v4/pkg/notifier"

"go.uber.org/zap"
"net/http"
"runtime"
Expand All @@ -46,6 +48,10 @@ type Mosdns struct {
httpAPIMux *http.ServeMux
httpAPIServer *http.Server

rootMetricsReg *metrics.Registry
pluginsMetricsReg *metrics.Registry
serversMetricsReg *metrics.Registry

sc *notifier.SafeClose
}

Expand All @@ -63,6 +69,12 @@ func RunMosdns(cfg *Config) error {
httpAPIMux: http.NewServeMux(),
sc: notifier.NewSafeClose(),
}
m.rootMetricsReg = metrics.NewRegistry()
m.pluginsMetricsReg = metrics.NewRegistry()
m.serversMetricsReg = metrics.NewRegistry()
m.rootMetricsReg.Set("plugins", m.pluginsMetricsReg)
m.rootMetricsReg.Set("servers", m.serversMetricsReg)
m.httpAPIMux.HandleFunc("/metrics/", metrics.HandleFunc(m.rootMetricsReg, m.logger))

// Init data manager
dupTag := make(map[string]struct{})
Expand Down Expand Up @@ -178,6 +190,14 @@ func (m *Mosdns) GetExecutables() map[string]executable_seq.Executable {
return m.execs
}

func (m *Mosdns) GetPluginMetricsReg() *metrics.Registry {
return m.pluginsMetricsReg
}

func (m *Mosdns) GetServerMetricsReg() *metrics.Registry {
return m.serversMetricsReg
}

func (m *Mosdns) GetMatchers() map[string]executable_seq.Matcher {
return m.matchers
}
Expand Down
12 changes: 11 additions & 1 deletion coremain/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package coremain

import (
"fmt"
"github.com/IrineSistiana/mosdns/v4/pkg/metrics"
"github.com/IrineSistiana/mosdns/v4/pkg/utils"
"go.uber.org/zap"
"sync"
Expand Down Expand Up @@ -149,12 +150,15 @@ func LoadNewPersetPluginFuncs() map[string]NewPersetPluginFunc {
// BP represents a basic plugin, which implements Plugin.
// It also has an internal logger, for convenience.
type BP struct {
Metrics metrics.Registry

tag, typ string

l *zap.Logger
s *zap.SugaredLogger

m *Mosdns
m *Mosdns
metricsReg *metrics.Registry
}

// NewBP creates a new BP and initials its logger.
Expand Down Expand Up @@ -185,6 +189,12 @@ func (p *BP) M() *Mosdns {
return p.m
}

func (p *BP) GetMetricsReg() *metrics.Registry {
return p.m.pluginsMetricsReg.GetOrSet(p.tag, func() metrics.Var {
return metrics.NewRegistry()
}).(*metrics.Registry)
}

func (p *BP) Close() error {
return nil
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
github.com/miekg/dns v1.1.49
github.com/mitchellh/mapstructure v1.5.0
github.com/nadoo/ipset v0.5.0
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475
github.com/spf13/cobra v1.4.0
github.com/spf13/viper v1.12.0
go.uber.org/zap v1.21.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,8 @@ github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
Expand Down
152 changes: 152 additions & 0 deletions pkg/metrics/metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*
* Copyright (C) 2020-2022, IrineSistiana
*
* This file is part of mosdns.
*
* mosdns is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* mosdns is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package metrics

import (
"encoding/json"
"github.com/rcrowley/go-metrics"
"go.uber.org/zap"
"net/http"
"sync"
)

type Var interface {
// Publish should return a build-in type or a map[string]interface{}
// of build-in types.
Publish() interface{}
}

type Registry struct {
l sync.RWMutex
m map[string]Var
}

func NewRegistry() *Registry {
return &Registry{
m: make(map[string]Var),
}
}

func (r *Registry) Get(name string) Var {
r.l.RLock()
defer r.l.RUnlock()
return r.m[name]
}

func (r *Registry) GetOrSet(name string, f func() Var) Var {
r.l.Lock()
defer r.l.Unlock()
v, ok := r.m[name]
if !ok {
v = f()
r.m[name] = v
}
return v
}

func (r *Registry) Set(name string, v Var) {
r.l.Lock()
defer r.l.Unlock()
r.m[name] = v
}

func (r *Registry) Publish() interface{} {
m := make(map[string]interface{})
r.l.RLock()
defer r.l.RUnlock()
for name, v := range r.m {
m[name] = v.Publish()
}
return m
}

type Histogram struct {
metrics.Histogram
}

func NewHistogram(reservoirSize int) *Histogram {
return &Histogram{Histogram: metrics.NewHistogram(metrics.NewUniformSample(reservoirSize))}
}

func (h *Histogram) Publish() interface{} {
m := make(map[string]interface{})
ps := h.Percentiles([]float64{0, 0.25, 0.5, 0.75, 1})
m["min"] = ps[0]
m["p25"] = ps[1]
m["p50"] = ps[2]
m["p75"] = ps[3]
m["max"] = ps[4]
m["avg"] = int64(h.Mean())
return m
}

type Counter struct {
metrics.Counter
}

func NewCounter() *Counter {
return &Counter{Counter: metrics.NewCounter()}
}

func (c *Counter) Publish() interface{} {
return c.Count()
}

type Gauge struct {
metrics.Gauge
}

func NewGauge() *Gauge {
return &Gauge{Gauge: metrics.NewGauge()}
}

type GaugeFunc struct {
l sync.Mutex
f func() int64
}

func NewGaugeFunc(f func() int64) *GaugeFunc {
return &GaugeFunc{f: f}
}

func (gf *GaugeFunc) Publish() interface{} {
gf.l.Lock()
defer gf.l.Unlock()
return gf.f()
}

func (g *Gauge) Publish() interface{} {
return g.Value()
}

func HandleFunc(r Var, lg *zap.Logger) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
b, err := json.MarshalIndent(r.Publish(), "", " ")
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
lg.Error("failed to encode json", zap.Error(err))
return
}
if _, err := w.Write(b); err != nil {
lg.Error("http write err", zap.Error(err))
}
}
}

0 comments on commit 561508c

Please # to comment.