Add JAX-RS and Spring filters for setting up MDC
[logging-analytics.git] / reference / logging-filter / logging-filter-spring / src / main / java / org / onap / logging / filter / spring / SpringClientFilter.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - Logging
4  * ================================================================================
5  * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.logging.filter.spring;
22
23 import java.io.IOException;
24 import java.nio.charset.Charset;
25 import java.nio.charset.StandardCharsets;
26 import java.time.ZoneOffset;
27 import java.time.ZonedDateTime;
28 import java.time.format.DateTimeFormatter;
29 import java.util.List;
30 import java.util.UUID;
31 import org.onap.logging.filter.base.Constants;
32 import org.onap.logging.filter.base.MDCSetup;
33 import org.onap.logging.filter.base.PropertyUtil;
34 import org.onap.logging.ref.slf4j.ONAPLogConstants;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37 import org.slf4j.MDC;
38 import org.slf4j.Marker;
39 import org.slf4j.MarkerFactory;
40 import org.springframework.http.HttpHeaders;
41 import org.springframework.http.HttpRequest;
42 import org.springframework.http.client.ClientHttpRequestExecution;
43 import org.springframework.http.client.ClientHttpRequestInterceptor;
44 import org.springframework.http.client.ClientHttpResponse;
45 import org.springframework.util.StreamUtils;
46
47 public class SpringClientFilter implements ClientHttpRequestInterceptor {
48     private final Logger logger = LoggerFactory.getLogger(this.getClass());
49     private static final String TRACE = "trace-#";
50     private MDCSetup mdcSetup = new MDCSetup();
51     private final String partnerName;
52     private static final Marker INVOKE_RETURN = MarkerFactory.getMarker("INVOKE-RETURN");
53
54     public SpringClientFilter() {
55         this.partnerName = getPartnerName();
56     }
57
58     @Override
59     public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
60             throws IOException {
61         processRequest(request, body);
62         ClientHttpResponse response = execution.execute(request, body);
63         processResponse(response);
64         return response;
65     }
66
67     protected void processRequest(HttpRequest request, byte[] body) throws IOException {
68         mdcSetup.setInvocationIdFromMDC();
69         setupMDC(request);
70         setupHeaders(request);
71         if (logger.isDebugEnabled()) {
72             logger.debug("===========================request begin================================================");
73             logger.debug("URI         : {}", request.getURI());
74             logger.debug("Method      : {}", request.getMethod());
75             logger.debug("Headers     : {}", request.getHeaders());
76             logger.debug("Request body: {}", new String(body, StandardCharsets.UTF_8));
77             logger.debug("==========================request end================================================");
78         }
79     }
80
81     protected void setupHeaders(HttpRequest clientRequest) {
82         HttpHeaders headers = clientRequest.getHeaders();
83         String requestId = extractRequestID(clientRequest);
84         headers.add(ONAPLogConstants.Headers.REQUEST_ID, requestId);
85         headers.add(Constants.HttpHeaders.HEADER_REQUEST_ID, requestId);
86         headers.add(Constants.HttpHeaders.TRANSACTION_ID, requestId);
87         headers.add(Constants.HttpHeaders.ECOMP_REQUEST_ID, requestId);
88         headers.add(ONAPLogConstants.Headers.INVOCATION_ID, MDC.get(ONAPLogConstants.MDCs.INVOCATION_ID));
89         headers.add(ONAPLogConstants.Headers.PARTNER_NAME, partnerName);
90     }
91
92     protected String extractRequestID(HttpRequest clientRequest) {
93         String requestId = MDC.get(ONAPLogConstants.MDCs.REQUEST_ID);
94         if (requestId == null || requestId.isEmpty() || requestId.equals(TRACE)) {
95             requestId = UUID.randomUUID().toString();
96             mdcSetup.setLogTimestamp();
97             mdcSetup.setElapsedTimeInvokeTimestamp();
98             logger.warn("Could not Find Request ID Generating New One: {}", clientRequest.getURI());
99             MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, requestId);
100         }
101         return requestId;
102     }
103
104     protected void setupMDC(HttpRequest clientRequest) {
105         MDC.put(ONAPLogConstants.MDCs.INVOKE_TIMESTAMP,
106                 ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT));
107         MDC.put(ONAPLogConstants.MDCs.TARGET_SERVICE_NAME, clientRequest.getURI().toString());
108         MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, ONAPLogConstants.ResponseStatus.INPROGRESS.toString());
109         MDC.put(ONAPLogConstants.MDCs.TARGET_ENTITY, extractTargetEntity(clientRequest));
110         if (MDC.get(ONAPLogConstants.MDCs.SERVICE_NAME) == null) {
111             MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, clientRequest.getURI().getPath());
112         }
113         mdcSetup.setServerFQDN();
114     }
115
116     protected String extractTargetEntity(HttpRequest clientRequest) {
117         HttpHeaders headers = clientRequest.getHeaders();
118         String headerTargetEntity = null;
119         List<String> headerTargetEntityList = headers.get(Constants.HttpHeaders.TARGET_ENTITY_HEADER);
120         if (headerTargetEntityList != null && !headerTargetEntityList.isEmpty())
121             headerTargetEntity = headerTargetEntityList.get(0);
122         String targetEntity = MDC.get(ONAPLogConstants.MDCs.TARGET_ENTITY);
123         if (targetEntity != null && !targetEntity.isEmpty()) {
124             return targetEntity;
125         } else if (headerTargetEntity != null && !headerTargetEntity.isEmpty()) {
126             targetEntity = headerTargetEntity;
127         } else {
128             targetEntity = Constants.DefaultValues.UNKNOWN_TARGET_ENTITY;
129             logger.warn("Could not Target Entity: {}", clientRequest.getURI());
130         }
131         return targetEntity;
132     }
133
134     protected void processResponse(ClientHttpResponse response) throws IOException {
135         if (logger.isDebugEnabled()) {
136             logger.debug("============================response begin==========================================");
137             logger.debug("Status code  : {}", response.getStatusCode());
138             logger.debug("Status text  : {}", response.getStatusText());
139             logger.debug("Headers      : {}", response.getHeaders());
140             logger.debug("Response body: {}", StreamUtils.copyToString(response.getBody(), Charset.defaultCharset()));
141             logger.debug("=======================response end=================================================");
142         }
143         mdcSetup.setLogTimestamp();
144         mdcSetup.setElapsedTimeInvokeTimestamp();
145         mdcSetup.setResponseStatusCode(response.getRawStatusCode());
146         int statusCode = response.getRawStatusCode();
147         MDC.put(ONAPLogConstants.MDCs.RESPONSE_CODE, String.valueOf(statusCode));
148         mdcSetup.setResponseDescription(statusCode);
149         logger.info(INVOKE_RETURN, "InvokeReturn");
150         mdcSetup.clearClientMDCs();
151     }
152
153     protected String getPartnerName() {
154         PropertyUtil p = new PropertyUtil();
155         return p.getProperty(Constants.Property.PARTNER_NAME);
156     }
157 }