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