missing logs

Add filters for audit and request/response log
Add filters for audit and request/response log

Issue-ID: CCSDK-3367
Signed-off-by: lalena.aria <lalena.aria@att.com>
Change-Id: Id292c1f5109f0c3846a0357d0618f607011825a4
diff --git a/ms/sliboot/pom.xml b/ms/sliboot/pom.xml
index 46e2c4f..d17d4e5 100644
--- a/ms/sliboot/pom.xml
+++ b/ms/sliboot/pom.xml
@@ -76,6 +76,12 @@
             <artifactId>springfox-swagger-ui</artifactId>
             <version>2.9.2</version>
         </dependency>
+        <!-- Needed by logging-analytics payload logging filter -->
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-spring-boot-starter-jaxrs</artifactId>
+            <version>3.4.4</version>
+        </dependency>
         <dependency>
             <groupId>org.onap.aaf.authz</groupId>
             <artifactId>aaf-cadi-client</artifactId>
diff --git a/services/pom.xml b/services/pom.xml
index 36f0425..00aa8d4 100644
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -22,6 +22,7 @@
         <ccsdk.project.version>${project.version}</ccsdk.project.version>
         <ccsdk.build.timestamp>${maven.build.timestamp}</ccsdk.build.timestamp>
         <maven.build.timestamp.format>yyyyMMdd'T'HHmmss'Z'</maven.build.timestamp.format>
+        <logging.analytics.version>1.6.9</logging.analytics.version>
     </properties>
 
     <dependencies>
@@ -95,7 +96,7 @@
         <dependency>
             <groupId>org.onap.logging-analytics</groupId>
             <artifactId>logging-filter-spring</artifactId>
-            <version>1.6.6</version>
+            <version>${logging.analytics.version}</version>
         </dependency>
         <dependency>
             <groupId>javax.ws.rs</groupId>
