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
Over 2 million developers have joined DZone.
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
  • Evaluating SOC Effectiveness Using Detection Coverage and Response Metrics

Trending

  • Java in a Container: Efficient Development and Deployment With Docker
  • Liquibase: Database Change Management and Automated Deployments
  • How AI Coding Assistants Are Changing Developer Flow
  • Querying Without a Query Language
  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 user avatar
Mohit Gupta
·
Oct. 30, 20 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
22.9K Views

Join the DZone community and get the full member experience.

Join For Free

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
  • Evaluating SOC Effectiveness Using Detection Coverage and Response Metrics

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • 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