Merge "Bump minor version"
[aai/aai-common.git] / aai-core / src / main / java / org / onap / aai / logging / LoggingContext.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 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  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
21  */
22 package org.onap.aai.logging;
23
24 import java.net.InetAddress;
25 import java.net.UnknownHostException;
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.Map;
29 import java.util.UUID;
30 import java.util.concurrent.TimeUnit;
31
32 import org.json.JSONArray;
33 import org.json.JSONException;
34 import org.json.JSONObject;
35 import org.onap.aai.exceptions.AAIException;
36 import org.slf4j.MDC;
37
38 import com.att.eelf.configuration.EELFLogger;
39 import com.att.eelf.configuration.EELFManager;
40
41 public class LoggingContext {
42
43         public enum StatusCode {
44                 COMPLETE,
45                 ERROR
46         }
47
48         private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(LoggingContext.class);
49
50         private static final String PREVIOUS_CONTEXTS_KEY = "_PREVIOUS_CONTEXTS";
51         
52         //Response codes from ECOMP Logging Guidelines
53         public static final String SUCCESS = "0";
54         public static final String PERMISSION_ERROR = "100";
55         public static final String AVAILABILITY_TIMEOUT_ERROR = "200";
56         public static final String DATA_ERROR = "200";
57         public static final String SCHEMA_ERROR = "400";
58         public static final String BUSINESS_PROCESS_ERROR = "500";
59         public static final String UNKNOWN_ERROR = "900";
60         
61         //ECOMP Specific Log Event Fields
62         public static enum LoggingField {
63                 START_TIME("startTime"),
64                 REQUEST_ID("requestId"),
65                 SERVICE_INSTANCE_ID("serviceInstanceId"),
66                 SERVER_NAME("serverName"),
67                 SERVICE_NAME("serviceName"),
68                 PARTNER_NAME("partnerName"),
69                 STATUS_CODE("statusCode"),
70                 RESPONSE_CODE("responseCode"),
71                 RESPONSE_DESCRIPTION("responseDescription"),
72                 INSTANCE_UUID("instanceUUID"),
73                 SEVERITY("severity"),
74                 SERVER_IP_ADDRESS("serverIpAddress"),
75                 ELAPSED_TIME("elapsedTime"),
76                 SERVER("server"),
77                 CLIENT_IP_ADDRESS("clientIpAddress"),
78                 UNUSED("unused"),
79                 PROCESS_KEY("processKey"),
80                 CUSTOM_FIELD_1("customField1"),
81                 CUSTOM_FIELD_2("customField2"),
82                 CUSTOM_FIELD_3("customField3"),
83                 CUSTOM_FIELD_4("customField4"),
84                 
85                 //ECOMP Specific Metric Log Event Fields
86                 TARGET_ENTITY("targetEntity"),
87                 TARGET_SERVICE_NAME("targetServiceName"),
88                 //A&AI Specific Log Event Fields
89                 COMPONENT("component"),
90                 STOP_WATCH_START("stopWatchStart");
91
92                 private final String text;
93
94                 private LoggingField(final String text) {
95                         this.text = text;
96                 }
97
98                 public String toString() {
99                         return text;
100                 }
101         }
102
103
104         public static void init() {
105                 LoggingContext.clear();
106                 LoggingContext.startTime();
107                 LoggingContext.server();
108                 LoggingContext.serverIpAddress();
109         }
110
111         public static void startTime() {
112                 MDC.put(LoggingField.START_TIME.toString(), LogFormatTools.getCurrentDateTime());
113         }
114
115         public static UUID requestId() {
116                 final String sUuid = MDC.get(LoggingField.REQUEST_ID.toString());
117
118                 if (sUuid == null) return null;
119
120                 return UUID.fromString(sUuid);
121         }
122
123         public static void requestId(UUID requestId) {
124                 MDC.put(LoggingField.REQUEST_ID.toString(), requestId.toString());
125         }
126
127         public static void requestId(String requestId) {
128                 try {
129                         if(requestId == null){
130                                 throw new IllegalArgumentException();
131                         }
132                         if (requestId.contains(":")) {
133                                 String[] uuidParts = requestId.split(":");
134                                 requestId = uuidParts[0];
135                         }
136                         MDC.put(LoggingField.REQUEST_ID.toString(), UUID.fromString(requestId).toString());
137                 } catch (IllegalArgumentException e) {
138                         final UUID generatedRequestUuid = UUID.randomUUID();
139                         MDC.put(LoggingField.REQUEST_ID.toString(), generatedRequestUuid.toString());
140                         LoggingContext.save();
141                         AAIException ex = new AAIException("AAI_7405", e);
142                         String responseCode = Integer.toString(ex.getErrorObject().getHTTPResponseCode().getStatusCode());
143                         LoggingContext.responseCode(responseCode);
144
145                         LOGGER.warn("Unable to use UUID " + requestId + " (Not formatted properly). Using generated UUID="
146                                         + generatedRequestUuid);
147                         LoggingContext.restore();
148
149                 }
150         }
151
152         public static void serviceInstanceId(String serviceInstanceId) {
153                 MDC.put(LoggingField.SERVICE_INSTANCE_ID.toString(), serviceInstanceId);
154         }
155
156         public static void serverName(String serverName) {
157                 MDC.put(LoggingField.SERVER_NAME.toString(), serverName);
158         }
159
160         public static void serviceName(String serviceName) {
161                 MDC.put(LoggingField.SERVICE_NAME.toString(), serviceName);
162         }
163
164         public static void partnerName(String partnerName) {
165                 MDC.put(LoggingField.PARTNER_NAME.toString(), partnerName);
166         }
167
168         public static void statusCode(LoggingContext.StatusCode statusCode) {
169                 MDC.put(LoggingField.STATUS_CODE.toString(), statusCode.toString());
170         }
171
172         public static String responseCode() {
173                 return (String) MDC.get(LoggingField.RESPONSE_CODE.toString());
174         }
175
176         public static void responseCode(String responseCode) {
177                 MDC.put(LoggingField.RESPONSE_CODE.toString(), responseCode);
178         }
179
180         public static void responseDescription(String responseDescription) {
181                 MDC.put(LoggingField.RESPONSE_DESCRIPTION.toString(), responseDescription);
182         }
183
184         public static Object instanceUuid() {
185                 return UUID.fromString(MDC.get(LoggingField.INSTANCE_UUID.toString()));
186         }
187
188         public static void instanceUuid(UUID instanceUuid) {
189                 MDC.put(LoggingField.INSTANCE_UUID.toString(), instanceUuid.toString());
190         }
191
192         public static void severity(int severity) {
193                 MDC.put(LoggingField.SEVERITY.toString(), String.valueOf(severity));
194         }
195
196         public static void successStatusFields() {
197                 responseCode(SUCCESS);
198                 statusCode(LoggingContext.StatusCode.COMPLETE);
199         }
200         private static void serverIpAddress() {
201                 try {
202                         MDC.put(LoggingField.SERVER_IP_ADDRESS.toString(), InetAddress.getLocalHost().getHostAddress());
203                 } catch (UnknownHostException e) {
204                         LOGGER.warn("Unable to resolve server IP address - will not be displayed in logged events");
205                 }
206         }
207
208         public static void elapsedTime(long elapsedTime, TimeUnit timeUnit) {
209                 MDC.put(LoggingField.ELAPSED_TIME.toString(), String.valueOf(TimeUnit.MILLISECONDS.convert(elapsedTime, timeUnit)));
210         }
211
212         private static void server() {
213                 try {
214                         MDC.put(LoggingField.SERVER.toString(),  InetAddress.getLocalHost().getCanonicalHostName());
215                 } catch (UnknownHostException e) {
216                         LOGGER.warn("Unable to resolve server IP address - hostname will not be displayed in logged events");
217                 }
218         }
219
220         public static void clientIpAddress(InetAddress clientIpAddress) {
221                 MDC.put(LoggingField.CLIENT_IP_ADDRESS.toString(), clientIpAddress.getHostAddress());
222         }
223
224         public static void clientIpAddress(String clientIpAddress) {
225                 try {
226                         MDC.put(LoggingField.CLIENT_IP_ADDRESS.toString(), InetAddress.getByName(clientIpAddress).getHostAddress());
227                 } catch (UnknownHostException e) {
228                         //Ignore, will not be thrown since InetAddress.getByName(String) only
229                         //checks the validity of the passed in string
230                 }
231         }
232
233         public static void unused(String unused) {
234                 LOGGER.warn("Using field '" + LoggingField.UNUSED + "' (seems like this should go unused...)");
235                 MDC.put(LoggingField.UNUSED.toString(), unused);
236         }
237
238         public static void processKey(String processKey) {
239                 MDC.put(LoggingField.PROCESS_KEY.toString(), processKey);
240         }
241
242         public static String customField1() {
243                 return MDC.get(LoggingField.CUSTOM_FIELD_1.toString());
244         }
245
246         public static void customField1(String customField1) {
247                 MDC.put(LoggingField.CUSTOM_FIELD_1.toString(), customField1);
248         }
249
250         public static void customField2(String customField2) {
251                 MDC.put(LoggingField.CUSTOM_FIELD_2.toString(), customField2);
252         }
253
254         public static void customField3(String customField3) {
255                 MDC.put(LoggingField.CUSTOM_FIELD_3.toString(), customField3);
256         }
257
258         public static void customField4(String customField4) {
259                 MDC.put(LoggingField.CUSTOM_FIELD_4.toString(), customField4);
260         }
261
262         public static void component(String component) {
263                 MDC.put(LoggingField.COMPONENT.toString(), component);
264         }
265
266         public static void targetEntity(String targetEntity) {
267                 MDC.put(LoggingField.TARGET_ENTITY.toString(), targetEntity);
268         }
269
270         public static void targetServiceName(String targetServiceName) {
271                 MDC.put(LoggingField.TARGET_SERVICE_NAME.toString(), targetServiceName);
272         }
273
274         public static boolean isStopWatchStarted() {
275                 final String rawStopWatchStart = MDC.get(LoggingField.STOP_WATCH_START.toString());
276                 if (rawStopWatchStart == null) {
277                         return false;
278                 }
279                 return true;
280         }
281         public static void stopWatchStart() {
282                 MDC.put(LoggingField.STOP_WATCH_START.toString(), String.valueOf(System.nanoTime()));
283         }
284
285         public static double stopWatchStop() {
286                 final long stopWatchEnd = System.nanoTime();
287                 final String rawStopWatchStart = MDC.get(LoggingField.STOP_WATCH_START.toString());
288
289                 if (rawStopWatchStart == null) throw new StopWatchNotStartedException();
290
291                 final Long stopWatchStart = Long.valueOf(rawStopWatchStart);
292
293                 MDC.remove(LoggingField.STOP_WATCH_START.toString());
294
295                 final double elapsedTimeMillis = (stopWatchEnd - stopWatchStart) / 1000.0 / 1000.0;
296
297                 LoggingContext.elapsedTime((long) elapsedTimeMillis, TimeUnit.MILLISECONDS);
298
299                 return elapsedTimeMillis;
300         }
301
302         public static void put(String key, String value) {
303                 MDC.put(key, value);
304         }
305
306         public static void clear() {
307                 MDC.clear();
308         }
309
310         public static void remove(String key) {
311                 MDC.remove(key);
312         }
313
314         public static void save() {
315                 final JSONObject context = new JSONObject();
316
317                 for (LoggingField field : LoggingField.values()) {
318                         if (field == LoggingField.ELAPSED_TIME) continue;
319
320                         try {
321                                 context.put(field.toString(), MDC.get(field.toString()));
322                         } catch (JSONException e) {
323                                 //Ignore - only occurs when the key is null (which can't happen)
324                                 //                      or the value is invalid (everything is converted to a string
325                                 //                      before it get put() to the MDC)
326                         }
327                 }
328
329                 final String rawJsonArray = MDC.get(PREVIOUS_CONTEXTS_KEY);
330
331                 if (rawJsonArray == null) {
332                         final JSONArray stack = new JSONArray()
333                                                                                         .put(context);
334
335                         MDC.put(PREVIOUS_CONTEXTS_KEY, stack.toString());
336                 } else {
337                         try {
338                                 final JSONArray stack = new JSONArray(rawJsonArray)
339                                                                                                 .put(context);
340
341                                 MDC.put(PREVIOUS_CONTEXTS_KEY, stack.toString());
342                         } catch (JSONException e) {
343                                 //Ignore
344                         }
345                 }
346         }
347
348         public static void restore() {
349                 
350                 final String rawPreviousContexts = MDC.get(PREVIOUS_CONTEXTS_KEY);
351         
352                 if (rawPreviousContexts == null) {
353                         throw new LoggingContextNotExistsException();
354                 }
355
356                 try {
357                         final JSONArray previousContexts = new JSONArray(rawPreviousContexts);
358                         final JSONObject previousContext = previousContexts.getJSONObject(previousContexts.length() - 1);
359
360                         @SuppressWarnings("unchecked")
361                         final Iterator<String> keys = previousContext.keys();
362                         boolean foundElapsedTime = false;
363                         while (keys.hasNext()) {
364                                 final String key = keys.next();
365                                 if (LoggingField.ELAPSED_TIME.toString().equals(key)) {
366                                         foundElapsedTime = true;
367                                 }
368                                 try {
369                                         MDC.put(key, previousContext.getString(key));
370                                 } catch (JSONException e) {
371                                         //Ignore, only occurs when the key is null (cannot happen)
372                                         //                      or the value is invalid (they are all strings)
373                                 }
374                         }
375                         if ( !foundElapsedTime ) {
376                                 MDC.remove(LoggingField.ELAPSED_TIME.toString());
377                         }
378                         MDC.put(PREVIOUS_CONTEXTS_KEY, removeLast(previousContexts).toString());
379                 } catch (JSONException e) {
380                         //Ignore, the previousContext is serialized from a JSONObject
381                 }
382         }
383         public static void restoreIfPossible() {
384                 try {
385                         restore();
386                 }
387                 catch (LoggingContextNotExistsException e) {
388                         //Ignore
389                 }
390         }
391
392         /**
393          * AJSC declares an ancient version of org.json:json in one of the parent POMs of this project.
394          * I tried to update our version of that library in our POM, but it's ignored because of the way
395          * AJSC has organized their <dependencies>.  Had they put it into the <dependencyManagement> section,
396          * this method would not be necessary.
397          */
398         private static JSONArray removeLast(JSONArray previousContexts) {
399                 final JSONArray result = new JSONArray();
400
401                 for (int i = 0; i < previousContexts.length() - 1; i++) {
402                         try {
403                                 result.put(previousContexts.getJSONObject(i));
404                         } catch (JSONException e) {
405                                 //Ignore - not possible
406                         }
407                 }
408
409                 return result;
410         }
411
412         public static Map<String, String> getCopy() {
413                 final Map<String, String> copy = new HashMap<String, String> ();
414
415                 for (LoggingField field : LoggingField.values()) {
416                         final String value = MDC.get(field.toString());
417
418                         if (value != null) copy.put(field.toString(), value);
419                 }
420
421                 return copy;
422         }
423 }