Hello!
In this article we will see how to add your own metrics in Prometheus Exporter Pro for Jira version 3.0.0-jira8 and up. The same feature will be implemented for Prometheus Exporter Pro for Bitbucket and Prometheus Exporter Pro for Confluence.
You can add your own metrics if the inbuilt metrics are not enough. For example, you have your own app for which you want to collect certain metrics. Or you want to use some core functionality to get new metrics (for example, to get more cluster metrics then available in the out of the box Prometheus Exporter).
You can find the source code for the article here.
You can find the video in English here.
let's start to add our own metrics to Prometheus Exporter Pro for Jira.
Install the Prometheus Exporter Pro for Jira jar file into your maven repo.
First of all you need to get the latest jar file from Atlassian marketplace. The version of the jar file must be 3.0.0-jira8 or higher.
Then add this file into your local repo or into your remote maven repo. In this article I will show you how to add this file to your local repo. You need to execute the following command:
atlas-mvn install:install-file -Dfile=prom-jira-exporter-3.0.0-jira8.jar -DgroupId=ru.andreymarkelov.atlas.plugins -DartifactId=prom-jira-exporter -Dversion=3.0.0-jira8 -Dpackaging=jar -DgeneratePom=true
You should see the following output:
Create a new app
Run atlas-create-jira-plugin. Enter the following information for the asked questions:
Define value for groupId: : ru.matveev.alexey.prometheus.jira.extension
Define value for artifactId: : sample-prometheus-metrics
Define value for version: 1.0.0-SNAPSHOT: :
Define value for package: ru.matveev.alexey.prometheus.jira.extension: :
Use OSGi Java Config: (Y/N/y/n) N: : N
I chose no for OSGI Java Config because I do not like it but you can use it if you wish.
Press Y to create the app.
Add Prometheus dependencies to the pom.xml file
Open your pom.xml file in the created app and add the following info:
Change Jira version to 8.20.0:
<jira.version>8.20.0</jira.version>
Add dependency to the added Prometheus Exporter Pro for Jira jar file which we added to your local maven repo.
<dependency> <groupId>ru.andreymarkelov.atlas.plugins</groupId> <artifactId>prom-jira-exporter</artifactId> <version>3.0.0-jira8</version> <scope>provided</scope> </dependency>
Import necessary classes from the Prometheus Exporter Pro for Jira app to your app
<Import-Package>org.springframework.osgi.*;resolution:="optional", org.eclipse.gemini.blueprint.*;resolution:="optional", com.anovaapps.atlassian.prometheus.spi.api.*;version="${prometheus.spi.version}", io.prometheus.client.*;version="${prometheus.spi.version}", *;resolution:="optional" </Import-Package>
Add prometheus.spi.version to the properties in the pom.xml file:
<prometheus.spi.version>1.0.0</prometheus.spi.version>
Add your metrics to the app
In this app we will create a metric which will show the number of issues in the project with the key "VIP" created more than 2 days ago and not closed. Also when selecting this metric we want to know the assignee of such issues.
Let's start.
First create a new package called metrics:
Now add this metric. We will call the file VipIssuesNotClosed.java
@Named
public class VipIssuesNotClosed extends PrometheusMetric {
private final Gauge vipIssuesNotClosedMetric = Gauge.build()
.name("vip_issues_not_closed")
.help("Shows the number of issues which are in the VIP project and not clsed withing 2 days. Label with the assignee of the issue is available.")
.labelNames("assignee")
.create();
public VipIssuesNotClosed() {
super("vip_issues_not_closed", "Shows the number of issues which are in the VIP project and not clsed withing 2 days. Label with the assignee of the issue is available.", true, true);
}
@Override
public PrometheusMetricResult collect() {
Map<String, Integer> assigneeMap = new HashedMap();
UserManager userManager = ComponentAccessor.getUserManager();
SearchService searchService = ComponentAccessor.getComponent(SearchService.class);
ApplicationUser appUser = userManager.getUserByKey("admin");
String jqlSearch = "project = VIP and created > -2d and resolution is empty";
SearchService.ParseResult parseResult = searchService.parseQuery(appUser, jqlSearch);
if (parseResult.isValid()) {
SearchResults<Issue> searchResult = null;
try {
searchResult = searchService.search(appUser, parseResult.getQuery(), PagerFilter.getUnlimitedFilter());
for (Issue issue : searchResult.getResults()) {
String assignee = issue.getAssignee().getUsername();
if (assigneeMap.containsKey(assignee)) {
assigneeMap.put(assignee, assigneeMap.get(assignee) + 1);
} else {
assigneeMap.put(assignee, 1);
}
}
for (Map.Entry<String, Integer> entry : assigneeMap.entrySet()) {
this.vipIssuesNotClosedMetric.labels(entry.getKey()).set(entry.getValue());
}
} catch (SearchException e) {
e.printStackTrace();
}
}
return new PrometheusMetricResult(this.vipIssuesNotClosedMetric.collect());
}
}
This file contains the code to get the values for our metric.
First, we extend our class from PrometheusMetric class which does all the job to import our metric to Prometheus Exporter Pro for Jira.
Then we define the metric. Since the number of issues can go up and down our metric will be a Gauge:
private final Gauge vipIssuesNotClosedMetric = Gauge.build()
.name("vip_issues_not_closed")
.help("Shows the number of issues which are in the VIP project and not clsed withing 2 days. Label with the assignee of the issue is available.")
.labelNames("assignee")
.create();
We call the constructor of the super class to initialise our metric properly:
super("vip_issues_not_closed", "Shows the number of issues which are in the VIP project and not clsed withing 2 days. Label with the assignee of the issue is available.", true, true);
The first and second parameters are the name and the description of the metric in our Metric menu in Jira, the third parameter defines if we need to collect the metric in the Prometheus job. The fourth parameter defines if we need to collect the metric in real time (each time prometheus calls the metric servlet in Jira). We want our metric to be collected by the job and by each call of Prometheus that is why both parameters equal to true.
The collect method does the job to extract the value for the metric. I did not try to create a reliable or clean code. I just wanted to show you how you can add a metric. For example, this code does not take into account issues which do not have an assignee. But the idea is that first we define managers which we need to get issues by a jql query. Then we define the jql query and get the result. Then we iterate over the result and count the number of issues for each assignee. Then we iterate over all assignees and set the number of issues to the metric for each assignee as a label.
Then create the MetricCollector.java file:
public class MetricCollector extends PrometheusMetricCollector {
public MetricCollector(VipIssuesNotClosed vipIssuesNotClosed) {
this.getMetrics().add(vipIssuesNotClosed);
}
}
This is the collector of our metric. This collector can contain many different metrics. First we extend it from the PrometheusMetricCollector and then we import our metric in the constructor and add it to the metric list.
Next we need to register our MetricCollector as a PrometheusMetric module in our app in the atlassian-plugin.xml file:
<prometheusMetric key="our-custom-metric-module" name="Our custom metric module" class="ru.matveev.alexey.prometheus.jira.extension.metrics.MetricCollector"/>
That is all. Now We can package our module and add to a Jira instance with Prometheus Exporter Pro for Jira version 3.0.0-jira8 and up.
Install the module
Package the file with the atlas-package command. Then take the jar file in the target folder and install it via Manage apps menu in Jira.
Push the upload button. Then open the Metric menu. You will be able to see that your metrics were added:
Now open the sample-prometheus-metrics and you will see how long it takes to collect the metric in nano seconds:
Now open the metric servlet which is used to export data to Prometheus. You will be able to see your metric there.
That is all for the article. Thank you!
Alexey Matveev
software developer
MagicButtonLabs
Philippines
1,575 accepted answers
0 comments