promhippie / hetzner_exporter Goto Github PK
View Code? Open in Web Editor NEWPrometheus exporter for Hetzner
Home Page: https://promhippie.github.io/hetzner_exporter/
License: Apache License 2.0
Prometheus exporter for Hetzner
Home Page: https://promhippie.github.io/hetzner_exporter/
License: Apache License 2.0
The upstream client library is not correctly working for products, we should fix that and implement the exporter afterward. Here is an example how the collector could look like:
package exporter
import (
"fmt"
"strconv"
"time"
"github.com/appscode/go-hetzner"
"github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"
"github.com/prometheus/client_golang/prometheus"
"github.com/dustin/go-humanize"
)
// ProductCollector collects metrics about the SSH keys.
type ProductCollector struct {
client *hetzner.Client
logger log.Logger
failures *prometheus.CounterVec
duration *prometheus.HistogramVec
timeout time.Duration
Up *prometheus.Desc
Traffic *prometheus.Desc
SetupVat *prometheus.Desc
Setup *prometheus.Desc
PriceVat *prometheus.Desc
Price *prometheus.Desc
}
// NewProductCollector returns a new ProductCollector.
func NewProductCollector(logger log.Logger, client *hetzner.Client, failures *prometheus.CounterVec, duration *prometheus.HistogramVec, timeout time.Duration) *ProductCollector {
failures.WithLabelValues("product").Add(0)
labels := []string{"id", "name"}
return &ProductCollector{
client: client,
logger: logger,
failures: failures,
duration: duration,
timeout: timeout,
Up: prometheus.NewDesc(
"hetzner_product_up",
"1 if the product is available",
labels,
nil,
),
Traffic: prometheus.NewDesc(
"hetzner_product_traffic_bytes",
"Show the inclusive traffic for this product",
labels,
nil,
),
SetupVat: prometheus.NewDesc(
"hetzner_product_setup_vat_euro",
"Setup VAT for the product in €",
labels,
nil,
),
Setup: prometheus.NewDesc(
"hetzner_product_setup_euro",
"Setup fee for the product in €",
labels,
nil,
),
PriceVat: prometheus.NewDesc(
"hetzner_product_price_vat_euro",
"Monthly VAT for the product in €",
labels,
nil,
),
Price: prometheus.NewDesc(
"hetzner_product_price_euro",
"Monthly fee for the product in €",
labels,
nil,
),
}
}
// Describe sends the super-set of all possible descriptors of metrics collected by this Collector.
func (c *ProductCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- c.Up
ch <- c.Traffic
ch <- c.SetupVat
ch <- c.Setup
ch <- c.PriceVat
ch <- c.Price
}
// Collect is called by the Prometheus registry when collecting metrics.
func (c *ProductCollector) Collect(ch chan<- prometheus.Metric) {
now := time.Now()
products, _, err := c.client.WithTimeout(c.timeout).Ordering.ListProducts()
c.duration.WithLabelValues("product").Observe(time.Since(now).Seconds())
if err != nil {
level.Error(c.logger).Log(
"msg", "Failed to fetch products",
"err", err,
)
c.failures.WithLabelValues("product").Inc()
return
}
level.Debug(c.logger).Log(
"msg", "Fetched products",
"count", len(products),
)
for _, product := range products {
var (
traffic float64
setup float64
setupVat float64
price float64
priceVat float64
)
labels := []string{
product.ID,
product.Name,
}
ch <- prometheus.MustNewConstMetric(
c.Up,
prometheus.GaugeValue,
1.0,
labels...,
)
if num, err := humanize.ParseBytes(product.Traffic); err == nil {
traffic = float64(num)
}
ch <- prometheus.MustNewConstMetric(
c.Traffic,
prometheus.GaugeValue,
traffic,
labels...,
)
if num, err := strconv.ParseFloat(product.PriceSetup, 64); err == nil {
setup = num
}
ch <- prometheus.MustNewConstMetric(
c.Setup,
prometheus.GaugeValue,
setup,
labels...,
)
if num, err := strconv.ParseFloat(product.PriceSetupVat, 64); err == nil {
setupVat = num
}
ch <- prometheus.MustNewConstMetric(
c.SetupVat,
prometheus.GaugeValue,
setupVat,
labels...,
)
if num, err := strconv.ParseFloat(product.Price, 64); err == nil {
price = num
}
ch <- prometheus.MustNewConstMetric(
c.Price,
prometheus.GaugeValue,
price,
labels...,
)
if num, err := strconv.ParseFloat(product.PriceVat, 64); err == nil {
priceVat = num
}
ch <- prometheus.MustNewConstMetric(
c.PriceVat,
prometheus.GaugeValue,
priceVat,
labels...,
)
}
}
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
github.com/prometheus/client_golang
, go
)docker/Dockerfile.linux.386
i386/alpine 3.20@sha256:fa66aa594ffa884dff44f4a97821756545834505df611c375a30c45926402f89
docker/Dockerfile.linux.amd64
alpine 3.20@sha256:eddacbc7e24bf8799a4ed3cdcfa50d4b88a323695ad80f317b6629883b2c2a78
docker/Dockerfile.linux.arm
arm32v6/alpine 3.20@sha256:5c7e326e3c8a8c51654a6c5d94dac98d7f6fc4b2a762d86aaf67b7e76a6aee46
docker/Dockerfile.linux.arm64
arm64v8/alpine 3.20@sha256:24ba417e25e780ff13c888ccb1badec5b027944666ff695681909bafe09a3944
.github/workflows/automerge.yml
tibdex/github-app-token v2
dependabot/fetch-metadata v2
.github/workflows/binaries.yml
actions/checkout v4
actions/setup-go v5
actionhippie/gpgsign v1
actionhippie/calens v1
ncipollo/release-action v1
.github/workflows/changes.yml
actions/checkout v4
actions/checkout v4
actions/setup-go v5
EndBug/add-and-commit v9
actions/checkout v4
actions/checkout v4
actions/setup-go v5
EndBug/add-and-commit v9
actions/checkout v4
actions/checkout v4
actions/setup-go v5
EndBug/add-and-commit v9
.github/workflows/docker.yml
actions/checkout v4
actions/setup-go v5
docker/metadata-action v5
docker/setup-qemu-action v3
docker/setup-buildx-action v3
docker/login-action v3
docker/login-action v3
docker/login-action v3
docker/build-push-action v6
actions/checkout v4
docker/metadata-action v5
actionhippie/manifest v1
docker/metadata-action v5
actionhippie/manifest v1
docker/metadata-action v5
actionhippie/manifest v1
actions/checkout v4
actionhippie/pushrm v1
actionhippie/pushrm v1
.github/workflows/docs.yml
actions/checkout v4
peaceiris/actions-hugo v3
peaceiris/actions-gh-pages v4
.github/workflows/flake.yml
tibdex/github-app-token v2
actions/checkout v4
cachix/install-nix-action v27
DeterminateSystems/update-flake-lock v23
.github/workflows/general.yml
actions/checkout v4
actions/setup-go v5
codacy/codacy-coverage-reporter-action v1
.github/workflows/kustomize.yml
actions/checkout v4
actionhippie/kustomize v2
go.mod
go 1.21
go 1.22.6
github.com/dustin/go-humanize v1.0.1
github.com/go-chi/chi/v5 v5.1.0
github.com/go-kit/log v0.2.1
github.com/joho/godotenv v1.5.1
github.com/oklog/run v1.1.0
github.com/prometheus/client_golang v1.19.1
github.com/prometheus/exporter-toolkit v0.11.0
github.com/stretchr/testify v1.9.0
github.com/urfave/cli/v2 v2.27.4
deploy/kubernetes/kustomization.yml
At least the Storagebox API currently has a rate limit implemented, which leads to 403 Forbidden
if the rate limit is actually hit. This leads to null values during metric scrapes. The documentation of hetzner_exporter suggests, that a scrape_limit of 1m should be set, which normally doesn't hit the API rate limit, however you can't always control the number of requests to the metrics endpoint: For example, what happens in a HA scenario where two or more prometheus instances hit the metrics endpoint.
What is your opinion about caching either the API responses or the calculated metrics for a specific amount of time (maybe even configurable via an environment variable?). I know this complicates the code a bit, but it should improve usablity. As I understand, at least some metrics like data usage for storage boxes doesn't even update this often (the homepage suggest this metric is calculated once every 5 min, at least in the webui)
So far all collectors are executed, but I'm sure there are cases where only a subset should be enabled. Let's add some option for that.
Currently the dockerfiles are missing the exposed port, that got to be added.
We got to drop the darwin/386 builds, they are not supported by the used Go version anymore. Soonish we should also add arm64 builds to stay compatible with current macOS hardware.
To have a unified project structure accross the whole promhippie GitHub
organization all projects should impelent a similar structure.
I have allocated a new port at https://github.com/prometheus/prometheus/wiki/Default-port-allocations, so we need to update it to port 9502
The Hetzner Robot API provides an endpoint to gather information about available servers on the marketplace, you can see details at https://robot.your-server.de/doc/webservice/en.html#get-order-server_market-product.
Maybe we should send a PR to the upstream client lib first to keep the implementation within the exporter mostly simple.
Hey,
I just found the project and I have to say its awesome. After setting it up I noticed that there are no metrics for Hetzner Storage boxes since they are also managed via the Robot I think adding metrics for those would be quite nice.
So far we already prepared some simple Hugo documentation. It should get some content to guide the installation.
Just prepare an initial version of the exporter which scrapes the most basic
metrics and defines the basic exporter structure.
The upstream client library is not correctly working for transactions, we should fix that and implement the exporter afterward. Here is an example how the collector could look like:
package exporter
import (
"fmt"
"time"
"github.com/appscode/go-hetzner"
"github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"
"github.com/prometheus/client_golang/prometheus"
)
// TransactionCollector collects metrics about the SSH keys.
type TransactionCollector struct {
client *hetzner.Client
logger log.Logger
failures *prometheus.CounterVec
duration *prometheus.HistogramVec
timeout time.Duration
Dummy *prometheus.Desc
}
// NewTransactionCollector returns a new TransactionCollector.
func NewTransactionCollector(logger log.Logger, client *hetzner.Client, failures *prometheus.CounterVec, duration *prometheus.HistogramVec, timeout time.Duration) *TransactionCollector {
failures.WithLabelValues("transaction").Add(0)
labels := []string{"id"}
return &TransactionCollector{
client: client,
logger: logger,
failures: failures,
duration: duration,
timeout: timeout,
Dummy: prometheus.NewDesc(
"hetzner_transaction_dummy",
"Dummy help",
labels,
nil,
),
}
}
// Describe sends the super-set of all possible descriptors of metrics collected by this Collector.
func (c *TransactionCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- c.Dummy
}
// Collect is called by the Prometheus registry when collecting metrics.
func (c *TransactionCollector) Collect(ch chan<- prometheus.Metric) {
now := time.Now()
transactions, _, err := c.client.WithTimeout(c.timeout).Ordering.ListTransactions()
c.duration.WithLabelValues("transaction").Observe(time.Since(now).Seconds())
if err != nil {
level.Error(c.logger).Log(
"msg", "Failed to fetch transactions",
"err", err,
)
c.failures.WithLabelValues("transaction").Inc()
return
}
level.Debug(c.logger).Log(
"msg", "Fetched transactions",
"count", len(transactions),
)
for _, transaction := range transactions {
level.Debug(c.logger).Log(
"record", fmt.Sprintf("%+v", transaction),
)
labels := []string{
transaction.ID,
}
ch <- prometheus.MustNewConstMetric(
c.Dummy,
prometheus.GaugeValue,
0.0,
labels...,
)
}
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.