Skip to content

Commit

Permalink
Merge pull request #94 from rajaSahil/Expose-Metrics
Browse files Browse the repository at this point in the history
feat(metrics): Expose LVM metrics
  • Loading branch information
Vishnu Attur authored Jun 28, 2021
2 parents e12ad25 + 1ffe421 commit 15a2c7c
Show file tree
Hide file tree
Showing 496 changed files with 54,070 additions and 13,829 deletions.
18 changes: 16 additions & 2 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ package main
import (
"flag"
"fmt"
"log"
"os"

config "github.com/openebs/lvm-localpv/pkg/config"
"github.com/openebs/lvm-localpv/pkg/driver"
"github.com/openebs/lvm-localpv/pkg/lvm"
"github.com/openebs/lvm-localpv/pkg/version"
"github.com/spf13/cobra"
"k8s.io/klog"
"log"
"os"
)

/*
Expand All @@ -37,6 +38,7 @@ import (
* --plugin=controller and to start it as agent, we have
* to pass --plugin=agent.
*/

func main() {
_ = flag.CommandLine.Parse([]string{})
var config = config.Default()
Expand Down Expand Up @@ -83,6 +85,18 @@ func main() {
"Whether to set iops, bps rate limit for pods accessing volumes",
)

cmd.PersistentFlags().StringVar(
&config.ListenAddress, "listen-address", "", "The TCP network address where the prometheus metrics endpoint will listen (example: `:9080`). The default is empty string, which means metrics endpoint is disabled.",
)

cmd.PersistentFlags().StringVar(
&config.MetricsPath, "metrics-path", "/metrics", "The HTTP path where prometheus metrics will be exposed. Default is `/metrics`.",
)

cmd.PersistentFlags().BoolVar(
&config.DisableExporterMetrics, "disable-exporter-metrics", true, "Exclude metrics about the exporter itself (process_*, go_*).",
)

config.RIopsLimitPerGB = cmd.PersistentFlags().StringSlice(
"riops-per-gb", []string{},
"Read IOPS per GB limit to use for each volume group prefix, "+
Expand Down
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ module github.com/openebs/lvm-localpv

go 1.14

replace google.golang.org/protobuf => google.golang.org/protobuf v1.25.0

replace k8s.io/api => k8s.io/api v0.20.2

replace k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.20.2
Expand Down Expand Up @@ -61,10 +63,12 @@ require (
github.com/onsi/gomega v1.7.0
github.com/openebs/lib-csi v0.6.0
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.11.0
github.com/prometheus/common v0.26.0 // indirect
github.com/spf13/cobra v1.1.1
github.com/stretchr/testify v1.6.1
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40
google.golang.org/grpc v1.34.2
k8s.io/api v0.20.2
k8s.io/apimachinery v0.20.2
Expand Down
41 changes: 41 additions & 0 deletions go.sum

Large diffs are not rendered by default.

78 changes: 78 additions & 0 deletions pkg/collector/collector.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
Copyright 2021 The OpenEBS 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 collector

import (
"github.com/openebs/lvm-localpv/pkg/lvm"
"github.com/prometheus/client_golang/prometheus"
"k8s.io/klog"
)

/*
lvmCollector collects vg total size, vg free size and lv size metrics
*/
type lvmCollector struct {
vgFreeMetric *prometheus.Desc
vgSizeMetric *prometheus.Desc
lvSizeMetric *prometheus.Desc
}

func NewLvmCollector() prometheus.Collector {
return &lvmCollector{
vgFreeMetric: prometheus.NewDesc(prometheus.BuildFQName("lvm", "vg", "free_size_bytes"),
"LVM VG free size in bytes",
[]string{"name"}, nil,
),
vgSizeMetric: prometheus.NewDesc(prometheus.BuildFQName("lvm", "vg", "total_size_bytes"),
"LVM VG total size in bytes",
[]string{"name"}, nil,
),
// Metric name is openebs_size_of_volume which stores the size of lv
lvSizeMetric: prometheus.NewDesc(prometheus.BuildFQName("openebs", "size_of", "volume"),
"LVM LV total size in bytes",
[]string{"volumename", "device"}, nil,
),
}
}

func (c *lvmCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- c.vgFreeMetric
ch <- c.vgSizeMetric
ch <- c.lvSizeMetric
}

func (c *lvmCollector) Collect(ch chan<- prometheus.Metric) {
vgList, err := lvm.ListLVMVolumeGroup(false)
if err != nil {
klog.Errorf("error in getting the list of lvm volume groups: %v", err)
} else {
for _, vg := range vgList {
ch <- prometheus.MustNewConstMetric(c.vgFreeMetric, prometheus.GaugeValue, vg.Free.AsApproximateFloat64(), vg.Name)
ch <- prometheus.MustNewConstMetric(c.vgSizeMetric, prometheus.GaugeValue, vg.Size.AsApproximateFloat64(), vg.Name)
}
}

lvList, err := lvm.ListLVMLogicalVolume()
if err != nil {
klog.Errorf("error in getting the list of lvm logical volumes: %v", err)
} else {
for _, lv := range lvList {
ch <- prometheus.MustNewConstMetric(c.lvSizeMetric, prometheus.GaugeValue, float64(lv.Size), lv.Name, lv.Device)

}
}
}
10 changes: 10 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@ type Config struct {
// WBpsLimitPerGB provides read bps rate limits per volume group type
// as a string slice, in the form ["vg1-prefix=100", "vg2-prefix=200"]
WBpsLimitPerGB *[]string

// The TCP network address where the prometheus metrics endpoint will listen (example: `:9080`).
// The default is empty string, which means metrics endpoint is disabled.
ListenAddress string

// The HTTP path where prometheus metrics will be exposed. Default is `/metrics`.
MetricsPath string

// Exclude metrics about the exporter itself (process_*, go_*).
DisableExporterMetrics bool
}

// Default returns a new instance of config
Expand Down
88 changes: 88 additions & 0 deletions pkg/driver/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,15 @@ package driver

import (
"errors"
"net/http"
"strings"
"sync"

"github.com/openebs/lvm-localpv/pkg/collector"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors"
"github.com/prometheus/client_golang/prometheus/promhttp"

"github.com/container-storage-interface/spec/lib/go/csi"
"github.com/openebs/lib-csi/pkg/btrfs"
k8sapi "github.com/openebs/lib-csi/pkg/client/k8s"
Expand Down Expand Up @@ -79,11 +85,93 @@ func NewNode(d *CSIDriver) csi.NodeServer {
}
}()

if d.config.ListenAddress != "" {
exposeMetrics(d.config.ListenAddress, d.config.MetricsPath, d.config.DisableExporterMetrics)
}

return &node{
driver: d,
}
}

//Function to register collectors to collect LVM related metrics and exporter metrics.
//
//If disableExporterMetrics is set to false, exporter will include metrics about itself i.e (process_*, go_*).
func registerCollectors(disableExporterMetrics bool) (*prometheus.Registry, error) {
registry := prometheus.NewRegistry()

if !disableExporterMetrics {
processCollector := collectors.NewProcessCollector(collectors.ProcessCollectorOpts{})
err := registry.Register(processCollector)
if err != nil {
klog.Errorf("failed to register process collector for exporter metrics collection: %s", err.Error())
return nil, err
}
goProcessCollector := collectors.NewGoCollector()
err = registry.Register(goProcessCollector)
if err != nil {
klog.Errorf("failed to register go process collector for exporter metrics collection: %s", err.Error())
return nil, err
}
}
lvmCollector := collector.NewLvmCollector()

err := registry.Register(lvmCollector)
if err != nil {
klog.Errorf("failed to register LVM collector for LVM metrics collection: %s", err.Error())
return nil, err
}
return registry, nil
}

type promLog struct{}

// Implementation of Println(...) method of Logger interface of prometheus client_go.
func (p *promLog) Println(v ...interface{}) {
klog.Error(v...)
}

func promLogger() *promLog {
return &promLog{}
}

//Function to start HTTP server to expose LVM metrics.
//
//Parameters:
//
//listenAddr: TCP network address where the prometheus metrics endpoint will listen.
//
//metricsPath: The HTTP path where prometheus metrics will be exposed.
//
//disableExporterMetrics: Exclude metrics about the exporter itself (process_*, go_*).
func exposeMetrics(listenAddr string, metricsPath string, disableExporterMetrics bool) {

// Registry with all the collectors registered
registry, err := registerCollectors(disableExporterMetrics)
if err != nil {
klog.Fatalf("Failed to register collectors for LVM metrics collection: %s", err.Error())
}

http.Handle(metricsPath, promhttp.InstrumentMetricHandler(registry, promhttp.HandlerFor(registry, promhttp.HandlerOpts{
ErrorLog: promLogger(),
})))
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte(`<html>
<head><title>LVM Exporter</title></head>
<body>
<h1>LVM Exporter</h1>
<p><a href="` + metricsPath + `">Metrics</a></p>
</body>
</html>`))
})

go func() {
if err := http.ListenAndServe(listenAddr, nil); err != nil {
klog.Fatalf("Failed to start HTTP server at specified address (%q) and metrics path (%q) to expose LVM metrics: %s", listenAddr, metricsPath, err.Error())
}
}()
}

// GetVolAndMountInfo get volume and mount info from node csi volume request
func GetVolAndMountInfo(
req *csi.NodePublishVolumeRequest,
Expand Down
Loading

0 comments on commit 15a2c7c

Please sign in to comment.