2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
20 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22 package org.onap.aai.logging;
24 import java.net.InetAddress;
25 import java.net.UnknownHostException;
26 import java.util.HashMap;
27 import java.util.Iterator;
29 import java.util.UUID;
30 import java.util.concurrent.TimeUnit;
32 import org.json.JSONArray;
33 import org.json.JSONException;
34 import org.json.JSONObject;
35 import org.onap.aai.exceptions.AAIException;
38 import com.att.eelf.configuration.EELFLogger;
39 import com.att.eelf.configuration.EELFManager;
41 public class LoggingContext {
43 public enum StatusCode {
48 private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(LoggingContext.class);
50 private static final String PREVIOUS_CONTEXTS_KEY = "_PREVIOUS_CONTEXTS";
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";
61 public static final Map<String, String> responseMap = new HashMap();
64 responseMap.put(SUCCESS, "Success");
65 responseMap.put(UNKNOWN_ERROR, "Unknown error");
67 //ECOMP Specific Log Event Fields
68 public static enum LoggingField {
69 START_TIME("startTime"),
70 REQUEST_ID("requestId"),
71 SERVICE_INSTANCE_ID("serviceInstanceId"),
72 SERVER_NAME("serverName"),
73 SERVICE_NAME("serviceName"),
74 PARTNER_NAME("partnerName"),
75 STATUS_CODE("statusCode"),
76 RESPONSE_CODE("responseCode"),
77 RESPONSE_DESCRIPTION("responseDescription"),
78 INSTANCE_UUID("instanceUUID"),
80 SERVER_IP_ADDRESS("serverIpAddress"),
81 ELAPSED_TIME("elapsedTime"),
83 CLIENT_IP_ADDRESS("clientIpAddress"),
85 PROCESS_KEY("processKey"),
86 CUSTOM_FIELD_1("customField1"),
87 CUSTOM_FIELD_2("customField2"),
88 CUSTOM_FIELD_3("customField3"),
89 CUSTOM_FIELD_4("customField4"),
91 //ECOMP Specific Metric Log Event Fields
92 TARGET_ENTITY("targetEntity"),
93 TARGET_SERVICE_NAME("targetServiceName"),
94 //A&AI Specific Log Event Fields
95 COMPONENT("component"),
96 STOP_WATCH_START("stopWatchStart");
98 private final String text;
100 private LoggingField(final String text) {
104 public String toString() {
110 public static void init() {
111 LoggingContext.clear();
112 LoggingContext.startTime();
113 LoggingContext.server();
114 LoggingContext.serverIpAddress();
117 public static void startTime() {
118 MDC.put(LoggingField.START_TIME.toString(), LogFormatTools.getCurrentDateTime());
121 public static UUID requestId() {
122 final String sUuid = MDC.get(LoggingField.REQUEST_ID.toString());
124 if (sUuid == null) return null;
126 return UUID.fromString(sUuid);
129 public static void requestId(UUID requestId) {
130 MDC.put(LoggingField.REQUEST_ID.toString(), requestId.toString());
133 public static void requestId(String requestId) {
135 if (requestId.contains(":")) {
136 String[] uuidParts = requestId.split(":");
137 requestId = uuidParts[0];
139 MDC.put(LoggingField.REQUEST_ID.toString(), UUID.fromString(requestId).toString());
140 } catch (IllegalArgumentException e) {
141 final UUID generatedRequestUuid = UUID.randomUUID();
142 MDC.put(LoggingField.REQUEST_ID.toString(), generatedRequestUuid.toString());
143 LoggingContext.save();
144 // set response code to 0 since we don't know what the outcome of this request is yet
145 String responseCode = LoggingContext.DATA_ERROR;
146 LoggingContext.responseCode(responseCode);
147 LoggingContext.responseDescription("Unable to use UUID " + requestId + " (Not formatted properly) ");
148 LoggingContext.statusCode(StatusCode.ERROR);
150 LOGGER.warn("Using generated UUID=" + generatedRequestUuid);
151 LoggingContext.restore();
156 public static void serviceInstanceId(String serviceInstanceId) {
157 MDC.put(LoggingField.SERVICE_INSTANCE_ID.toString(), serviceInstanceId);
160 public static void serverName(String serverName) {
161 MDC.put(LoggingField.SERVER_NAME.toString(), serverName);
164 public static void serviceName(String serviceName) {
165 MDC.put(LoggingField.SERVICE_NAME.toString(), serviceName);
168 public static void partnerName(String partnerName) {
169 MDC.put(LoggingField.PARTNER_NAME.toString(), partnerName);
172 public static void statusCode(LoggingContext.StatusCode statusCode) {
173 MDC.put(LoggingField.STATUS_CODE.toString(), statusCode.toString());
176 public static String responseCode() {
177 return (String) MDC.get(LoggingField.RESPONSE_CODE.toString());
180 public static void responseCode(String responseCode) {
181 MDC.put(LoggingField.RESPONSE_CODE.toString(), responseCode);
184 public static void responseDescription(String responseDescription) {
185 MDC.put(LoggingField.RESPONSE_DESCRIPTION.toString(), responseDescription);
188 public static Object instanceUuid() {
189 return UUID.fromString(MDC.get(LoggingField.INSTANCE_UUID.toString()));
192 public static void instanceUuid(UUID instanceUuid) {
193 MDC.put(LoggingField.INSTANCE_UUID.toString(), instanceUuid.toString());
196 public static void severity(int severity) {
197 MDC.put(LoggingField.SEVERITY.toString(), String.valueOf(severity));
200 public static void successStatusFields() {
201 responseCode(SUCCESS);
202 statusCode(LoggingContext.StatusCode.COMPLETE);
203 responseDescription("Success");
205 private static void serverIpAddress() {
207 MDC.put(LoggingField.SERVER_IP_ADDRESS.toString(), InetAddress.getLocalHost().getHostAddress());
208 } catch (UnknownHostException e) {
209 LOGGER.warn("Unable to resolve server IP address - will not be displayed in logged events");
213 public static void elapsedTime(long elapsedTime, TimeUnit timeUnit) {
214 MDC.put(LoggingField.ELAPSED_TIME.toString(), String.valueOf(TimeUnit.MILLISECONDS.convert(elapsedTime, timeUnit)));
217 private static void server() {
219 MDC.put(LoggingField.SERVER.toString(), InetAddress.getLocalHost().getCanonicalHostName());
220 } catch (UnknownHostException e) {
221 LOGGER.warn("Unable to resolve server IP address - hostname will not be displayed in logged events");
225 public static void clientIpAddress(InetAddress clientIpAddress) {
226 MDC.put(LoggingField.CLIENT_IP_ADDRESS.toString(), clientIpAddress.getHostAddress());
229 public static void clientIpAddress(String clientIpAddress) {
231 MDC.put(LoggingField.CLIENT_IP_ADDRESS.toString(), InetAddress.getByName(clientIpAddress).getHostAddress());
232 } catch (UnknownHostException e) {
233 //Ignore, will not be thrown since InetAddress.getByName(String) only
234 //checks the validity of the passed in string
238 public static void unused(String unused) {
239 LOGGER.warn("Using field '" + LoggingField.UNUSED + "' (seems like this should go unused...)");
240 MDC.put(LoggingField.UNUSED.toString(), unused);
243 public static void processKey(String processKey) {
244 MDC.put(LoggingField.PROCESS_KEY.toString(), processKey);
247 public static String customField1() {
248 return MDC.get(LoggingField.CUSTOM_FIELD_1.toString());
251 public static void customField1(String customField1) {
252 MDC.put(LoggingField.CUSTOM_FIELD_1.toString(), customField1);
255 public static void customField2(String customField2) {
256 MDC.put(LoggingField.CUSTOM_FIELD_2.toString(), customField2);
259 public static void customField3(String customField3) {
260 MDC.put(LoggingField.CUSTOM_FIELD_3.toString(), customField3);
263 public static void customField4(String customField4) {
264 MDC.put(LoggingField.CUSTOM_FIELD_4.toString(), customField4);
267 public static void component(String component) {
268 MDC.put(LoggingField.COMPONENT.toString(), component);
271 public static void targetEntity(String targetEntity) {
272 MDC.put(LoggingField.TARGET_ENTITY.toString(), targetEntity);
275 public static void targetServiceName(String targetServiceName) {
276 MDC.put(LoggingField.TARGET_SERVICE_NAME.toString(), targetServiceName);
279 public static boolean isStopWatchStarted() {
280 final String rawStopWatchStart = MDC.get(LoggingField.STOP_WATCH_START.toString());
281 if (rawStopWatchStart == null) {
286 public static void stopWatchStart() {
287 MDC.put(LoggingField.STOP_WATCH_START.toString(), String.valueOf(System.nanoTime()));
290 public static double stopWatchStop() {
291 final long stopWatchEnd = System.nanoTime();
292 final String rawStopWatchStart = MDC.get(LoggingField.STOP_WATCH_START.toString());
294 if (rawStopWatchStart == null) throw new StopWatchNotStartedException();
296 final Long stopWatchStart = Long.valueOf(rawStopWatchStart);
298 MDC.remove(LoggingField.STOP_WATCH_START.toString());
300 final double elapsedTimeMillis = (stopWatchEnd - stopWatchStart) / 1000.0 / 1000.0;
302 LoggingContext.elapsedTime((long) elapsedTimeMillis, TimeUnit.MILLISECONDS);
304 return elapsedTimeMillis;
307 public static void put(String key, String value) {
311 public static void clear() {
315 public static void remove(String key) {
319 public static void save() {
320 final JSONObject context = new JSONObject();
322 for (LoggingField field : LoggingField.values()) {
323 if (field == LoggingField.ELAPSED_TIME) continue;
326 context.put(field.toString(), MDC.get(field.toString()));
327 } catch (JSONException e) {
328 //Ignore - only occurs when the key is null (which can't happen)
329 // or the value is invalid (everything is converted to a string
330 // before it get put() to the MDC)
334 final String rawJsonArray = MDC.get(PREVIOUS_CONTEXTS_KEY);
336 if (rawJsonArray == null) {
337 final JSONArray stack = new JSONArray()
340 MDC.put(PREVIOUS_CONTEXTS_KEY, stack.toString());
343 final JSONArray stack = new JSONArray(rawJsonArray)
346 MDC.put(PREVIOUS_CONTEXTS_KEY, stack.toString());
347 } catch (JSONException e) {
353 public static void restore() {
355 final String rawPreviousContexts = MDC.get(PREVIOUS_CONTEXTS_KEY);
357 if (rawPreviousContexts == null) {
358 throw new LoggingContextNotExistsException();
362 final JSONArray previousContexts = new JSONArray(rawPreviousContexts);
363 final JSONObject previousContext = previousContexts.getJSONObject(previousContexts.length() - 1);
365 @SuppressWarnings("unchecked")
366 final Iterator<String> keys = previousContext.keys();
367 boolean foundElapsedTime = false;
368 while (keys.hasNext()) {
369 final String key = keys.next();
370 if (LoggingField.ELAPSED_TIME.toString().equals(key)) {
371 foundElapsedTime = true;
374 MDC.put(key, previousContext.getString(key));
375 } catch (JSONException e) {
376 //Ignore, only occurs when the key is null (cannot happen)
377 // or the value is invalid (they are all strings)
380 if ( !foundElapsedTime ) {
381 MDC.remove(LoggingField.ELAPSED_TIME.toString());
383 MDC.put(PREVIOUS_CONTEXTS_KEY, removeLast(previousContexts).toString());
384 } catch (JSONException e) {
385 //Ignore, the previousContext is serialized from a JSONObject
388 public static void restoreIfPossible() {
392 catch (LoggingContextNotExistsException e) {
398 * AJSC declares an ancient version of org.json:json in one of the parent POMs of this project.
399 * I tried to update our version of that library in our POM, but it's ignored because of the way
400 * AJSC has organized their <dependencies>. Had they put it into the <dependencyManagement> section,
401 * this method would not be necessary.
403 private static JSONArray removeLast(JSONArray previousContexts) {
404 final JSONArray result = new JSONArray();
406 for (int i = 0; i < previousContexts.length() - 1; i++) {
408 result.put(previousContexts.getJSONObject(i));
409 } catch (JSONException e) {
410 //Ignore - not possible
417 public static Map<String, String> getCopy() {
418 final Map<String, String> copy = new HashMap<String, String> ();
420 for (LoggingField field : LoggingField.values()) {
421 final String value = MDC.get(field.toString());
423 if (value != null) copy.put(field.toString(), value);