Skip to content

Commit

Permalink
implement systemd-resolved metrics collector (#119)
Browse files Browse the repository at this point in the history
* implement systemd-resolved metrics collector

 - collect systemd-resolved metrics through dbus
 - add new option to enable collector

Fixes: #37

---------

Signed-off-by: egmc <[email protected]>
  • Loading branch information
egmc authored Jan 11, 2024
1 parent 63d00c7 commit 7f2bb6e
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 1 deletion.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
15 changes: 15 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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")
)

Expand Down Expand Up @@ -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 != "" {
Expand Down
172 changes: 172 additions & 0 deletions systemd/resolved/resolved.go
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit 7f2bb6e

Please sign in to comment.