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