diff --git a/pom.xml b/pom.xml
index b1a0504..a7a5640 100644
--- a/pom.xml
+++ b/pom.xml
@@ -163,6 +163,21 @@
spring-boot-starter-actuator
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+
+ io.micrometer
+ micrometer-core
+
+
+
+ io.micrometer
+ micrometer-registry-prometheus
+
+
eu.dnetlib.dhp
diff --git a/src/main/java/eu/openaire/api/OpenaireRestApiApplication.java b/src/main/java/eu/openaire/api/OpenaireRestApiApplication.java
index ef5d1cf..0aeea35 100644
--- a/src/main/java/eu/openaire/api/OpenaireRestApiApplication.java
+++ b/src/main/java/eu/openaire/api/OpenaireRestApiApplication.java
@@ -2,8 +2,10 @@ package eu.openaire.api;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
@SpringBootApplication
+@EnableAspectJAutoProxy
public class OpenaireRestApiApplication {
public static void main(String[] args) {
diff --git a/src/main/java/eu/openaire/api/config/metrics/MetricsAspect.java b/src/main/java/eu/openaire/api/config/metrics/MetricsAspect.java
new file mode 100644
index 0000000..4f947dd
--- /dev/null
+++ b/src/main/java/eu/openaire/api/config/metrics/MetricsAspect.java
@@ -0,0 +1,50 @@
+package eu.openaire.api.config.metrics;
+
+import io.micrometer.core.annotation.Timed;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.Timer;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.lang.reflect.Method;
+
+@Aspect
+@Component
+public class MetricsAspect {
+
+ private final MeterRegistry meterRegistry;
+
+ @Autowired
+ public MetricsAspect(MeterRegistry meterRegistry) {
+ this.meterRegistry = meterRegistry;
+ }
+
+ /***
+ * Advice for timing methods annotated with {@link Timed}.
+ */
+ @Around("@annotation(io.micrometer.core.annotation.Timed)")
+ public Object timeAnnotatedMethods(ProceedingJoinPoint joinPoint) throws Throwable {
+ Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
+
+ String className = joinPoint.getTarget().getClass().getSimpleName();
+ String methodName = method.getName();
+ String timerName = className + "." + methodName;
+
+ Timer.Sample sample = Timer.start(meterRegistry);
+
+ try {
+ return joinPoint.proceed();
+ } finally {
+ sample.stop(Timer.builder(timerName)
+ .tags("application", "openaire-search-api")
+ .tags("class", className)
+ .tags("method", methodName)
+ .publishPercentiles(0.5, 0.95)
+ .register(meterRegistry));
+ }
+ }
+}
diff --git a/src/main/java/eu/openaire/api/services/DataSourceService.java b/src/main/java/eu/openaire/api/services/DataSourceService.java
index 9c075bf..2f1b60a 100644
--- a/src/main/java/eu/openaire/api/services/DataSourceService.java
+++ b/src/main/java/eu/openaire/api/services/DataSourceService.java
@@ -11,6 +11,7 @@ import eu.openaire.api.mappers.response.ResponseResultsMapper;
import eu.openaire.api.mappers.response.entities.DatasourceMapper;
import eu.openaire.api.repositories.SolrRepository;
import eu.openaire.api.solr.SolrQueryParams;
+import io.micrometer.core.annotation.Timed;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.apache.logging.log4j.LogManager;
@@ -37,6 +38,7 @@ public class DataSourceService {
private final Logger log = LogManager.getLogger(this.getClass());
@SneakyThrows
+ @Timed
public Datasource getById(String id) {
var doc = solrRepository.getById(id);
@@ -48,6 +50,7 @@ public class DataSourceService {
}
@SneakyThrows
+ @Timed
public SearchResponse search(DataSourceRequest request) {
SolrQueryParams solrQueryParams = dataSourceRequestMapper.toSolrQuery(request);
diff --git a/src/main/java/eu/openaire/api/services/OrganizationService.java b/src/main/java/eu/openaire/api/services/OrganizationService.java
index 602e431..e549ad3 100644
--- a/src/main/java/eu/openaire/api/services/OrganizationService.java
+++ b/src/main/java/eu/openaire/api/services/OrganizationService.java
@@ -11,6 +11,7 @@ import eu.openaire.api.mappers.response.ResponseResultsMapper;
import eu.openaire.api.mappers.response.entities.OrganizationMapper;
import eu.openaire.api.repositories.SolrRepository;
import eu.openaire.api.solr.SolrQueryParams;
+import io.micrometer.core.annotation.Timed;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.apache.logging.log4j.LogManager;
@@ -37,6 +38,7 @@ public class OrganizationService {
private final Logger log = LogManager.getLogger(this.getClass());
@SneakyThrows
+ @Timed
public Organization getById(String id) {
var doc = solrRepository.getById(id);
@@ -48,6 +50,7 @@ public class OrganizationService {
}
@SneakyThrows
+ @Timed
public SearchResponse search(OrganizationRequest request) {
SolrQueryParams solrQueryParams = organizationRequestMapper.toSolrQuery(request);
diff --git a/src/main/java/eu/openaire/api/services/ProjectService.java b/src/main/java/eu/openaire/api/services/ProjectService.java
index 191554e..fbecfc6 100644
--- a/src/main/java/eu/openaire/api/services/ProjectService.java
+++ b/src/main/java/eu/openaire/api/services/ProjectService.java
@@ -11,6 +11,7 @@ import eu.openaire.api.mappers.response.ResponseResultsMapper;
import eu.openaire.api.mappers.response.entities.ProjectMapper;
import eu.openaire.api.repositories.SolrRepository;
import eu.openaire.api.solr.SolrQueryParams;
+import io.micrometer.core.annotation.Timed;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.apache.logging.log4j.LogManager;
@@ -37,6 +38,7 @@ public class ProjectService {
private final Logger log = LogManager.getLogger(this.getClass());
@SneakyThrows
+ @Timed
public Project getById(String id) {
var doc = solrRepository.getById(id);
@@ -48,6 +50,7 @@ public class ProjectService {
}
@SneakyThrows
+ @Timed
public SearchResponse search(ProjectRequest request) {
SolrQueryParams solrQueryParams = projectRequestMapper.toSolrQuery(request);
diff --git a/src/main/java/eu/openaire/api/services/ResearchProductService.java b/src/main/java/eu/openaire/api/services/ResearchProductService.java
index 84a9d09..5e6318c 100644
--- a/src/main/java/eu/openaire/api/services/ResearchProductService.java
+++ b/src/main/java/eu/openaire/api/services/ResearchProductService.java
@@ -11,6 +11,7 @@ import eu.openaire.api.mappers.response.ResponseResultsMapper;
import eu.openaire.api.mappers.response.entities.ResearchProductMapper;
import eu.openaire.api.repositories.SolrRepository;
import eu.openaire.api.solr.SolrQueryParams;
+import io.micrometer.core.annotation.Timed;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.apache.logging.log4j.LogManager;
@@ -37,6 +38,7 @@ public class ResearchProductService {
private final Logger log = LogManager.getLogger(this.getClass());
@SneakyThrows
+ @Timed
public GraphResult getById(String id) {
var doc = solrRepository.getById(id);
@@ -49,6 +51,7 @@ public class ResearchProductService {
}
@SneakyThrows
+ @Timed
public SearchResponse search(ResearchProductsRequest request) {
SolrQueryParams solrQueryParams = researchProductsRequestMapper.toSolrQuery(request);
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 78f42bf..d62d9de 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -15,8 +15,10 @@ server.error.include-stacktrace=never
# Enable the health endpoint
management.endpoint.health.enabled=true
-# Expose the health endpoint
-management.endpoints.web.exposure.include=health,info
+# Expose health, info and metrics endpoint
+management.endpoints.web.exposure.include=health,info,prometheus
+management.endpoint.prometheus.enabled=true
+management.metrics.export.prometheus.enabled=true
# Customize health endpoint settings
management.endpoint.health.show-details=always