diff --git a/services/src/main/java/org/onap/ccsdk/apps/filters/AuditLogFilter.java b/services/src/main/java/org/onap/ccsdk/apps/filters/AuditLogFilter.java
new file mode 100644
index 0000000..b6d52c5
--- /dev/null
+++ b/services/src/main/java/org/onap/ccsdk/apps/filters/AuditLogFilter.java
@@ -0,0 +1,43 @@
+package org.onap.ccsdk.apps.filters
+;
+
+import javax.servlet.http.HttpServletRequest;
+import org.onap.logging.filter.base.AuditLogServletFilter;
+import org.onap.logging.ref.slf4j.ONAPLogConstants;
+import org.slf4j.MDC;
+import org.springframework.stereotype.Component;
+
+@Component
+public class AuditLogFilter extends AuditLogServletFilter {
+    private static final String MDC_HTTP_METHOD_KEY = "HttpMethod";
+
+    @Override
+    protected void additionalPreHandling(HttpServletRequest httpServletRequest) {
+        // Don't overwrite service instance id if it was set outside of this automated method
+        if (MDC.get(ONAPLogConstants.MDCs.SERVICE_INSTANCE_ID) == null) {
+            String serviceInstanceId = getServiceInstanceId(httpServletRequest.getRequestURI());
+            if (serviceInstanceId != null) {
+                MDC.put(ONAPLogConstants.MDCs.SERVICE_INSTANCE_ID, serviceInstanceId);
+            }
+        }
+        MDC.put(MDC_HTTP_METHOD_KEY, httpServletRequest.getMethod());
+    }
+
+    // restconf URLs follow a pattern, this method attempts to extract the service instance id according to that pattern
+    protected String getServiceInstanceId(String path) {
+        int idx = path.indexOf("service-list");
+        if (idx != -1) {
+            // chomp off service-list/
+            String str = path.substring(idx + 13);
+            idx = str.indexOf("/");
+            //if there is another forward slash with more information chomp it off
+            if (idx != -1) {
+                return str.substring(0, idx);
+            } else {
+                return str;
+            }
+        }
+        return null;
+    }
+
+}
\ No newline at end of file
diff --git a/services/src/main/java/org/onap/ccsdk/apps/filters/PayloadLoggingFilter.java b/services/src/main/java/org/onap/ccsdk/apps/filters/PayloadLoggingFilter.java
new file mode 100644
index 0000000..e53c50a
--- /dev/null
+++ b/services/src/main/java/org/onap/ccsdk/apps/filters/PayloadLoggingFilter.java
@@ -0,0 +1,322 @@
+package org.onap.ccsdk.apps.filters;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.CharArrayWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ReadListener;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.WriteListener;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+import org.onap.logging.filter.base.AbstractServletFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class PayloadLoggingFilter extends AbstractServletFilter implements Filter {
+
+	private static final Logger log = LoggerFactory.getLogger(PayloadLoggingFilter.class);
+
+	@Override
+	public void init(FilterConfig filterConfig) throws ServletException {
+	}
+
+	@Override
+	public void destroy() {
+	}
+
+	@Override
+	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+		RequestWrapper req = new RequestWrapper((HttpServletRequest) request);
+		Request requestData = req.getMessageRequest();
+		
+		StringBuilder requestHeaders = new StringBuilder("REQUEST|");
+	    requestHeaders.append(requestData.method);
+	    requestHeaders.append(":");
+	    requestHeaders.append(requestData.uri);
+	    requestHeaders.append("|");
+	    mapstr(requestHeaders, requestData.headers);
+
+	    log.info(requestHeaders.toString());
+	    log.info("REQUEST BODY|{}", requestData.body);
+
+		ResponseWrapper res = new ResponseWrapper((HttpServletResponse) response);
+
+		chain.doFilter(req, res);
+
+		Response responseData = res.getMessageResponse();
+		
+		StringBuilder responseHeaders = new StringBuilder();
+        responseHeaders.append("RESPONSE HEADERS|");
+        mapstr(responseHeaders, responseData.headers);
+        responseHeaders.append("Status:").append(responseData.code);
+        responseHeaders.append(";IsCommitted:").append(res.isCommitted());
+
+        log.info(responseHeaders.toString());
+		log.info("RESPONSE BODY|{}", responseData.body);
+
+		res.writeBody();
+	}
+
+	private static class Request {
+
+		public String method;
+		public String uri;
+		public Map<String, Object> headers;
+		public Map<String, Object> param;
+		public String body;
+
+		@Override
+		public String toString() {
+			StringBuilder ss = new StringBuilder();
+			ss.append("REQUEST|").append(method).append(":").append(uri).append("|");
+			ss.append("Headers: ");
+			mapstr(ss, headers);
+			if (param != null && !param.isEmpty()) {
+				ss.append("Parameters: ");
+				mapstr(ss, param);
+			}
+			ss.append("REQUEST BODY|\n");
+			ss.append(body);
+			return ss.toString();
+		}
+	}
+
+	private static class Response {
+
+		public int code;
+		public String message;
+		public Map<String, Object> headers;
+		public String body;
+
+		@Override
+		public String toString() {
+			StringBuilder ss = new StringBuilder();
+			ss.append("HTTP Response: ").append(code).append(" ").append(message).append("\n");
+			ss.append("Headers:\n");
+			mapstr(ss, headers);
+			ss.append("Body:\n");
+			ss.append(body);
+			return ss.toString();
+		}
+	}
+
+	private static class RequestWrapper extends HttpServletRequestWrapper {
+
+		private final String body;
+
+		public RequestWrapper(HttpServletRequest request) throws IOException {
+			super(request);
+
+			StringBuilder stringBuilder = new StringBuilder();
+			InputStream inputStream = request.getInputStream();
+			if (inputStream != null) {
+				try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
+					char[] charBuffer = new char[128];
+					int bytesRead = -1;
+					while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
+						stringBuilder.append(charBuffer, 0, bytesRead);
+					}
+				}
+			}
+			body = stringBuilder.toString();
+		}
+
+		@Override
+		public ServletInputStream getInputStream() throws IOException {
+			final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
+			ServletInputStream servletInputStream = new ServletInputStream() {
+
+				@Override
+				public int read() throws IOException {
+					return byteArrayInputStream.read();
+				}
+
+				@Override
+				public boolean isFinished() {
+					return byteArrayInputStream.available() == 0;
+				}
+
+				@Override
+				public boolean isReady() {
+					return true;
+				}
+
+				@Override
+				public void setReadListener(ReadListener listener) {
+				}
+			};
+			return servletInputStream;
+		}
+
+		@Override
+		public BufferedReader getReader() throws IOException {
+			return new BufferedReader(new InputStreamReader(getInputStream()));
+		}
+
+		public String getBody() {
+			return body;
+		}
+
+		public Request getMessageRequest() {
+			Request r = new Request();
+			r.method = getMethod();
+			r.uri = getRequestURI();
+			r.param = getParamMap();
+
+			r.headers = new HashMap<>();
+			Enumeration<String> headerNames = getHeaderNames();
+			while (headerNames.hasMoreElements()) {
+				String name = headerNames.nextElement();
+
+				if (name.equalsIgnoreCase("authorization")) {
+					r.headers.put(name, "***REDACTED***");
+					continue;
+				}
+
+				Enumeration<String> values = getHeaders(name);
+				List<String> valueList = new ArrayList<>();
+				while (values.hasMoreElements()) {
+					valueList.add(values.nextElement());
+				}
+				if (valueList.size() > 1) {
+					r.headers.put(name, valueList);
+				} else if (valueList.size() > 0) {
+					r.headers.put(name, valueList.get(0));
+				}
+			}
+
+			r.body = getBody();
+
+			return r;
+		}
+
+		private Map<String, Object> getParamMap() {
+			Map<String, String[]> parameterMap = getParameterMap();
+			Map<String, Object> paramMap = new HashMap<>();
+			if (parameterMap != null) {
+				for (Entry<String, String[]> entry : parameterMap.entrySet()) {
+					String name = entry.getKey();
+					String[] values = entry.getValue();
+					if (values != null && values.length > 0) {
+						if (values.length == 1) {
+							paramMap.put(name, values[0]);
+						} else {
+							paramMap.put(name, Arrays.<String> asList(values));
+						}
+					}
+				}
+			}
+			return paramMap;
+		}
+	}
+
+	public class ResponseWrapper extends HttpServletResponseWrapper {
+
+		private CharArrayWriter writer = new CharArrayWriter();
+
+		private String statusMessage;
+
+		public ResponseWrapper(HttpServletResponse response) {
+			super(response);
+		}
+
+		@Override
+		public PrintWriter getWriter() {
+			return new PrintWriter(writer);
+		}
+
+		@Override
+		public ServletOutputStream getOutputStream() {
+			return new ServletOutputStream() {
+
+				@Override
+				public void write(int b) throws IOException {
+					writer.write(b);
+				}
+
+				@Override
+				public void setWriteListener(WriteListener listener) {
+				}
+
+				@Override
+				public boolean isReady() {
+					return true;
+				}
+			};
+		}
+
+		@SuppressWarnings("deprecation")
+		@Override
+		public void setStatus(int sc, String sm) {
+			super.setStatus(sc, sm);
+			statusMessage = sm;
+		}
+
+		public Response getMessageResponse() {
+			Response r = new Response();
+			r.code = getStatus();
+			r.message = statusMessage == null ? "" : statusMessage;
+
+			r.headers = new HashMap<>();
+			Collection<String> headerNames = getHeaderNames();
+			for (String name : headerNames) {
+
+				if (name.equalsIgnoreCase("authorization")) {
+					r.headers.put(name, "***REDACTED***");
+					continue;
+				}
+
+				Collection<String> values = getHeaders(name);
+				List<String> valueList = new ArrayList<>(values);
+				if (valueList.size() > 1) {
+					r.headers.put(name, valueList);
+				} else {
+					r.headers.put(name, valueList.get(0));
+				}
+			}
+
+			r.body = writer.toString();
+
+			return r;
+		}
+
+		public void writeBody() throws IOException {
+			String body = writer.toString();
+			setContentLength(body.length());
+			super.getWriter().write(body);
+		}
+	}
+
+	private static void mapstr(StringBuilder ss, Map<String, Object> m) {
+		if (m != null) {
+			for (Entry<String, Object> entry : m.entrySet()) {
+				ss.append(entry.getKey()).append(": ").append(entry.getValue()).append(";");
+			}
+		}
+	}
+}
\ No newline at end of file