From 7f2bb6ee747d4656dddc585dbaf5c360cf4936b0 Mon Sep 17 00:00:00 2001 From: sohei iwahori Date: Fri, 12 Jan 2024 02:14:08 +0900 Subject: [PATCH] implement systemd-resolved metrics collector (#119) * implement systemd-resolved metrics collector - collect systemd-resolved metrics through dbus - add new option to enable collector Fixes: #37 --------- Signed-off-by: egmc --- go.mod | 2 +- main.go | 15 +++ systemd/resolved/resolved.go | 172 +++++++++++++++++++++++++++++++++++ 3 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 systemd/resolved/resolved.go diff --git a/go.mod b/go.mod index e50b891..0a14fee 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/alecthomas/kingpin/v2 v2.3.2 github.com/coreos/go-systemd/v22 v22.5.0 github.com/go-kit/log v0.2.1 + github.com/godbus/dbus/v5 v5.0.4 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.17.0 github.com/prometheus/common v0.45.0 @@ -17,7 +18,6 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect - github.com/godbus/dbus/v5 v5.0.4 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/kr/text v0.2.0 // indirect diff --git a/main.go b/main.go index 651b5e6..8731109 100644 --- a/main.go +++ b/main.go @@ -21,6 +21,7 @@ import ( "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log/level" "github.com/prometheus-community/systemd_exporter/systemd" + "github.com/prometheus-community/systemd_exporter/systemd/resolved" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/common/promlog" @@ -44,6 +45,8 @@ func main() { "web.max-requests", "Maximum number of parallel scrape requests. Use 0 to disable.", ).Default("40").Int() + enableResolvedgMetrics = kingpin.Flag("systemd.collector.enable-resolved", "Enable systemd-resolved statistics").Bool() + toolkitFlags = webflag.AddFlags(kingpin.CommandLine, ":9558") ) @@ -86,6 +89,18 @@ func main() { exporterMetricsRegistry, handler, ) } + if *enableResolvedgMetrics { + resolvedCollector, err := resolved.NewCollector(logger) + if err != nil { + level.Error(logger).Log("msg", "Couldn't create resolved collector", "err", err) + os.Exit(1) + } + + if err := r.Register(resolvedCollector); err != nil { + level.Error(logger).Log("msg", "Couldn't register resolved collector", "err", err) + os.Exit(1) + } + } http.Handle(*metricsPath, handler) if *metricsPath != "/" && *metricsPath != "" { diff --git a/systemd/resolved/resolved.go b/systemd/resolved/resolved.go new file mode 100644 index 0000000..1a28267 --- /dev/null +++ b/systemd/resolved/resolved.go @@ -0,0 +1,172 @@ +// Copyright 2023 The Prometheus 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 resolved + +import ( + "context" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/godbus/dbus/v5" + "github.com/prometheus/client_golang/prometheus" +) + +const ( + namespace = "systemd" + subsystem = "resolved" +) + +type Collector struct { + ctx context.Context + logger log.Logger +} + +var ( + resolvedCurrentTransactions = prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "current_transactions"), + "Resolved Current Transactions", + nil, nil, + ) + resolvedTotalTransactions = prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "transactions_total"), + "Resolved Total Transactions", + nil, nil, + ) + resolvedCurrentCacheSize = prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "current_cache_size"), + "Resolved Current Cache Size", + nil, nil, + ) + resolvedTotalCacheHits = prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "cache_hits_total"), + "Resolved Total Cache Hits", + nil, nil, + ) + resolvedTotalCacheMisses = prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "cache_misses_total"), + "Resolved Total Cache Misses", + nil, nil, + ) + resolvedTotalSecure = prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "dnssec_secure_total"), + "Resolved Total number of DNSSEC Verdicts Secure", + nil, nil, + ) + resolvedTotalInsecure = prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "dnssec_insecure_total"), + "Resolved Total number of DNSSEC Verdicts Insecure", + nil, nil, + ) + resolvedTotalBogus = prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "dnssec_bogus_total"), + "Resolved Total number of DNSSEC Verdicts Boguss", + nil, nil, + ) + resolvedTotalIndeterminate = prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "dnssec_indeterminate_total"), + "Resolved Total number of DNSSEC Verdicts Indeterminat", + nil, nil, + ) +) + +// NewCollector returns a new Collector exporing resolved statistics +func NewCollector(logger log.Logger) (*Collector, error) { + + ctx := context.TODO() + return &Collector{ + ctx: ctx, + logger: logger, + }, nil +} + +// Collect gathers metrics from resolved +func (c *Collector) Collect(ch chan<- prometheus.Metric) { + err := c.collect(ch) + if err != nil { + level.Error(c.logger).Log("msg", "error collecting resolved metrics", + "err", err) + } +} + +// Describe gathers descriptions of metrics +func (c *Collector) Describe(desc chan<- *prometheus.Desc) { + desc <- resolvedCurrentTransactions + desc <- resolvedTotalTransactions + desc <- resolvedCurrentCacheSize + desc <- resolvedTotalCacheHits + desc <- resolvedTotalCacheMisses + desc <- resolvedTotalSecure + desc <- resolvedTotalInsecure + desc <- resolvedTotalBogus + desc <- resolvedTotalIndeterminate +} + +func parseProperty(object dbus.BusObject, path string) (ret []float64, err error) { + variant, err := object.GetProperty(path) + if err != nil { + return nil, err + } + for _, v := range variant.Value().([]interface{}) { + i := v.(uint64) + ret = append(ret, float64(i)) + } + return ret, err +} + +func (c *Collector) collect(ch chan<- prometheus.Metric) error { + + conn, err := dbus.ConnectSystemBus() + if err != nil { + return err + } + + defer conn.Close() + + obj := conn.Object("org.freedesktop.resolve1", "/org/freedesktop/resolve1") + + cacheStats, err := parseProperty(obj, "org.freedesktop.resolve1.Manager.CacheStatistics") + if err != nil { + return err + } + + ch <- prometheus.MustNewConstMetric(resolvedCurrentCacheSize, prometheus.GaugeValue, + float64(cacheStats[0])) + ch <- prometheus.MustNewConstMetric(resolvedTotalCacheHits, prometheus.CounterValue, + float64(cacheStats[1])) + ch <- prometheus.MustNewConstMetric(resolvedTotalCacheMisses, prometheus.CounterValue, + float64(cacheStats[2])) + + transactionStats, err := parseProperty(obj, "org.freedesktop.resolve1.Manager.TransactionStatistics") + ch <- prometheus.MustNewConstMetric(resolvedCurrentTransactions, prometheus.GaugeValue, + float64(transactionStats[0])) + ch <- prometheus.MustNewConstMetric(resolvedTotalTransactions, prometheus.CounterValue, + float64(transactionStats[1])) + if err != nil { + return err + } + + dnssecStats, err := parseProperty(obj, "org.freedesktop.resolve1.Manager.DNSSECStatistics") + ch <- prometheus.MustNewConstMetric(resolvedTotalSecure, prometheus.CounterValue, + float64(dnssecStats[0])) + ch <- prometheus.MustNewConstMetric(resolvedTotalInsecure, prometheus.CounterValue, + float64(dnssecStats[1])) + ch <- prometheus.MustNewConstMetric(resolvedTotalBogus, prometheus.CounterValue, + float64(dnssecStats[2])) + ch <- prometheus.MustNewConstMetric(resolvedTotalIndeterminate, prometheus.CounterValue, + float64(dnssecStats[3])) + if err != nil { + return err + } + return nil +}