Initial commit
This commit is contained in:
190
metrics/metrics.go
Normal file
190
metrics/metrics.go
Normal file
@@ -0,0 +1,190 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"globalfintech/golib/tlog"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
consulapi "github.com/hashicorp/consul/api"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/prometheus/client_golang/prometheus/push"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultAddr string = "9166"
|
||||
)
|
||||
|
||||
// Counter describes a metric that accumulates values monotonically.
|
||||
// An example of a counter is the number of received HTTP requests.
|
||||
type Counter interface {
|
||||
With(labelValues ...string) Counter
|
||||
Add(delta float64)
|
||||
Inc()
|
||||
}
|
||||
|
||||
// Gauge describes a metric that takes specific values over time.
|
||||
// An example of a gauge is the current depth of a job queue.
|
||||
type Gauge interface {
|
||||
With(labelValues ...string) Gauge
|
||||
Set(value float64)
|
||||
Add(delta float64)
|
||||
Sub(delta float64)
|
||||
}
|
||||
|
||||
// Histogram describes a metric that takes repeated observations of the same
|
||||
// kind of thing, and produces a statistical summary of those observations,
|
||||
// typically expressed as quantiles or buckets. An example of a histogram is
|
||||
// HTTP request latencies.
|
||||
type Histogram interface {
|
||||
With(labelValues ...string) Histogram
|
||||
Observe(value float64)
|
||||
}
|
||||
|
||||
// LabelValues is a type alias that provides validation on its With method.
|
||||
// Metrics may include it as a member to help them satisfy With semantics and
|
||||
// save some code duplication.
|
||||
type LabelValues []string
|
||||
|
||||
// With validates the input, and returns a new aggregate labelValues.
|
||||
func (lvs LabelValues) With(labelValues ...string) LabelValues {
|
||||
if len(labelValues)%2 != 0 {
|
||||
labelValues = append(labelValues, "unknown")
|
||||
}
|
||||
return append(lvs, labelValues...)
|
||||
}
|
||||
|
||||
// new a *ProcessMetrics
|
||||
// productName,serviceRegion,appName all those params must be passed
|
||||
// port if not be pass,will use defaultAddr 9166
|
||||
func NewProcessMetrics(productName, serviceRegion, appName string, port ...string) (*ProcessMetrics, error) {
|
||||
if len(productName) == 0 || len(serviceRegion) == 0 || len(appName) == 0 {
|
||||
err := errors.New("productName,serviceRegion,appName all those params must be passed")
|
||||
tlog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
addr := defaultAddr
|
||||
if len(port) > 0 {
|
||||
addr = port[0]
|
||||
}
|
||||
var processMetrics ProcessMetrics
|
||||
processMetrics.Port = addr
|
||||
processMetrics.ProductName = productName
|
||||
processMetrics.ServiceRegion = serviceRegion
|
||||
processMetrics.Appname = appName
|
||||
return &processMetrics, nil
|
||||
}
|
||||
|
||||
type ProcessMetrics struct {
|
||||
Port string // port default 9166
|
||||
ProductName string
|
||||
ServiceRegion string
|
||||
Appname string
|
||||
}
|
||||
|
||||
// get real work port
|
||||
func (s *ProcessMetrics) GetMetricsPort() string {
|
||||
if len(s.Port) > 0 {
|
||||
return s.Port
|
||||
}
|
||||
return defaultAddr
|
||||
}
|
||||
|
||||
// Init Export on GF default port 9166
|
||||
// If you want custom listen port, just pass your port to MetricsParams struct
|
||||
// return exporter http server
|
||||
func (s *ProcessMetrics) InitExporter() *http.Server {
|
||||
h := http.NewServeMux()
|
||||
h.Handle("/metrics", promhttp.Handler())
|
||||
h.HandleFunc("/health_checker", s.healthChecker)
|
||||
addr := defaultAddr
|
||||
if len(s.Port) > 0 {
|
||||
addr = s.Port
|
||||
} else {
|
||||
s.Port = defaultAddr
|
||||
}
|
||||
server := &http.Server{
|
||||
Addr: ":" + addr,
|
||||
Handler: h,
|
||||
ReadTimeout: 30 * time.Second,
|
||||
ReadHeaderTimeout: 30 * time.Second,
|
||||
IdleTimeout: 30 * time.Second,
|
||||
WriteTimeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
{
|
||||
var tags []string
|
||||
|
||||
tags = append(tags, fmt.Sprintf("app=%s", s.ProductName))
|
||||
tags = append(tags, fmt.Sprintf("country=%s", s.ServiceRegion))
|
||||
s.initExporterOnExistHttpServer(addr, "/health_checker", tags, s.Appname)
|
||||
}
|
||||
go func() {
|
||||
if err := server.ListenAndServe(); err != nil {
|
||||
tlog.Fatal(err)
|
||||
}
|
||||
}()
|
||||
return server
|
||||
}
|
||||
|
||||
func (s *ProcessMetrics) healthChecker(resp http.ResponseWriter, req *http.Request) {
|
||||
data := map[string]interface{}{
|
||||
"code": 0,
|
||||
"message": "ok",
|
||||
"server_time": time.Now().Unix(),
|
||||
}
|
||||
res, _ := json.Marshal(data)
|
||||
resp.Write(res)
|
||||
}
|
||||
|
||||
// Init Pusher
|
||||
// return prometheus pusher
|
||||
func InitPusher(gateway string, job string) *push.Pusher {
|
||||
host, _ := os.Hostname()
|
||||
return push.New(gateway, job).Grouping("instance", host)
|
||||
}
|
||||
|
||||
// InitExporterOnExistHttpServer Init http exporter
|
||||
// Why we init exporter on exist http server:
|
||||
// to avoid new custom port
|
||||
// which should add healthCheckRouter - like /healthChecker func
|
||||
// must export a route: /metrics router for prometheus
|
||||
// promhttp.Handler().ServeHTTP(c.Ctx.ResponseWriter, c.Ctx.Request)
|
||||
func (s *ProcessMetrics) initExporterOnExistHttpServer(port string, healthCheckRouter string, tags []string, name string, id ...string) {
|
||||
config := consulapi.DefaultConfig()
|
||||
client, err := consulapi.NewClient(config)
|
||||
if err != nil {
|
||||
tlog.Error("consul client error : ", err)
|
||||
return
|
||||
}
|
||||
registration := new(consulapi.AgentServiceRegistration)
|
||||
registration.Name = name
|
||||
intPort, _ := strconv.Atoi(port)
|
||||
registration.Port = intPort
|
||||
hostName, _ := os.Hostname()
|
||||
if len(id) > 0 {
|
||||
registration.ID = registration.Name + ":" + id[0]
|
||||
} else {
|
||||
registration.ID = registration.Name + ":" + hostName
|
||||
}
|
||||
|
||||
registration.Tags = append(tags, "lang=go")
|
||||
|
||||
registration.Check = new(consulapi.AgentServiceCheck)
|
||||
registration.Check.HTTP = fmt.Sprintf("http://%s:%s%s",
|
||||
"127.0.0.1", port, healthCheckRouter)
|
||||
registration.Check.Interval = "5s"
|
||||
registration.Check.Timeout = "3s"
|
||||
// 为兼容现有的 平滑逻辑
|
||||
//err = client.Agent().ServiceDeregister(registration.ID)
|
||||
|
||||
err = client.Agent().ServiceRegister(registration)
|
||||
|
||||
if err != nil {
|
||||
tlog.Error(err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user