448f8b98095a37905a065ad01f9a5ae203f2b033
[aai/aai-service.git] / ajsc-aai / src / main / java / org / openecomp / aai / interceptors / AAILogJAXRSInInterceptor.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * org.openecomp.aai
4  * ================================================================================
5  * Copyright (C) 2017 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.openecomp.aai.interceptors;
22
23 import java.io.InputStream;
24 import java.text.DateFormat;
25 import java.text.SimpleDateFormat;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.Date;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.UUID;
32 import java.util.regex.Matcher;
33 import java.util.regex.Pattern;
34
35 import javax.ws.rs.core.MediaType;
36
37 import org.apache.commons.io.IOUtils;
38 import org.apache.cxf.helpers.CastUtils;
39 import org.apache.cxf.interceptor.Fault;
40 import org.apache.cxf.interceptor.LoggingMessage;
41 import org.apache.cxf.jaxrs.ext.MessageContext;
42 import org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor;
43 import org.apache.cxf.message.Message;
44 import org.openecomp.aai.exceptions.AAIException;
45 import org.openecomp.aai.logging.AAILogger;
46 import org.openecomp.aai.logging.LogLine;
47 import org.openecomp.aai.rest.util.EchoResponse;
48 import org.openecomp.aai.util.AAIConfig;
49 import org.openecomp.aai.util.AAIConstants;
50 import org.openecomp.aai.util.HbaseSaltPrefixer;
51 import org.slf4j.MDC;
52
53 public class AAILogJAXRSInInterceptor extends JAXRSInInterceptor {
54
55         protected final String COMPONENT = "aairest";
56         protected final String CAMEL_REQUEST ="CamelHttpUrl";
57         private static final Pattern uuidPattern = Pattern.compile("^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$");
58         
59         /**
60          * {@inheritDoc}
61          */
62         public void handleMessage(Message message) {
63                 boolean go = false;
64                 AAILogger aaiLogger = new AAILogger(AAILogJAXRSInInterceptor.class.getName());
65                 LogLine logline = new LogLine();
66                 LogLine auditLogline = new LogLine();
67                 String uri = null;
68                 String query = null;
69                 try {
70                 
71                         uri = (String)message.get(CAMEL_REQUEST);
72                         if (uri != null) { 
73                                 query = (String)message.get(Message.QUERY_STRING);
74                         }
75                         
76                         if (AAIConfig.get(AAIConstants.AAI_LOGGING_HBASE_INTERCEPTOR).equalsIgnoreCase("true") &&
77                                         AAIConfig.get(AAIConstants.AAI_LOGGING_HBASE_ENABLED).equalsIgnoreCase("true")) {
78                                 go = true;
79                                 message.getExchange().put("AAI_LOGGING_HBASE_ENABLED", 1);
80                                 if (AAIConfig.get(AAIConstants.AAI_LOGGING_HBASE_LOGREQUEST).equalsIgnoreCase("true") ) {
81                                         message.getExchange().put("AAI_LOGGING_HBASE_LOGREQUEST", 1);
82                                 }
83                                 if (AAIConfig.get(AAIConstants.AAI_LOGGING_HBASE_LOGRESPONSE).equalsIgnoreCase("true") ) {
84                                         message.getExchange().put("AAI_LOGGING_HBASE_LOGRESPONSE", 1);
85                                 }
86                         }
87                         if (AAIConfig.get(AAIConstants.AAI_LOGGING_TRACE_ENABLED).equalsIgnoreCase("true") ) {
88                                 go = true;
89                                 message.getExchange().put("AAI_LOGGING_TRACE_ENABLED", 1);
90                                 if (AAIConfig.get(AAIConstants.AAI_LOGGING_TRACE_LOGREQUEST).equalsIgnoreCase("true") ) {
91                                         message.getExchange().put("AAI_LOGGING_TRACE_LOGREQUEST", 1);
92                                 }
93                                 if (AAIConfig.get(AAIConstants.AAI_LOGGING_TRACE_LOGRESPONSE).equalsIgnoreCase("true") ) {
94                                         message.getExchange().put("AAI_LOGGING_TRACE_LOGRESPONSE", 1);
95                                 }
96                         }
97                 } catch (AAIException e1) {
98                         logline.add("Property", AAIConstants.AAI_LOGGING_TRACE_ENABLED);
99                         logline.add("Property", AAIConstants.AAI_LOGGING_HBASE_ENABLED);
100                         aaiLogger.error(e1.getErrorObject(), logline);
101                 }
102                 
103                 if (uri.contains(EchoResponse.echoPath)) {
104                         // if it's a health check, we don't want to log ANYTHING if it's a lightweight one
105                         if (query == null) {
106                                 if (message.getExchange().containsKey("AAI_LOGGING_HBASE_ENABLED")) {
107                                         message.getExchange().remove("AAI_LOGGING_HBASE_ENABLED");
108                                 }
109                                 if (message.getExchange().containsKey("AAI_LOGGING_TRACE_ENABLED")) { 
110                                         message.getExchange().remove("AAI_LOGGING_TRACE_ENABLED");
111                                 }
112                                 go = false;
113                         }
114                 }
115                 else if (uri.contains("/translog/")) {
116                         // if it's a translog query, we don't want to log the responses
117                         if (message.getExchange().containsKey("AAI_LOGGING_HBASE_LOGRESPONSE")) {
118                                 message.getExchange().remove("AAI_LOGGING_HBASE_LOGRESPONSE");
119                         }
120                         if (message.getExchange().containsKey("AAI_LOGGING_TRACE_LOGRESPONSE")) {
121                                 message.getExchange().remove("AAI_LOGGING_TRACE_LOGRESPONSE");
122                         }
123                 }
124                 
125                 if (go == false) { // there's nothing to do 
126                         return;
127                 }
128
129                 // DONE: get a TXID based on hostname, time (YYYYMMDDHHMMSSMILLIS,  and LoggingMessage.nextId(); 20150326145301-1
130                 String now = genDate(aaiLogger, logline);
131
132                 message.getExchange().put("AAI_RQST_TM", now);
133
134                 String id = (String)message.getExchange().get(LoggingMessage.ID_KEY);
135
136                 String fullId = null;
137                 try {
138                         if (id == null) {
139                                 id = LoggingMessage.nextId();
140                         }
141                         fullId = AAIConfig.get(AAIConstants.AAI_NODENAME) + "-" + now + "-" + id;
142                         fullId = HbaseSaltPrefixer.getInstance().prependSalt(fullId);
143                         message.getExchange().put(LoggingMessage.ID_KEY, fullId);
144                 } catch (AAIException e1) {
145                         aaiLogger.debug(logline, "config problem", e1);
146                 }
147                 if (fullId == null) { 
148                         fullId = now + "-" + id;
149                         fullId = HbaseSaltPrefixer.getInstance().prependSalt(fullId);
150                 }
151                 message.put(LoggingMessage.ID_KEY, fullId);
152                 final LoggingMessage buffer = new LoggingMessage("Message", fullId);
153
154                 Integer responseCode = (Integer)message.get(Message.RESPONSE_CODE);
155                 if (responseCode != null) {
156                         buffer.getResponseCode().append(responseCode);
157                 }
158
159                 String encoding = (String)message.get(Message.ENCODING);
160
161                 if (encoding != null) {
162                         buffer.getEncoding().append(encoding);
163                 }
164                 String httpMethod = (String)message.get(Message.HTTP_REQUEST_METHOD);
165                 if (httpMethod != null) {
166                         buffer.getHttpMethod().append(httpMethod);
167                 }
168
169                 String ct = (String)message.get(Message.CONTENT_TYPE);
170                 if (ct != null) {
171                         if ("*/*".equals(ct)) {
172                                 message.put(Message.CONTENT_TYPE, MediaType.APPLICATION_JSON);
173                                 ct = MediaType.APPLICATION_JSON;
174                         }
175                         buffer.getContentType().append(ct);
176
177                 }
178                 Object headers = message.get(Message.PROTOCOL_HEADERS);
179                 if (headers != null) {
180                         buffer.getHeader().append(headers);
181                         
182                         Map<String, List<String>> headersList = CastUtils.cast((Map<?, ?>)message.get(Message.PROTOCOL_HEADERS));
183                         String transId = "";
184                         String fromAppId = null;
185                         List<String> xt = headersList.get("X-TransactionId");
186                         String newTransId = transId;
187                         boolean missingTransId = false;
188                         boolean replacedTransId = false;
189                         String logMsg = null;
190                         if (xt != null) {
191                                 for (String transIdValue : xt) {
192                                         transId = transIdValue;
193                                 }       
194                                 Matcher matcher = uuidPattern.matcher(transId);
195                                 if (!matcher.find()) {
196                                         replacedTransId = true;
197                                         // check if there's a colon, and check the first group?
198                                         if (transId.contains(":")) {
199                                                 String[] uuidParts = transId.split(":");
200                                                 Matcher matcher2 = uuidPattern.matcher(uuidParts[0]);
201                                                 if (matcher2.find()) { 
202                                                         newTransId = uuidParts[0];
203                                                 } else {
204                                                         // punt, we tried to find it, it has a colon but no UUID-1
205                                                         newTransId = UUID.randomUUID().toString();
206                                                 }
207                                         } else {
208                                                 newTransId = UUID.randomUUID().toString();
209                                         }
210                                 }
211                         } else { 
212                                 newTransId = UUID.randomUUID().toString();
213                                 missingTransId = true;
214                         }
215                                                 
216                         if (missingTransId || replacedTransId) {
217                                 List<String> txList = new ArrayList<String>();
218                                 txList.add(newTransId);
219                                 headersList.put("X-TransactionId", txList);
220                                 if (missingTransId) { 
221                                         logMsg = "Missing requestID. Assigned " + newTransId;
222                                 } else if (replacedTransId) { 
223                                         logMsg = "Replaced invalid requestID of " + transId + " Assigned " + newTransId;
224                                 }
225                                 MDC.put("RequestId",newTransId);
226                         }
227                         else {
228                                 MDC.put("RequestId",transId);
229                         }
230                         
231                         
232                         List<String> fromAppIdList = headersList.get("X-FromAppId");
233                         if (fromAppIdList != null) {
234                                 for (String fromAppIdValue : fromAppIdList) {
235                                         fromAppId = fromAppIdValue;
236                                 }
237                                 MDC.put("PartnerName",fromAppId);
238                         }
239                         
240                         List<String> contentType = headersList.get("Content-Type");
241                         if (contentType == null) {
242                                 ct = (String)message.get(Message.CONTENT_TYPE);
243                                 headersList.put(Message.CONTENT_TYPE, Collections.singletonList(ct));
244                         }
245                         logline.init(COMPONENT, newTransId, fromAppId, "interceptIn");
246                         auditLogline.init(COMPONENT, newTransId, fromAppId, "REST " + httpMethod + " "
247                                         + ((query != null)? uri+"?"+query : uri));
248                         if (logMsg != null) {
249                                 logline.add(logMsg, true);
250                         }
251                         logline.add("HbaseTxId", fullId);
252                         aaiLogger.info(logline, true, "0");
253                 }
254
255
256                 if (uri != null) {
257                         buffer.getAddress().append(uri);
258                         if (query != null) {
259                                 buffer.getAddress().append("?").append(query);
260                         }
261                 }
262
263                 InputStream is = message.getContent(InputStream.class);
264                 if (is != null) {
265                         try {
266                                 String currentPayload = IOUtils.toString(is, "UTF-8");
267                                 IOUtils.closeQuietly(is);
268                                 buffer.getPayload().append(currentPayload);
269                                 is = IOUtils.toInputStream(currentPayload, "UTF-8");
270                                 message.setContent(InputStream.class, is);
271                                 IOUtils.closeQuietly(is);
272                         } catch (Exception e) { 
273                                 // It's ok to not have request input content
274                                 // throw new Fault(e); 
275                         }
276                 }
277
278                 // this will be saved in the message exchange, and can be pulled out later...
279                 message.getExchange().put(fullId + "_REQUEST", buffer.toString());
280                 message.getExchange().put("AUDIT_LOGLINE", auditLogline);
281
282         }
283
284         /**
285          * Gen date.
286          *
287          * @param aaiLogger the aai logger
288          * @param logline the logline
289          * @return the string
290          */
291         protected String genDate(AAILogger aaiLogger, LogLine logline) {
292                 Date date = new Date();
293                 DateFormat formatter = null;
294                 try {
295                         formatter = new SimpleDateFormat(AAIConfig.get(AAIConstants.HBASE_TABLE_TIMESTAMP_FORMAT));
296                 } catch (AAIException ex) {
297                         logline.add("Property", AAIConstants.HBASE_TABLE_TIMESTAMP_FORMAT);
298                         aaiLogger.error(ex.getErrorObject(), logline);
299                 } finally {
300                         if (formatter == null) {
301                                 formatter = new SimpleDateFormat("YYMMdd-HH:mm:ss:SSS");
302                         }
303                 }
304
305                 return formatter.format(date);
306         }
307
308 }