initial
Signed-off-by: Vasiliy Tolstov <v.tolstov@sdstack.com>
This commit is contained in:
commit
8fc004ab36
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/libvirt_exporter
|
22
LICENSE
Normal file
22
LICENSE
Normal file
@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 sdstack
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
22
README.md
Normal file
22
README.md
Normal file
@ -0,0 +1,22 @@
|
||||
# Prometheus libvirt exporter
|
||||
|
||||
Supported metrics
|
||||
```
|
||||
libvirt_domain_block_stats_read_bytes_total{domain="...",source_file="...",target_device="..."}
|
||||
libvirt_domain_block_stats_read_requests_total{domain="...",source_file="...",target_device="..."}
|
||||
libvirt_domain_block_stats_write_bytes_total{domain="...",source_file="...",target_device="..."}
|
||||
libvirt_domain_block_stats_write_requests_total{domain="...",source_file="...",target_device="..."}
|
||||
libvirt_domain_info_cpu_time_seconds_total{domain="..."}
|
||||
libvirt_domain_info_maximum_memory_bytes{domain="..."}
|
||||
libvirt_domain_info_memory_usage_bytes{domain="..."}
|
||||
libvirt_domain_info_virtual_cpus{domain="..."}
|
||||
libvirt_domain_interface_stats_receive_bytes_total{domain="...",source_bridge="...",target_device="..."}
|
||||
libvirt_domain_interface_stats_receive_drops_total{domain="...",source_bridge="...",target_device="..."}
|
||||
libvirt_domain_interface_stats_receive_errors_total{domain="...",source_bridge="...",target_device="..."}
|
||||
libvirt_domain_interface_stats_receive_packets_total{domain="...",source_bridge="...",target_device="..."}
|
||||
libvirt_domain_interface_stats_transmit_bytes_total{domain="...",source_bridge="...",target_device="..."}
|
||||
libvirt_domain_interface_stats_transmit_drops_total{domain="...",source_bridge="...",target_device="..."}
|
||||
libvirt_domain_interface_stats_transmit_errors_total{domain="...",source_bridge="...",target_device="..."}
|
||||
libvirt_domain_interface_stats_transmit_packets_total{domain="...",source_bridge="...",target_device="..."}
|
||||
libvirt_up
|
||||
```
|
534
common.go
Normal file
534
common.go
Normal file
@ -0,0 +1,534 @@
|
||||
package promlibvirt
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"sdstack.com/sdstack/compute"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
libvirt_plain "github.com/sdstack/go-libvirt-plain"
|
||||
libvirt_dbus "github.com/sdstack/go-libvirt-dbus"
|
||||
)
|
||||
|
||||
var (
|
||||
// exporter metrics
|
||||
libvirtUpDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "", "up"),
|
||||
"Whether scraping libvirt's metrics was successful.",
|
||||
nil,
|
||||
nil)
|
||||
|
||||
// memory metrics
|
||||
libvirtDomainMemoryMaximumDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_memory", "maximum_bytes"),
|
||||
"Maximum allowed memory of the domain, in bytes.",
|
||||
[]string{"domain"},
|
||||
nil)
|
||||
libvirtDomainMemoryCurrentDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_memory", "current_bytes"),
|
||||
"Memory usage of the domain, in bytes.",
|
||||
[]string{"domain"},
|
||||
nil)
|
||||
libvirtDomainMemoryResidentDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_memory", "resident_bytes"),
|
||||
"Memory usage of the domain, in bytes.",
|
||||
[]string{"domain"},
|
||||
nil)
|
||||
libvirtDomainMemoryLastUpdateDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_memory", "last_update_stats"),
|
||||
"Last update of memory stats, in seconds.",
|
||||
[]string{"domain"},
|
||||
nil)
|
||||
|
||||
// cpu metrics
|
||||
libvirtDomainCpuTimeDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_cpu", "time_seconds_total"),
|
||||
"Amount of CPU time used by the domain, in seconds.",
|
||||
[]string{"domain"},
|
||||
nil)
|
||||
libvirtDomainCpuSystemDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_cpu", "system_seconds_total"),
|
||||
"Amount of CPU time used by the domain, in seconds.",
|
||||
[]string{"domain"},
|
||||
nil)
|
||||
libvirtDomainCpuUserDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_cpu", "user_seconds_total"),
|
||||
"Amount of CPU time used by the domain, in seconds.",
|
||||
[]string{"domain"},
|
||||
nil)
|
||||
|
||||
// vcpu metrics
|
||||
libvirtDomainVcpuMaximumDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_vcpu", "maximum"),
|
||||
"Number of maximum virtual CPUs for the domain.",
|
||||
[]string{"domain"},
|
||||
nil)
|
||||
libvirtDomainVcpuCurrentDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_vcpu", "current"),
|
||||
"Number of current virtual CPUs for the domain.",
|
||||
[]string{"domain"},
|
||||
nil)
|
||||
|
||||
// block metrics
|
||||
libvirtDomainBlockAllocBytesDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "alloc_bytes_total"),
|
||||
"Number of bytes allocated for device, in bytes.",
|
||||
[]string{"domain", "source", "target"},
|
||||
nil)
|
||||
libvirtDomainBlockCapBytesDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "cap_bytes_total"),
|
||||
"Number of bytes capacity for device, in bytes.",
|
||||
[]string{"domain", "source", "target"},
|
||||
nil)
|
||||
libvirtDomainBlockPhysBytesDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "phy_bytes_total"),
|
||||
"Number of bytes physical for device, in bytes.",
|
||||
[]string{"domain", "source", "target"},
|
||||
nil)
|
||||
|
||||
libvirtDomainBlockRdBytesDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "read_bytes_total"),
|
||||
"Number of bytes read from device, in bytes.",
|
||||
[]string{"domain", "source", "target"},
|
||||
nil)
|
||||
libvirtDomainBlockRdReqsDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "read_requests_total"),
|
||||
"Number of read requests from device.",
|
||||
[]string{"domain", "source", "target"},
|
||||
nil)
|
||||
libvirtDomainBlockRdTimesDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "read_seconds_total"),
|
||||
"Amount of time spent reading from a block device, in seconds.",
|
||||
[]string{"domain", "source", "target"},
|
||||
nil)
|
||||
|
||||
libvirtDomainBlockWrBytesDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "write_bytes_total"),
|
||||
"Number of bytes written from a block device, in bytes.",
|
||||
[]string{"domain", "source", "target"},
|
||||
nil)
|
||||
libvirtDomainBlockWrReqsDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "write_requests_total"),
|
||||
"Number of write requests from a block device.",
|
||||
[]string{"domain", "source", "target"},
|
||||
nil)
|
||||
libvirtDomainBlockWrTimesDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "write_seconds_total"),
|
||||
"Amount of time spent writing from a block device, in seconds.",
|
||||
[]string{"domain", "source", "target"},
|
||||
nil)
|
||||
|
||||
libvirtDomainBlockFlReqsDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "flush_requests_total"),
|
||||
"Number of flush requests from a block device.",
|
||||
[]string{"domain", "source", "target"},
|
||||
nil)
|
||||
libvirtDomainBlockFlTimesDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "flush_seconds_total"),
|
||||
"Amount of time spent flushing of a block device, in seconds.",
|
||||
[]string{"domain", "source", "target"},
|
||||
nil)
|
||||
|
||||
// network metrcis
|
||||
libvirtDomainNetRxBytesDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_net", "receive_bytes_total"),
|
||||
"Number of bytes received on a network interface, in bytes.",
|
||||
[]string{"domain", "source", "target"},
|
||||
nil)
|
||||
libvirtDomainNetRxPktsDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_net", "receive_packets_total"),
|
||||
"Number of packets received on a network interface.",
|
||||
[]string{"domain", "source", "target"},
|
||||
nil)
|
||||
libvirtDomainNetRxErrsDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_net", "receive_errors_total"),
|
||||
"Number of packet receive errors on a network interface.",
|
||||
[]string{"domain", "source", "target"},
|
||||
nil)
|
||||
libvirtDomainNetRxDropDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_net", "receive_drops_total"),
|
||||
"Number of packet receive drops on a network interface.",
|
||||
[]string{"domain", "source", "target"},
|
||||
nil)
|
||||
|
||||
libvirtDomainNetTxBytesDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_net", "transmit_bytes_total"),
|
||||
"Number of bytes transmitted on a network interface, in bytes.",
|
||||
[]string{"domain", "source", "target"},
|
||||
nil)
|
||||
libvirtDomainNetTxPktsDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_net", "transmit_packets_total"),
|
||||
"Number of packets transmitted on a network interface.",
|
||||
[]string{"domain", "source", "target"},
|
||||
nil)
|
||||
libvirtDomainNetTxErrsDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_net", "transmit_errors_total"),
|
||||
"Number of packet transmit errors on a network interface.",
|
||||
[]string{"domain", "source", "target"},
|
||||
nil)
|
||||
libvirtDomainNetTxDropDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_net", "transmit_drops_total"),
|
||||
"Number of packet transmit drops on a network interface.",
|
||||
[]string{"domain", "source", "target"},
|
||||
nil)
|
||||
)
|
||||
|
||||
// CollectDomain extracts Prometheus metrics from a libvirt domain.
|
||||
func CollectStats(ch chan<- prometheus.Metric, stats map[string]map[string]interface{}) error {
|
||||
|
||||
for dname, items := range stats {
|
||||
for ikey, ival := range items {
|
||||
idx := strings.Index(ikey, ".")
|
||||
idxl := strings.LastIndex(ikey, ".")
|
||||
key := ikey[:idx]
|
||||
switch key {
|
||||
default:
|
||||
fmt.Printf("zz %s %s %s\n", dname, ikey, ival)
|
||||
/*
|
||||
case "block":
|
||||
case "net":
|
||||
case "cpu":
|
||||
case "block":
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainVcpuCurrentDesc,
|
||||
prometheus.GaugeValue,
|
||||
float64(ival.(uint32)),
|
||||
dname, items[ikey[:idxl]+".path", items[ikey[:idxl]+".name")
|
||||
*/
|
||||
case "vcpu":
|
||||
switch ikey[idx+1:] {
|
||||
default:
|
||||
fmt.Printf("xx %s %s %s\n", dname, ikey, ival)
|
||||
case "maximum":
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainVcpuMaximumDesc,
|
||||
prometheus.GaugeValue,
|
||||
float64(ival.(uint32)),
|
||||
dname)
|
||||
case "current":
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainVcpuCurrentDesc,
|
||||
prometheus.GaugeValue,
|
||||
float64(ival.(uint32)),
|
||||
dname)
|
||||
}
|
||||
|
||||
case "cpu":
|
||||
switch ikey[idx+1:] {
|
||||
case "user":
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainCpuUserDesc,
|
||||
prometheus.CounterValue,
|
||||
float64(ival.(uint64))/1e9,
|
||||
dname)
|
||||
case "system":
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainCpuSystemDesc,
|
||||
prometheus.CounterValue,
|
||||
float64(ival.(uint64))/1e9,
|
||||
dname)
|
||||
case "time":
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainCpuTimeDesc,
|
||||
prometheus.CounterValue,
|
||||
float64(ival.(uint64))/1e9,
|
||||
dname)
|
||||
}
|
||||
case "balloon":
|
||||
switch ikey[idx+1:] {
|
||||
default:
|
||||
panic(fmt.Sprintf("xxx %s %s %s\n", dname, ikey, ival))
|
||||
case "last-update":
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainMemoryLastUpdateDesc,
|
||||
prometheus.GaugeValue,
|
||||
float64(ival.(uint64)),
|
||||
dname)
|
||||
case "maximum":
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainMemoryMaximumDesc,
|
||||
prometheus.GaugeValue,
|
||||
float64(ival.(uint64))*1024,
|
||||
dname)
|
||||
case "current":
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainMemoryCurrentDesc,
|
||||
prometheus.GaugeValue,
|
||||
float64(ival.(uint64))*1024,
|
||||
dname)
|
||||
case "rss":
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainMemoryResidentDesc,
|
||||
prometheus.GaugeValue,
|
||||
float64(ival.(uint64))*1024,
|
||||
dname)
|
||||
}
|
||||
}
|
||||
/*
|
||||
if blockStats.RdBytesSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBlockRdBytesDesc,
|
||||
prometheus.CounterValue,
|
||||
float64(blockStats.RdBytes),
|
||||
domainName,
|
||||
disk.Source.File.File,
|
||||
disk.Target.Dev)
|
||||
}
|
||||
|
||||
if blockStats.RdReqSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBlockRdReqDesc,
|
||||
prometheus.CounterValue,
|
||||
float64(blockStats.RdReq),
|
||||
domainName,
|
||||
disk.Source.File.File,
|
||||
disk.Target.Dev)
|
||||
}
|
||||
if blockStats.RdTotalTimesSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBlockRdTotalTimesDesc,
|
||||
prometheus.CounterValue,
|
||||
float64(blockStats.RdTotalTimes)/1e9,
|
||||
domainName,
|
||||
disk.Source.File.File,
|
||||
disk.Target.Dev)
|
||||
}
|
||||
if blockStats.WrBytesSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBlockWrBytesDesc,
|
||||
prometheus.CounterValue,
|
||||
float64(blockStats.WrBytes),
|
||||
domainName,
|
||||
disk.Source.File.File,
|
||||
disk.Target.Dev)
|
||||
}
|
||||
if blockStats.WrReqSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBlockWrReqDesc,
|
||||
prometheus.CounterValue,
|
||||
float64(blockStats.WrReq),
|
||||
domainName,
|
||||
disk.Source.File.File,
|
||||
disk.Target.Dev)
|
||||
}
|
||||
if blockStats.WrTotalTimesSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBlockWrTotalTimesDesc,
|
||||
prometheus.CounterValue,
|
||||
float64(blockStats.WrTotalTimes)/1e9,
|
||||
domainName,
|
||||
disk.Source.File.File,
|
||||
disk.Target.Dev)
|
||||
}
|
||||
if blockStats.FlushReqSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBlockFlushReqDesc,
|
||||
prometheus.CounterValue,
|
||||
float64(blockStats.FlushReq),
|
||||
domainName,
|
||||
disk.Source.File.File,
|
||||
disk.Target.Dev)
|
||||
}
|
||||
if blockStats.FlushTotalTimesSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBlockFlushTotalTimesDesc,
|
||||
prometheus.CounterValue,
|
||||
float64(blockStats.FlushTotalTimes)/1e9,
|
||||
domainName,
|
||||
disk.Source.File.File,
|
||||
disk.Target.Dev)
|
||||
}
|
||||
|
||||
if interfaceStats.RxBytesSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainInterfaceRxBytesDesc,
|
||||
prometheus.CounterValue,
|
||||
float64(interfaceStats.RxBytes),
|
||||
domainName,
|
||||
iface.Source.Bridge,
|
||||
iface.Target.Dev)
|
||||
}
|
||||
if interfaceStats.RxPacketsSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainInterfaceRxPacketsDesc,
|
||||
prometheus.CounterValue,
|
||||
float64(interfaceStats.RxPackets),
|
||||
domainName,
|
||||
iface.Source.Bridge,
|
||||
iface.Target.Dev)
|
||||
}
|
||||
if interfaceStats.RxErrsSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainInterfaceRxErrsDesc,
|
||||
prometheus.CounterValue,
|
||||
float64(interfaceStats.RxErrs),
|
||||
domainName,
|
||||
iface.Source.Bridge,
|
||||
iface.Target.Dev)
|
||||
}
|
||||
if interfaceStats.RxDropSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainInterfaceRxDropDesc,
|
||||
prometheus.CounterValue,
|
||||
float64(interfaceStats.RxDrop),
|
||||
domainName,
|
||||
iface.Source.Bridge,
|
||||
iface.Target.Dev)
|
||||
}
|
||||
if interfaceStats.TxBytesSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainInterfaceTxBytesDesc,
|
||||
prometheus.CounterValue,
|
||||
float64(interfaceStats.TxBytes),
|
||||
domainName,
|
||||
iface.Source.Bridge,
|
||||
iface.Target.Device)
|
||||
}
|
||||
if interfaceStats.TxPacketsSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainInterfaceTxPacketsDesc,
|
||||
prometheus.CounterValue,
|
||||
float64(interfaceStats.TxPackets),
|
||||
domainName,
|
||||
iface.Source.Bridge,
|
||||
iface.Target.Device)
|
||||
}
|
||||
if interfaceStats.TxErrsSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainInterfaceTxErrsDesc,
|
||||
prometheus.CounterValue,
|
||||
float64(interfaceStats.TxErrs),
|
||||
domainName,
|
||||
iface.Source.Bridge,
|
||||
iface.Target.Device)
|
||||
}
|
||||
if interfaceStats.TxDropSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainInterfaceTxDropDesc,
|
||||
prometheus.CounterValue,
|
||||
float64(interfaceStats.TxDrop),
|
||||
domainName,
|
||||
iface.Source.Bridge,
|
||||
iface.Target.Device)
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CollectFromLibvirt obtains Prometheus metrics from all domains in a
|
||||
// libvirt setup.
|
||||
func CollectFromLibvirt(ch chan<- prometheus.Metric, uri string) error {
|
||||
var err error
|
||||
var hyper string
|
||||
var driver string
|
||||
var proto string
|
||||
var stats map[string]map[string]interface{}
|
||||
|
||||
u, err := url.Parse(uri)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// qemu+tcp native
|
||||
// plain+qemu+tcp
|
||||
|
||||
fields := strings.Fields(u.Scheme, "+")
|
||||
switch len(fields) {
|
||||
case 3:
|
||||
driver = fields[0]
|
||||
hyper = fields[1]
|
||||
proto = fields[2]
|
||||
case 2:
|
||||
driver = "auto"
|
||||
hyper = fields[0]
|
||||
proto = fields[1]
|
||||
default:
|
||||
driver = "auto"
|
||||
hyper =
|
||||
}
|
||||
|
||||
switch u.Scheme {
|
||||
default:
|
||||
return fmt.Errorf("invalid driver: %s", u.Scheme)
|
||||
case "dbus":
|
||||
if idx > 0 {
|
||||
|
||||
}
|
||||
lv := libvirt_dbus.NewConn(DriverQEMU)
|
||||
err := lv.Connect("")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stats, err = lv.ConnectGetAllDomainStats(0, 0) //536870912
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return CollectStats(ch, stats)
|
||||
}
|
||||
|
||||
// LibvirtExporter implements a Prometheus exporter for libvirt state.
|
||||
type LibvirtExporter struct {
|
||||
uri net.URL
|
||||
}
|
||||
|
||||
// Describe returns metadata for all Prometheus metrics that may be exported.
|
||||
func (e *LibvirtExporter) Describe(ch chan<- *prometheus.Desc) {
|
||||
ch <- libvirtUpDesc
|
||||
|
||||
ch <- libvirtDomainMemoryMaximumDesc
|
||||
ch <- libvirtDomainMemoryCurrentDesc
|
||||
ch <- libvirtDomainMemoryResidentDesc
|
||||
ch <- libvirtDomainMemoryLastUpdateDesc
|
||||
|
||||
ch <- libvirtDomainCpuTimeDesc
|
||||
ch <- libvirtDomainCpuSystemDesc
|
||||
ch <- libvirtDomainCpuUserDesc
|
||||
|
||||
ch <- libvirtDomainVcpuMaximumDesc
|
||||
ch <- libvirtDomainVcpuCurrentDesc
|
||||
|
||||
ch <- libvirtDomainBlockRdBytesDesc
|
||||
ch <- libvirtDomainBlockRdReqsDesc
|
||||
ch <- libvirtDomainBlockRdTimesDesc
|
||||
ch <- libvirtDomainBlockWrBytesDesc
|
||||
ch <- libvirtDomainBlockWrReqsDesc
|
||||
ch <- libvirtDomainBlockWrTimesDesc
|
||||
ch <- libvirtDomainBlockFlReqsDesc
|
||||
ch <- libvirtDomainBlockFlTimesDesc
|
||||
}
|
||||
|
||||
// Collect scrapes Prometheus metrics from libvirt.
|
||||
func (e *LibvirtExporter) Collect(ch chan<- prometheus.Metric) {
|
||||
err := CollectFromLibvirt(ch, e.uri)
|
||||
if err == nil {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtUpDesc,
|
||||
prometheus.GaugeValue,
|
||||
1.0)
|
||||
} else {
|
||||
log.Printf("Failed to scrape metrics: %s", err)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtUpDesc,
|
||||
prometheus.GaugeValue,
|
||||
0.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func NewLibvirtExporter(uri string) (*LibvirtExporter, error) {
|
||||
u, err := url.Parse(uri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &LibvirtExporter{uri: u}, nil
|
||||
}
|
38
prometheus-libvirt-exporter/main.go
Normal file
38
prometheus-libvirt-exporter/main.go
Normal file
@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
promlibvirt "sdstack.com/sdstack/prometheus-libvirt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
listenAddress = flag.String("web.listen-address", ":9177", "Address to listen on for web interface and telemetry.")
|
||||
metricsPath = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.")
|
||||
libvirtURI = flag.String("libvirt.uri", "qemu:///system", "Libvirt URI from which to extract metrics.")
|
||||
)
|
||||
flag.Parse()
|
||||
|
||||
exporter, err := promlibvirt.NewLibvirtExporter(*libvirtURI)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
prometheus.MustRegister(exporter)
|
||||
|
||||
http.Handle(*metricsPath, prometheus.Handler())
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(`
|
||||
<html>
|
||||
<head><title>Libvirt Exporter</title></head>
|
||||
<body>
|
||||
<h1>Libvirt Exporter</h1>
|
||||
<p><a href='` + *metricsPath + `'>Metrics</a></p>
|
||||
</body>
|
||||
</html>`))
|
||||
})
|
||||
log.Fatal(http.ListenAndServe(*listenAddress, nil))
|
||||
}
|
Loading…
Reference in New Issue
Block a user