DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Newsletter
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Unified Observability Exporters: Metrics, Logs, and Tracing
  • Unified Observability: Metrics, Logs, and Tracing of App and Database Tiers in a Single Grafana Console
  • How to Optimize AWS Observability Tools
  • Key ML Classification Metrics You Need to Understand

Trending

  • Google Cloud KMS vs. AWS KMS: Java Encryption Guide
  • Introduction to Error Prone: How to Catch Bugs at Compile Time
  • Kubernetes Rolling Updates Are Lying to You — and Your Users Are Paying for It
  • Slopsquatting: Building a Scanner That Catches AI-Hallucinated Packages Before They Reach Production

Draft This article hasn't been published, so readers can't see it.

In moderation This article is waiting for review, so readers can't see it yet.

Deleted This article has been deleted, so readers can't see it.

  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Monitoring and Observability
  4. Exposing SonarQube Metrics to Grafana

Exposing SonarQube Metrics to Grafana

Follow this tutorial in order to learn how to show SonarQube metrics such as code coverage, number of lines, etc. in the Grafana dashboard.

By 
Mohit Gupta
·
Oct. 30, 20 · Tutorial
Post on X (opens in a new tab) Share on LinkedIn (opens in a new tab)
23.2K Views

Join the DZone community Save articles, join the discussion, and download Refcards and Trend Reports with a free account.

Join for free Already a member? Log in

There may be cases when we want to show measures of a metric of the Sonarqube into the Grafana dashboard. Here, we are going to one simple way to expose the Sonarqube metrics data to the Grafana dashboard using SpringBoot.

Following software are required for this tutorial:

  • SonarQube
  • Grafana ( with SimpleJson plugin )
  • An IDE for creating REST endpoints ( using SpringBoot)

This tutorial is divided into 3 sections: 

  1. Analyze a project on SonarQube
  2. Create REST endpoints required for the SimpleJson plugin
  3. Create a Grafana dashboard.

1. Analyse a Project on SonarQube

SonarQube is an open-source platform developed by SonarSource for continuous inspection of code quality to perform automatic reviews with static analysis of code to detect bugs, code smells, and security vulnerabilities on 20+ programming languages.

You can follow the steps under Analyse a Project section from the following link:

https://docs.sonarqube.org/latest/setup/get-started-2-minutes/

If you did not get Code Coverage metrics using this approach, you need to use plugins that generate coverage reports. Some such plugins are Jacoco, Cobertura, etc. Here, we are using the Jacoco plugin. You can add the Jacoco plugin in maven as below —

Java
 




x
14


 
1
    <plugin>
2
        <groupId>org.jacoco</groupId>
3
        <artifactId>jacoco-maven-plugin</artifactId>
4
        <version>0.8.5</version>
5
        <executions>
6
          <execution>
7
            <id>report</id>
8
            <goals>
9
              <goal>prepare-agent</goal>
10
              <goal>report</goal>
11
            </goals>
12
          </execution>
13
        </executions>
14
      </plugin>


If required you can also include the following plugin —  

Java
 




xxxxxxxxxx
1


 
1
            <plugin>
2
                <groupId>org.apache.maven.plugins</groupId>
3
                <artifactId>maven-surefire-plugin</artifactId>
4
            </plugin>



Run the maven command with goal including "clean install" along with the sonar maven command (provided while creating a project for analysis in Sonarqube).

2. Create REST Endpoints Required for SimpleJson Plugin

In this step, we are creating REST endpoints required for SimpleJson plugin. These endpoints can be created in any backend technologies like SpringBoot, Node, etc. Here, we are using SpringBoot to create REST endpoints, you can use other technologies also. Following link provide details about SimpleJson plugin of Grafana. References for other technologies are also provided in the link.

https://grafana.com/grafana/plugins/grafana-simple-json-datasource

Create following endpoints which are being used by SimpleJson plugin during multiple phases:

  1.  "/" — should return 200 ok. Used for "Test connection" on the datasource config page.
  2.  "/search" — used by the find metric options on the query tab in panels. Here, we provide various Sonarqube metrics such as nloc, complexity, coverage, etc.
  3. "/query" — should return metrics based on input. Here we are returning Sonarqube measures (data) for metric (passed on Query tab) based on time range.
  4. "/annotation" — should return annotation. Here, I have provided simple dummy implementation.

You can also implement other two optional REST endpoints:

  1. "/tag-keys" — should return tag keys for ad hoc filters.
  2. "/tag-values" — should return tag values for ad hoc filters.

Here, is the link of my repository where I have implemented these endpoints.

https://github.com/35mohitgupta/grafana-rest-sonar-connection

NOTE: I am providing a simple implementation with minimum code. Like, I have provided empty implementation of endpoints like "/", "/tag-keys", etc., hard-coded implementations, just to make understanding the concept simpler and easy. Also I have created a "/test" endpoints just for testing the response data, you can ignore this endpoint. I have implemented only time-series type, not table type, as my goal is to display metrics in form of a graph, not in a table.

Following is the controller class for the REST endpoint implementation:

Java
 




