diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 12f95c6..3071ce0 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,5 +1,9 @@ # Release-Notes +## Sprint 18 (01.10.2024 - 22.10.2024) +## Hinzugefügt +- Micrometer Metriken + ## Sprint 16 (20.08.2024 - 09.09.2024) ### Hinzugefügt - Schadcode-Erkennung und Mimetype-Prüfung diff --git a/pom.xml b/pom.xml index d960808..85f9f43 100644 --- a/pom.xml +++ b/pom.xml @@ -65,7 +65,7 @@ 1.0.9 - 1.18.26 + 1.18.30 UTF-8 @@ -201,9 +201,13 @@ woodstox-core 7.0.0 + + org.apache.camel.springboot + camel-micrometer-starter + ${camel.version} + - diff --git a/src/main/java/de/muenchen/mobidam/config/MetricsConfiguration.java b/src/main/java/de/muenchen/mobidam/config/MetricsConfiguration.java new file mode 100644 index 0000000..0a33d1f --- /dev/null +++ b/src/main/java/de/muenchen/mobidam/config/MetricsConfiguration.java @@ -0,0 +1,72 @@ +/* + * The MIT License + * Copyright © 2024 Landeshauptstadt München | it@M + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package de.muenchen.mobidam.config; + +import de.muenchen.mobidam.security.FileSizeProcessor; +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.Gauge; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Timer; +import lombok.Getter; +import lombok.Setter; +import org.apache.camel.CamelContext; +import org.springframework.stereotype.Component; + +@Component +@Getter +@Setter +public class MetricsConfiguration { + + private final MeterRegistry meterRegistry; + private final MetricsNameConfig metricsNameConfig; + private final CamelContext camelContext; + private final FileSizeProcessor fileSizeProcessor; + + private final Counter beginnCounter; + private final Counter endeCounter; + private final Counter fehlerCounter; + private final Counter erfolgCounter; + private final Counter warnungenCounter; + private final Gauge inflightExchanges; + private final Gauge maxFileSize; + private Timer processingTime; + + public MetricsConfiguration(final MeterRegistry meterRegistry, MetricsNameConfig metricsNameConfig, CamelContext camelContext, + FileSizeProcessor fileSizeProcessor) { + this.meterRegistry = meterRegistry; + this.metricsNameConfig = metricsNameConfig; + this.camelContext = camelContext; + this.fileSizeProcessor = fileSizeProcessor; + this.beginnCounter = Counter.builder(metricsNameConfig.getBeginnCounterMetric()).register(meterRegistry); + this.endeCounter = Counter.builder(metricsNameConfig.getEndCounterMetric()).register(meterRegistry); + this.fehlerCounter = Counter.builder(metricsNameConfig.getFehlerCounterMetric()).register(meterRegistry); + this.erfolgCounter = Counter.builder(metricsNameConfig.getErfolgCounterMetric()).register(meterRegistry); + this.warnungenCounter = Counter.builder(metricsNameConfig.getWarnungenCounterMetric()).register(meterRegistry); + this.inflightExchanges = Gauge.builder(metricsNameConfig.getInflightExchangesMetric(), camelContext, context -> context.getInflightRepository().size()) + .register(meterRegistry); + this.processingTime = Timer.builder(metricsNameConfig.getProcessingTimeMetric()).register(meterRegistry); + this.maxFileSize = Gauge.builder(metricsNameConfig.getMaxFileSizeMetric(), fileSizeProcessor::getMaxStreamSize).register(meterRegistry); + + } + +} diff --git a/src/main/java/de/muenchen/mobidam/config/MetricsNameConfig.java b/src/main/java/de/muenchen/mobidam/config/MetricsNameConfig.java new file mode 100644 index 0000000..24b9bc4 --- /dev/null +++ b/src/main/java/de/muenchen/mobidam/config/MetricsNameConfig.java @@ -0,0 +1,50 @@ +/* + * The MIT License + * Copyright © 2024 Landeshauptstadt München | it@M + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package de.muenchen.mobidam.config; + +import lombok.Getter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +@Getter +public class MetricsNameConfig { + + @Value("${mobidam.metrics.beginn-counter-metric}") + private String beginnCounterMetric; + @Value("${mobidam.metrics.ende-counter-metric}") + private String endCounterMetric; + @Value("${mobidam.metrics.erfolg-counter-metric}") + private String erfolgCounterMetric; + @Value("${mobidam.metrics.fehler-counter-metric}") + private String fehlerCounterMetric; + @Value("${mobidam.metrics.warnungen-counter-metric}") + private String warnungenCounterMetric; + @Value("${mobidam.metrics.processing-time-metric}") + private String processingTimeMetric; + @Value("${mobidam.metrics.inflight-exchanges-metric}") + private String inflightExchangesMetric; + @Value("${mobidam.metrics.max-file-size-metric}") + private String maxFileSizeMetric; + +} diff --git a/src/main/java/de/muenchen/mobidam/config/SecurityConfiguration.java b/src/main/java/de/muenchen/mobidam/config/SecurityConfiguration.java new file mode 100644 index 0000000..c44d652 --- /dev/null +++ b/src/main/java/de/muenchen/mobidam/config/SecurityConfiguration.java @@ -0,0 +1,59 @@ +/* + * The MIT License + * Copyright © 2024 Landeshauptstadt München | it@M + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package de.muenchen.mobidam.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; + +/** + * The central class for configuration of all security aspects. + */ +@Configuration +@Profile("!no-security") +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) +public class SecurityConfiguration { + + @Bean + public SecurityFilterChain securityFilterChain(final HttpSecurity http) throws Exception { + + return http + .authorizeHttpRequests((requests) -> requests.requestMatchers( + // allow access to /actuator/info + AntPathRequestMatcher.antMatcher("/actuator/info"), + // allow access to /actuator/health for OpenShift Health Check + AntPathRequestMatcher.antMatcher("/actuator/health"), + // allow access to single metrics values + AntPathRequestMatcher.antMatcher("/actuator/metrics/*"), + // allow access to /actuator/metrics for Prometheus monitoring in OpenShift + AntPathRequestMatcher.antMatcher("/actuator/metrics")) + .permitAll()) + .build(); + } +} diff --git a/src/main/java/de/muenchen/mobidam/mobilithek/InterfaceMessageFactory.java b/src/main/java/de/muenchen/mobidam/mobilithek/InterfaceMessageFactory.java index 0155490..d2df758 100644 --- a/src/main/java/de/muenchen/mobidam/mobilithek/InterfaceMessageFactory.java +++ b/src/main/java/de/muenchen/mobidam/mobilithek/InterfaceMessageFactory.java @@ -23,6 +23,7 @@ package de.muenchen.mobidam.mobilithek; import de.muenchen.mobidam.Constants; +import de.muenchen.mobidam.config.MetricsConfiguration; import de.muenchen.mobidam.integration.client.domain.DatentransferCreateDTO; import de.muenchen.mobidam.sstmanagment.EreignisTyp; import java.time.LocalDateTime; @@ -35,8 +36,12 @@ @AllArgsConstructor public class InterfaceMessageFactory { + private MetricsConfiguration metricsConfiguration; + public void mobilithekMessageStart(Exchange exchange) { + metricsConfiguration.getBeginnCounter().increment(); + var dto = new DatentransferCreateDTO(); dto.setEreignis(EreignisTyp.BEGINN.name()); dto.setZeitstempel(LocalDateTime.now()); @@ -47,6 +52,8 @@ public void mobilithekMessageStart(Exchange exchange) { public void mobilithekMessageSuccess(Exchange exchange) { + metricsConfiguration.getErfolgCounter().increment(); + var dto = new DatentransferCreateDTO(); dto.setEreignis(EreignisTyp.ERFOLG.name()); dto.setZeitstempel(LocalDateTime.now()); @@ -59,6 +66,8 @@ public void mobilithekMessageSuccess(Exchange exchange) { public void mobilithekMessageError(Exchange exchange) { + metricsConfiguration.getFehlerCounter().increment(); + var dto = new DatentransferCreateDTO(); dto.setEreignis(EreignisTyp.FEHLER.name()); dto.setZeitstempel(LocalDateTime.now()); @@ -71,6 +80,8 @@ public void mobilithekMessageError(Exchange exchange) { public void mobilithekMessageEnd(Exchange exchange) { + metricsConfiguration.getEndeCounter().increment(); + var dto = new DatentransferCreateDTO(); dto.setEreignis(EreignisTyp.ENDE.name()); dto.setZeitstempel(LocalDateTime.now()); diff --git a/src/main/java/de/muenchen/mobidam/mobilithek/MobilithekEaiRouteBuilder.java b/src/main/java/de/muenchen/mobidam/mobilithek/MobilithekEaiRouteBuilder.java index b8bc3ee..e6820c4 100644 --- a/src/main/java/de/muenchen/mobidam/mobilithek/MobilithekEaiRouteBuilder.java +++ b/src/main/java/de/muenchen/mobidam/mobilithek/MobilithekEaiRouteBuilder.java @@ -86,6 +86,7 @@ public void configure() { .process("mimeTypeProcessor") .process("codeDetectionProcessor") .process("s3ObjectKeyProvider") + .process("fileSizeProcessor") .toD("aws2-s3://${header.bucketName}?accessKey=RAW(${header.accessKey})&secretKey=RAW(${header.secretKey})®ion=${properties:camel.component.aws2-s3.region}&overrideEndpoint=true&uriEndpointOverride=${properties:camel.component.aws2-s3.override-endpoint}").id(MOBIDAM_ENDPOINT_S3_ID) .bean("interfaceMessageFactory", "mobilithekMessageSuccess") .bean("sstManagementIntegrationService", "logDatentransfer") diff --git a/src/main/java/de/muenchen/mobidam/scheduler/MobilithekJobExecute.java b/src/main/java/de/muenchen/mobidam/scheduler/MobilithekJobExecute.java index a341b5a..89f63af 100644 --- a/src/main/java/de/muenchen/mobidam/scheduler/MobilithekJobExecute.java +++ b/src/main/java/de/muenchen/mobidam/scheduler/MobilithekJobExecute.java @@ -24,6 +24,7 @@ import de.muenchen.mobidam.Constants; import de.muenchen.mobidam.config.Interfaces; +import de.muenchen.mobidam.config.MetricsConfiguration; import de.muenchen.mobidam.mobilithek.MobilithekEaiRouteBuilder; import lombok.AllArgsConstructor; import lombok.Getter; @@ -47,6 +48,8 @@ public class MobilithekJobExecute implements Job { private Interfaces mobidamInterfaces; + private MetricsConfiguration metricsConfiguration; + @Produce(MobilithekEaiRouteBuilder.MOBIDAM_S3_ROUTE) private ProducerTemplate producer; @@ -55,12 +58,11 @@ public void execute(JobExecutionContext context) throws JobExecutionException { var identifier = context.getJobDetail().getJobDataMap().get(Constants.INTERFACE_TYPE); log.info("Scheduler starts mobilithek '{}' request at '{}'.", identifier, context.getFireTime().toString()); - var exchange = ExchangeBuilder.anExchange(getCamelContext()) + var exchange = metricsConfiguration.getProcessingTime().record(() -> ExchangeBuilder.anExchange(getCamelContext()) .withHeader(Constants.INTERFACE_TYPE, getMobidamInterfaces().getInterfaces().get(identifier)) - .build(); + .build()); producer.send(exchange); - } } diff --git a/src/main/java/de/muenchen/mobidam/security/FileSizeProcessor.java b/src/main/java/de/muenchen/mobidam/security/FileSizeProcessor.java new file mode 100644 index 0000000..3917747 --- /dev/null +++ b/src/main/java/de/muenchen/mobidam/security/FileSizeProcessor.java @@ -0,0 +1,48 @@ +/* + * The MIT License + * Copyright © 2024 Landeshauptstadt München | it@M + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package de.muenchen.mobidam.security; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.converter.stream.InputStreamCache; +import org.springframework.stereotype.Service; + +@Service +@NoArgsConstructor +@Slf4j +@Getter +public class FileSizeProcessor implements Processor { + + private long maxStreamSize = 0L; + + @Override + public void process(Exchange exchange) throws Exception { + InputStreamCache stream = exchange.getMessage().getBody(InputStreamCache.class); + stream.reset(); + maxStreamSize = Math.max(maxStreamSize, stream.length()); + } + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 57484af..efcece3 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -34,12 +34,14 @@ management: enabled-by-default: false web: exposure: - include: health,info + include: health,info,metrics endpoint: info: enabled: true health: enabled: true + metrics: + enabled: true info: env: enabled: true @@ -82,4 +84,13 @@ mobidam: bucket-credential-config: s3-bucket-1: access-key-env-var: ... - secret-key-env-var: ... \ No newline at end of file + secret-key-env-var: ... + metrics: + beginn-counter-metric: mobidam.exchanges.ereignis.beginn.counter + ende-counter-metric: mobidam.exchanges.ereignis.ende.counter + fehler-counter-metric: mobidam.exchanges.ereignis.fehler.counter + erfolg-counter-metric: mobidam.exchanges.ereignis.erfolg.counter + warnungen-counter-metric: mobidam.exchanges.ereignis.warnungen.counter + inflight-exchanges-metric: mobidam.exchanges.inflight + processing-time-metric: mobidam.exchanges.processingtime + max-file-size-metric: mobidam.exchanges.filesize.max diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index 49fac21..a801d17 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -42,3 +42,12 @@ mobidam: int-mdasc-mdasdev: access-key-env-var: MOBIDAM_INT-MDASC-MDASDEV_ACCESS_KEY secret-key-env-var: MOBIDAM_INT-MDASC-MDASDEV_SECRET_KEY + metrics: + beginn-counter-metric: mobidam.exchanges.ereignis.beginn.counter + ende-counter-metric: mobidam.exchanges.ereignis.ende.counter + fehler-counter-metric: mobidam.exchanges.ereignis.fehler.counter + erfolg-counter-metric: mobidam.exchanges.ereignis.erfolg.counter + warnungen-counter-metric: mobidam.exchanges.ereignis.warnungen.counter + inflight-exchanges-metric: mobidam.exchanges.inflight + processing-time-metric: mobidam.exchanges.processingtime + max-file-size-metric: mobidam.exchanges.filesize.max