From 234ca6ac1631871c68e475e1440d9b58fa870da2 Mon Sep 17 00:00:00 2001
From: capossele <angelocapossele@gmail.com>
Date: Tue, 9 Jun 2020 09:14:29 +0100
Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20Prometheus?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 go.mod                           |  2 +
 go.sum                           | 24 +++++++++
 packages/shutdown/order.go       |  1 +
 pluginmgr/research/plugins.go    |  2 +
 plugins/prometheus/data.go       | 50 +++++++++++++++++
 plugins/prometheus/info.go       | 35 ++++++++++++
 plugins/prometheus/metrics.go    | 25 +++++++++
 plugins/prometheus/parameters.go | 19 +++++++
 plugins/prometheus/plugin.go     | 92 ++++++++++++++++++++++++++++++++
 9 files changed, 250 insertions(+)
 create mode 100644 plugins/prometheus/data.go
 create mode 100644 plugins/prometheus/info.go
 create mode 100644 plugins/prometheus/metrics.go
 create mode 100644 plugins/prometheus/parameters.go
 create mode 100644 plugins/prometheus/plugin.go

diff --git a/go.mod b/go.mod
index 7ed8a345..2c336d11 100644
--- a/go.mod
+++ b/go.mod
@@ -8,6 +8,7 @@ require (
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/drand/drand v0.8.1
 	github.com/drand/kyber v1.0.1-0.20200331114745-30e90cc60f99
+	github.com/gin-gonic/gin v1.6.3
 	github.com/gobuffalo/packr/v2 v2.7.1
 	github.com/golang/protobuf v1.3.5
 	github.com/gorilla/websocket v1.4.1
@@ -19,6 +20,7 @@ require (
 	github.com/mr-tron/base58 v1.1.3
 	github.com/panjf2000/ants/v2 v2.2.2
 	github.com/pkg/errors v0.9.1
+	github.com/prometheus/client_golang v1.5.1
 	github.com/spf13/pflag v1.0.5
 	github.com/spf13/viper v1.6.2
 	github.com/stretchr/testify v1.5.1
diff --git a/go.sum b/go.sum
index 613421d5..3df9c12d 100644
--- a/go.sum
+++ b/go.sum
@@ -81,6 +81,10 @@ github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI
 github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
+github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
+github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
+github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
 github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
 github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
@@ -90,6 +94,14 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
 github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4=
 github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
+github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
+github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
+github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
+github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
+github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
+github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
 github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
@@ -153,6 +165,7 @@ github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22
 github.com/jonboulle/clockwork v0.1.1-0.20190114141812-62fb9bc030d1 h1:qBCV/RLV02TSfQa7tFmxTihnG+u+7JXByOkhlkR5rmQ=
 github.com/jonboulle/clockwork v0.1.1-0.20190114141812-62fb9bc030d1/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
 github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
@@ -177,6 +190,8 @@ github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8
 github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
 github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
 github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
+github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
+github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
 github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@@ -185,6 +200,8 @@ github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc
 github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
 github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
 github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
+github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
@@ -192,8 +209,10 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
 github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc=
 github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
@@ -303,7 +322,11 @@ github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
 github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
+github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
+github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
+github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
+github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
 github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
 github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
@@ -419,6 +442,7 @@ golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191025090151-53bf42e6b339/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/packages/shutdown/order.go b/packages/shutdown/order.go
index 5a4288ee..1efadc17 100644
--- a/packages/shutdown/order.go
+++ b/packages/shutdown/order.go
@@ -7,6 +7,7 @@ const (
 	PriorityMissingMessagesMonitoring
 	PriorityRemoteLog
 	PriorityAnalysis
+	PriorityPrometheus
 	PriorityMetrics
 	PriorityAutopeering
 	PriorityGossip
diff --git a/pluginmgr/research/plugins.go b/pluginmgr/research/plugins.go
index 7a8c8c59..435e6cb1 100644
--- a/pluginmgr/research/plugins.go
+++ b/pluginmgr/research/plugins.go
@@ -5,6 +5,7 @@ import (
 	analysisclient "github.com/iotaledger/goshimmer/plugins/analysis/client"
 	analysisdashboard "github.com/iotaledger/goshimmer/plugins/analysis/dashboard"
 	analysisserver "github.com/iotaledger/goshimmer/plugins/analysis/server"
+	"github.com/iotaledger/goshimmer/plugins/prometheus"
 	"github.com/iotaledger/goshimmer/plugins/remotelog"
 	"github.com/iotaledger/hive.go/node"
 )
@@ -15,4 +16,5 @@ var PLUGINS = node.Plugins(
 	analysisclient.Plugin,
 	fpctest.App,
 	analysisdashboard.Plugin,
+	prometheus.Plugin,
 )
diff --git a/plugins/prometheus/data.go b/plugins/prometheus/data.go
new file mode 100644
index 00000000..15198f47
--- /dev/null
+++ b/plugins/prometheus/data.go
@@ -0,0 +1,50 @@
+package prometheus
+
+import (
+	"os"
+	"path/filepath"
+
+	"github.com/iotaledger/goshimmer/plugins/config"
+	"github.com/iotaledger/goshimmer/plugins/database"
+	"github.com/prometheus/client_golang/prometheus"
+)
+
+var (
+	dataSizes *prometheus.GaugeVec
+)
+
+func init() {
+	dataSizes = prometheus.NewGaugeVec(
+		prometheus.GaugeOpts{
+			Name: "iota_data_sizes_bytes",
+			Help: "Data sizes in bytes.",
+		},
+		[]string{"name"},
+	)
+
+	registry.MustRegister(dataSizes)
+
+	addCollect(colectData)
+}
+
+func colectData() {
+	dataSizes.Reset()
+	dbSize, err := directorySize(config.Node.GetString(database.CfgDatabaseDir))
+	if err == nil {
+		dataSizes.WithLabelValues("database").Set(float64(dbSize))
+	}
+}
+
+func directorySize(path string) (int64, error) {
+	var size int64
+	err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
+		if err != nil {
+			return err
+		}
+		if !info.IsDir() {
+			size += info.Size()
+		}
+		return err
+	})
+	return size, err
+}
diff --git a/plugins/prometheus/info.go b/plugins/prometheus/info.go
new file mode 100644
index 00000000..3f796c11
--- /dev/null
+++ b/plugins/prometheus/info.go
@@ -0,0 +1,35 @@
+package prometheus
+
+import (
+	"github.com/iotaledger/goshimmer/plugins/banner"
+	"github.com/prometheus/client_golang/prometheus"
+)
+
+var (
+	infoApp  *prometheus.GaugeVec
+	infoTips prometheus.Gauge
+)
+
+func init() {
+	infoApp = prometheus.NewGaugeVec(
+		prometheus.GaugeOpts{
+			Name: "iota_info_app",
+			Help: "Node software name and version.",
+		},
+		[]string{"name", "version"},
+	)
+	infoTips = prometheus.NewGauge(prometheus.GaugeOpts{
+		Name: "iota_info_tips",
+		Help: "Number of tips.",
+	})
+
+	infoApp.WithLabelValues(banner.AppName, banner.AppVersion).Set(1)
+	registry.MustRegister(infoApp)
+	registry.MustRegister(infoTips)
+	addCollect(collectInfo)
+}
+
+func collectInfo() {
+	// Tips
+	infoTips.Set(0)
+}
diff --git a/plugins/prometheus/metrics.go b/plugins/prometheus/metrics.go
new file mode 100644
index 00000000..efeb6593
--- /dev/null
+++ b/plugins/prometheus/metrics.go
@@ -0,0 +1,25 @@
+package prometheus
+
+import (
+	"github.com/iotaledger/goshimmer/plugins/metrics"
+	"github.com/prometheus/client_golang/prometheus"
+)
+
+var (
+	messagesPerSecond prometheus.Gauge
+)
+
+func init() {
+	messagesPerSecond = prometheus.NewGauge(prometheus.GaugeOpts{
+		Name: "iota_messages_per_second",
+		Help: "Number of messages per second.",
+	})
+
+	registry.MustRegister(messagesPerSecond)
+
+	addCollect(collectServer)
+}
+
+func collectServer() {
+	messagesPerSecond.Set(float64(metrics.ReceivedMessagesPerSecond()))
+}
diff --git a/plugins/prometheus/parameters.go b/plugins/prometheus/parameters.go
new file mode 100644
index 00000000..085702ee
--- /dev/null
+++ b/plugins/prometheus/parameters.go
@@ -0,0 +1,19 @@
+package prometheus
+
+import (
+	flag "github.com/spf13/pflag"
+)
+
+const (
+	CfgPrometheusGoMetrics       = "prometheus.goMetrics"
+	CfgPrometheusProcessMetrics  = "prometheus.processMetrics"
+	CfgPrometheusPromhttpMetrics = "prometheus.promhttpMetrics"
+	CfgPrometheusBindAddress     = "prometheus.bindAddress"
+)
+
+func init() {
+	flag.String(CfgPrometheusBindAddress, "localhost:9311", "the bind address on which the Prometheus exporter listens on")
+	flag.Bool(CfgPrometheusGoMetrics, false, "include go metrics")
+	flag.Bool(CfgPrometheusProcessMetrics, false, "include process metrics")
+	flag.Bool(CfgPrometheusPromhttpMetrics, false, "include promhttp metrics")
+}
diff --git a/plugins/prometheus/plugin.go b/plugins/prometheus/plugin.go
new file mode 100644
index 00000000..893e4c90
--- /dev/null
+++ b/plugins/prometheus/plugin.go
@@ -0,0 +1,92 @@
+package prometheus
+
+import (
+	"context"
+	"net/http"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/iotaledger/goshimmer/packages/shutdown"
+	"github.com/iotaledger/goshimmer/plugins/config"
+	"github.com/iotaledger/hive.go/daemon"
+	"github.com/iotaledger/hive.go/logger"
+	"github.com/iotaledger/hive.go/node"
+	"github.com/prometheus/client_golang/prometheus"
+	"github.com/prometheus/client_golang/prometheus/promhttp"
+)
+
+// Plugin Prometheus
+var (
+	Plugin = node.NewPlugin("Prometheus", node.Disabled, configure, run)
+	log    *logger.Logger
+
+	server   *http.Server
+	registry = prometheus.NewRegistry()
+	collects []func()
+)
+
+func configure(plugin *node.Plugin) {
+	log = logger.NewLogger(plugin.Name)
+
+	if config.Node.GetBool(CfgPrometheusGoMetrics) {
+		registry.MustRegister(prometheus.NewGoCollector())
+	}
+	if config.Node.GetBool(CfgPrometheusProcessMetrics) {
+		registry.MustRegister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}))
+	}
+}
+
+func addCollect(collect func()) {
+	collects = append(collects, collect)
+}
+
+func run(plugin *node.Plugin) {
+	log.Info("Starting Prometheus exporter ...")
+
+	if err := daemon.BackgroundWorker("Prometheus exporter", func(shutdownSignal <-chan struct{}) {
+		log.Info("Starting Prometheus exporter ... done")
+
+		engine := gin.New()
+		engine.Use(gin.Recovery())
+		engine.GET("/metrics", func(c *gin.Context) {
+			for _, collect := range collects {
+				collect()
+			}
+			handler := promhttp.HandlerFor(
+				registry,
+				promhttp.HandlerOpts{
+					EnableOpenMetrics: true,
+				},
+			)
+			if config.Node.GetBool(CfgPrometheusPromhttpMetrics) {
+				handler = promhttp.InstrumentMetricHandler(registry, handler)
+			}
+			handler.ServeHTTP(c.Writer, c.Request)
+		})
+
+		bindAddr := config.Node.GetString(CfgPrometheusBindAddress)
+		server = &http.Server{Addr: bindAddr, Handler: engine}
+
+		go func() {
+			log.Infof("You can now access the Prometheus exporter using: http://%s/metrics", bindAddr)
+			if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
+				log.Error("Stopping Prometheus exporter due to an error ... done")
+			}
+		}()
+
+		<-shutdownSignal
+		log.Info("Stopping Prometheus exporter ...")
+
+		if server != nil {
+			ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+			err := server.Shutdown(ctx)
+			if err != nil {
+				log.Error(err.Error())
+			}
+			cancel()
+		}
+		log.Info("Stopping Prometheus exporter ... done")
+	}, shutdown.PriorityPrometheus); err != nil {
+		log.Panic(err)
+	}
+}
-- 
GitLab