Repository: gridsuite/geo-data-server
Pull request #151: Implement geo data observer metrics
Author: login: ghazwarhili
Created: 2025-04-01T14:19:18Z | Merged: 2025-04-02T13:46:54Z



Diff:
diff --git a/pom.xml b/pom.xml
index 3269836c..0343511d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -153,7 +153,6 @@
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-actuator</artifactId>
-            <scope>runtime</scope>
         </dependency>
         <dependency>
             <groupId>io.micrometer</groupId>
diff --git a/src/main/java/org/gridsuite/geodata/server/GeoDataExecutionService.java b/src/main/java/org/gridsuite/geodata/server/GeoDataExecutionService.java
index 2bdcf554..66b25dd1 100644
--- a/src/main/java/org/gridsuite/geodata/server/GeoDataExecutionService.java
+++ b/src/main/java/org/gridsuite/geodata/server/GeoDataExecutionService.java
@@ -7,12 +7,13 @@
 package org.gridsuite.geodata.server;
 
 import jakarta.annotation.PreDestroy;
+import lombok.NonNull;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadPoolExecutor;
 import java.util.function.Supplier;
 
 /**
@@ -20,10 +21,12 @@
  */
 @Service
 public class GeoDataExecutionService {
-    private final ExecutorService executorService;
+    private final ThreadPoolExecutor executorService;
 
-    public GeoDataExecutionService(@Value("${max-concurrent-requests}") int maxConcurrentRequests) {
-        this.executorService = Executors.newFixedThreadPool(maxConcurrentRequests);
+    public GeoDataExecutionService(@Value("${max-concurrent-requests}") int maxConcurrentRequests,
+                                   @NonNull GeoDataObserver geoDataObserver) {
+        executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(maxConcurrentRequests);
+        geoDataObserver.createThreadPoolMetric(executorService);
     }
 
     @PreDestroy
diff --git a/src/main/java/org/gridsuite/geodata/server/GeoDataObserver.java b/src/main/java/org/gridsuite/geodata/server/GeoDataObserver.java
new file mode 100644
index 00000000..8949d283
--- /dev/null
+++ b/src/main/java/org/gridsuite/geodata/server/GeoDataObserver.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2025, RTE (http://www.rte-france.com)
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.gridsuite.geodata.server;
+
+import io.micrometer.core.instrument.Gauge;
+import io.micrometer.core.instrument.MeterRegistry;
+import lombok.NonNull;
+import org.springframework.stereotype.Service;
+
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * @author Ghazwa Rehili <ghazwa.rehili at rte-france.com>
+ */
+@Service
+public class GeoDataObserver {
+
+    private static final String OBSERVATION_PREFIX = "app.geo-data.";
+    private static final String TASK_POOL_METER_NAME_PREFIX = OBSERVATION_PREFIX + "tasks.pool.";
+    private static final String TASK_TYPE_TAG_NAME = "type";
+    private static final String TASK_TYPE_TAG_VALUE_CURRENT = "current";
+    private static final String TASK_TYPE_TAG_VALUE_PENDING = "pending";
+    private final MeterRegistry meterRegistry;
+
+    public GeoDataObserver(@NonNull MeterRegistry meterRegistry) {
+        this.meterRegistry = meterRegistry;
+    }
+
+    public void createThreadPoolMetric(ThreadPoolExecutor threadPoolExecutor) {
+        Gauge.builder(TASK_POOL_METER_NAME_PREFIX + TASK_TYPE_TAG_VALUE_CURRENT,
+                        threadPoolExecutor, ThreadPoolExecutor::getActiveCount)
+                .description("The number of active request tasks in the thread pool")
+                .tag(TASK_TYPE_TAG_NAME, TASK_TYPE_TAG_VALUE_CURRENT)
+                .register(meterRegistry);
+
+        Gauge.builder(TASK_POOL_METER_NAME_PREFIX + TASK_TYPE_TAG_VALUE_PENDING,
+                        threadPoolExecutor, executor -> executor.getQueue().size())
+                .description("The number of pending request tasks in the thread pool")
+                .tag(TASK_TYPE_TAG_NAME, TASK_TYPE_TAG_VALUE_PENDING)
+                .register(meterRegistry);
+    }
+}
diff --git a/src/test/java/org/gridsuite/geodata/server/GeoDataControllerTest.java b/src/test/java/org/gridsuite/geodata/server/GeoDataControllerTest.java
index db6b0b44..e8754f3c 100644
--- a/src/test/java/org/gridsuite/geodata/server/GeoDataControllerTest.java
+++ b/src/test/java/org/gridsuite/geodata/server/GeoDataControllerTest.java
@@ -61,6 +61,9 @@ class GeoDataControllerTest {
     @MockBean
     private LineRepository lineRepository;
 
+    @MockBean
+    private GeoDataObserver geoDataObserver;
+
     private static final String GEO_DATA_SUBSTATIONS = "/geo_data_substations.json";
     private static final String GEO_DATA_LINES = "/geo_data_lines.json";
 


Reviews:
user: login: etiennehomer
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T11:03:26Z
user: login: etiennehomer
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T11:33:17Z
user: login: ghazwarhili
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T12:43:22Z
user: login: ghazwarhili
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T12:43:38Z
user: login: etiennehomer
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T12:50:56Z
user: login: ghazwarhili
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T13:34:54Z
user: login: etiennehomer
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T13:46:01Z

Review comments:
diff_hunk: @@ -0,0 +1,101 @@
+/**
+ * Copyright (c) 2025, RTE (http://www.rte-france.com)
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.gridsuite.geodata.server;
+
+import io.micrometer.core.instrument.Counter;
+import io.micrometer.core.instrument.Gauge;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.observation.Observation;
+import io.micrometer.observation.ObservationRegistry;
+import lombok.NonNull;
+import org.gridsuite.geodata.server.dto.LineGeoData;
+import org.gridsuite.geodata.server.dto.SubstationGeoData;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * @author Ghazwa Rehili <ghazwa.rehili at rte-france.com>
+ */
+@Service
+public class GeoDataObserver {
+
+    private static final String OBSERVATION_PREFIX = "app.geo-data.";
+    private static final String TASK_POOL_METER_NAME_PREFIX = OBSERVATION_PREFIX + "tasks.";
path: src/main/java/org/gridsuite/geodata/server/GeoDataObserver.java
user: login: etiennehomer
body: ```suggestion
    private static final String TASK_POOL_METER_NAME_PREFIX = OBSERVATION_PREFIX + "tasks.pool";
```
created_at: 2025-04-01T15:48:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,101 @@
+/**
+ * Copyright (c) 2025, RTE (http://www.rte-france.com)
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.gridsuite.geodata.server;
+
+import io.micrometer.core.instrument.Counter;
+import io.micrometer.core.instrument.Gauge;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.observation.Observation;
+import io.micrometer.observation.ObservationRegistry;
+import lombok.NonNull;
+import org.gridsuite.geodata.server.dto.LineGeoData;
+import org.gridsuite.geodata.server.dto.SubstationGeoData;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * @author Ghazwa Rehili <ghazwa.rehili at rte-france.com>
+ */
+@Service
+public class GeoDataObserver {
+
+    private static final String OBSERVATION_PREFIX = "app.geo-data.";
+    private static final String TASK_POOL_METER_NAME_PREFIX = OBSERVATION_PREFIX + "tasks.";
+    private static final String TASK_TYPE_TAG_NAME = "type";
+    private static final String TASK_TYPE_TAG_VALUE_CURRENT = "current";
+    private static final String TASK_TYPE_TAG_VALUE_PENDING = "pending";
+    private static final String GET_LINES_OBSERVATION_NAME = OBSERVATION_PREFIX + "lineGeoData.";
+    private static final String GET_SUBSTATIONS_OBSERVATION_NAME = OBSERVATION_PREFIX + "substationGeoData.";
+    private static final String NUMBER_LINES_METER_NAME = OBSERVATION_PREFIX + GET_LINES_OBSERVATION_NAME + "count";
+    private static final String NUMBER_SUBSTATIONS_METER_NAME = OBSERVATION_PREFIX + GET_SUBSTATIONS_OBSERVATION_NAME + "count";
+    private static final String NETWORK_ID_TAG_NAME = "networkId";
+    private final ObservationRegistry observationRegistry;
+    private final MeterRegistry meterRegistry;
+
+    public GeoDataObserver(@NonNull ObservationRegistry observationRegistry, @NonNull MeterRegistry meterRegistry) {
+        this.observationRegistry = observationRegistry;
+        this.meterRegistry = meterRegistry;
+    }
+
+    public <E extends Throwable> List<LineGeoData> observeLinesData(String networkId, Observation.CheckedCallable<List<LineGeoData>, E> callable) throws E {
path: src/main/java/org/gridsuite/geodata/server/GeoDataObserver.java
user: login: etiennehomer
body: I'm not sure we need this metric. createThreadPoolMetric() is enough I think
created_at: 2025-04-02T11:03:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,101 @@
+/**
+ * Copyright (c) 2025, RTE (http://www.rte-france.com)
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.gridsuite.geodata.server;
+
+import io.micrometer.core.instrument.Counter;
+import io.micrometer.core.instrument.Gauge;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.observation.Observation;
+import io.micrometer.observation.ObservationRegistry;
+import lombok.NonNull;
+import org.gridsuite.geodata.server.dto.LineGeoData;
+import org.gridsuite.geodata.server.dto.SubstationGeoData;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * @author Ghazwa Rehili <ghazwa.rehili at rte-france.com>
+ */
+@Service
+public class GeoDataObserver {
+
+    private static final String OBSERVATION_PREFIX = "app.geo-data.";
+    private static final String TASK_POOL_METER_NAME_PREFIX = OBSERVATION_PREFIX + "tasks.";
+    private static final String TASK_TYPE_TAG_NAME = "type";
+    private static final String TASK_TYPE_TAG_VALUE_CURRENT = "current";
+    private static final String TASK_TYPE_TAG_VALUE_PENDING = "pending";
+    private static final String GET_LINES_OBSERVATION_NAME = OBSERVATION_PREFIX + "lineGeoData.";
+    private static final String GET_SUBSTATIONS_OBSERVATION_NAME = OBSERVATION_PREFIX + "substationGeoData.";
+    private static final String NUMBER_LINES_METER_NAME = OBSERVATION_PREFIX + GET_LINES_OBSERVATION_NAME + "count";
+    private static final String NUMBER_SUBSTATIONS_METER_NAME = OBSERVATION_PREFIX + GET_SUBSTATIONS_OBSERVATION_NAME + "count";
+    private static final String NETWORK_ID_TAG_NAME = "networkId";
+    private final ObservationRegistry observationRegistry;
+    private final MeterRegistry meterRegistry;
+
+    public GeoDataObserver(@NonNull ObservationRegistry observationRegistry, @NonNull MeterRegistry meterRegistry) {
+        this.observationRegistry = observationRegistry;
+        this.meterRegistry = meterRegistry;
+    }
+
+    public <E extends Throwable> List<LineGeoData> observeLinesData(String networkId, Observation.CheckedCallable<List<LineGeoData>, E> callable) throws E {
+        Observation observation = createLinesObservation(networkId);
+        List<LineGeoData> linesData = observation.observeChecked(callable);
+        if (linesData != null) {
+            recordLinesCount(networkId, linesData.size());
+        }
+        return linesData;
+    }
+
+    public <E extends Throwable> List<SubstationGeoData> observeSubstationsData(String networkId, Observation.CheckedCallable<List<SubstationGeoData>, E> callable) throws E {
+        Observation observation = createSubstationsObservation(networkId);
+        List<SubstationGeoData> substationsData = observation.observeChecked(callable);
+        if (substationsData != null) {
+            recordSubstationsCount(networkId, substationsData.size());
+        }
+        return substationsData;
+    }
+
+    private Observation createLinesObservation(String networkId) {
+        return Observation.createNotStarted(GeoDataObserver.GET_LINES_OBSERVATION_NAME, observationRegistry)
+                .lowCardinalityKeyValue(NETWORK_ID_TAG_NAME, networkId);
+    }
+
+    private Observation createSubstationsObservation(String networkId) {
+        return Observation.createNotStarted(GeoDataObserver.GET_SUBSTATIONS_OBSERVATION_NAME, observationRegistry)
+                .lowCardinalityKeyValue(NETWORK_ID_TAG_NAME, networkId);
+    }
+
+    private void recordLinesCount(String networkId, long count) {
+        Counter.builder(GeoDataObserver.NUMBER_LINES_METER_NAME)
+                .tag(NETWORK_ID_TAG_NAME, networkId)
+                .register(meterRegistry)
+                .increment(count);
+    }
+
+    private void recordSubstationsCount(String networkId, long count) {
+        Counter.builder(GeoDataObserver.NUMBER_SUBSTATIONS_METER_NAME)
+                .tag(NETWORK_ID_TAG_NAME, networkId)
+                .register(meterRegistry)
+                .increment(count);
+    }
+
+    public void createThreadPoolMetric(ThreadPoolExecutor threadPoolExecutor) {
path: src/main/java/org/gridsuite/geodata/server/GeoDataObserver.java
user: login: etiennehomer
body: Here are the metrics we really need
created_at: 2025-04-02T11:33:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,101 @@
+/**
+ * Copyright (c) 2025, RTE (http://www.rte-france.com)
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.gridsuite.geodata.server;
+
+import io.micrometer.core.instrument.Counter;
+import io.micrometer.core.instrument.Gauge;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.observation.Observation;
+import io.micrometer.observation.ObservationRegistry;
+import lombok.NonNull;
+import org.gridsuite.geodata.server.dto.LineGeoData;
+import org.gridsuite.geodata.server.dto.SubstationGeoData;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * @author Ghazwa Rehili <ghazwa.rehili at rte-france.com>
+ */
+@Service
+public class GeoDataObserver {
+
+    private static final String OBSERVATION_PREFIX = "app.geo-data.";
+    private static final String TASK_POOL_METER_NAME_PREFIX = OBSERVATION_PREFIX + "tasks.";
+    private static final String TASK_TYPE_TAG_NAME = "type";
+    private static final String TASK_TYPE_TAG_VALUE_CURRENT = "current";
+    private static final String TASK_TYPE_TAG_VALUE_PENDING = "pending";
+    private static final String GET_LINES_OBSERVATION_NAME = OBSERVATION_PREFIX + "lineGeoData.";
+    private static final String GET_SUBSTATIONS_OBSERVATION_NAME = OBSERVATION_PREFIX + "substationGeoData.";
+    private static final String NUMBER_LINES_METER_NAME = OBSERVATION_PREFIX + GET_LINES_OBSERVATION_NAME + "count";
+    private static final String NUMBER_SUBSTATIONS_METER_NAME = OBSERVATION_PREFIX + GET_SUBSTATIONS_OBSERVATION_NAME + "count";
+    private static final String NETWORK_ID_TAG_NAME = "networkId";
+    private final ObservationRegistry observationRegistry;
+    private final MeterRegistry meterRegistry;
+
+    public GeoDataObserver(@NonNull ObservationRegistry observationRegistry, @NonNull MeterRegistry meterRegistry) {
+        this.observationRegistry = observationRegistry;
+        this.meterRegistry = meterRegistry;
+    }
+
+    public <E extends Throwable> List<LineGeoData> observeLinesData(String networkId, Observation.CheckedCallable<List<LineGeoData>, E> callable) throws E {
+        Observation observation = createLinesObservation(networkId);
+        List<LineGeoData> linesData = observation.observeChecked(callable);
+        if (linesData != null) {
+            recordLinesCount(networkId, linesData.size());
+        }
+        return linesData;
+    }
+
+    public <E extends Throwable> List<SubstationGeoData> observeSubstationsData(String networkId, Observation.CheckedCallable<List<SubstationGeoData>, E> callable) throws E {
+        Observation observation = createSubstationsObservation(networkId);
+        List<SubstationGeoData> substationsData = observation.observeChecked(callable);
+        if (substationsData != null) {
+            recordSubstationsCount(networkId, substationsData.size());
+        }
+        return substationsData;
+    }
+
+    private Observation createLinesObservation(String networkId) {
+        return Observation.createNotStarted(GeoDataObserver.GET_LINES_OBSERVATION_NAME, observationRegistry)
+                .lowCardinalityKeyValue(NETWORK_ID_TAG_NAME, networkId);
+    }
+
+    private Observation createSubstationsObservation(String networkId) {
+        return Observation.createNotStarted(GeoDataObserver.GET_SUBSTATIONS_OBSERVATION_NAME, observationRegistry)
+                .lowCardinalityKeyValue(NETWORK_ID_TAG_NAME, networkId);
+    }
+
+    private void recordLinesCount(String networkId, long count) {
+        Counter.builder(GeoDataObserver.NUMBER_LINES_METER_NAME)
+                .tag(NETWORK_ID_TAG_NAME, networkId)
+                .register(meterRegistry)
+                .increment(count);
+    }
+
+    private void recordSubstationsCount(String networkId, long count) {
+        Counter.builder(GeoDataObserver.NUMBER_SUBSTATIONS_METER_NAME)
+                .tag(NETWORK_ID_TAG_NAME, networkId)
+                .register(meterRegistry)
+                .increment(count);
+    }
+
+    public void createThreadPoolMetric(ThreadPoolExecutor threadPoolExecutor) {
path: src/main/java/org/gridsuite/geodata/server/GeoDataObserver.java
user: login: ghazwarhili
body: done
created_at: 2025-04-02T12:43:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,101 @@
+/**
+ * Copyright (c) 2025, RTE (http://www.rte-france.com)
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.gridsuite.geodata.server;
+
+import io.micrometer.core.instrument.Counter;
+import io.micrometer.core.instrument.Gauge;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.observation.Observation;
+import io.micrometer.observation.ObservationRegistry;
+import lombok.NonNull;
+import org.gridsuite.geodata.server.dto.LineGeoData;
+import org.gridsuite.geodata.server.dto.SubstationGeoData;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * @author Ghazwa Rehili <ghazwa.rehili at rte-france.com>
+ */
+@Service
+public class GeoDataObserver {
+
+    private static final String OBSERVATION_PREFIX = "app.geo-data.";
+    private static final String TASK_POOL_METER_NAME_PREFIX = OBSERVATION_PREFIX + "tasks.";
+    private static final String TASK_TYPE_TAG_NAME = "type";
+    private static final String TASK_TYPE_TAG_VALUE_CURRENT = "current";
+    private static final String TASK_TYPE_TAG_VALUE_PENDING = "pending";
+    private static final String GET_LINES_OBSERVATION_NAME = OBSERVATION_PREFIX + "lineGeoData.";
+    private static final String GET_SUBSTATIONS_OBSERVATION_NAME = OBSERVATION_PREFIX + "substationGeoData.";
+    private static final String NUMBER_LINES_METER_NAME = OBSERVATION_PREFIX + GET_LINES_OBSERVATION_NAME + "count";
+    private static final String NUMBER_SUBSTATIONS_METER_NAME = OBSERVATION_PREFIX + GET_SUBSTATIONS_OBSERVATION_NAME + "count";
+    private static final String NETWORK_ID_TAG_NAME = "networkId";
+    private final ObservationRegistry observationRegistry;
+    private final MeterRegistry meterRegistry;
+
+    public GeoDataObserver(@NonNull ObservationRegistry observationRegistry, @NonNull MeterRegistry meterRegistry) {
+        this.observationRegistry = observationRegistry;
+        this.meterRegistry = meterRegistry;
+    }
+
+    public <E extends Throwable> List<LineGeoData> observeLinesData(String networkId, Observation.CheckedCallable<List<LineGeoData>, E> callable) throws E {
path: src/main/java/org/gridsuite/geodata/server/GeoDataObserver.java
user: login: ghazwarhili
body: Okey
created_at: 2025-04-02T12:43:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -182,5 +182,9 @@
             <artifactId>h2</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
path: pom.xml
user: login: etiennehomer
body: You can remove this dep
created_at: 2025-04-02T12:50:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -182,5 +182,9 @@
             <artifactId>h2</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
path: pom.xml
user: login: ghazwarhili
body: scope runtime removed from spring-boot-starter-actuator
created_at: 2025-04-02T13:34:54Z
author_association: CONTRIBUTOR

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-04-02T13:42:32Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=org.gridsuite%3Ageo-data-server&pullRequest=151) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=org.gridsuite%3Ageo-data-server&pullRequest=151&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=org.gridsuite%3Ageo-data-server&pullRequest=151&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=org.gridsuite%3Ageo-data-server&pullRequest=151&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [93.8% Coverage on New Code](https://sonarcloud.io/component_measures?id=org.gridsuite%3Ageo-data-server&pullRequest=151&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=org.gridsuite%3Ageo-data-server&pullRequest=151&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=org.gridsuite%3Ageo-data-server&pullRequest=151)


author_association: NONE