From 1810a9697a3b7844327d3e3738435cf8d60d7a36 Mon Sep 17 00:00:00 2001 From: David Shadix Date: Mon, 31 Jul 2023 13:11:29 -0400 Subject: [PATCH 01/10] init changes to include artifactory openmetrics --- artifactory/openmetrics.go | 30 ++++++++++++++++++++ collector/collector.go | 16 +++++++++++ collector/openMetrics.go | 58 ++++++++++++++++++++++++++++++++++++++ config/config.go | 5 +++- 4 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 artifactory/openmetrics.go create mode 100644 collector/openMetrics.go diff --git a/artifactory/openmetrics.go b/artifactory/openmetrics.go new file mode 100644 index 0000000..6940fe6 --- /dev/null +++ b/artifactory/openmetrics.go @@ -0,0 +1,30 @@ +package artifactory + +import ( + "github.com/go-kit/log/level" +) + +const openMetricsEndpoint = "v1/metrics" + +type OpenMetrics struct { + Metric string + NodeId string +} + +// FetchReplications makes the API call to replication endpoint and returns []Replication +func (c *Client) FetchOpenMetrics() (OpenMetrics, error) { + var openMetrics OpenMetrics + level.Debug(c.logger).Log("msg", "Fetching openMetrics") + resp, err := c.FetchHTTP(openMetricsEndpoint) + if err != nil { + if err.(*APIError).status == 404 { + return openMetrics, nil + } + return openMetrics, err + } + openMetrics.NodeId = resp.NodeId + openMetrics.Metric = string(resp.Body) + level.Debug(c.logger).Log("msg", "OpenMetrics from Artifactory", "body", string(resp.Body)) + + return openMetrics, nil +} diff --git a/collector/collector.go b/collector/collector.go index 22cece3..03e0783 100755 --- a/collector/collector.go +++ b/collector/collector.go @@ -68,6 +68,9 @@ var ( "mirrorLag": newMetric("mirror_lag", "federation", "Federation mirror lag in milliseconds.", federationLabelNames), "unavailableMirror": newMetric("unavailable_mirror", "federation", "Unsynchronized federated mirror status", append([]string{"status"}, federationLabelNames...)), } + openMetrics = metrics{ + "openMetrics": newMetric("open_metrics", "openmetrics", "OpenMetrics proxied from Artifactory", append([]string{"metrics"}, defaultLabelNames...)), + } ) func init() { @@ -99,6 +102,11 @@ func (e *Exporter) Describe(ch chan<- *prometheus.Desc) { ch <- m } } + if e.optionalMetrics.OpenMetrics { + for _, m := range openMetrics { + ch <- m + } + } ch <- e.up.Desc() ch <- e.totalScrapes.Desc() @@ -154,6 +162,14 @@ func (e *Exporter) scrape(ch chan<- prometheus.Metric) (up float64) { } } + // Collect and export open metrics + if e.optionalMetrics.OpenMetrics { + err = e.exportOpenMetrics(ch) + if err != nil { + return 0 + } + } + // Collect and export system metrics err = e.exportSystem(license, ch) if err != nil { diff --git a/collector/openMetrics.go b/collector/openMetrics.go new file mode 100644 index 0000000..1673f0a --- /dev/null +++ b/collector/openMetrics.go @@ -0,0 +1,58 @@ +package collector + +import ( + "strings" + + "github.com/go-kit/log/level" + "github.com/prometheus/client_golang/prometheus" + io_prometheus_client "github.com/prometheus/client_model/go" + "github.com/prometheus/common/expfmt" +) + +func (e *Exporter) exportOpenMetrics(ch chan<- prometheus.Metric) error { + // Fetch Open Metrics + openMetrics, err := e.client.FetchOpenMetrics() + if err != nil { + level.Error(e.logger).Log("msg", "There was an issue when try to fetch openMetrics") + e.totalAPIErrors.Inc() + return err + } + + level.Debug(e.logger).Log("msg", "OpenMetrics from Artifactory util", "body", openMetrics.Metric) + + // assign openMetrics.Metric to a string variable + openMetricsString := openMetrics.Metric + + parser := expfmt.TextParser{} + metrics, err := parser.TextToMetricFamilies(strings.NewReader(openMetricsString)) + if err != nil { + // handle the error + return err + } + + for _, family := range metrics { + for _, metric := range family.Metric { + // create a new metric descriptor + desc := prometheus.NewDesc( + prometheus.BuildFQName("remote", "openmetric", family.GetName()), + family.GetHelp(), + nil, + nil, + ) + + // create a new metric and collect it + switch family.GetType() { + case io_prometheus_client.MetricType_COUNTER: + ch <- prometheus.MustNewConstMetric(desc, prometheus.CounterValue, metric.GetCounter().GetValue()) + case io_prometheus_client.MetricType_GAUGE: + ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, metric.GetGauge().GetValue()) + // case textparse.MetricTypeHistogram: + // // handle histograms + // case textparse.MetricTypeSummary: + // // handle summaries + } + } + } + + return nil +} diff --git a/config/config.go b/config/config.go index 839245b..a576ea6 100644 --- a/config/config.go +++ b/config/config.go @@ -22,7 +22,7 @@ var ( optionalMetrics = kingpin.Flag("optional-metric", "optional metric to be enabled. Pass multiple times to enable multiple optional metrics.").PlaceHolder("metric-name").Strings() ) -var optionalMetricsList = []string{"artifacts", "replication_status", "federation_status"} +var optionalMetricsList = []string{"artifacts", "replication_status", "federation_status", "open_metrics"} // Credentials represents Username and Password or API Key for // Artifactory Authentication @@ -37,6 +37,7 @@ type OptionalMetrics struct { Artifacts bool ReplicationStatus bool FederationStatus bool + OpenMetrics bool } // Config represents all configuration options for running the Exporter. @@ -88,6 +89,8 @@ func NewConfig() (*Config, error) { optMetrics.ReplicationStatus = true case "federation_status": optMetrics.FederationStatus = true + case "open_metrics": + optMetrics.OpenMetrics = true default: return nil, fmt.Errorf("unknown optional metric: %s. Valid optional metrics are: %s", metric, optionalMetricsList) } From 1a3cf5eee905049ecb32d38a85674133f1cb0d6e Mon Sep 17 00:00:00 2001 From: David Shadix Date: Tue, 1 Aug 2023 09:28:46 -0400 Subject: [PATCH 02/10] updates readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b8385eb..cf9d432 100755 --- a/README.md +++ b/README.md @@ -201,6 +201,7 @@ Supported optional metrics: * `artifacts` - Extracts number of artifacts created/downloaded for each repository. Enabling this will add `artifactory_artifacts_*` metrics. Please note that on large Artifactory instances, this may impact the performance. * `replication_status` - Extracts status of replication for each repository which has replication enabled. Enabling this will add the `status` label to `artifactory_replication_enabled` metric. * `federation_status` - Extracts federation metrics. Enabling this will add two new metrics: `artifactory_federation_mirror_lag`, and `artifactory_federation_unavailable_mirror`. Please note that these metrics are only available in Artifactory Enterprise Plus and version 7.18.3 and above. +* `open_metrics` - Exposes Open Metrics from the JFrog Platform. For more information about Open Metrics, please refer to [JFrog Platform Open Metrics](https://jfrog.com/help/r/jfrog-platform-administration-documentation/open-metrics). ### Grafana Dashboard From 7c6c4dae82d9ae055843f05369791b2786564c52 Mon Sep 17 00:00:00 2001 From: David Shadix Date: Mon, 7 Aug 2023 16:25:02 -0400 Subject: [PATCH 03/10] remove space --- collector/artifacts.go | 1 - 1 file changed, 1 deletion(-) diff --git a/collector/artifacts.go b/collector/artifacts.go index 0f3990a..6a20610 100644 --- a/collector/artifacts.go +++ b/collector/artifacts.go @@ -3,7 +3,6 @@ package collector import ( "encoding/json" "fmt" - "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" ) From 3dffa70b68c54b1eedb0da971d0ede4dd4576ad9 Mon Sep 17 00:00:00 2001 From: David Shadix Date: Mon, 7 Aug 2023 16:46:24 -0400 Subject: [PATCH 04/10] rename file, cleanup --- collector/openMetrics.go | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/collector/openMetrics.go b/collector/openMetrics.go index 1673f0a..b8f74cb 100644 --- a/collector/openMetrics.go +++ b/collector/openMetrics.go @@ -18,10 +18,10 @@ func (e *Exporter) exportOpenMetrics(ch chan<- prometheus.Metric) error { return err } - level.Debug(e.logger).Log("msg", "OpenMetrics from Artifactory util", "body", openMetrics.Metric) + level.Debug(e.logger).Log("msg", "OpenMetrics from Artifactory util", "body", openMetrics.PromMetrics) // assign openMetrics.Metric to a string variable - openMetricsString := openMetrics.Metric + openMetricsString := openMetrics.PromMetrics parser := expfmt.TextParser{} metrics, err := parser.TextToMetricFamilies(strings.NewReader(openMetricsString)) @@ -32,12 +32,11 @@ func (e *Exporter) exportOpenMetrics(ch chan<- prometheus.Metric) error { for _, family := range metrics { for _, metric := range family.Metric { - // create a new metric descriptor + // create a new descriptor desc := prometheus.NewDesc( - prometheus.BuildFQName("remote", "openmetric", family.GetName()), + prometheus.BuildFQName("jfrog", "openmetrics", *family.Name), family.GetHelp(), - nil, - nil, + nil, nil, ) // create a new metric and collect it @@ -46,10 +45,6 @@ func (e *Exporter) exportOpenMetrics(ch chan<- prometheus.Metric) error { ch <- prometheus.MustNewConstMetric(desc, prometheus.CounterValue, metric.GetCounter().GetValue()) case io_prometheus_client.MetricType_GAUGE: ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, metric.GetGauge().GetValue()) - // case textparse.MetricTypeHistogram: - // // handle histograms - // case textparse.MetricTypeSummary: - // // handle summaries } } } From 769204f00f458879911f883a587a5c98c9ec1910 Mon Sep 17 00:00:00 2001 From: David Shadix Date: Mon, 7 Aug 2023 16:46:43 -0400 Subject: [PATCH 05/10] update logs --- artifactory/openmetrics.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/artifactory/openmetrics.go b/artifactory/openmetrics.go index 6940fe6..e3ca87c 100644 --- a/artifactory/openmetrics.go +++ b/artifactory/openmetrics.go @@ -7,11 +7,11 @@ import ( const openMetricsEndpoint = "v1/metrics" type OpenMetrics struct { - Metric string - NodeId string + PromMetrics string + NodeId string } -// FetchReplications makes the API call to replication endpoint and returns []Replication +// FetchOpenMetrics makes the API call to open metrics endpoint and returns all the open metrics func (c *Client) FetchOpenMetrics() (OpenMetrics, error) { var openMetrics OpenMetrics level.Debug(c.logger).Log("msg", "Fetching openMetrics") @@ -22,9 +22,11 @@ func (c *Client) FetchOpenMetrics() (OpenMetrics, error) { } return openMetrics, err } - openMetrics.NodeId = resp.NodeId - openMetrics.Metric = string(resp.Body) + level.Debug(c.logger).Log("msg", "OpenMetrics from Artifactory", "body", string(resp.Body)) + openMetrics.NodeId = resp.NodeId + openMetrics.PromMetrics = string(resp.Body) + return openMetrics, nil } From d9b2711dfe703e74398dc666ad94244fd160ed2b Mon Sep 17 00:00:00 2001 From: David Shadix Date: Mon, 7 Aug 2023 16:46:57 -0400 Subject: [PATCH 06/10] remove extra line --- collector/collector.go | 1 - 1 file changed, 1 deletion(-) diff --git a/collector/collector.go b/collector/collector.go index 03e0783..5b04455 100755 --- a/collector/collector.go +++ b/collector/collector.go @@ -2,7 +2,6 @@ package collector import ( "strings" - "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/version" ) From 2fe9d7be6be4a5a4b733c9b086fca60fcc061718 Mon Sep 17 00:00:00 2001 From: David Shadix Date: Mon, 7 Aug 2023 17:15:46 -0400 Subject: [PATCH 07/10] add labels to metrics desc --- collector/collector.go | 3 ++- collector/openMetrics.go | 11 +++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/collector/collector.go b/collector/collector.go index 5b04455..086cd33 100755 --- a/collector/collector.go +++ b/collector/collector.go @@ -2,6 +2,7 @@ package collector import ( "strings" + "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/version" ) @@ -68,7 +69,7 @@ var ( "unavailableMirror": newMetric("unavailable_mirror", "federation", "Unsynchronized federated mirror status", append([]string{"status"}, federationLabelNames...)), } openMetrics = metrics{ - "openMetrics": newMetric("open_metrics", "openmetrics", "OpenMetrics proxied from Artifactory", append([]string{"metrics"}, defaultLabelNames...)), + "openMetrics": newMetric("open_metrics", "openmetrics", "OpenMetrics proxied from JFrog Platform", defaultLabelNames), } ) diff --git a/collector/openMetrics.go b/collector/openMetrics.go index b8f74cb..97a443e 100644 --- a/collector/openMetrics.go +++ b/collector/openMetrics.go @@ -32,11 +32,18 @@ func (e *Exporter) exportOpenMetrics(ch chan<- prometheus.Metric) error { for _, family := range metrics { for _, metric := range family.Metric { + // create labels map + labels := make(map[string]string) + for _, label := range metric.Label { + labels[*label.Name] = *label.Value + } + // create a new descriptor desc := prometheus.NewDesc( - prometheus.BuildFQName("jfrog", "openmetrics", *family.Name), + family.GetName(), family.GetHelp(), - nil, nil, + nil, + labels, ) // create a new metric and collect it From 592e9fe6b15599a72d50ff908830a95c49215984 Mon Sep 17 00:00:00 2001 From: David Shadix Date: Mon, 7 Aug 2023 17:18:07 -0400 Subject: [PATCH 08/10] fix spacing? --- config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index a576ea6..f35b4c8 100644 --- a/config/config.go +++ b/config/config.go @@ -37,7 +37,7 @@ type OptionalMetrics struct { Artifacts bool ReplicationStatus bool FederationStatus bool - OpenMetrics bool + OpenMetrics bool } // Config represents all configuration options for running the Exporter. From ca7bc2bc189e02f87673502a1d74db70b654d0ab Mon Sep 17 00:00:00 2001 From: David Shadix Date: Mon, 7 Aug 2023 17:18:55 -0400 Subject: [PATCH 09/10] change indent to spaces --- config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index f35b4c8..dbf801f 100644 --- a/config/config.go +++ b/config/config.go @@ -37,7 +37,7 @@ type OptionalMetrics struct { Artifacts bool ReplicationStatus bool FederationStatus bool - OpenMetrics bool + OpenMetrics bool } // Config represents all configuration options for running the Exporter. From 1e5cdb37d900c6c9d2135b75262a4978e4d82b6c Mon Sep 17 00:00:00 2001 From: davidshadix <57724746+davidshadix@users.noreply.github.com> Date: Tue, 8 Aug 2023 09:23:10 -0400 Subject: [PATCH 10/10] Update config/config.go Co-authored-by: Jeff Billimek --- config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index dbf801f..101dcce 100644 --- a/config/config.go +++ b/config/config.go @@ -37,7 +37,7 @@ type OptionalMetrics struct { Artifacts bool ReplicationStatus bool FederationStatus bool - OpenMetrics bool + OpenMetrics bool } // Config represents all configuration options for running the Exporter.