Skip to content

Commit 140d0f2

Browse files
authored
Merge pull request #190 from kit-data-manager/prometheus_monitoring
Prometheus monitoring
2 parents cef69c2 + acaafc2 commit 140d0f2

13 files changed

+150
-17
lines changed

build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ dependencies {
6363
implementation 'org.springframework.boot:spring-boot-starter-web'
6464
implementation 'org.springframework.boot:spring-boot-starter-actuator'
6565

66+
// monitoring
67+
implementation 'io.micronaut.micrometer:micronaut-micrometer-registry-prometheus:5.8.0'
68+
implementation 'org.springframework.boot:spring-boot-starter-actuator:3.3.4'
69+
6670
// springdoc
6771
implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:${springDocVersion}"
6872
implementation "org.springdoc:springdoc-openapi-starter-common:${springDocVersion}"

settings/application-default.properties

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,23 @@ spring.servlet.multipart.max-file-size=100MB
1919
spring.servlet.multipart.max-request-size=100MB
2020
# Logging settings
2121
logging.level.root=ERROR
22-
logging.level.edu.kit.datamanager=INFO
22+
logging.level.edu.kit.datamanager=DEBUG
2323
springdoc.swagger-ui.disable-swagger-default-url=true
2424
# Actuator settings
2525
info.app.name=Mapping-Service
2626
info.app.description=Generic mapping service supporting different mapping implementations.
2727
info.app.group=edu.kit.datamanager
2828
info.app.version=1.0.4
2929
management.endpoint.health.probes.enabled=true
30-
management.endpoints.web.exposure.include=*
31-
management.health.rabbit.enabled:false
32-
management.health.elasticsearch.enabled:false
30+
management.endpoint.health.enabled: true
31+
management.endpoint.health.show-details: when-authorized
32+
management.endpoint.health.sensitive: true
33+
management.endpoints.web.exposure.include: health,info
34+
35+
#spring.security.user.name=admin
36+
#spring.security.user.password=secret
37+
#spring.security.user.roles=ADMIN
38+
3339
###############################################################################
3440
# Spring Cloud
3541
###############################################################################
@@ -56,6 +62,10 @@ mapping-service.pluginLocation=file://INSTALLATION_DIR/plugins
5662
mapping-service.mappingSchemasLocation=file://INSTALLATION_DIR/mappingSchemas
5763
# Folder where job output files for async mapping executions are stored
5864
mapping-service.jobOutput=file://INSTALLATION_DIR/jobOutput
65+
66+
management.metrics.export.prometheus.enabled=true
67+
management.endpoint.metrics.enabled=true
68+
5969
# Execution timeout for script calls
6070
mapping-service.executionTimeout=30
6171

src/main/java/edu/kit/datamanager/mappingservice/MappingServiceApplication.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
import com.google.common.collect.ImmutableSet;
44
import com.google.common.reflect.ClassPath;
55
import edu.kit.datamanager.mappingservice.configuration.ApplicationProperties;
6-
import edu.kit.datamanager.mappingservice.plugins.PluginLoader;
76
import edu.kit.datamanager.mappingservice.plugins.PluginManager;
7+
import io.micrometer.core.instrument.MeterRegistry;
8+
import edu.kit.datamanager.mappingservice.plugins.PluginLoader;
89
import edu.kit.datamanager.mappingservice.util.PythonRunnerUtil;
910
import edu.kit.datamanager.mappingservice.util.ShellRunnerUtil;
1011
import edu.kit.datamanager.security.filter.KeycloakJwtProperties;
@@ -13,6 +14,7 @@
1314
import java.io.IOException;
1415
import org.slf4j.Logger;
1516
import org.slf4j.LoggerFactory;
17+
import org.springframework.beans.factory.annotation.Autowired;
1618
import org.springframework.boot.SpringApplication;
1719
import org.springframework.boot.autoconfigure.SpringBootApplication;
1820
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -32,6 +34,13 @@ public class MappingServiceApplication {
3234

3335
private static final Logger LOG = LoggerFactory.getLogger(MappingServiceApplication.class);
3436

37+
@Autowired
38+
private final MeterRegistry meterRegistry;
39+
40+
MappingServiceApplication(MeterRegistry meterRegistry) {
41+
this.meterRegistry = meterRegistry;
42+
}
43+
3544
@Bean
3645
public ApplicationProperties applicationProperties() {
3746
return new ApplicationProperties();
@@ -46,7 +55,7 @@ public PluginLoader pluginLoader() {
4655
public PluginManager pluginManager() {
4756
PythonRunnerUtil.init(applicationProperties());
4857
ShellRunnerUtil.init(applicationProperties());
49-
return new PluginManager(applicationProperties(), pluginLoader());
58+
return new PluginManager(applicationProperties(), pluginLoader(), meterRegistry);
5059
}
5160

5261
@Bean

src/main/java/edu/kit/datamanager/mappingservice/configuration/StaticResourcesConfiguration.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
*/
1616
package edu.kit.datamanager.mappingservice.configuration;
1717

18+
import edu.kit.datamanager.mappingservice.rest.impl.PreHandleInterceptor;
19+
import org.springframework.beans.factory.annotation.Autowired;
1820
import org.springframework.context.annotation.Configuration;
21+
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
1922
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
2023
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
2124
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@@ -28,10 +31,16 @@
2831
*/
2932
@Configuration
3033
public class StaticResourcesConfiguration implements WebMvcConfigurer {
34+
private final PreHandleInterceptor preHandleInterceptor;
3135

3236
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
3337
"classpath:/static/"};
3438

39+
@Autowired
40+
public StaticResourcesConfiguration(PreHandleInterceptor preHandleInterceptor) {
41+
this.preHandleInterceptor = preHandleInterceptor;
42+
}
43+
3544
@Override
3645
public void addResourceHandlers(ResourceHandlerRegistry registry) {
3746
registry.addResourceHandler("/static/**").addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS);
@@ -43,4 +52,9 @@ public void configurePathMatch(PathMatchConfigurer configurer) {
4352
urlPathHelper.setUrlDecode(false);
4453
configurer.setUrlPathHelper(urlPathHelper);
4554
}
55+
56+
@Override
57+
public void addInterceptors(InterceptorRegistry registry) {
58+
registry.addInterceptor(preHandleInterceptor);
59+
}
4660
}

src/main/java/edu/kit/datamanager/mappingservice/configuration/WebSecurityConfig.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
3636
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
3737
import org.springframework.security.config.http.SessionCreationPolicy;
38+
import org.springframework.security.config.Customizer;
3839
import org.springframework.security.web.SecurityFilterChain;
3940
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
4041
import org.springframework.security.web.firewall.DefaultHttpFirewall;
@@ -105,6 +106,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
105106
requestMatchers(AUTH_WHITELIST_SWAGGER_UI).permitAll().
106107
anyRequest().authenticated()
107108
).
109+
httpBasic(Customizer.withDefaults()).
108110
cors(cors -> cors.configurationSource(corsConfigurationSource())).
109111
sessionManagement(
110112
session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));

src/main/java/edu/kit/datamanager/mappingservice/impl/MappingService.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
import edu.kit.datamanager.mappingservice.plugins.MappingPluginState;
3232
import edu.kit.datamanager.mappingservice.plugins.PluginManager;
3333
import edu.kit.datamanager.mappingservice.util.FileUtil;
34+
import io.micrometer.core.instrument.Counter;
35+
import io.micrometer.core.instrument.MeterRegistry;
3436
import org.apache.commons.codec.binary.Hex;
3537
import org.apache.commons.io.FileUtils;
3638
import org.slf4j.Logger;
@@ -89,16 +91,18 @@ public class MappingService {
8991
*/
9092
private Path jobsOutputDirectory;
9193

92-
private final ApplicationProperties applicationProperties;
94+
private ApplicationProperties applicationProperties;
95+
private final MeterRegistry meterRegistry;
9396

9497
/**
9598
* Logger for this class.
9699
*/
97100
private final static Logger LOGGER = LoggerFactory.getLogger(MappingService.class);
98101

99102
@Autowired
100-
public MappingService(ApplicationProperties applicationProperties) {
103+
public MappingService(ApplicationProperties applicationProperties, MeterRegistry meterRegistry) {
101104
this.applicationProperties = applicationProperties;
105+
this.meterRegistry = meterRegistry;
102106
init(this.applicationProperties);
103107
}
104108

@@ -212,6 +216,9 @@ public Optional<Path> executeMapping(URI contentUrl, String mappingId) throws Ma
212216
if (optionalMappingRecord.isPresent()) {
213217
LOGGER.trace("Mapping for id {} found.", mappingId);
214218
mappingRecord = optionalMappingRecord.get();
219+
220+
Counter.builder("mapping_service.plugin_usage").tag("plugin", mappingRecord.getMappingType()).register(meterRegistry).increment();
221+
215222
Path mappingFile = Paths.get(mappingRecord.getMappingDocumentUri());
216223
// execute mapping
217224
Path resultFile;

src/main/java/edu/kit/datamanager/mappingservice/plugins/PluginManager.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
package edu.kit.datamanager.mappingservice.plugins;
1616

1717
import edu.kit.datamanager.mappingservice.configuration.ApplicationProperties;
18+
import io.micrometer.core.instrument.Gauge;
19+
import io.micrometer.core.instrument.MeterRegistry;
1820
import edu.kit.datamanager.mappingservice.exception.MappingServiceException;
1921
import org.slf4j.Logger;
2022
import org.slf4j.LoggerFactory;
@@ -62,10 +64,12 @@ public class PluginManager {
6264
* instantiation time.
6365
*/
6466
@Autowired
65-
public PluginManager(ApplicationProperties applicationProperties, PluginLoader pluginLoader) {
67+
public PluginManager(ApplicationProperties applicationProperties, PluginLoader pluginLoader, MeterRegistry meterRegistry) {
6668
this.applicationProperties = applicationProperties;
6769
this.pluginLoader = pluginLoader;
6870
reloadPlugins();
71+
72+
Gauge.builder("mapping_service.plugins_total", () -> plugins.size()).register(meterRegistry);
6973
}
7074

7175
/**

src/main/java/edu/kit/datamanager/mappingservice/rest/impl/MappingAdministrationController.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import edu.kit.datamanager.mappingservice.rest.PluginInformation;
2929
import edu.kit.datamanager.util.AuthenticationHelper;
3030
import edu.kit.datamanager.util.ControllerUtils;
31+
import io.micrometer.core.instrument.Gauge;
32+
import io.micrometer.core.instrument.MeterRegistry;
3133
import io.swagger.v3.core.util.Json;
3234
import org.slf4j.Logger;
3335
import org.slf4j.LoggerFactory;
@@ -86,10 +88,12 @@ public class MappingAdministrationController implements IMappingAdministrationCo
8688
*/
8789
private final MappingService mappingService;
8890

89-
public MappingAdministrationController(IMappingRecordDao mappingRecordDao, PluginManager pluginManager, MappingService mappingService) {
91+
public MappingAdministrationController(IMappingRecordDao mappingRecordDao, PluginManager pluginManager, MappingService mappingService, MeterRegistry meterRegistry) {
9092
this.mappingRecordDao = mappingRecordDao;
9193
this.mappingService = mappingService;
9294
this.pluginManager = pluginManager;
95+
96+
Gauge.builder("mapping_service.schemes_total", mappingRecordDao::count).register(meterRegistry);
9397
}
9498

9599
@Override

src/main/java/edu/kit/datamanager/mappingservice/rest/impl/MappingExecutionController.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
import edu.kit.datamanager.mappingservice.plugins.MappingPluginState;
3333
import edu.kit.datamanager.mappingservice.rest.IMappingExecutionController;
3434
import edu.kit.datamanager.mappingservice.util.FileUtil;
35+
import io.micrometer.core.instrument.Counter;
36+
import io.micrometer.core.instrument.DistributionSummary;
37+
import io.micrometer.core.instrument.MeterRegistry;
3538
import org.apache.commons.io.FilenameUtils;
3639
import org.slf4j.Logger;
3740
import org.slf4j.LoggerFactory;
@@ -72,11 +75,17 @@ public class MappingExecutionController implements IMappingExecutionController {
7275
private final MappingService mappingService;
7376
protected JobManager jobManager;
7477
private final IMappingRecordDao mappingRecordDao;
78+
private final MeterRegistry meterRegistry;
79+
private final DistributionSummary documentsInSizeMetric;
80+
private final DistributionSummary documentsOutSizeMetric;
7581

76-
public MappingExecutionController(MappingService mappingService, IMappingRecordDao mappingRecordDao, JobManager jobManager) {
82+
public MappingExecutionController(MappingService mappingService, IMappingRecordDao mappingRecordDao, JobManager jobManager, MeterRegistry meterRegistry) {
7783
this.mappingService = mappingService;
7884
this.mappingRecordDao = mappingRecordDao;
7985
this.jobManager = jobManager;
86+
this.meterRegistry = meterRegistry;
87+
this.documentsInSizeMetric = DistributionSummary.builder("mapping_service.documents.input_size").baseUnit("bytes").register(meterRegistry);
88+
this.documentsOutSizeMetric = DistributionSummary.builder("mapping_service.documents.output_size").baseUnit("bytes").register(meterRegistry);
8089
}
8190

8291
@Override
@@ -161,6 +170,10 @@ public void mapDocument(MultipartFile document, String mappingID, HttpServletReq
161170
LOG.error(message, ex);
162171
throw new MappingServiceException(message);
163172
} finally {
173+
Counter.builder("mapping_service.mapping_usage").tag("mappingID", mappingID).register(meterRegistry).increment();
174+
this.documentsInSizeMetric.record(document.getSize());
175+
this.documentsOutSizeMetric.record(result.toFile().length());
176+
164177
LOG.trace("Result file successfully transferred to client. Removing file {} from disk.", result);
165178
try {
166179
Files.delete(result);
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package edu.kit.datamanager.mappingservice.rest.impl;
2+
3+
import io.micrometer.core.instrument.Counter;
4+
import io.micrometer.core.instrument.Gauge;
5+
import io.micrometer.core.instrument.MeterRegistry;
6+
import jakarta.servlet.http.HttpServletRequest;
7+
import jakarta.servlet.http.HttpServletResponse;
8+
import org.slf4j.Logger;
9+
import org.slf4j.LoggerFactory;
10+
import org.springframework.beans.factory.annotation.Autowired;
11+
import org.springframework.lang.Nullable;
12+
import org.springframework.stereotype.Service;
13+
import org.springframework.web.servlet.HandlerInterceptor;
14+
15+
import java.security.MessageDigest;
16+
import java.util.HashSet;
17+
18+
@Service
19+
public class PreHandleInterceptor implements HandlerInterceptor {
20+
private final HashSet<String> uniqueUsers = new HashSet<>();
21+
private final Counter counter;
22+
23+
/**
24+
* Logger for this class.
25+
*/
26+
private final static Logger LOGGER = LoggerFactory.getLogger(PreHandleInterceptor.class);
27+
28+
@Autowired
29+
PreHandleInterceptor(MeterRegistry meterRegistry) {
30+
Gauge.builder("mapping_service.unique_users", uniqueUsers::size).register(meterRegistry);
31+
counter = Counter.builder("mapping_service.requests_served").register(meterRegistry);
32+
}
33+
34+
@Override
35+
public boolean preHandle(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Object handler) throws Exception {
36+
String forwardedFor = request.getHeader("X-Forwarded-For");
37+
LOGGER.debug("X-Forwarded-For: {}", forwardedFor);
38+
String clientIp = null;
39+
40+
if (forwardedFor != null) {
41+
String[] ipList = forwardedFor.split(", ");
42+
if (ipList.length > 0) clientIp = ipList[0];
43+
LOGGER.debug("Client IP from X-Forwarded-For: {}", clientIp);
44+
}
45+
46+
String remoteIp = request.getRemoteAddr();
47+
LOGGER.debug("Client IP from getRemoteAddr: {}", remoteIp);
48+
String ip = clientIp == null ? remoteIp : clientIp;
49+
LOGGER.debug("Using {} for monitoring", ip);
50+
51+
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
52+
messageDigest.update(ip.getBytes());
53+
uniqueUsers.add(new String(messageDigest.digest()));
54+
55+
counter.increment();
56+
57+
return true;
58+
}
59+
}

src/test/java/edu/kit/datamanager/mappingservice/TestConfig.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import edu.kit.datamanager.mappingservice.configuration.ApplicationProperties;
88
import edu.kit.datamanager.mappingservice.plugins.PluginLoader;
99
import edu.kit.datamanager.mappingservice.plugins.PluginManager;
10+
import io.micrometer.core.instrument.MeterRegistry;
11+
import org.springframework.beans.factory.annotation.Autowired;
1012
import org.springframework.context.annotation.Bean;
1113
import org.springframework.context.annotation.ComponentScan;
1214
import org.springframework.context.annotation.Configuration;
@@ -18,6 +20,8 @@
1820
@Configuration
1921
@ComponentScan("edu.kit.datamanager.mappingservice")
2022
public class TestConfig {
23+
@Autowired
24+
private MeterRegistry meterRegistry;
2125

2226
@Bean
2327
public ApplicationProperties applicationProperties() {
@@ -31,6 +35,6 @@ public PluginLoader pluginLoader() {
3135

3236
@Bean
3337
public PluginManager pluginManager() {
34-
return new PluginManager(applicationProperties(), pluginLoader());
38+
return new PluginManager(applicationProperties(), pluginLoader(), meterRegistry);
3539
}
3640
}

0 commit comments

Comments
 (0)