Git Product home page Git Product logo

hetzner_exporter's People

Contributors

albertogviana avatar dependabot[bot] avatar renovate-bot avatar renovate[bot] avatar tboerger avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

hetzner_exporter's Issues

Export products

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...,
		)
	}
}

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

dockerfile
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-actions
.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
gomod
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
kustomize
deploy/kubernetes/kustomization.yml

  • Check this box to trigger a request for Renovate to run again on this repository

Suggestion: Caching of Hetzner API Calls

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)

Make collectors configurable

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.

Drop darwin/386 release builds

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.

Storagebox metrics

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.

Provide some documentation

So far we already prepared some simple Hugo documentation. It should get some content to guide the installation.

Initial release of basic version

Just prepare an initial version of the exporter which scrapes the most basic
metrics and defines the basic exporter structure.

Export transactions

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...,
		)
	}
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.