From 3477cf37f00bc8dff4b74836d836d3b8846e21c4 Mon Sep 17 00:00:00 2001 From: "raviteja.karumuri" Date: Wed, 13 Nov 2024 17:25:31 +0000 Subject: Entry and Exit Logging Issue-ID: CCSDK-4040 Change-Id: I0dc6a7d398b4d414a5c82bb31f61e36be31134a0 Signed-off-by: Raviteja Karumuri --- .../ReactiveEntryExitFilterConfig.java | 17 ++++ .../util/v3/ReactiveEntryExitFilter.java | 97 ++++++++++++++++++++++ .../util/v3/ReactiveEntryExitFilterCondition.java | 21 +++++ 3 files changed, 135 insertions(+) create mode 100644 a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ReactiveEntryExitFilterConfig.java create mode 100644 a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/util/v3/ReactiveEntryExitFilter.java create mode 100644 a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/util/v3/ReactiveEntryExitFilterCondition.java (limited to 'a1-policy-management/src/main/java/org') diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ReactiveEntryExitFilterConfig.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ReactiveEntryExitFilterConfig.java new file mode 100644 index 00000000..5c82b3fb --- /dev/null +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ReactiveEntryExitFilterConfig.java @@ -0,0 +1,17 @@ +package org.onap.ccsdk.oran.a1policymanagementservice.configuration; + +import org.onap.ccsdk.oran.a1policymanagementservice.util.v3.ReactiveEntryExitFilter; +import org.onap.ccsdk.oran.a1policymanagementservice.util.v3.ReactiveEntryExitFilterCondition; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.server.WebFilter; + +@Configuration +public class ReactiveEntryExitFilterConfig { + @Bean + @Conditional(ReactiveEntryExitFilterCondition.class) + public WebFilter reactiveEntryExitFilter() { + return new ReactiveEntryExitFilter(); + } +} diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/util/v3/ReactiveEntryExitFilter.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/util/v3/ReactiveEntryExitFilter.java new file mode 100644 index 00000000..34376614 --- /dev/null +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/util/v3/ReactiveEntryExitFilter.java @@ -0,0 +1,97 @@ +/*- + * ========================LICENSE_START================================= + * ONAP : ccsdk oran + * ====================================================================== + * Copyright (C) 2024 OpenInfra Foundation Europe. All rights reserved. + * ====================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================LICENSE_END=================================== + */ + +package org.onap.ccsdk.oran.a1policymanagementservice.util.v3; + +import org.reactivestreams.Publisher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpRequestDecorator; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.http.server.reactive.ServerHttpResponseDecorator; +import org.springframework.stereotype.Component; +import org.springframework.util.MultiValueMap; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; +import org.springframework.web.server.WebFilterChain; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.lang.invoke.MethodHandles; +import java.nio.channels.Channels; +import java.nio.charset.StandardCharsets; + +public class ReactiveEntryExitFilter implements WebFilter { + + private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + @Override + public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { + ServerHttpRequest httpRequest = exchange.getRequest(); + ServerHttpResponse httpResponse = exchange.getResponse(); + MultiValueMap queryParams = httpRequest.getQueryParams(); + logger.info("Request received with path: {} and the Request Id: {}", httpRequest.getPath(), exchange.getRequest().getId()); + if (!queryParams.isEmpty()) + logger.trace("For the request Id: {}, the Query parameters are: {}", exchange.getRequest().getId(), queryParams); + + ServerHttpRequestDecorator loggingServerHttpRequestDecorator = new ServerHttpRequestDecorator(exchange.getRequest()) { + String requestBody = ""; + @Override + public Flux getBody() { + return super.getBody().doOnNext(dataBuffer -> { + try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) { + Channels.newChannel(byteArrayOutputStream).write(dataBuffer.asByteBuffer().asReadOnlyBuffer()); + requestBody = byteArrayOutputStream.toString(StandardCharsets.UTF_8); + if (requestBody != null) + logger.trace("For the request ID: {} the received request body: {}", exchange.getRequest().getId(), requestBody); + } catch (IOException e) { + logger.info("For the request ID: {} we got the error during processing: {}", exchange.getRequest().getId(), e.getMessage()); + logger.trace("For the request ID: {} the received request body: {}", exchange.getRequest().getId(), requestBody); + } + }); + } + }; + + ServerHttpResponseDecorator loggingServerHttpResponseDecorator = new ServerHttpResponseDecorator(exchange.getResponse()) { + String responseBody = ""; + @Override + public Mono writeWith(Publisher body) { + Flux buffer = Flux.from(body); + return super.writeWith(buffer.doOnNext(dataBuffer -> { + try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) { + Channels.newChannel(byteArrayOutputStream).write(dataBuffer.toByteBuffer().asReadOnlyBuffer()); + responseBody = byteArrayOutputStream.toString(StandardCharsets.UTF_8); + logger.info("For the request ID: {} the Status code of the response: {}", exchange.getRequest().getId(), httpResponse.getStatusCode()); + logger.trace("For the request ID: {} the response is: {} ", exchange.getRequest().getId(), responseBody); + } catch (Exception e) { + logger.info("For the request ID: {} we got an Error during processing: {}", exchange.getRequest().getId(), e.getMessage()); + logger.trace("For the request ID: {} the response body :: {}", exchange.getRequest().getId(), responseBody); + } + })); + } + }; + return chain.filter(exchange.mutate().request(loggingServerHttpRequestDecorator).response(loggingServerHttpResponseDecorator).build()); + } + + +} diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/util/v3/ReactiveEntryExitFilterCondition.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/util/v3/ReactiveEntryExitFilterCondition.java new file mode 100644 index 00000000..70094c9d --- /dev/null +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/util/v3/ReactiveEntryExitFilterCondition.java @@ -0,0 +1,21 @@ +package org.onap.ccsdk.oran.a1policymanagementservice.util.v3; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.type.AnnotatedTypeMetadata; + +import java.lang.invoke.MethodHandles; + +public class ReactiveEntryExitFilterCondition implements Condition { + + private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + @Override + public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + String reactiveFilterEnabled = context.getEnvironment().getProperty("logging.reactive-entry-exit-filter-enabled", "false"); + logger.info("Reactive Entry Exit filter is enabled: {}", reactiveFilterEnabled); + return Boolean.parseBoolean(reactiveFilterEnabled); + } +} -- cgit 1.2.3-korg