Prometheus开发Exporter简介
Exporter 本身是一个http 服务,其指标结果只要符合 Prometheus 规范就可以被 Prometheus 使用。
Prometheus中metric的类型
Prometheus的Client Library提供度量的四种基本类型包括
// Counter 计数器
// Gauge 仪表盘
// Histogram 直方图
// Summary 概要
// Prometheus中metric的格式
// 格式:<metric name>{<label name>=<label value>, ...}
// 例如:api_http_requests_total{method="POST", handler="/messages"}
// metric name: 唯一标识,命名遵循[a-zA-Z_:][a-zA-Z0-9_:]*.
Counter
Gauge
Histogram
Histogram包含三个指标
<basename>: 度量值名称
<basename>_count: 样本反正总次数
<basename>_sum: 样本发生次数中值的总和
<basename>_bucket{le="+Inf"}: 每个区间的样本数
Summary
Histogram和Summary的对比
Prometheus中的Jobs和INSTANCES
Instances
// 仅采集的API endpoint
Jobs
// 相同目的的Instances
// 例如: 四个节点上的api-server
job: api-server
instance 1: 1.2.3.4:5670
instance 2: 1.2.3.4:5671
instance 3: 5.6.7.8:5670
instance 4: 5.6.7.8:5671
// Job: 会增加Job名称
// instance: 增加host: port
开发一个简单Exporter
监听HTTP请求返回一行字符串
lexporter_request_count{user="admin"} 1000
package main
import (
"fmt"
"net/http"
)
func HelloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "lexporter_request_count{user=\"admin\"} 1000" )
}
func main () {
http.HandleFunc("/metrics", HelloHandler)
http.ListenAndServe(":8000", nil)
}
配置Prometheus,将exporter到Prometheus中
计数器
example1
package main
import (
"fmt"
"net/http"
)
type Counter struct {
count int64
}
func (c *Counter) Add(count int64) int64 {
c.count += count
return c.count
}
var counter = new(Counter)
func HelloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "lexporter_request_count{user=\"admin\"} %d",counter.Add(10) )
}
func main () {
http.HandleFunc("/metrics", HelloHandler)
http.ListenAndServe(":8000", nil)
}
example2
package main
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"net/http"
)
func main() {
// counter
requestTotal := prometheus.NewCounter(prometheus.CounterOpts{
Name: "request_total",
Help: "request total",
})
codeStatus := prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "status_code_total",
Help: "status_code total",
},[]string{"code"})
requestTotal.Add(10)
codeStatus.WithLabelValues("200").Add(10)
codeStatus.WithLabelValues("500").Add(20)
codeStatus.WithLabelValues("404").Add(30)
prometheus.MustRegister(requestTotal)
prometheus.MustRegister(codeStatus)
// 暴露
http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(":8888", nil)
}
Gauge(固定label和非固定label)
package main
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"net/http"
)
func main() {
// counter
// guage
// historgram
// summary
// metrics name(label=label_value) metrics_valu
// 有lable
// label/label_value 固定
// 无label(固定lable)
// lable/label_value 变化的
cpu := prometheus.NewGauge(prometheus.GaugeOpts{
Name: "cpu",
Help: "cpu total",
// 没有lable和固定lable一样的
ConstLabels: prometheus.Labels{"a":"xxx"},
})
// 非固定label
disk := prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "disk",
Help: "disk total",
},[]string{"mount"})
cpu.Set(2222)
disk.WithLabelValues("/mnt/sda1:").Set(100)
disk.WithLabelValues("/mnt/sda2:").Set(200)
disk.WithLabelValues("/mnt/sda3:").Set(200)
disk.WithLabelValues("/mnt/sda4:").Set(200)
// 注册指标信息
prometheus.MustRegister(cpu)
prometheus.MustRegister(disk)
// 暴露
http.Handle("/metrics",promhttp.Handler())
http.ListenAndServe(":8888",nil)
}
historgram
example1
package main
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"net/http"
)
func main() {
// historgram
request_time := prometheus.NewHistogramVec(prometheus.HistogramOpts{
Name: "request_time",
Help: "request time",
},[]string{"url"})
prometheus.MustRegister(request_time)
request_time.WithLabelValues("/aaa").Observe(6)
// 暴露
http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(":8888", nil)
}
summary
package main
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"net/http"
)
func main() {
// summary
requestsummary := prometheus.NewSummaryVec(prometheus.SummaryOpts{
Name: "request_time_summary",
Help: "request time summary",
Objectives: map[float64]float64{0.5: 0.05,0.9:0.09},
},[]string{"url"})
prometheus.MustRegister(requestsummary)
requestsummary.WithLabelValues("/aaa").Observe(6)
requestsummary.WithLabelValues("/aaa").Observe(2)
// 暴露
http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(":8888", nil)
}
值的修改(事件触发或者时间触发)
package main
import (
"fmt"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"math/rand"
"net/http"
"strconv"
"time"
)
func main() {
// 无label(固定lable)
// lable/label_value 变化的
cpu := prometheus.NewGauge(prometheus.GaugeOpts{
Name: "cpu",
Help: "cpu total",
// 没有lable和固定lable一样的
ConstLabels: prometheus.Labels{"a":"xxx"},
})
// 非固定label
disk := prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "disk",
Help: "disk total",
},[]string{"mount"})
cpu.Set(2222)
disk.WithLabelValues("/mnt/sda1:").Set(100)
disk.WithLabelValues("/mnt/sda2:").Set(200)
disk.WithLabelValues("/mnt/sda3:").Set(200)
disk.WithLabelValues("/mnt/sda4:").Set(200)
codeStatus := prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "status_code_total",
Help: "status_code total",
},[]string{"code"})
codeStatus.WithLabelValues("200").Add(10)
codeStatus.WithLabelValues("500").Add(20)
codeStatus.WithLabelValues("404").Add(30)
// counter
requestTotal := prometheus.NewCounter(prometheus.CounterOpts{
Name: "request_total",
Help: "request total",
})
requestTotal.Add(10)
// 值的修改
// 修改的时间 => 触发
// 时间触发
// 磁盘使用, cpu使用,内存使用
go func() {
for range time.Tick(time.Second) {
disk.WithLabelValues("/mnt/sda1").Set(float64(rand.Int()))
}
}()
// 事件触发,业务请求
http.HandleFunc("/",func(w http.ResponseWriter,r *http.Request){
requestTotal.Inc()
codeStatus.WithLabelValues(strconv.Itoa(rand.Intn(5) * 100)).Add(1)
fmt.Fprintf(w,"hi")
})
// 注册指标信息
prometheus.MustRegister(cpu)
prometheus.MustRegister(disk)
prometheus.MustRegister(requestTotal)
// 暴露
http.Handle("/metrics",promhttp.Handler())
http.ListenAndServe(":8888",nil)
}