2 * ============LICENSE_START=======================================================
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
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=========================================================
21 package org.onap.aai.logging;
23 import com.att.eelf.configuration.EELFLogger;
24 import com.att.eelf.configuration.EELFManager;
26 import java.net.InetAddress;
27 import java.net.UnknownHostException;
28 import java.util.HashMap;
29 import java.util.Iterator;
31 import java.util.UUID;
32 import java.util.concurrent.TimeUnit;
34 import org.json.JSONArray;
35 import org.json.JSONException;
36 import org.json.JSONObject;
39 public class LoggingContext {
41 public enum StatusCode {
45 private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(LoggingContext.class);
47 private static final String PREVIOUS_CONTEXTS_KEY = "_PREVIOUS_CONTEXTS";
49 // Response codes from Logging Guidelines
50 public static final String SUCCESS = "0";
51 public static final String PERMISSION_ERROR = "100";
52 public static final String AVAILABILITY_TIMEOUT_ERROR = "200";
53 public static final String DATA_ERROR = "300";
54 public static final String SCHEMA_ERROR = "400";
55 public static final String BUSINESS_PROCESS_ERROR = "500";
56 public static final String UNKNOWN_ERROR = "900";
58 protected static final Map<String, String> responseMap = new HashMap();
61 responseMap.put(SUCCESS, "Success");
62 responseMap.put(UNKNOWN_ERROR, "Unknown error");
65 // Specific Log Event Fields
66 public enum LoggingField {
67 START_TIME("startTime"), REQUEST_ID("requestId"), SERVICE_INSTANCE_ID("serviceInstanceId"), SERVER_NAME(
68 "serverName"), SERVICE_NAME("serviceName"), PARTNER_NAME("partnerName"), STATUS_CODE(
69 "statusCode"), RESPONSE_CODE("responseCode"), RESPONSE_DESCRIPTION(
70 "responseDescription"), INSTANCE_UUID("instanceUUID"), SEVERITY(
71 "severity"), SERVER_IP_ADDRESS(
72 "serverIpAddress"), ELAPSED_TIME("elapsedTime"), SERVER(
73 "server"), CLIENT_IP_ADDRESS("clientIpAddress"), UNUSED(
74 "unused"), PROCESS_KEY("processKey"), CUSTOM_FIELD_1(
75 "customField1"), CUSTOM_FIELD_2(
76 "customField2"), CUSTOM_FIELD_3(
77 "customField3"), CUSTOM_FIELD_4(
80 // Specific Metric Log Event Fields
81 TARGET_ENTITY("targetEntity"), TARGET_SERVICE_NAME("targetServiceName"),
82 // A&AI Specific Log Event Fields
83 COMPONENT("component"), STOP_WATCH_START("stopWatchStart");
85 private final String text;
87 private LoggingField(final String text) {
92 public String toString() {
97 public static void init() {
98 LoggingContext.clear();
99 LoggingContext.startTime();
100 LoggingContext.server();
101 LoggingContext.serverIpAddress();
104 public static void startTime() {
105 MDC.put(LoggingField.START_TIME.toString(), LogFormatTools.getCurrentDateTime());
108 public static UUID requestId() {
109 final String sUuid = MDC.get(LoggingField.REQUEST_ID.toString());
114 return UUID.fromString(sUuid);
117 public static void requestId(UUID requestId) {
118 MDC.put(LoggingField.REQUEST_ID.toString(), requestId.toString());
121 public static void requestId(String requestId) {
123 if (requestId.contains(":")) {
124 String[] uuidParts = requestId.split(":");
125 requestId = uuidParts[0];
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);
138 LOGGER.warn("Using generated UUID=" + generatedRequestUuid);
139 LoggingContext.restore();
144 public static void serviceInstanceId(String serviceInstanceId) {
145 MDC.put(LoggingField.SERVICE_INSTANCE_ID.toString(), serviceInstanceId);
148 public static void serverName(String serverName) {
149 MDC.put(LoggingField.SERVER_NAME.toString(), serverName);
152 public static void serviceName(String serviceName) {
153 MDC.put(LoggingField.SERVICE_NAME.toString(), serviceName);
156 public static void partnerName(String partnerName) {
157 MDC.put(LoggingField.PARTNER_NAME.toString(), partnerName);
160 public static void statusCode(StatusCode statusCode) {
161 MDC.put(LoggingField.STATUS_CODE.toString(), statusCode.toString());
164 public static String responseCode() {
165 return MDC.get(LoggingField.RESPONSE_CODE.toString());
168 public static void responseCode(String responseCode) {
169 MDC.put(LoggingField.RESPONSE_CODE.toString(), responseCode);
172 public static void responseDescription(String responseDescription) {
173 MDC.put(LoggingField.RESPONSE_DESCRIPTION.toString(), responseDescription);
176 public static Object instanceUuid() {
177 return UUID.fromString(MDC.get(LoggingField.INSTANCE_UUID.toString()));
180 public static void instanceUuid(UUID instanceUuid) {
181 MDC.put(LoggingField.INSTANCE_UUID.toString(), instanceUuid.toString());
184 public static void severity(int severity) {
185 MDC.put(LoggingField.SEVERITY.toString(), String.valueOf(severity));
188 public static void successStatusFields() {
189 responseCode(SUCCESS);
190 statusCode(StatusCode.COMPLETE);
191 responseDescription("Success");
194 private static void serverIpAddress() {
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");
202 public static void elapsedTime(long elapsedTime, TimeUnit timeUnit) {
203 MDC.put(LoggingField.ELAPSED_TIME.toString(),
204 String.valueOf(TimeUnit.MILLISECONDS.convert(elapsedTime, timeUnit)));
207 private static void server() {
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");
215 public static void clientIpAddress(InetAddress clientIpAddress) {
216 MDC.put(LoggingField.CLIENT_IP_ADDRESS.toString(), clientIpAddress.getHostAddress());
219 public static void clientIpAddress(String clientIpAddress) {
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
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);
233 public static void processKey(String processKey) {
234 MDC.put(LoggingField.PROCESS_KEY.toString(), processKey);
237 public static String customField1() {
238 return MDC.get(LoggingField.CUSTOM_FIELD_1.toString());
241 public static void customField1(String customField1) {
242 MDC.put(LoggingField.CUSTOM_FIELD_1.toString(), customField1);
245 public static void customField2(String customField2) {
246 MDC.put(LoggingField.CUSTOM_FIELD_2.toString(), customField2);
249 public static void customField3(String customField3) {
250 MDC.put(LoggingField.CUSTOM_FIELD_3.toString(), customField3);
253 public static void customField4(String customField4) {
254 MDC.put(LoggingField.CUSTOM_FIELD_4.toString(), customField4);
257 public static void component(String component) {
258 MDC.put(LoggingField.COMPONENT.toString(), component);
261 public static void targetEntity(String targetEntity) {
262 MDC.put(LoggingField.TARGET_ENTITY.toString(), targetEntity);
265 public static void targetServiceName(String targetServiceName) {
266 MDC.put(LoggingField.TARGET_SERVICE_NAME.toString(), targetServiceName);
269 public static boolean isStopWatchStarted() {
270 final String rawStopWatchStart = MDC.get(LoggingField.STOP_WATCH_START.toString());
271 return rawStopWatchStart != null;
274 public static void stopWatchStart() {
275 MDC.put(LoggingField.STOP_WATCH_START.toString(), String.valueOf(System.nanoTime()));
278 public static double stopWatchStop() {
279 final long stopWatchEnd = System.nanoTime();
280 final String rawStopWatchStart = MDC.get(LoggingField.STOP_WATCH_START.toString());
282 if (rawStopWatchStart == null)
283 throw new StopWatchNotStartedException();
285 final Long stopWatchStart = Long.valueOf(rawStopWatchStart);
287 MDC.remove(LoggingField.STOP_WATCH_START.toString());
289 final double elapsedTimeMillis = (stopWatchEnd - stopWatchStart) / 1000.0 / 1000.0;
291 LoggingContext.elapsedTime((long) elapsedTimeMillis, TimeUnit.MILLISECONDS);
293 return elapsedTimeMillis;
296 public static void put(String key, String value) {
300 public static void clear() {
304 public static void remove(String key) {
308 public static void save() {
309 final JSONObject context = new JSONObject();
311 for (LoggingField field : LoggingField.values()) {
312 if (field == LoggingField.ELAPSED_TIME)
316 context.put(field.toString(), MDC.get(field.toString()));
317 } catch (JSONException e) {
318 // Ignore - only occurs when the key is null (which can't happen)
319 // or the value is invalid (everything is converted to a string
320 // before it get put() to the MDC)
324 final String rawJsonArray = MDC.get(PREVIOUS_CONTEXTS_KEY);
326 if (rawJsonArray == null) {
327 final JSONArray stack = new JSONArray().put(context);
329 MDC.put(PREVIOUS_CONTEXTS_KEY, stack.toString());
332 final JSONArray stack = new JSONArray(rawJsonArray).put(context);
334 MDC.put(PREVIOUS_CONTEXTS_KEY, stack.toString());
335 } catch (JSONException e) {
341 public static void restore() {
343 final String rawPreviousContexts = MDC.get(PREVIOUS_CONTEXTS_KEY);
345 if (rawPreviousContexts == null) {
346 throw new LoggingContextNotExistsException();
350 final JSONArray previousContexts = new JSONArray(rawPreviousContexts);
351 final JSONObject previousContext = previousContexts.getJSONObject(previousContexts.length() - 1);
353 @SuppressWarnings("unchecked")
354 final Iterator<String> keys = previousContext.keys();
355 boolean foundElapsedTime = false;
356 while (keys.hasNext()) {
357 final String key = keys.next();
358 if (LoggingField.ELAPSED_TIME.toString().equals(key)) {
359 foundElapsedTime = true;
362 MDC.put(key, previousContext.getString(key));
363 } catch (JSONException e) {
364 // Ignore, only occurs when the key is null (cannot happen)
365 // or the value is invalid (they are all strings)
368 if (!foundElapsedTime) {
369 MDC.remove(LoggingField.ELAPSED_TIME.toString());
371 MDC.put(PREVIOUS_CONTEXTS_KEY, removeLast(previousContexts).toString());
372 } catch (JSONException e) {
373 // Ignore, the previousContext is serialized from a JSONObject
377 public static void restoreIfPossible() {
380 } catch (LoggingContextNotExistsException e) {
386 * AJSC declares an ancient version of org.json:json in one of the parent POMs of this project.
387 * I tried to update our version of that library in our POM, but it's ignored because of the way
388 * AJSC has organized their <dependencies>. Had they put it into the <dependencyManagement> section,
389 * this method would not be necessary.
391 private static JSONArray removeLast(JSONArray previousContexts) {
392 final JSONArray result = new JSONArray();
394 for (int i = 0; i < previousContexts.length() - 1; i++) {
396 result.put(previousContexts.getJSONObject(i));
397 } catch (JSONException e) {
398 // Ignore - not possible
405 public static Map<String, String> getCopy() {
406 final Map<String, String> copy = new HashMap<>();
408 for (LoggingField field : LoggingField.values()) {
409 final String value = MDC.get(field.toString());
412 copy.put(field.toString(), value);