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