2

I want to categorize specific metrics I have in SonarQube to fit my needs.

In detail: I built a Gatling Plugin for SonarQube that reads the stats which Gatling writes and puts them into SonarQube Metrics.

Now I want to categorize my measures according to the requests I did with Gatling. So, for example I have the global stats by Gatling (10,000 requests, 50ms per request, etc.) and I also have the data for the requests (for request 1 there were 1,000 requests, 40ms per request, etc.).

How is it possible to assign the request to a measure in Sonar?

A possible solution I could think about was to link the measures to specific contexts in Sonar. So, I will save the measures for the requests in a special context while the global stats are saved within the global context.

But: how can I access my measures in the Ruby-Template afterwards and what would be a good context to pick?

Update: I tried to save the same measure multiple times with the request name as the Measure.data-parameter but that resulted in an error.

I also tried changing the resources-Context Sonar saves the measure in. But I did not succeed to query the measures afterwards in the widget, they seemed to have disappeared.

kummerer94
  • 171
  • 10

3 Answers3

1

I try to do exactly the same thing with sonarQube 6.1.

(As a proof of concept I put some static measures on the java-Files of the plugin project.)

Currently I wrote a plugin with a Sensor and a Metric. But I can't see my measures in the sonarQube web interface.

I deploy with

mvn package org.codehaus.sonar:sonar-dev-maven-plugin::upload -DsonarHome=...

and test with

mvn sonar:sonar

which both works fine.

Could someone see, if there is a failure in the code?

The Sensor:

import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.api.batch.sensor.SensorDescriptor;

public class SampleSensor implements Sensor {

  public void describe(SensorDescriptor sensorDescriptor) {
    sensorDescriptor.name("Sensor for Gatling Log files");
  }

  public void execute(org.sonar.api.batch.sensor.SensorContext ctx) {
    for (InputFile inputFile : ctx.fileSystem().inputFiles(ctx.fileSystem().predicates().hasLanguage("java"))) {
      ctx.<Float>newMeasure().forMetric(SampleMetrics.THROUGHPUT).on(inputFile).withValue(10.5).save();
    }
  }
}

The Metric

import org.sonar.api.measures.*;    
import java.util.Arrays;
import java.util.List;

public class SampleMetrics implements Metrics {

  static final Metric THROUGHPUT = new Metric.Builder("throughput", "Request Throughput", Metric.ValueType.FLOAT)
      .setDescription("Requests per second").setQualitative(false).setDomain(CoreMetrics.DOMAIN_RELIABILITY).create();

  public List<Metric> getMetrics() {
    return Arrays.asList(THROUGHPUT);
  }
}

The Plugin

import org.sonar.api.*;

public class SamplePlugin implements Plugin {
  public void define(Context context) {
    context.addExtension(SampleMetrics.class);
    context.addExtension(SampleSensor.class);
  }
}
0

After trying to work a bit with a Resource I was able to save the measures and group them by the requests I got from the Gatling files.

It was a lot of try and error I had to do and the documentation by SonarQube is just awful when it comes to reverse engineering.

I had to use a deprecated method to index my resources (SensorContext.index(Resource resource)) because I don't know any other way.

For example: Though there is a new plugin API (which is declared @Beta in the 4.5.1 version of SonarQube) it is not once mentioned in the official plugin documentation and you have to search through the source files to find it. However, I continued working with the old API.

To retrieve the measures afterwards in the .html.erb-Template, I used the following code in my widget:

m = measure('your_metric_name')
ProjectMeasure.find(:all,
                :from => ['project_measures as p, snapshots as s'],
                :conditions => ['p.metric_id=? AND s.id = p.snapshot_id 
                AND s.parent_snapshot_id = ?', m.metric.id, m.snapshot_id]

This will return all the measures you made regarding this project (make sure that your resource's getParent() method returns the project you are analysing with SonarQube). I saved the category via measure.setData("category") in Java and was able to categorize them in the widget through this trick.

If someone is stuck here too, I will add additional code (especially on how to create a new resource to save your multiple measures). Just comment please.

kummerer94
  • 171
  • 10
0

I will try to summarize this a bit.

If you want to provide additional measures to the sonarqube analysis, the approach of Markus Schwarz (see above) should be the right way. The code should work after a full restart of the sonarqube server.

It seems like the hot deployment is not enough to "deploy" a new custom metric. Although the new metric is available via the metric search api (http://localhost:9000/api/metrics/search?ps=500) new measures of that metric are not saved in the database a full restart.

Then you should see your measures of the project after an analysis:

http://localhost:9000/api/measures/component_tree?metricKeys=[YOUR_METRIC_KEY]&baseComponentKey=[YOUR_COMPONENT_TREE]

A very good example on this kind of plugin is the pretty new pitest plugin: https://github.com/SonarQubeCommunity/sonar-pitest

For the widget, it should be enough to get the measures via the api shown above. This should solve the issue of kummerer94. The pitest plugin is a good starting point also for the creating a widget or dashboard. See

https://github.com/SonarQubeCommunity/sonar-pitest/blob/master/src/main/resources/org/sonar/plugins/pitest/pitest_dashboard_widget.html.erb

for details.

user984200
  • 273
  • 1
  • 6
  • 17