diff --git a/go.mod b/go.mod index 7ed8a345a92ebbfaa561c10d6c418187e3ecfafc..2c336d11a1ca55e21691c1225660ac5640b4ad57 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 613421d525e1404c5d4d0fd9e35be08f4c33f53b..3df9c12d6c690677300219912c8251826ab613f4 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 5a4288ee18096343bb2363ff79ed69b467b32fb4..1efadc17b29c7e5d8e93efe729b7b7c88b28298e 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 7a8c8c59bcf7d71f9a71e584da62891c361437a7..435e6cb161aec2f21468280eac904d1eabd78b50 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 0000000000000000000000000000000000000000..15198f47f1145d9f764104ce5ef3aa3104d76842 --- /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 0000000000000000000000000000000000000000..3f796c110a8e5b7bfaf6656f17d18966c3a6e56c --- /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 0000000000000000000000000000000000000000..efeb6593c0c349af22b20b25dd7d27f7d27e1c78 --- /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 0000000000000000000000000000000000000000..085702eeabf2e09c633c5a3c1ab3c83a8b762e76 --- /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 0000000000000000000000000000000000000000..893e4c902aee53d5a0f78b35e1d6f724ca766e77 --- /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) + } +}