x


 
1
@CrossOrigin
2
@RestController
3
public class SonarAPIController {
4

          
5
    @Autowired
6
    private SonarApiService sonarApiService;
7
    
8
    @GetMapping("/")
9
    public ResponseEntity<String> testDataSourceConnection(){
10
        System.out.println(">>>>>> testing datasource connection-\n");
11
        return new ResponseEntity<String>("Test connection established",HttpStatus.OK);
12
    }
13
    
14
    @PostMapping("/search")
15
    public ResponseEntity<List<String>> getMetrics(@RequestBody JSONObject request){
16
        System.out.println(">>>>>> getting metrics -\n"+request);
17
        List<String> metrics = Arrays.asList("coverage","new_violations","ncloc");
18
        return new ResponseEntity<List<String>>(metrics, HttpStatus.OK);
19
    }
20
    
21
    @PostMapping("/annotations")
22
    public ResponseEntity<List<String>> getAnnotations(@RequestBody AnnotationRequest request){
23
        System.out.println(">>>>>> getting annotation -\n"+request);
24
        List<String> metrics = Arrays.asList("coverage","new_violations","ncloc","complexity");
25
        return new ResponseEntity<List<String>>(metrics, HttpStatus.OK);
26
    }
27
    
28
    @PostMapping("/query")
29
    public ResponseEntity<List<Object>> query(@RequestBody QueryRequest request){
30
        System.out.println(">>>>>> querying -\n"+request);
31
        List<Object> response = new ArrayList<Object>();
32
        Range range = request.getRange();
33
        for(Target target: request.getTargets()) {
34
            String metric = target.getTarget();
35
            QueryType type = target.getType();
36
            if(type == QueryType.timeserie) {
37
                List<List<Object>> datapoints = sonarApiService.getDataPoint(range, metric);
38
                System.out.println("datapoints - "+datapoints);
39
                TimeserieQueryResponse timeQuery = new TimeserieQueryResponse();
40
                timeQuery.setDatapoints(datapoints);
41
                timeQuery.setTarget(metric);
42
                response.add(timeQuery);
43
            }else {
44
                TableQueryResponse tableQuery = new TableQueryResponse();
45
                response.add(tableQuery);
46
            }
47
            
48
        }
49
        return new ResponseEntity<List<Object>>(response, HttpStatus.OK);
50
    }
51
    
52
    @PostMapping("/tag-keys")
53
    public List<TagKeysResponse> getTagKey(@RequestBody JSONObject request){
54
        List<TagKeysResponse> tagKeys = new ArrayList<TagKeysResponse>();
55
        return null;
56
    }
57
    
58
}



NOTE: Here, many DTO classes are being used. These are created based on requests and responses required by the endpoints.You can go through the repository, whose link is passed, to get these classes.

Here is the service class method used in the controller to get the data from the Sonarqube, you can provide another implementation of this method where we can provide from date and to date as request parameter to the Sonarqube API request.

Java
 




xxxxxxxxxx
1
37


 
1
@Service()
2
public class SonarApiServiceImpl implements SonarApiService{
3

          
4
    @Override
5
    public List<List<Object>> getDataPoint(Range range, String metrics) {
6
        List<List<Object>> datapoints = new ArrayList<>();
7
        RestTemplate restTemplate = new RestTemplate();
8
        String historyMetrics = "http://localhost:9000/api/measures/search_history";
9
        UriComponentsBuilder builder = UriComponentsBuilder
10
                .fromUriString(historyMetrics)
11
                // Add query parameter
12
                .queryParam("component", "com.infy.sonar:sonar-spring-demo")
13
                .queryParam("metrics", metrics);
14
        MeasureHistoryResponse measureHistoryResponse = restTemplate.getForObject(builder.toUriString(), MeasureHistoryResponse.class);
15
        System.out.println("sonar response - "+measureHistoryResponse);
16
        for(Measure measure: measureHistoryResponse.getMeasures()) {
17
            for(MeasureHistory measureHistory: measure.getHistory()) {
18
                ZonedDateTime zonedDateTime = measureHistory.getDate();
19
                System.out.println("zoned time - "+zonedDateTime);
20
                Long epochSecond = zonedDateTime.toEpochSecond();
21
                LocalDateTime historyTime = zonedDateTime.toLocalDateTime();
22
                LocalDateTime rangeFrom = range.getFrom();
23
                LocalDateTime rangeTo = range.getTo();
24
                System.out.println("history - "+historyTime);
25
                System.out.println("from - "+rangeFrom);
26
                System.out.println("to - "+rangeTo);
27
                System.out.println("epoch sec - "+epochSecond);
28
                if(historyTime.isBefore(range.getFrom()) || historyTime.isAfter(range.getTo()))
29
                    continue;
30
                List<Object> datapoint = Arrays.asList(measureHistory.getValue(),epochSecond*1000);
31
                datapoints.add(datapoint);
32
            }
33
        }
34
        return datapoints;
35
    }
36

          
37
}



3. Create Grafana Dashboard

In this step, first, we have to install the SimpleJson plugin. You can install the SimpleJson datasource plugin in Grafana by running the following command:

grafana-cli plugins install grafana-simple-json-datasource

After the installation, you need to restart the grafana-server.

Once the SimpleJson datasource is installed, we can use it as datasource. Now select it as a datasource and provide details as per following snapshot:

SimpleJSON

Here, "http://localhost:8600"  is the server where the REST endpoints, created in previous steps, are hosted.
Now, create grafana dashboard. I am creating two pannel one showing coverage and number of lines of code in guage form while other in line-graph form. Here is the screenshot for the creation of the panel.

coverage-meter

Panel for Coverage and Number of lines of code in Guage form.

panel for coverage

Pannel for Coverage and Number of Lines of Code in Line Graph form.

Thanks for reading!!

Grafana Metric (unit)

Opinions expressed by DZone contributors are their own.

Related

  • Unified Observability Exporters: Metrics, Logs, and Tracing
  • Unified Observability: Metrics, Logs, and Tracing of App and Database Tiers in a Single Grafana Console
  • How to Optimize AWS Observability Tools
  • Key ML Classification Metrics You Need to Understand

Partner Resources

×

Comments

Loading comments

The comments didn't load

Please try again in a moment.

Likes

Loading

The next likes didn't load. Please try again.

The likes didn't load

Please try again in a moment.

See who liked this

Log in or join DZone for free to see who liked this article.

Log in Join for free
  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook