\r
package org.onap.clamp.clds.util;\r
\r
+import com.att.eelf.configuration.EELFLogger;\r
+import com.att.eelf.configuration.EELFManager;\r
+\r
+import java.net.HttpURLConnection;\r
import java.net.InetAddress;\r
import java.net.UnknownHostException;\r
import java.text.DateFormat;\r
import java.util.Date;\r
import java.util.TimeZone;\r
import java.util.UUID;\r
+import java.time.ZoneOffset;\r
+import java.time.ZonedDateTime;\r
+import java.time.format.DateTimeFormatter;\r
import javax.validation.constraints.NotNull;\r
+import javax.servlet.http.HttpServletRequest;\r
+\r
import org.slf4j.MDC;\r
+import org.slf4j.event.Level;\r
+import org.springframework.security.core.context.SecurityContextHolder;\r
\r
-import com.att.eelf.configuration.EELFLogger;\r
-import com.att.eelf.configuration.EELFManager;\r
+import org.onap.clamp.clds.service.DefaultUserNameHandler;\r
+import org.onap.logging.ref.slf4j.ONAPLogConstants;\r
\r
/**\r
* This class handles the special info that appear in the log, like RequestID,\r
* time context, ...\r
*/\r
-public final class LoggingUtils {\r
- \r
- protected static final EELFLogger logger = EELFManager.getInstance().getLogger(LoggingUtils.class);\r
+public class LoggingUtils {\r
+ protected static final EELFLogger logger = EELFManager.getInstance().getLogger(LoggingUtils.class);\r
\r
private static final DateFormat DATE_FORMAT = createDateFormat();\r
\r
+ /** String constant for messages <tt>ENTERING</tt>, <tt>EXITING</tt>, etc. */\r
+ private static final String EMPTY_MESSAGE = "";\r
+ private static final String INVOCATIONID_OUT = "InvocationIDOut";\r
+ private static final String TARGET_ENTITY = "TargetEngity";\r
+\r
+ /** Logger delegate. */\r
+ private EELFLogger mLogger;\r
+ /** Automatic UUID, overrideable per adapter or per invocation. */\r
+ private static UUID sInstanceUUID = UUID.randomUUID();\r
/**\r
- * Private constructor to avoid creating instances of util class.\r
+ * Constructor\r
*/\r
- private LoggingUtils() {\r
+ public LoggingUtils(final EELFLogger loggerP) {\r
+ this.mLogger = checkNotNull(loggerP);\r
}\r
\r
/**\r
//Defaulting to HTTP/1.1 protocol\r
MDC.put("Protocol", "HTTP/1.1");\r
try {\r
- MDC.put("ServerFQDN", InetAddress.getLocalHost().getCanonicalHostName());\r
- MDC.put("ServerIPAddress", InetAddress.getLocalHost().getHostAddress());\r
+ MDC.put("ServerFQDN", InetAddress.getLocalHost().getCanonicalHostName());\r
+ MDC.put("ServerIPAddress", InetAddress.getLocalHost().getHostAddress());\r
} catch (UnknownHostException e) {\r
- logger.error("Failed to initiate setRequestContext", e);\r
+ logger.error("Failed to initiate setRequestContext", e);\r
}\r
}\r
\r
* @return A string with the request ID\r
*/\r
public static String getRequestId() {\r
- String requestId;\r
-\r
- requestId = (String) MDC.get("RequestID");\r
+ String requestId = (String) MDC.get(ONAPLogConstants.MDCs.REQUEST_ID);\r
if (requestId == null || requestId.isEmpty()) {\r
requestId = UUID.randomUUID().toString();\r
- MDC.put("RequestId", requestId);\r
+ MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, requestId);\r
}\r
return requestId;\r
}\r
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));\r
return dateFormat;\r
}\r
+ \r
+ \r
+ \r
+ /*********************************************************************************************\r
+ * Method for ONAP Application Logging Specification v1.2\r
+ ********************************************************************************************/\r
+\r
+ /**\r
+ * Report <tt>ENTERING</tt> marker.\r
+ *\r
+ * @param request non-null incoming request (wrapper).\r
+ * @return this.\r
+ */\r
+ public void entering(HttpServletRequest request, String serviceName) {\r
+ checkNotNull(request);\r
+ // Extract MDC values from standard HTTP headers.\r
+ final String requestID = defaultToUUID(request.getHeader(ONAPLogConstants.Headers.REQUEST_ID));\r
+ final String invocationID = defaultToUUID(request.getHeader(ONAPLogConstants.Headers.INVOCATION_ID));\r
+ final String partnerName = defaultToEmpty(request.getHeader(ONAPLogConstants.Headers.PARTNER_NAME));\r
+ \r
+ // Default the partner name to the user name used to login to clamp\r
+ if (partnerName.equalsIgnoreCase(EMPTY_MESSAGE)) {\r
+ MDC.put(ONAPLogConstants.MDCs.PARTNER_NAME, new DefaultUserNameHandler().retrieveUserName(SecurityContextHolder.getContext()));\r
+ }\r
+\r
+ // Set standard MDCs. Override this entire method if you want to set\r
+ // others, OR set them BEFORE or AFTER the invocation of #entering,\r
+ // depending on where you need them to appear, OR extend the\r
+ // ServiceDescriptor to add them.\r
+ MDC.put(ONAPLogConstants.MDCs.ENTRY_TIMESTAMP,\r
+ ZonedDateTime.now(ZoneOffset.UTC)\r
+ .format(DateTimeFormatter.ISO_INSTANT));\r
+ MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, requestID);\r
+ MDC.put(ONAPLogConstants.MDCs.INVOCATION_ID, invocationID);\r
+ MDC.put(ONAPLogConstants.MDCs.CLIENT_IP_ADDRESS, defaultToEmpty(request.getRemoteAddr()));\r
+ MDC.put(ONAPLogConstants.MDCs.SERVER_FQDN, defaultToEmpty(request.getServerName()));\r
+ MDC.put(ONAPLogConstants.MDCs.INSTANCE_UUID, defaultToEmpty(sInstanceUUID));\r
+\r
+ // Default the service name to the requestURI, in the event that\r
+ // no value has been provided.\r
+ if (serviceName == null ||\r
+ serviceName.equalsIgnoreCase(EMPTY_MESSAGE)) {\r
+ MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, request.getRequestURI());\r
+ }\r
+ \r
+ this.mLogger.info("ENTRY");\r
+ }\r
+\r
+ /**\r
+ * Report <tt>EXITING</tt> marker.\r
+ *\r
+ * @return this.\r
+ */\r
+ public void exiting(String code, String descrption, Level severity, ONAPLogConstants.ResponseStatus status) {\r
+ try {\r
+ MDC.put(ONAPLogConstants.MDCs.RESPONSE_CODE, defaultToEmpty(code));\r
+ MDC.put(ONAPLogConstants.MDCs.RESPONSE_DESCRIPTION, defaultToEmpty(descrption));\r
+ MDC.put(ONAPLogConstants.MDCs.RESPONSE_SEVERITY, defaultToEmpty(severity));\r
+ MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, defaultToEmpty(status));\r
+ this.mLogger.info("EXIT");\r
+ }\r
+ finally {\r
+ MDC.clear();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Report pending invocation with <tt>INVOKE</tt> marker,\r
+ * setting standard ONAP logging headers automatically.\r
+ *\r
+ * @param builder request builder, for setting headers.\r
+ * @param sync whether synchronous, nullable.\r
+ * @return invocation ID to be passed with invocation.\r
+ */\r
+ public HttpURLConnection invoke(final HttpURLConnection con, String targetEntity, String targetServiceName) {\r
+ final String invocationID = UUID.randomUUID().toString();\r
+\r
+ // Set standard HTTP headers on (southbound request) builder.\r
+ con.setRequestProperty(ONAPLogConstants.Headers.REQUEST_ID,\r
+ defaultToEmpty(MDC.get(ONAPLogConstants.MDCs.REQUEST_ID)));\r
+ con.setRequestProperty(ONAPLogConstants.Headers.INVOCATION_ID,\r
+ invocationID);\r
+ con.setRequestProperty(ONAPLogConstants.Headers.PARTNER_NAME,\r
+ defaultToEmpty(MDC.get(ONAPLogConstants.MDCs.PARTNER_NAME)));\r
+\r
+ invokeContext(targetEntity, targetServiceName, invocationID);\r
+\r
+ // Log INVOKE*, with the invocationID as the message body.\r
+ // (We didn't really want this kind of behavior in the standard,\r
+ // but is it worse than new, single-message MDC?)\r
+ this.mLogger.info("INVOKE");\r
+ this.mLogger.info("INVOKE-" + ONAPLogConstants.InvocationMode.SYNCHRONOUS.toString() + "{"+ invocationID +"}");\r
+ return con;\r
+ }\r
+ public void invokeReturn() {\r
+ // Add the Invoke-return marker and clear the needed MDC\r
+ this.mLogger.info("INVOKE-RETURN");\r
+ invokeReturnContext();\r
+ }\r
+\r
+ /**\r
+ * Dependency-free nullcheck.\r
+ *\r
+ * @param in to be checked.\r
+ * @param <T> argument (and return) type.\r
+ * @return input arg.\r
+ */\r
+ private static <T> T checkNotNull(final T in) {\r
+ if (in == null) {\r
+ throw new NullPointerException();\r
+ }\r
+ return in;\r
+ }\r
+\r
+ /**\r
+ * Dependency-free string default.\r
+ *\r
+ * @param in to be filtered.\r
+ * @return input string or null.\r
+ */\r
+ private static String defaultToEmpty(final Object in) {\r
+ if (in == null) {\r
+ return "";\r
+ }\r
+ return in.toString();\r
+ }\r
+\r
+ /**\r
+ * Dependency-free string default.\r
+ *\r
+ * @param in to be filtered.\r
+ * @return input string or null.\r
+ */\r
+ private static String defaultToUUID(final String in) {\r
+ if (in == null) {\r
+ return UUID.randomUUID().toString();\r
+ }\r
+ return in;\r
+ }\r
+\r
+ /**\r
+ * Set target related logging variables in thread local data via MDC\r
+ *\r
+ * @param targetEntity Target entity (an external/sub component, for ex. "sdc")\r
+ * @param targetServiceName Target service name (name of API invoked on target)\r
+ * @param invocationId The invocation ID\r
+ */\r
+ private void invokeContext (String targetEntity, String targetServiceName, String invocationID) {\r
+ MDC.put(TARGET_ENTITY, defaultToEmpty(targetEntity));\r
+ MDC.put(ONAPLogConstants.MDCs.TARGET_SERVICE_NAME, defaultToEmpty(targetServiceName));\r
+ MDC.put(INVOCATIONID_OUT, invocationID);\r
+ MDC.put(ONAPLogConstants.MDCs.INVOKE_TIMESTAMP,\r
+ ZonedDateTime.now(ZoneOffset.UTC)\r
+ .format(DateTimeFormatter.ISO_INSTANT));\r
+ }\r
\r
+ /**\r
+ * Clear target related logging variables in thread local data via MDC\r
+ *\r
+ */\r
+ private void invokeReturnContext () {\r
+ MDC.remove(TARGET_ENTITY);\r
+ MDC.remove(ONAPLogConstants.MDCs.TARGET_SERVICE_NAME);\r
+ MDC.remove(INVOCATIONID_OUT);\r
+ }\r
}\r