Intégration de prometheus
This commit is contained in:
commit
ddab175c90
21
.gitgnore
Normal file
21
.gitgnore
Normal file
@ -0,0 +1,21 @@
|
||||
# Allowlisting gitignore template for GO projects prevents us
|
||||
# from adding various unwanted local files, such as generated
|
||||
# files, developer configurations or IDE-specific files etc.
|
||||
#
|
||||
# Recommended: Go.AllowList.gitignore
|
||||
|
||||
# Ignore everything
|
||||
*
|
||||
|
||||
# But not these files...
|
||||
!/.gitignore
|
||||
|
||||
!*.proto
|
||||
!*.go
|
||||
!go.sum
|
||||
!go.mod
|
||||
|
||||
!README.md
|
||||
!LICENSE
|
||||
|
||||
!Makefile
|
65
cmd/qemu/metrics/compute.go
Normal file
65
cmd/qemu/metrics/compute.go
Normal file
@ -0,0 +1,65 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strconv"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"libvirt.org/go/libvirt"
|
||||
)
|
||||
|
||||
var (
|
||||
// Compute
|
||||
libvirtNodeCPUUsage = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "node", "cpu_time_seconds_total"),
|
||||
"CPU usage of node",
|
||||
[]string{"cluster", "node", "thread"},
|
||||
nil)
|
||||
|
||||
libvirtNodeMemoryUsageBytes = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "node", "memory_usage_bytes"),
|
||||
"Memory usage of the node, in bytes.",
|
||||
[]string{"cluster", "node", "total"},
|
||||
nil)
|
||||
)
|
||||
|
||||
func CollectNode(conn *libvirt.Connect, ch chan<- prometheus.Metric, hostname string) error {
|
||||
config, err := Config()
|
||||
if err != nil {
|
||||
log.Fatalf("Fail to read file: %v", err)
|
||||
}
|
||||
|
||||
// Node
|
||||
node_info, err := conn.GetNodeInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodeCPU, _ := conn.GetCPUStats(int(libvirt.NODE_CPU_STATS_ALL_CPUS), 0) // rate(libvirt_node_cpu_time_seconds_total[10s]) * 100
|
||||
nodeMemory, _ := conn.GetMemoryStats(libvirt.NODE_MEMORY_STATS_ALL_CELLS, 0)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtNodeCPUUsage,
|
||||
prometheus.CounterValue,
|
||||
float64(nodeCPU.Kernel+nodeCPU.User+nodeCPU.Iowait)/1e9, // From nsec to sec
|
||||
config.Section("").Key("id").String(),
|
||||
hostname,
|
||||
strconv.FormatInt(int64(node_info.Sockets*node_info.Cores*node_info.Threads), 10),
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtNodeMemoryUsageBytes,
|
||||
prometheus.GaugeValue,
|
||||
float64(nodeMemory.Total-(nodeMemory.Buffers+nodeMemory.Free+nodeMemory.Cached))*1024,
|
||||
config.Section("").Key("id").String(),
|
||||
hostname,
|
||||
strconv.FormatInt(int64(nodeMemory.Total), 10),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *LibvirtExporter) DescribeNode(ch chan<- *prometheus.Desc) {
|
||||
ch <- libvirtNodeCPUUsage
|
||||
ch <- libvirtNodeMemoryUsageBytes
|
||||
}
|
739
cmd/qemu/metrics/domains.go
Normal file
739
cmd/qemu/metrics/domains.go
Normal file
@ -0,0 +1,739 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"log"
|
||||
"strconv"
|
||||
|
||||
"deevirt.fr/compute/cmd/qemu/metrics/schema"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"gopkg.in/ini.v1"
|
||||
"libvirt.org/go/libvirt"
|
||||
)
|
||||
|
||||
var (
|
||||
// Domain CPU
|
||||
libvirtDomainInfoMaxMemBytes = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain", "memory_maximum_allocated_bytes"),
|
||||
"Maximum allowed memory of the domain, in bytes.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id"},
|
||||
nil)
|
||||
libvirtDomainInfoMemoryUsageBytes = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain", "memory_allocated_bytes"),
|
||||
"Memory usage of the domain, in bytes.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id"},
|
||||
nil)
|
||||
libvirtDomainInfoNrVirtCPU = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain", "virtual_cpus"),
|
||||
"Number of virtual CPUs for the domain.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id"},
|
||||
nil)
|
||||
libvirtDomainInfoCPUTime = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain", "cpu_time_seconds_total"),
|
||||
"Amount of CPU time used by the domain, in seconds.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id"},
|
||||
nil)
|
||||
libvirtDomainInfoVirDomainState = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain", "state"),
|
||||
"Virtual domain state. 0: no state, 1: the domain is running, 2: the domain is blocked on resource,"+
|
||||
" 3: the domain is paused by user, 4: the domain is being shut down, 5: the domain is shut off,"+
|
||||
"6: the domain is crashed, 7: the domain is suspended by guest power management",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id"},
|
||||
nil)
|
||||
|
||||
// VCPU
|
||||
libvirtDomainVcpuState = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_vcpu", "state"),
|
||||
"VCPU state. 0: offline, 1: running, 2: blocked",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "vcpu"},
|
||||
nil)
|
||||
libvirtDomainVcpuTime = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_vcpu", "time_seconds_total"),
|
||||
"Amount of CPU time used by the domain's VCPU, in seconds.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "vcpu"},
|
||||
nil)
|
||||
libvirtDomainVcpuWait = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_vcpu", "wait_seconds_total"),
|
||||
"Vcpu's wait_sum metric. CONFIG_SCHEDSTATS has to be enabled",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "vcpu"},
|
||||
nil)
|
||||
libvirtDomainVcpuDelay = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_vcpu", "delay_seconds_total"),
|
||||
"Amount of CPU time used by the domain's VCPU, in seconds. "+
|
||||
"Vcpu's delay metric. Time the vcpu thread was enqueued by the "+
|
||||
"host scheduler, but was waiting in the queue instead of running. "+
|
||||
"Exposed to the VM as a steal time.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "vcpu"},
|
||||
nil)
|
||||
|
||||
// Domain Balloon
|
||||
libvirtDomainBalloonStatCurrentBytes = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_balloon", "current_bytes"),
|
||||
"The memory currently used (in bytes).",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id"},
|
||||
nil)
|
||||
libvirtDomainBalloonStatMaximumBytes = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_balloon", "maximum_bytes"),
|
||||
"The maximum memory (in bytes).",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id"},
|
||||
nil)
|
||||
libvirtDomainBalloonStatSwapInBytes = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_balloon", "swap_in_bytes"),
|
||||
"The amount of data read from swap space (in bytes).",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id"},
|
||||
nil)
|
||||
libvirtDomainBalloonStatSwapOutBytes = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_balloon", "swap_out_bytes"),
|
||||
"The amount of memory written out to swap space (in bytes).",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id"},
|
||||
nil)
|
||||
libvirtDomainBalloonStatMajorFaultTotal = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_balloon", "major_fault_total"),
|
||||
"Page faults occur when a process makes a valid access to virtual memory that is not available. "+
|
||||
"When servicing the page fault, if disk IO is required, it is considered a major fault.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id"},
|
||||
nil)
|
||||
libvirtDomainBalloonStatMinorFaultTotal = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_balloon", "minor_fault_total"),
|
||||
"Page faults occur when a process makes a valid access to virtual memory that is not available. "+
|
||||
"When servicing the page not fault, if disk IO is required, it is considered a minor fault.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id"},
|
||||
nil)
|
||||
libvirtDomainBalloonStatUnusedBytes = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_balloon", "unused_bytes"),
|
||||
"The amount of memory left completely unused by the system. Memory that is available but used for "+
|
||||
"reclaimable caches should NOT be reported as free. This value is expressed in bytes.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id"},
|
||||
nil)
|
||||
libvirtDomainBalloonStatAvailableBytes = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_balloon", "available_bytes"),
|
||||
"The total amount of usable memory as seen by the domain. This value may be less than the amount of "+
|
||||
"memory assigned to the domain if a balloon driver is in use or if the guest OS does not initialize all "+
|
||||
"assigned pages. This value is expressed in bytes.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id"},
|
||||
nil)
|
||||
libvirtDomainBalloonStatRssBytes = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_balloon", "rss_bytes"),
|
||||
"Resident Set Size of the process running the domain. This value is in bytes",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id"},
|
||||
nil)
|
||||
libvirtDomainBalloonStatUsableBytes = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_balloon", "usable_bytes"),
|
||||
"How much the balloon can be inflated without pushing the guest system to swap, corresponds "+
|
||||
"to 'Available' in /proc/meminfo",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id"},
|
||||
nil)
|
||||
libvirtDomainBalloonStatDiskCachesBytes = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_balloon", "disk_cache_bytes"),
|
||||
"The amount of memory, that can be quickly reclaimed without additional I/O (in bytes)."+
|
||||
"Typically these pages are used for caching files from disk.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id"},
|
||||
nil)
|
||||
|
||||
// Domain Block
|
||||
libvirtDomainBlockRdBytes = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "read_bytes_total"),
|
||||
"Number of bytes read from a block device, in bytes.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "target_device"},
|
||||
nil)
|
||||
libvirtDomainBlockRdReq = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "read_requests_total"),
|
||||
"Number of read requests from a block device.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "target_device"},
|
||||
nil)
|
||||
libvirtDomainBlockRdTotalTimeSeconds = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "read_time_seconds_total"),
|
||||
"Total time spent on reads from a block device, in seconds.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "target_device"},
|
||||
nil)
|
||||
libvirtDomainBlockWrBytes = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "write_bytes_total"),
|
||||
"Number of bytes written to a block device, in bytes.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "target_device"},
|
||||
nil)
|
||||
libvirtDomainBlockWrReq = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "write_requests_total"),
|
||||
"Number of write requests to a block device.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "target_device"},
|
||||
nil)
|
||||
libvirtDomainBlockWrTotalTimes = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "write_time_seconds_total"),
|
||||
"Total time spent on writes on a block device, in seconds",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "target_device"},
|
||||
nil)
|
||||
libvirtDomainBlockFlushReq = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "flush_requests_total"),
|
||||
"Total flush requests from a block device.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "target_device"},
|
||||
nil)
|
||||
libvirtDomainBlockFlushTotalTimeSeconds = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "flush_time_seconds_total"),
|
||||
"Total time in seconds spent on cache flushing to a block device",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "target_device"},
|
||||
nil)
|
||||
libvirtDomainBlockAllocation = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "allocation"),
|
||||
"Offset of the highest written sector on a block device.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "target_device"},
|
||||
nil)
|
||||
libvirtDomainBlockCapacityBytes = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "capacity_bytes"),
|
||||
"Logical size in bytes of the block device backing image.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "target_device"},
|
||||
nil)
|
||||
libvirtDomainBlockPhysicalSizeBytes = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_block", "physicalsize_bytes"),
|
||||
"Physical size in bytes of the container of the backing image.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "target_device"},
|
||||
nil)
|
||||
|
||||
// Domain Net
|
||||
libvirtDomainInterfaceRxBytes = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_interface", "receive_bytes_total"),
|
||||
"Number of bytes received on a network interface, in bytes.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "target_device"},
|
||||
nil)
|
||||
libvirtDomainInterfaceRxPackets = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_interface", "receive_packets_total"),
|
||||
"Number of packets received on a network interface.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "target_device"},
|
||||
nil)
|
||||
libvirtDomainInterfaceRxErrs = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_interface", "receive_errors_total"),
|
||||
"Number of packet receive errors on a network interface.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "target_device"},
|
||||
nil)
|
||||
libvirtDomainInterfaceRxDrop = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_interface", "receive_drops_total"),
|
||||
"Number of packet receive drops on a network interface.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "target_device"},
|
||||
nil)
|
||||
libvirtDomainInterfaceTxBytes = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_interface", "transmit_bytes_total"),
|
||||
"Number of bytes transmitted on a network interface, in bytes.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "target_device"},
|
||||
nil)
|
||||
libvirtDomainInterfaceTxPackets = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_interface", "transmit_packets_total"),
|
||||
"Number of packets transmitted on a network interface.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "target_device"},
|
||||
nil)
|
||||
libvirtDomainInterfaceTxErrs = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_interface", "transmit_errors_total"),
|
||||
"Number of packet transmit errors on a network interface.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "target_device"},
|
||||
nil)
|
||||
libvirtDomainInterfaceTxDrop = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "domain_interface", "transmit_drops_total"),
|
||||
"Number of packet transmit drops on a network interface.",
|
||||
[]string{"cluster_id", "company_id", "datacenter_id", "domain_id", "target_device"},
|
||||
nil)
|
||||
)
|
||||
|
||||
func CollectDomain(ch chan<- prometheus.Metric, stat libvirt.DomainStats, hostname string) error {
|
||||
config, err := Config()
|
||||
if err != nil {
|
||||
log.Fatalf("Fail to read file: %v", err)
|
||||
}
|
||||
|
||||
domainUUID, err := stat.Domain.GetUUIDString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Decode XML description of domain to get block device names, etc.
|
||||
xmlDesc, err := stat.Domain.GetXMLDesc(0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var desc schema.Domain
|
||||
err = xml.Unmarshal([]byte(xmlDesc), &desc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Report domain info.
|
||||
info, err := stat.Domain.GetInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainInfoMaxMemBytes,
|
||||
prometheus.GaugeValue,
|
||||
float64(info.MaxMem)*1024,
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainInfoMemoryUsageBytes,
|
||||
prometheus.GaugeValue,
|
||||
float64(info.Memory)*1024,
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainInfoNrVirtCPU,
|
||||
prometheus.GaugeValue,
|
||||
float64(info.NrVirtCpu),
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainInfoCPUTime,
|
||||
prometheus.CounterValue,
|
||||
float64(info.CpuTime)/1e9, // From nsec to sec
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainInfoVirDomainState,
|
||||
prometheus.GaugeValue,
|
||||
float64(info.State),
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID)
|
||||
|
||||
// Block Stats
|
||||
CollectDomainVCPU(ch, stat.Vcpu, hostname, domainUUID, config, desc)
|
||||
CollectDomainBlock(ch, stat.Block, hostname, domainUUID, config, desc)
|
||||
CollectDomainNet(ch, stat.Net, hostname, domainUUID, config, desc)
|
||||
CollectDomainBalloon(ch, stat.Balloon, hostname, domainUUID, config, desc)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func CollectDomainVCPU(ch chan<- prometheus.Metric, stat []libvirt.DomainStatsVcpu, hostname string, domainUUID string, config *ini.File, desc schema.Domain) {
|
||||
for idx, vcpu := range stat {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainVcpuState,
|
||||
prometheus.GaugeValue,
|
||||
float64(vcpu.State),
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
strconv.FormatInt(int64(idx), 10))
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainVcpuTime,
|
||||
prometheus.CounterValue,
|
||||
float64(vcpu.Time)/1000/1000/1000, // From nsec to sec
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
strconv.FormatInt(int64(idx), 10))
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainVcpuWait,
|
||||
prometheus.CounterValue,
|
||||
float64(vcpu.Wait)/1e9, // From nsec to sec
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
strconv.FormatInt(int64(idx), 10))
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainVcpuDelay,
|
||||
prometheus.CounterValue,
|
||||
float64(vcpu.Delay)/1e9, // From nsec to sec
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
strconv.FormatInt(int64(idx), 10))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func CollectDomainBalloon(ch chan<- prometheus.Metric, stat *libvirt.DomainStatsBalloon, hostname string, domainUUID string, config *ini.File, desc schema.Domain) {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBalloonStatCurrentBytes,
|
||||
prometheus.GaugeValue,
|
||||
float64(stat.Current)*1024,
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBalloonStatMaximumBytes,
|
||||
prometheus.GaugeValue,
|
||||
float64(stat.Maximum)*1024,
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBalloonStatSwapInBytes,
|
||||
prometheus.GaugeValue,
|
||||
float64(stat.SwapIn)*1024,
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBalloonStatSwapOutBytes,
|
||||
prometheus.GaugeValue,
|
||||
float64(stat.SwapOut)*1024,
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBalloonStatMajorFaultTotal,
|
||||
prometheus.CounterValue,
|
||||
float64(stat.MajorFault),
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBalloonStatMinorFaultTotal,
|
||||
prometheus.CounterValue,
|
||||
float64(stat.MinorFault),
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBalloonStatUnusedBytes,
|
||||
prometheus.GaugeValue,
|
||||
float64(stat.Unused)*1024,
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBalloonStatAvailableBytes,
|
||||
prometheus.GaugeValue,
|
||||
float64(stat.Available)*1024,
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBalloonStatRssBytes,
|
||||
prometheus.GaugeValue,
|
||||
float64(stat.Rss)*1024,
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBalloonStatUsableBytes,
|
||||
prometheus.GaugeValue,
|
||||
float64(stat.Usable)*1024,
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBalloonStatDiskCachesBytes,
|
||||
prometheus.GaugeValue,
|
||||
float64(stat.DiskCaches)*1024,
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID)
|
||||
|
||||
}
|
||||
|
||||
func CollectDomainBlock(ch chan<- prometheus.Metric, stat []libvirt.DomainStatsBlock, hostname string, domainUUID string, config *ini.File, desc schema.Domain) {
|
||||
for _, block := range stat {
|
||||
|
||||
if block.RdBytesSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBlockRdBytes,
|
||||
prometheus.CounterValue,
|
||||
float64(block.RdBytes),
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
block.Name)
|
||||
}
|
||||
if block.RdReqsSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBlockRdReq,
|
||||
prometheus.CounterValue,
|
||||
float64(block.RdReqs),
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
block.Name)
|
||||
}
|
||||
if block.RdTimesSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBlockRdTotalTimeSeconds,
|
||||
prometheus.CounterValue,
|
||||
float64(block.RdTimes)/1e9,
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
block.Name)
|
||||
}
|
||||
if block.WrBytesSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBlockWrBytes,
|
||||
prometheus.CounterValue,
|
||||
float64(block.WrBytes),
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
block.Name)
|
||||
}
|
||||
if block.WrReqsSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBlockWrReq,
|
||||
prometheus.CounterValue,
|
||||
float64(block.WrReqs),
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
block.Name)
|
||||
}
|
||||
if block.WrTimesSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBlockWrTotalTimes,
|
||||
prometheus.CounterValue,
|
||||
float64(block.WrTimes)/1e9,
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
block.Name)
|
||||
}
|
||||
if block.FlReqsSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBlockFlushReq,
|
||||
prometheus.CounterValue,
|
||||
float64(block.FlReqs),
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
block.Name)
|
||||
}
|
||||
if block.FlTimesSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBlockFlushTotalTimeSeconds,
|
||||
prometheus.CounterValue,
|
||||
float64(block.FlTimes)/1e9,
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
block.Name)
|
||||
}
|
||||
if block.AllocationSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBlockAllocation,
|
||||
prometheus.GaugeValue,
|
||||
float64(block.Allocation),
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
block.Name)
|
||||
}
|
||||
if block.CapacitySet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBlockCapacityBytes,
|
||||
prometheus.GaugeValue,
|
||||
float64(block.Capacity),
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
block.Name)
|
||||
}
|
||||
if block.PhysicalSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainBlockPhysicalSizeBytes,
|
||||
prometheus.GaugeValue,
|
||||
float64(block.Physical),
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
block.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func CollectDomainNet(ch chan<- prometheus.Metric, stat []libvirt.DomainStatsNet, hostname string, domainUUID string, config *ini.File, desc schema.Domain) {
|
||||
for _, iface := range stat {
|
||||
|
||||
if iface.RxBytesSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainInterfaceRxBytes,
|
||||
prometheus.CounterValue,
|
||||
float64(iface.RxBytes),
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
iface.Name)
|
||||
}
|
||||
if iface.RxPktsSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainInterfaceRxPackets,
|
||||
prometheus.CounterValue,
|
||||
float64(iface.RxPkts),
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
iface.Name)
|
||||
}
|
||||
if iface.RxErrsSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainInterfaceRxErrs,
|
||||
prometheus.CounterValue,
|
||||
float64(iface.RxErrs),
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
iface.Name)
|
||||
}
|
||||
if iface.RxDropSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainInterfaceRxDrop,
|
||||
prometheus.CounterValue,
|
||||
float64(iface.RxDrop),
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
iface.Name)
|
||||
}
|
||||
if iface.TxBytesSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainInterfaceTxBytes,
|
||||
prometheus.CounterValue,
|
||||
float64(iface.TxBytes),
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
iface.Name)
|
||||
}
|
||||
if iface.TxPktsSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainInterfaceTxPackets,
|
||||
prometheus.CounterValue,
|
||||
float64(iface.TxPkts),
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
iface.Name)
|
||||
}
|
||||
if iface.TxErrsSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainInterfaceTxErrs,
|
||||
prometheus.CounterValue,
|
||||
float64(iface.TxErrs),
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
iface.Name)
|
||||
}
|
||||
if iface.TxDropSet {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtDomainInterfaceTxDrop,
|
||||
prometheus.CounterValue,
|
||||
float64(iface.TxDrop),
|
||||
config.Section("").Key("id").String(),
|
||||
desc.Metadata.DeevirtInstance.DeevirtCompanyID,
|
||||
desc.Metadata.DeevirtInstance.DeevirtDatacenterID,
|
||||
domainUUID,
|
||||
iface.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func CollectDomains(conn *libvirt.Connect, ch chan<- prometheus.Metric, hostname string) error {
|
||||
|
||||
stats, err := conn.GetAllDomainStats([]*libvirt.Domain{},
|
||||
libvirt.DOMAIN_STATS_STATE|libvirt.DOMAIN_STATS_CPU_TOTAL|libvirt.DOMAIN_STATS_BALLOON|
|
||||
libvirt.DOMAIN_STATS_VCPU|libvirt.DOMAIN_STATS_BLOCK|libvirt.DOMAIN_STATS_INTERFACE,
|
||||
libvirt.CONNECT_GET_ALL_DOMAINS_STATS_RUNNING|libvirt.CONNECT_GET_ALL_DOMAINS_STATS_SHUTOFF)
|
||||
defer func(stats []libvirt.DomainStats) {
|
||||
for _, stat := range stats {
|
||||
stat.Domain.Free()
|
||||
}
|
||||
}(stats)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, stat := range stats {
|
||||
err = CollectDomain(ch, stat, hostname)
|
||||
if err != nil {
|
||||
log.Printf("Failed to scrape metrics: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *LibvirtExporter) DescribeDomains(ch chan<- *prometheus.Desc) {
|
||||
// Domain info
|
||||
ch <- libvirtDomainInfoMaxMemBytes
|
||||
ch <- libvirtDomainInfoMemoryUsageBytes
|
||||
ch <- libvirtDomainInfoNrVirtCPU
|
||||
ch <- libvirtDomainInfoCPUTime
|
||||
ch <- libvirtDomainInfoVirDomainState
|
||||
|
||||
// VCPU info
|
||||
ch <- libvirtDomainVcpuState
|
||||
ch <- libvirtDomainVcpuTime
|
||||
ch <- libvirtDomainVcpuWait
|
||||
ch <- libvirtDomainVcpuDelay
|
||||
|
||||
// Domain Balloon Memory
|
||||
ch <- libvirtDomainBalloonStatCurrentBytes
|
||||
ch <- libvirtDomainBalloonStatMaximumBytes
|
||||
ch <- libvirtDomainBalloonStatSwapInBytes
|
||||
ch <- libvirtDomainBalloonStatSwapOutBytes
|
||||
ch <- libvirtDomainBalloonStatMajorFaultTotal
|
||||
ch <- libvirtDomainBalloonStatMinorFaultTotal
|
||||
ch <- libvirtDomainBalloonStatUnusedBytes
|
||||
ch <- libvirtDomainBalloonStatAvailableBytes
|
||||
ch <- libvirtDomainBalloonStatRssBytes
|
||||
ch <- libvirtDomainBalloonStatUsableBytes
|
||||
ch <- libvirtDomainBalloonStatDiskCachesBytes
|
||||
|
||||
// Domain block stats
|
||||
ch <- libvirtDomainBlockRdBytes
|
||||
ch <- libvirtDomainBlockRdReq
|
||||
ch <- libvirtDomainBlockRdTotalTimeSeconds
|
||||
ch <- libvirtDomainBlockWrBytes
|
||||
ch <- libvirtDomainBlockWrReq
|
||||
ch <- libvirtDomainBlockWrTotalTimes
|
||||
ch <- libvirtDomainBlockFlushReq
|
||||
ch <- libvirtDomainBlockFlushTotalTimeSeconds
|
||||
ch <- libvirtDomainBlockAllocation
|
||||
ch <- libvirtDomainBlockCapacityBytes
|
||||
ch <- libvirtDomainBlockPhysicalSizeBytes
|
||||
|
||||
// Domain net interfaces stats
|
||||
ch <- libvirtDomainInterfaceRxBytes
|
||||
ch <- libvirtDomainInterfaceRxPackets
|
||||
ch <- libvirtDomainInterfaceRxErrs
|
||||
ch <- libvirtDomainInterfaceRxDrop
|
||||
ch <- libvirtDomainInterfaceTxBytes
|
||||
ch <- libvirtDomainInterfaceTxPackets
|
||||
ch <- libvirtDomainInterfaceTxErrs
|
||||
ch <- libvirtDomainInterfaceTxDrop
|
||||
}
|
92
cmd/qemu/metrics/schema/domain.go
Normal file
92
cmd/qemu/metrics/schema/domain.go
Normal file
@ -0,0 +1,92 @@
|
||||
package schema
|
||||
|
||||
type Domain struct {
|
||||
Devices Devices `xml:"devices"`
|
||||
Metadata Metadata `xml:"metadata"`
|
||||
}
|
||||
|
||||
type Metadata struct {
|
||||
DeevirtInstance Instance `xml:"instance"`
|
||||
}
|
||||
|
||||
type Instance struct {
|
||||
DeevirtCompanyID string `xml:"company_id"`
|
||||
DeevirtDatacenterID string `xml:"datacenter_id"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
UserName string `xml:",chardata"`
|
||||
UserUUID string `xml:"uuid,attr"`
|
||||
}
|
||||
|
||||
type Project struct {
|
||||
ProjectName string `xml:",chardata"`
|
||||
ProjectUUID string `xml:"uuid,attr"`
|
||||
}
|
||||
|
||||
type Root struct {
|
||||
RootType string `xml:"type,attr"`
|
||||
RootUUID string `xml:"uuid,attr"`
|
||||
}
|
||||
|
||||
type Devices struct {
|
||||
Disks []Disk `xml:"disk"`
|
||||
Interfaces []Interface `xml:"interface"`
|
||||
}
|
||||
|
||||
type Disk struct {
|
||||
Device string `xml:"device,attr"`
|
||||
Driver DiskDriver `xml:"driver"`
|
||||
Source DiskSource `xml:"source"`
|
||||
Target DiskTarget `xml:"target"`
|
||||
DiskType string `xml:"type,attr"`
|
||||
Serial string `xml:"serial"`
|
||||
}
|
||||
|
||||
type DiskDriver struct {
|
||||
Type string `xml:"type,attr"`
|
||||
Cache string `xml:"cache,attr"`
|
||||
Discard string `xml:"discard,attr"`
|
||||
}
|
||||
|
||||
type DiskSource struct {
|
||||
File string `xml:"file,attr"`
|
||||
Name string `xml:"name,attr"`
|
||||
}
|
||||
|
||||
type DiskTarget struct {
|
||||
Device string `xml:"dev,attr"`
|
||||
Bus string `xml:"bus,attr"`
|
||||
}
|
||||
|
||||
type Interface struct {
|
||||
Source InterfaceSource `xml:"source"`
|
||||
Target InterfaceTarget `xml:"target"`
|
||||
Virtualport InterfaceVirtualPort `xml:"virtualport"`
|
||||
}
|
||||
|
||||
type InterfaceVirtualPort struct {
|
||||
Parameters InterfaceVirtualPortParam `xml:"parameters"`
|
||||
}
|
||||
type InterfaceVirtualPortParam struct {
|
||||
InterfaceID string `xml:"interfaceid,attr"`
|
||||
}
|
||||
|
||||
type InterfaceSource struct {
|
||||
Bridge string `xml:"bridge,attr"`
|
||||
}
|
||||
|
||||
type InterfaceTarget struct {
|
||||
Device string `xml:"dev,attr"`
|
||||
}
|
||||
|
||||
type VirDomainMemoryStats struct {
|
||||
MajorFault uint64
|
||||
MinorFault uint64
|
||||
Unused uint64
|
||||
Available uint64
|
||||
ActualBalloon uint64
|
||||
Rss uint64
|
||||
Usable uint64
|
||||
DiskCaches uint64
|
||||
}
|
150
cmd/qemu/metrics/server.go
Normal file
150
cmd/qemu/metrics/server.go
Normal file
@ -0,0 +1,150 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"gopkg.in/ini.v1"
|
||||
"libvirt.org/go/libvirt"
|
||||
)
|
||||
|
||||
var (
|
||||
Version = ""
|
||||
|
||||
libvirtUpDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "", "up"),
|
||||
"Whether scraping libvirt's metrics was successful.",
|
||||
nil,
|
||||
nil)
|
||||
libvirtVersionsInfoDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("libvirt", "", "versions_info"),
|
||||
"Versions of virtualization components",
|
||||
[]string{"hypervisor_running", "libvirtd_running", "libvirt_library"},
|
||||
nil)
|
||||
|
||||
errorsMap map[string]struct{}
|
||||
)
|
||||
|
||||
func Config() (*ini.File, error) {
|
||||
return ini.Load("/etc/deevirt/config.ini")
|
||||
}
|
||||
|
||||
// WriteErrorOnce writes message to stdout only once
|
||||
// for the error
|
||||
// "err" - an error message
|
||||
// "name" - name of an error, to count it
|
||||
func WriteErrorOnce(err string, name string) {
|
||||
if _, ok := errorsMap[name]; !ok {
|
||||
log.Printf("%s", err)
|
||||
errorsMap[name] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// CollectFromLibvirt obtains Prometheus metrics from all domains in a
|
||||
// libvirt setup.
|
||||
func CollectFromLibvirt(ch chan<- prometheus.Metric, uri string) error {
|
||||
conn, err := libvirt.NewConnect(uri)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
hostname, err := conn.GetHostname()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hypervisorVersionNum, err := conn.GetVersion() // virConnectGetVersion, hypervisor running, e.g. QEMU
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hypervisorVersion := fmt.Sprintf("%d.%d.%d", hypervisorVersionNum/1000000%1000, hypervisorVersionNum/1000%1000, hypervisorVersionNum%1000)
|
||||
|
||||
libvirtdVersionNum, err := conn.GetLibVersion() // virConnectGetLibVersion, libvirt daemon running
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
libvirtdVersion := fmt.Sprintf("%d.%d.%d", libvirtdVersionNum/1000000%1000, libvirtdVersionNum/1000%1000, libvirtdVersionNum%1000)
|
||||
|
||||
libraryVersionNum, err := libvirt.GetVersion() // virGetVersion, version of libvirt (dynamic) library used by this binary (exporter), not the daemon version
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
libraryVersion := fmt.Sprintf("%d.%d.%d", libraryVersionNum/1000000%1000, libraryVersionNum/1000%1000, libraryVersionNum%1000)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
libvirtVersionsInfoDesc,
|
||||
prometheus.GaugeValue,
|
||||
1.0,
|
||||
hypervisorVersion,
|
||||
libvirtdVersion,
|
||||
libraryVersion)
|
||||
|
||||
CollectNode(conn, ch, hostname)
|
||||
CollectDomains(conn, ch, hostname)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LibvirtExporter implements a Prometheus exporter for libvirt state.
|
||||
type LibvirtExporter struct {
|
||||
uri string
|
||||
}
|
||||
|
||||
// NewLibvirtExporter creates a new Prometheus exporter for libvirt.
|
||||
func NewLibvirtExporter(uri string) (*LibvirtExporter, error) {
|
||||
return &LibvirtExporter{
|
||||
uri: uri,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Describe returns metadata for all Prometheus metrics that may be exported.
|
||||
func (e *LibvirtExporter) Describe(ch chan<- *prometheus.Desc) {
|
||||
// Status and versions
|
||||
ch <- libvirtUpDesc
|
||||
e.DescribeNode(ch)
|
||||
e.DescribeDomains(ch)
|
||||
}
|
||||
|
||||
// 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 Server(c *libvirt.Connect) {
|
||||
exporter, err := NewLibvirtExporter("qemu:///system")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
prometheus.MustRegister(exporter)
|
||||
|
||||
http.Handle("/metrics", promhttp.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='/metrics'>Metrics</a></p>
|
||||
</body>
|
||||
</html>`))
|
||||
})
|
||||
log.Fatal(http.ListenAndServe(":9177", nil))
|
||||
}
|
32
cmd/qemu/qemu.go
Normal file
32
cmd/qemu/qemu.go
Normal file
@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"deevirt.fr/compute/cmd/qemu/metrics"
|
||||
"libvirt.org/go/libvirt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := libvirt.EventRegisterDefaultImpl()
|
||||
if err != nil {
|
||||
log.Fatalf("Échec d'EventRegisterDefaultImpl: %v", err)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
conn, err := libvirt.NewConnect("qemu:///system")
|
||||
if err != nil {
|
||||
log.Println("Connexion Error")
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
conn.SetKeepAlive(5, 3)
|
||||
|
||||
go metrics.Server(conn)
|
||||
//go app.NewDomainsMonitor(conn)
|
||||
|
||||
for {
|
||||
libvirt.EventRunDefaultImpl()
|
||||
}
|
||||
}
|
20
go.mod
Normal file
20
go.mod
Normal file
@ -0,0 +1,20 @@
|
||||
module deevirt.fr/compute
|
||||
|
||||
go 1.22.9
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/denisbrodbeck/machineid v1.0.1 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/prometheus/client_golang v1.20.5 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.55.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
libvirt.org/go/libvirt v1.11001.0 // indirect
|
||||
)
|
28
go.sum
Normal file
28
go.sum
Normal file
@ -0,0 +1,28 @@
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ=
|
||||
github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
|
||||
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
libvirt.org/go/libvirt v1.11001.0 h1:QJgpslxY7qkpXZIDxdMHpkDl7FfhgQJwqRTGBbg/S8E=
|
||||
libvirt.org/go/libvirt v1.11001.0/go.mod h1:1WiFE8EjZfq+FCVog+rvr1yatKbKZ9FaFMZgEqxEJqQ=
|
Loading…
x
Reference in New Issue
Block a user