Added logging interceptor for Spring 53/58753/4
authorvempo <vitaliy.emporopulo@amdocs.com>
Thu, 2 Aug 2018 14:25:25 +0000 (17:25 +0300)
committerAvi Gaffa <avi.gaffa@amdocs.com>
Mon, 6 Aug 2018 08:24:42 +0000 (08:24 +0000)
Change-Id: I1de1f6baca48f36f05e32231f5a7e900738bd900
Issue-ID: SDC-1580
Signed-off-by: vempo <vitaliy.emporopulo@amdocs.com>
onboarding/pom.xml
openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-spring/pom.xml
openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-spring/src/main/java/org/openecomp/sdc/logging/servlet/spring/LoggingInterceptor.java [new file with mode: 0644]
openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-spring/src/test/java/org/openecomp/sdc/logging/servlet/spring/LoggingInterceptorTest.java [new file with mode: 0644]

index bbc6396..f310178 100644 (file)
                 <version>1.16.20</version>
                 <scope>provided</scope>
             </dependency>
+            <dependency>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring-webmvc</artifactId>
+                <version>${spring.framework.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.commons</groupId>
                 <artifactId>commons-text</artifactId>
index b556a2a..8b87fba 100644 (file)
     <modelVersion>4.0.0</modelVersion>
     <artifactId>openecomp-sdc-logging-spring</artifactId>
 
+    <dependencies>
+        <dependency>
+            <groupId>org.openecomp.sdc</groupId>
+            <artifactId>openecomp-sdc-logging-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-webmvc</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
 
 </project>
\ No newline at end of file
diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-spring/src/main/java/org/openecomp/sdc/logging/servlet/spring/LoggingInterceptor.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-spring/src/main/java/org/openecomp/sdc/logging/servlet/spring/LoggingInterceptor.java
new file mode 100644 (file)
index 0000000..a467a9e
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright © 2016-2018 European Support Limited
+ *
+ * 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.
+ */
+
+package org.openecomp.sdc.logging.servlet.spring;
+
+import static org.openecomp.sdc.logging.api.StatusCode.COMPLETE;
+import static org.openecomp.sdc.logging.api.StatusCode.ERROR;
+
+import java.util.Objects;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.openecomp.sdc.logging.api.Logger;
+import org.openecomp.sdc.logging.api.LoggerFactory;
+import org.openecomp.sdc.logging.api.StatusCode;
+import org.openecomp.sdc.logging.servlet.CombinedTracker;
+import org.openecomp.sdc.logging.servlet.HttpHeader;
+import org.openecomp.sdc.logging.servlet.RequestProcessingResult;
+import org.openecomp.sdc.logging.servlet.Tracker;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+/**
+ * <p>IMPORTANT: For this interceptor to work, all exceptions must be properly handled before being returned to a
+ * client. Any unexpected, automatically handled exception bypasses the interceptor and will not be logged.</p>
+ * <p>The interceptor must be either registered in Spring configuration XML as a bean, or programmatically as described
+ * in <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-config-interceptors">
+ * Spring MVC Config: Interceptors</a>.</p>
+ *
+ * @author evitaliy
+ * @since 02 Aug 2018
+ */
+public class LoggingInterceptor extends HandlerInterceptorAdapter {
+
+    static final String LOGGING_TRACKER_KEY = "onap.logging.tracker";
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(LoggingInterceptor.class);
+
+    private final HttpHeader partnerNameHeader;
+    private final HttpHeader requestIdHeader;
+
+    public LoggingInterceptor(HttpHeader partnerNameHeader, HttpHeader requestIdHeader) {
+        this.partnerNameHeader = Objects.requireNonNull(partnerNameHeader);
+        this.requestIdHeader = Objects.requireNonNull(requestIdHeader);
+    }
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
+        Class<?> resourceClass = getResourceType(handler);
+        Tracker tracker = new CombinedTracker(resourceClass, partnerNameHeader, requestIdHeader);
+        request.setAttribute(LOGGING_TRACKER_KEY, tracker);
+        tracker.preRequest(request);
+        return true;
+    }
+
+    @Override
+    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
+            Exception ex) {
+
+        Tracker tracker = (Tracker) request.getAttribute(LOGGING_TRACKER_KEY);
+
+        if (tracker == null) {
+            LOGGER.debug("No logging tracker received");
+            return;
+        }
+
+        tracker.postRequest(new ServletResponseResult(response.getStatus()));
+    }
+
+    private Class<?> getResourceType(Object handler) {
+
+        if (handler instanceof HandlerMethod) {
+            return ((HandlerMethod) handler).getMethod().getDeclaringClass();
+        }
+
+        return LoggingInterceptor.class;
+    }
+
+    static class ServletResponseResult implements RequestProcessingResult {
+
+        private final HttpStatus status;
+
+        ServletResponseResult(int status) {
+            this.status = HttpStatus.valueOf(status);
+        }
+
+        @Override
+        public int getStatus() {
+            return status.value();
+        }
+
+        @Override
+        public StatusCode getStatusCode() {
+            return status.is2xxSuccessful() || status.is3xxRedirection() ? COMPLETE : ERROR;
+        }
+
+        @Override
+        public String getStatusPhrase() {
+            return status.getReasonPhrase();
+        }
+    }
+}
\ No newline at end of file
diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-spring/src/test/java/org/openecomp/sdc/logging/servlet/spring/LoggingInterceptorTest.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-spring/src/test/java/org/openecomp/sdc/logging/servlet/spring/LoggingInterceptorTest.java
new file mode 100644 (file)
index 0000000..ccd0b70
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright © 2016-2018 European Support Limited
+ *
+ * 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.
+ */
+
+package org.openecomp.sdc.logging.servlet.spring;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.openecomp.sdc.logging.api.StatusCode.COMPLETE;
+import static org.openecomp.sdc.logging.api.StatusCode.ERROR;
+import static org.openecomp.sdc.logging.servlet.spring.LoggingInterceptor.LOGGING_TRACKER_KEY;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.junit.Test;
+import org.openecomp.sdc.logging.servlet.HttpHeader;
+import org.openecomp.sdc.logging.servlet.RequestProcessingResult;
+import org.openecomp.sdc.logging.servlet.Tracker;
+
+/**
+ * Audit tracking via Spring interceptor.
+ *
+ * @author evitaliy
+ * @since 05 Aug 2018
+ */
+public class LoggingInterceptorTest {
+
+    @Test(expected = NullPointerException.class)
+    public void exceptionThrownWhenPartnerNameHeaderNull() {
+        new LoggingInterceptor(null, mock(HttpHeader.class));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void exceptionThrownWhenRequestIdHeaderNull() {
+        new LoggingInterceptor(mock(HttpHeader.class), null);
+    }
+
+    @Test
+    public void trackerAddedWhenBeforeRequest() {
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        LoggingInterceptor interceptor = new LoggingInterceptor(mock(HttpHeader.class), mock(HttpHeader.class));
+        interceptor.preHandle(request, mock(HttpServletResponse.class), null);
+        verify(request).setAttribute(eq(LOGGING_TRACKER_KEY), any(Tracker.class));
+    }
+
+    @Test
+    public void trackerInvokedWhenPresentInRequest() {
+
+        Tracker tracker = mock(Tracker.class);
+
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        when(request.getAttribute(LOGGING_TRACKER_KEY)).thenReturn(tracker);
+
+        HttpServletResponse response = mock(HttpServletResponse.class);
+        when(response.getStatus()).thenReturn(200);
+
+        LoggingInterceptor interceptor = new LoggingInterceptor(mock(HttpHeader.class), mock(HttpHeader.class));
+        interceptor.afterCompletion(request, response, null, null);
+        verify(tracker).postRequest(any(RequestProcessingResult.class));
+    }
+
+    @Test
+    public void errorStatusWhenInformationalCode() {
+        final int status = 101;
+        LoggingInterceptor.ServletResponseResult result = new LoggingInterceptor.ServletResponseResult(status);
+        assertEquals(status, result.getStatus());
+        assertEquals(ERROR, result.getStatusCode());
+    }
+
+    @Test
+    public void errorStatusWhenClientErrorCode() {
+        final int status = 404;
+        LoggingInterceptor.ServletResponseResult result = new LoggingInterceptor.ServletResponseResult(status);
+        assertEquals(status, result.getStatus());
+        assertEquals(ERROR, result.getStatusCode());
+    }
+
+    @Test
+    public void errorStatusWhenServerErrorCode() {
+        final int status = 503;
+        LoggingInterceptor.ServletResponseResult result = new LoggingInterceptor.ServletResponseResult(status);
+        assertEquals(status, result.getStatus());
+        assertEquals(ERROR, result.getStatusCode());
+    }
+
+    @Test
+    public void completeStatusWhenSuccessCode() {
+        final int status = 204;
+        LoggingInterceptor.ServletResponseResult result = new LoggingInterceptor.ServletResponseResult(status);
+        assertEquals(status, result.getStatus());
+        assertEquals(COMPLETE, result.getStatusCode());
+    }
+
+    @Test
+    public void completeStatusWhenRedirectionCode() {
+        final int status = 307;
+        LoggingInterceptor.ServletResponseResult result = new LoggingInterceptor.ServletResponseResult(status);
+        assertEquals(status, result.getStatus());
+        assertEquals(COMPLETE, result.getStatusCode());
+    }
+}
\ No newline at end of file