diff --git a/main.cpu.txt b/main.cpu.txt new file mode 100644 index 0000000..156ef3c --- /dev/null +++ b/main.cpu.txt @@ -0,0 +1,77 @@ +package main + +import ( + "flag" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" + log "github.com/sirupsen/logrus" + "net/http" + "sreExporter/collector" + "strings" +) + +var ( + metricsPath string = "https://github.com/strive-after/demo-exporter" + version string = "v1.0" + listenAddress string + help bool + disable string //命令行传入的需要关闭的指标 + disables []string //处理命令行传入的根据,分割为一个切片做处理 +) + +func init() { + flag.StringVar(&listenAddress, "addr", ":9100", "addr") + flag.BoolVar(&help, "h", false, "help") + flag.StringVar(&disable, "disable", "", "关闭的指标收集器") +} + +// main函数作为总入口 提供web url /metrices以及访问/的时候提供一些基本介绍 +func main() { + flag.Parse() + if help { + flag.Usage() + return + } + disables = strings.Split(disable, ",") + //手动开关 + //通过用户输入的我们做关闭 + for scraper, _ := range collector.Scrapers { + for _, v := range disables { + if v == scraper.Name() { + collector.Scrapers[scraper] = false + break + } + } + } + + //访问/的时候返回一些基础提示 + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(` + ` + collector.Name() + ` + +

` + collector.Name() + `

+

Metrics

+

Build

+
` + version + `
+ + `)) + }) + //根据开关来判断指标的是否需要收集 这里只有代码里面的判断 用户手动开关还未做 + enabledScrapers := []collector.Scraper{} + for scraper, enabled := range collector.Scrapers { + if enabled { + log.Info("Scraper enabled ", scraper.Name()) + enabledScrapers = append(enabledScrapers, scraper) + } + } + + //注册自身采集器 + exporter := collector.New(collector.NewMetrics(), enabledScrapers) + prometheus.MustRegister(exporter) + + http.Handle("/metrics", promhttp.Handler()) + //监听端口 + if err := http.ListenAndServe(listenAddress, nil); err != nil { + log.Printf("Error occur when start server %v", err) + } +} diff --git a/main.go b/main.go index 156ef3c..34942b4 100644 --- a/main.go +++ b/main.go @@ -1,77 +1,97 @@ package main import ( - "flag" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" - log "github.com/sirupsen/logrus" "net/http" - "sreExporter/collector" - "strings" + "sync" ) -var ( - metricsPath string = "https://github.com/strive-after/demo-exporter" - version string = "v1.0" - listenAddress string - help bool - disable string //命令行传入的需要关闭的指标 - disables []string //处理命令行传入的根据,分割为一个切片做处理 -) +type ClusterManager struct { + sync.Mutex + Zone string + metricMapCounters map[string]string + metricMapGauges map[string]string +} -func init() { - flag.StringVar(&listenAddress, "addr", ":9100", "addr") - flag.BoolVar(&help, "h", false, "help") - flag.StringVar(&disable, "disable", "", "关闭的指标收集器") +// Simulate prepare the data +func (c *ClusterManager) ReallyExpensiveAssessmentOfTheSystemState() ( + metrics map[string]float64, +) { + metrics = map[string]float64{ + "oom_crashes_total": 42.00, + "ram_usage": 6.023e23, + } + return } -// main函数作为总入口 提供web url /metrices以及访问/的时候提供一些基本介绍 -func main() { - flag.Parse() - if help { - flag.Usage() - return +// 通过NewClusterManager方法创建结构体及对应的指标信息,代码如下所示。 +// NewClusterManager creates the two Descs OOMCountDesc and RAMUsageDesc. Note +// that the zone is set as a ConstLabel. (It's different in each instance of the +// ClusterManager, but constant over the lifetime of an instance.) Then there is +// a variable label "host", since we want to partition the collected metrics by +// host. Since all Descs created in this way are consistent across instances, +// with a guaranteed distinction by the "zone" label, we can register different +// ClusterManager instances with the same registry. +func NewClusterManager(zone string) *ClusterManager { + return &ClusterManager{ + Zone: zone, + metricMapGauges: map[string]string{ + "ram_usage": "ram_usage_bytes", + }, + metricMapCounters: map[string]string{ + "oom_crashes": "oom_crashes_total", + }, } - disables = strings.Split(disable, ",") - //手动开关 - //通过用户输入的我们做关闭 - for scraper, _ := range collector.Scrapers { - for _, v := range disables { - if v == scraper.Name() { - collector.Scrapers[scraper] = false - break - } - } +} + +//首先,采集器必须实现prometheus.Collector接口,也必须实现Describe和Collect方法。实现接口的代码如下所示。 +// Describe simply sends the two Descs in the struct to the channel. +// Prometheus的注册器调用Collect来抓取参数 +// 将收集的数据传递到Channel中并返回 +// 收集的指标信息来自Describe,可以并发地执行抓取工作,但是必须要保证线程的安全 + +func (c *ClusterManager) Describe(ch chan<- *prometheus.Desc) { + // prometheus.NewDesc(prometheus.BuildFQName(namespace, "", metricName), docString, labels, nil) + for _, v := range c.metricMapGauges { + ch <- prometheus.NewDesc(prometheus.BuildFQName(c.Zone, "", v), v, nil, nil) } - //访问/的时候返回一些基础提示 - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(` - ` + collector.Name() + ` - -

` + collector.Name() + `

-

Metrics

-

Build

-
` + version + `
- - `)) - }) - //根据开关来判断指标的是否需要收集 这里只有代码里面的判断 用户手动开关还未做 - enabledScrapers := []collector.Scraper{} - for scraper, enabled := range collector.Scrapers { - if enabled { - log.Info("Scraper enabled ", scraper.Name()) - enabledScrapers = append(enabledScrapers, scraper) - } + for _, v := range c.metricMapCounters { + ch <- prometheus.NewDesc(prometheus.BuildFQName(c.Zone, "", v), v, nil, nil) } +} - //注册自身采集器 - exporter := collector.New(collector.NewMetrics(), enabledScrapers) - prometheus.MustRegister(exporter) +// Collect方法是核心,它会抓取你需要的所有数据,根据需求对其进行分析,然后将指标发送回客户端库。 +// 用于传递所有可能指标的定义描述符 +// 可以在程序运行期间添加新的描述,收集新的指标信息 +// 重复的描述符将被忽略。两个不同的Collector不要设置相同的描述符 +func (c *ClusterManager) Collect(ch chan<- prometheus.Metric) { + c.Lock() + defer c.Unlock() + m := c.ReallyExpensiveAssessmentOfTheSystemState() + for k, v := range m { + t := prometheus.GaugeValue + if c.metricMapCounters[k] != "" { + t = prometheus.CounterValue + } + c.registerConstMetric(ch, k, v, t) + } +} - http.Handle("/metrics", promhttp.Handler()) - //监听端口 - if err := http.ListenAndServe(listenAddress, nil); err != nil { - log.Printf("Error occur when start server %v", err) +// 用于传递所有可能指标的定义描述符给指标 +func (c *ClusterManager) registerConstMetric(ch chan<- prometheus.Metric, metric string, val float64, valType prometheus.ValueType, labelValues ...string) { + descr := prometheus.NewDesc(prometheus.BuildFQName(c.Zone, "", metric), metric, nil, nil) + if m, err := prometheus.NewConstMetric(descr, valType, val, labelValues...); err == nil { + ch <- m } } + +func main() { + workerCA := NewClusterManager("xiaodian") + reg := prometheus.NewPedanticRegistry() + reg.MustRegister(workerCA) + //当promhttp.Handler()被执行时,所有metric被序列化输出。题外话,其实输出的格式既可以是plain text,也可以是protocol Buffers。 + http.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{})) + http.ListenAndServe("9100", nil) +} diff --git a/readme.md b/readme.md index 755d40e..f5840dc 100644 --- a/readme.md +++ b/readme.md @@ -16,7 +16,7 @@ cd sreExporter CGO_ENABLED=0 GOOS=linux GOARCH=arm64 GO111MODULE=on go mod tidy CGO_ENABLED=0 GOOS=linux GOARCH=arm64 GO111MODULE=on go build -o exporter.bin main.go docker build -t sre/exporter:arm64 . -kubectl rollout restart deployment -n sre ginbase +kubectl rollout restart deployment -n kuboard sre-exporter ./exporter ```