l2 management maturity pdp-d 51/38351/3
authorJorge Hernandez <jh1730@att.com>
Mon, 26 Mar 2018 04:34:27 +0000 (23:34 -0500)
committerJorge Hernandez <jh1730@att.com>
Mon, 26 Mar 2018 15:08:52 +0000 (10:08 -0500)
configurable log location
metric/audit log for transaction metrics conforming to
new field definition.
support metrics/audits records with custom logback filters
so they are not intrusive with developer log testing.

Change-Id: I7a4dcc6790b85539e613ad8705e731e7298ce106
Issue-ID: POLICY-533
Signed-off-by: Jorge Hernandez <jh1730@att.com>
20 files changed:
feature-eelf/src/main/feature/config/logback-eelf.xml
feature-simulators/src/test/java/org/onap/policy/drools/simulators/DMaaPSimulatorTest.java
packages/base/src/files/etc/profile.d/env.sh
packages/docker/src/main/docker/docker-install.sh
packages/install/src/files/base.conf
policy-endpoints/src/main/java/org/onap/policy/drools/http/server/internal/JettyJerseyServer.java
policy-management/src/main/java/org/onap/policy/drools/server/restful/RestManager.java
policy-management/src/main/java/org/onap/policy/drools/system/Main.java
policy-management/src/main/java/org/onap/policy/drools/system/PolicyEngine.java
policy-management/src/main/server-gen/bin/policy-management-controller
policy-management/src/main/server/config/logback.xml
policy-utils/src/main/java/org/onap/policy/drools/utils/LoggerUtil.java [deleted file]
policy-utils/src/main/java/org/onap/policy/drools/utils/NetworkUtil.java
policy-utils/src/main/java/org/onap/policy/drools/utils/logging/LoggerMarkerFilter.java [new file with mode: 0644]
policy-utils/src/main/java/org/onap/policy/drools/utils/logging/LoggerUtil.java [new file with mode: 0644]
policy-utils/src/main/java/org/onap/policy/drools/utils/logging/MDCTransaction.java [new file with mode: 0644]
policy-utils/src/test/java/org/onap/policy/drools/utils/NetworkUtilTest.java
policy-utils/src/test/java/org/onap/policy/drools/utils/logging/LoggerUtilTest.java [moved from policy-utils/src/test/java/org/onap/policy/drools/utils/LoggerUtilTest.java with 55% similarity]
policy-utils/src/test/java/org/onap/policy/drools/utils/logging/MDCTransactionTest.java [new file with mode: 0644]
policy-utils/src/test/resources/logback-test.xml [new file with mode: 0644]

index d76eb20..4dafd45 100644 (file)
@@ -2,7 +2,7 @@
   ============LICENSE_START=======================================================
   feature-eelf
   ================================================================================
-  Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+  Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
   ================================================================================
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
        <property name="networkLogName" value="network" />
 
        <property name="defaultPattern"
-               value="%X{BeginTimestamp}|%X{EndTimestamp}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{ServerName}|%X{ServiceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ElapsedTime}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}||%X{ProcessKey}|%X{TargetVirtualEntity}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}|%msg%n" />
+               value="%X{BeginTimestamp}|%X{EndTimestamp}|%X{RequestID}|%X{ServiceInstanceId}|%thread|%X{ServerName}|%X{ServiceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ElapsedTime}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}||%X{ProcessKey}|%X{TargetVirtualEntity}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}|%msg%n" />
        <property name="defaultMetricPattern"
-               value="%X{BeginTimestamp}|%X{EndTimestamp}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{ServerName}|%X{ServiceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ElapsedTime}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}||%X{ProcessKey}|%X{TargetVirtualEntity}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}|%msg%n" />
+               value="%X{BeginTimestamp}|%X{EndTimestamp}|%X{RequestID}|%X{ServiceInstanceId}|%thread|%X{ServerName}|%X{ServiceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ElapsedTime}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}||%X{ProcessKey}|%X{TargetVirtualEntity}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}|%msg%n" />
        <property name="defaultAuditPattern"
-               value="%X{BeginTimestamp}|%X{EndTimestamp}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{ServerName}|%X{ServiceName}|%X{PartnerName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ElapsedTime}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}||%X{ProcessKey}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}|%msg%n" />
+               value="%X{BeginTimestamp}|%X{EndTimestamp}|%X{RequestID}|%X{ServiceInstanceId}|%thread|%X{ServerName}|%X{ServiceName}|%X{PartnerName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ElapsedTime}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}||%X{ProcessKey}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}|%msg%n" />
        <property name="defaultErrorPattern"
-               value="%d{yyyy-MM-dd'T'HH:mm:ss.SSS+00:00, UTC}|%X{RequestId}|%thread|%X{ServiceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}|%X{ErrorCategory}|%X{ErrorCode}|%X{ErrorDesciption}|%msg%replace(%xException){'\n',' - '}%nopex%n" />
+               value="%d{yyyy-MM-dd'T'HH:mm:ss.SSS+00:00, UTC}|%X{RequestID}|%thread|%X{ServiceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}|%X{ErrorCategory}|%X{ErrorCode}|%X{ErrorDesciption}|%msg%replace(%xException){'\n',' - '}%nopex%n" />
                
        <property name="networkPattern" value="[%d|%t]%m%n" />
        <property name="debugPattern" value="[%date|%level|%logger{0}|%thread] %replace(%msg){'\n', ' '}%n" />
index 415c520..b16804e 100644 (file)
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * feature-simulators
  * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -37,7 +37,7 @@ import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.onap.policy.drools.http.server.HttpServletServer;
-import org.onap.policy.drools.utils.LoggerUtil;
+import org.onap.policy.drools.utils.logging.LoggerUtil;
 import org.onap.policy.drools.utils.NetworkUtil;
 
 public class DMaaPSimulatorTest {
@@ -361,4 +361,4 @@ public class DMaaPSimulatorTest {
                        this.b = b;
                }
        }
-}
\ No newline at end of file
+}
index be8e747..9707660 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START=======================================================
 # Base Package
 # ================================================================================
-# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
 # ================================================================================
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
 ###
 
 export POLICY_HOME=${{POLICY_HOME}}
+export POLICY_LOGS=${{POLICY_LOGS}}
 export JAVA_HOME=${{JAVA_HOME}}
 export ENGINE_MANAGEMENT_USER=${{ENGINE_MANAGEMENT_USER}}
 export ENGINE_MANAGEMENT_PASSWORD=${{ENGINE_MANAGEMENT_PASSWORD}}
index e65329d..2ff6a0b 100644 (file)
@@ -4,7 +4,7 @@
 # ============LICENSE_START=======================================================
 # Installation Package
 # ================================================================================
-# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
 # ================================================================================
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -390,6 +390,13 @@ function install_base() {
                exit 1
        fi      
        
+       if [[ -n ${POLICY_LOGS} ]]; then
+               if ! /bin/mkdir -p "${POLICY_LOGS}" > /dev/null 2>&1; then      
+                       echo "error: aborting base installation: cannot create ${POLICY_LOGS}"
+                       exit 1
+               fi      
+       fi
+       
        BASE_TGZ=$(ls base-*.tar.gz)
        if [ ! -r ${BASE_TGZ} ]; then
                echo "error: aborting: base package is not accessible"
index d92abed..f1a37d0 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START=======================================================
 # ONAP POLICY
 # ================================================================================
-# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
 # ================================================================================
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
 # SYSTEM software configuration 
 
 POLICY_HOME=/opt/app/policy
+POLICY_LOGS=/opt/app/policy/logs
 JAVA_HOME=/opt/jdk1.8.0_77
 M2_HOME=/opt/app/policy/3rdparty/apache-maven-3.3.1
 
index f882c92..4f7c151 100644 (file)
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * policy-endpoints
  * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -129,12 +129,7 @@ public class JettyJerseyServer extends JettyServletServer {
 
                String hostname = this.connector.getHost();
                if (hostname == null || hostname.isEmpty() || hostname.equals(NetworkUtil.IPv4_WILDCARD_ADDRESS)) {
-                       try {
-                               hostname = InetAddress.getLocalHost().getHostName();
-                       } catch (UnknownHostException e) {
-                               logger.warn("{}: can't resolve connector's hostname: {}", this, hostname, e);
-                               hostname = "localhost";
-                       }
+                       hostname = NetworkUtil.getHostname();
                }
 
                swaggerServlet.setInitParameter(SWAGGER_API_BASEPATH,
index cd1edca..15c9723 100644 (file)
@@ -64,7 +64,7 @@ import org.onap.policy.drools.protocol.configuration.ControllerConfiguration;
 import org.onap.policy.drools.protocol.configuration.PdpdConfiguration;
 import org.onap.policy.drools.system.PolicyController;
 import org.onap.policy.drools.system.PolicyEngine;
-import org.onap.policy.drools.utils.LoggerUtil;
+import org.onap.policy.drools.utils.logging.LoggerUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
index 314bbc0..4321600 100644 (file)
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * policy-management
  * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 package org.onap.policy.drools.system;
 
-import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Paths;
 import java.util.Properties;
 
 import org.onap.policy.drools.persistence.SystemPersistence;
 import org.onap.policy.drools.properties.PolicyProperties;
-import org.onap.policy.drools.utils.LoggerUtil;
+import org.onap.policy.drools.utils.logging.LoggerUtil;
+import org.onap.policy.drools.utils.logging.MDCTransaction;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -56,7 +56,6 @@ public class Main {
    * main
    *
    * @param args program arguments
-   * @throws IOException
    */
   public static void main(String[] args) {
 
@@ -110,16 +109,23 @@ public class Main {
 
     /* 2. Start the Engine with the basic services only (no Policy Controllers) */
 
+    MDCTransaction trans =
+        MDCTransaction.newTransaction(null, null).setServiceName(Main.class.getSimpleName()).
+          setTargetEntity("engine").setTargetServiceName("start");
     try {
       final boolean success = PolicyEngine.manager.start();
       if (!success) {
-        logger.warn("Main: {} has been partially started", PolicyEngine.manager);
+        trans.setStatusCode(false).setResponseDescription("partial start").flush();
+        logger.warn(LoggerUtil.TRANSACTION_LOG_MARKER, "Main: {} has been partially started", PolicyEngine.manager);
+      } else {
+        trans.setStatusCode(true).transaction();
       }
     } catch (final IllegalStateException e) {
-      logger.warn("Main: cannot start {} (bad state) because of {}", PolicyEngine.manager,
-          e.getMessage(), e);
+      trans.setStatusCode(false).setResponseCode(e.getClass().getSimpleName()).setResponseDescription(e.getMessage()).flush();
+      logger.warn(LoggerUtil.TRANSACTION_LOG_MARKER, "Main: cannot start {} (bad state) because of {}", PolicyEngine.manager, e.getMessage(), e);
     } catch (final Exception e) {
-      logger.warn("Main: cannot start {} because of {}", PolicyEngine.manager, e.getMessage(), e);
+      trans.setStatusCode(false).setResponseCode(e.getClass().getSimpleName()).setResponseDescription(e.getMessage()).flush();
+      logger.warn(LoggerUtil.TRANSACTION_LOG_MARKER, "Main: cannot start {} because of {}", PolicyEngine.manager, e.getMessage(), e);
       System.exit(1);
     }
 
@@ -130,14 +136,24 @@ public class Main {
       final String controllerName =
           controllerProperties.getProperty(PolicyProperties.PROPERTY_CONTROLLER_NAME);
       try {
+        trans =
+            MDCTransaction.newTransaction(null, null).setServiceName(Main.class.getSimpleName()).
+                setTargetEntity("controller:" + controllerName).setTargetServiceName("start");
+
         final PolicyController controller =
             PolicyEngine.manager.createPolicyController(controllerName, controllerProperties);
         controller.start();
+
+        trans.setStatusCode(true).
+            setResponseDescription(controller.getDrools().getCanonicalSessionNames().toString()).
+            transaction();
       } catch (final Exception e) {
-        logger.error("Main: cannot instantiate policy-controller {} because of {}", controllerName,
-            e.getMessage(), e);
+        trans.setStatusCode(false).setResponseCode(e.getClass().getSimpleName()).setResponseDescription(e.getMessage()).flush();
+        logger.error(LoggerUtil.TRANSACTION_LOG_MARKER, "Main: cannot instantiate policy-controller {} because of {}",
+            controllerName, e.getMessage(), e);
       } catch (final LinkageError e) {
-        logger.warn("Main: cannot instantiate policy-controller {} (linkage) because of {}",
+        trans.setStatusCode(false).setResponseCode(e.getClass().getSimpleName()).setResponseDescription(e.getMessage()).flush();
+        logger.warn(LoggerUtil.TRANSACTION_LOG_MARKER, "Main: cannot instantiate policy-controller {} (linkage) because of {}",
             controllerName, e.getMessage(), e);
       }
     }
index a1fee76..d727557 100644 (file)
@@ -44,6 +44,8 @@ import org.onap.policy.drools.protocol.coders.EventProtocolCoder;
 import org.onap.policy.drools.protocol.configuration.ControllerConfiguration;
 import org.onap.policy.drools.protocol.configuration.PdpdConfiguration;
 import org.onap.policy.drools.server.restful.RestManager;
+import org.onap.policy.drools.utils.logging.LoggerUtil;
+import org.onap.policy.drools.utils.logging.MDCTransaction;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -139,7 +141,6 @@ public interface PolicyEngine extends Startable, Lockable, TopicListener {
   /**
    * registers a new Policy Controller with the Policy Engine initialized per properties.
    *
-   * @param controller name
    * @param properties properties to initialize the Policy Controller
    * @throws IllegalArgumentException when invalid or insufficient properties are provided
    * @throws IllegalStateException when the engine is in a state where this operation is not
@@ -276,7 +277,6 @@ public interface PolicyEngine extends Startable, Lockable, TopicListener {
   /**
    * Attempts the dispatching of an "event" object over communication infrastructure "busType"
    *
-   * @param eventBus Communication infrastructure identifier
    * @param topic topic
    * @param event the event object to send
    *
@@ -292,7 +292,6 @@ public interface PolicyEngine extends Startable, Lockable, TopicListener {
   /**
    * Attempts the dispatching of an "event" object over communication infrastructure "busType"
    *
-   * @param eventBus Communication infrastructure enum
    * @param topic topic
    * @param event the event object to send
    *
@@ -308,7 +307,6 @@ public interface PolicyEngine extends Startable, Lockable, TopicListener {
   /**
    * Attempts delivering of an String over communication infrastructure "busType"
    *
-   * @param eventBus Communication infrastructure identifier
    * @param topic topic
    * @param event the event object to send
    *
@@ -591,12 +589,22 @@ private static final String ENGINE_LOCKED_MSG = "Policy Engine is locked";
 
     final String entity = config.getEntity();
 
+    MDCTransaction mdcTrans = MDCTransaction.newTransaction(config.getRequestID(), "brmsgw");
+    if (this.getSources().size() == 1) {
+      Topic topic = this.getSources().get(0);
+      mdcTrans.setServiceName(topic.getTopic()).setRemoteHost(topic.getServers().toString()).
+        setTargetEntity(config.getEntity());
+    }
+
     switch (entity) {
-      case PdpdConfiguration.CONFIG_ENTITY_CONTROLLER:          
-        return controllerConfig(config);
+      case PdpdConfiguration.CONFIG_ENTITY_CONTROLLER:
+        boolean success = controllerConfig(config);
+        mdcTrans.resetSubTransaction().setStatusCode(success).transaction();
+        return success;
       default:
         final String msg = "Configuration Entity is not supported: " + entity;
-        logger.warn(msg);
+        mdcTrans.resetSubTransaction().setStatusCode(false).setResponseDescription(msg).flush();
+        logger.warn(LoggerUtil.TRANSACTION_LOG_MARKER_NAME, msg);
         throw new IllegalArgumentException(msg);
     }
   }
@@ -613,11 +621,18 @@ private static final String ENGINE_LOCKED_MSG = "Policy Engine is locked";
     }
 
     for (final ControllerConfiguration configController : configControllers) {
+      MDCTransaction mdcTrans =
+          MDCTransaction.newSubTransaction(null).setTargetEntity(configController.getName()).
+              setTargetServiceName(configController.getOperation()).
+              setTargetVirtualEntity(configController.getDrools().toString());
       try {
         final PolicyController policyController = this.updatePolicyController(configController);
         policyControllers.add(policyController);
+        mdcTrans.setStatusCode(true).transaction();
       } catch (final Exception e) {
-        logger.error("{}: cannot update-policy-controllers because of {}", this, e.getMessage(), e);
+        mdcTrans.setStatusCode(false).setResponseCode(e.getClass().getName()).
+            setResponseDescription(e.getMessage()).flush();
+        logger.error(LoggerUtil.TRANSACTION_LOG_MARKER_NAME, "{}: cannot update-policy-controllers because of {}", this, e.getMessage(), e);
       }
     }
 
@@ -1423,18 +1438,23 @@ private static final String ENGINE_LOCKED_MSG = "Policy Engine is locked";
       /* only this one supported for now */
       final List<ControllerConfiguration> configControllers = config.getControllers();
       if (configControllers == null || configControllers.isEmpty()) {
-        if (logger.isInfoEnabled())
-          logger.info("No controller configuration provided: " + config);
+        logger.info("No controller configuration provided: {}" + config);
         return false;
       }
-      final List<PolicyController> policyControllers =
-          this.updatePolicyControllers(config.getControllers());
-      if (policyControllers == null || policyControllers.isEmpty())
-        return false;
-      else if (policyControllers.size() == configControllers.size())
-        return true;
 
-      return false;      
+      final List<PolicyController> policyControllers = this.updatePolicyControllers(config.getControllers());
+
+      boolean success;
+
+      if (policyControllers == null || policyControllers.isEmpty()) {
+        success = false;
+      } else if (policyControllers.size() == configControllers.size()) {
+        success = true;
+      } else {
+        success = false;
+      }
+
+      return success;
   }
 
   @Override
index a9f8ce0..cc6a8c7 100644 (file)
@@ -4,7 +4,7 @@
 # ============LICENSE_START=======================================================
 # ONAP POLICY
 # ================================================================================
-# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
 # ================================================================================
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -42,11 +42,11 @@ function um_start() {
       RETVAL=0
       return
     fi
-    mkdir -p $_DIR/logs
-    if [ -e $_DIR/logs/$PNAME.out.1 ]; then mv $_DIR/logs/$PNAME.out.1 $_DIR/logs/$PNAME.out.2; fi
-    if [ -e $_DIR/logs/$PNAME.err.1 ]; then mv $_DIR/logs/$PNAME.err.1 $_DIR/logs/$PNAME.err.2; fi
-    if [ -e $_DIR/logs/$PNAME.out ]; then mv $_DIR/logs/$PNAME.out $_DIR/logs/$PNAME.out.1; fi
-    if [ -e $_DIR/logs/$PNAME.err ]; then mv $_DIR/logs/$PNAME.err $_DIR/logs/$PNAME.err.1; fi
+    mkdir -p $_LOGS
+    if [ -e $_LOGS/$PNAME.out.1 ]; then mv $_LOGS/$PNAME.out.1 $_LOGS/$PNAME.out.2; fi
+    if [ -e $_LOGS/$PNAME.err.1 ]; then mv $_LOGS/$PNAME.err.1 $_LOGS/$PNAME.err.2; fi
+    if [ -e $_LOGS/$PNAME.out ]; then mv $_LOGS/$PNAME.out $_LOGS/$PNAME.out.1; fi
+    if [ -e $_LOGS/$PNAME.err ]; then mv $_LOGS/$PNAME.err $_LOGS/$PNAME.err.1; fi
     CP=$(ls $_DIR/lib/*.jar | xargs -I X printf ":%s" X)
 
     # If 'system.properties' exists, convert it into JVM arguments.
@@ -66,7 +66,7 @@ function um_start() {
            # to subprocesses
            exec {cfg}>&-
        fi
-       nohup $JAVA_HOME/bin/java -Dkie.maven.settings.custom=$_DIR/config/kie_settings.xml -Dlog4j.configuration=file:$_DIR/config/log4j.properties -cp $_DIR/config:$_DIR/lib:$CP "${systemProperties[@]}" "$@" $CLASS > >( while read line; do echo "$(date): ${line}"; done > $_DIR/logs/$PNAME.out) 2> >( while read line; do echo "$(date): ${line}"; done > $_DIR/logs/$PNAME.err) &
+       nohup $JAVA_HOME/bin/java -Dkie.maven.settings.custom=$_DIR/config/kie_settings.xml -Dlog4j.configuration=file:$_DIR/config/log4j.properties -cp $_DIR/config:$_DIR/lib:$CP "${systemProperties[@]}" "$@" $CLASS > >( while read line; do echo "$(date): ${line}"; done > $_LOGS/$PNAME.out) 2> >( while read line; do echo "$(date): ${line}"; done > $_LOGS/$PNAME.err) &
 
        _PID=$!
        echo $_PID > $_PIDFILE
@@ -167,6 +167,12 @@ function update_monitor() {
 # main
 
 _DIR=${POLICY_HOME}
+_LOGS=${POLICY_LOGS}
+
+if [[ -z ${POLICY_LOGS} ]]; then
+       _LOGS="${POLICY_HOME}"/logs
+fi
+
 CONTROLLER=policy-management-controller
 
 RETVAL=0
index 1801c43..538fcf8 100644 (file)
@@ -2,7 +2,7 @@
   ============LICENSE_START=======================================================
   policy-management
   ================================================================================
-  Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+  Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
   ================================================================================
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
 
 <configuration scan="true" scanPeriod="30 seconds" debug="false">
 
-       <property name="logDir" value="logs" />
+       <property name="logDir" value="${POLICY_LOGS}" />
 
        <property name="errorLog" value="error" />
        <property name="debugLog" value="debug" />
        <property name="networkLog" value="network" />
 
-       <property name="debugPattern" value="[%date|%level|%logger{0}|%thread] %msg%n" />
+       <property name="metricLog" value="metric" />
+       <property name="transactionLog" value="audit" />
+
+       <property name="debugPattern" value="[%d{yyyy-MM-dd'T'HH:mm:ss.SSS+00:00, UTC}|%level|%logger{0}|%thread] %msg%n" />
        <property name="errorPattern" value="${debugPattern}" />
-       <property name="networkPattern" value="[%d|%t]%m%n" />
+       <property name="networkPattern" value="[%d{yyyy-MM-dd'T'HH:mm:ss.SSS+00:00, UTC}|%t]%m%n" />
+
+       <property name="metricPattern" value="%X{RequestID}|%X{InvocationID}|%X{ServiceName}|%X{PartnerName}|%X{BeginTimestamp}|%X{EndTimestamp}|%X{ElapsedTime}|%X{ServiceInstanceID}|%X{VirtualServerName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%X{Severity}|%X{TargetEntity}|%X{TargetServiceName}|%X{Server}|%X{ServerIPAddress}|%X{ServerFQDN}|%X{ClientIPAddress}|%X{ProcessKey}|%X{RemoteHost}|%X{AlertSeverity}|%X{TargetVirtualEntity}|%level|%thread| %msg%n"/>
+       <property name="transactionPattern" value="${metricPattern}" />
 
        <appender name="ErrorOut" class="ch.qos.logback.core.rolling.RollingFileAppender">
                <file>${logDir}/${errorLog}.log</file>
-               <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
-                       <fileNamePattern>${logDir}/${errorLog}.%i.log.zip</fileNamePattern>
-                       <minIndex>1</minIndex>
-                       <maxIndex>5</maxIndex>
+               <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+                       <fileNamePattern>${logDir}/${errorLog}.%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern>
+                       <maxFileSize>50MB</maxFileSize>
+                       <maxHistory>30</maxHistory>
+                       <totalSizeCap>10GB</totalSizeCap>
                </rollingPolicy>
                <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
                        <level>WARN</level>
                </filter>
-               <triggeringPolicy
-                       class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
-                       <maxFileSize>15MB</maxFileSize>
-               </triggeringPolicy>
                <encoder>
                        <pattern>${errorPattern}</pattern>
                </encoder>
        
        <appender name="DebugOut" class="ch.qos.logback.core.rolling.RollingFileAppender">
                <file>${logDir}/${debugLog}.log</file>
-               <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
-                       <fileNamePattern>${logDir}/${debugLog}.%i.log.zip</fileNamePattern>
-                       <minIndex>1</minIndex>
-                       <maxIndex>9</maxIndex>
+               <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+                       <fileNamePattern>${logDir}/${debugLog}.%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern>
+                       <maxFileSize>50MB</maxFileSize>
+                       <maxHistory>30</maxHistory>
+                       <totalSizeCap>10GB</totalSizeCap>
                </rollingPolicy>
-               <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
-                       <maxFileSize>20MB</maxFileSize>
-               </triggeringPolicy>
                <encoder>
                        <pattern>${debugPattern}</pattern>
                </encoder>
 
        <appender name="NetworkOut" class="ch.qos.logback.core.rolling.RollingFileAppender">
                <file>${logDir}/${networkLog}.log</file>
-               <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
-                       <fileNamePattern>${logDir}/${networkLog}.%i.log.zip</fileNamePattern>
-                       <minIndex>1</minIndex>
-                       <maxIndex>9</maxIndex>
+               <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+                       <fileNamePattern>${logDir}/${networkLog}.%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern>
+                       <maxFileSize>50MB</maxFileSize>
+                       <maxHistory>30</maxHistory>
+                       <totalSizeCap>10GB</totalSizeCap>
                </rollingPolicy>
-               <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
-                       <maxFileSize>15MB</maxFileSize>
-               </triggeringPolicy>
                <encoder>
                        <pattern>${networkPattern}</pattern>
                </encoder>              
                <appender-ref ref="NetworkOut" />
        </appender>
 
+       <appender name="MetricOut" class="ch.qos.logback.core.rolling.RollingFileAppender">
+               <file>${logDir}/${metricLog}.log</file>
+               <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+                       <fileNamePattern>${logDir}/${metricLog}.%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern>
+                       <maxFileSize>50MB</maxFileSize>
+                       <maxHistory>30</maxHistory>
+                       <totalSizeCap>10GB</totalSizeCap>
+               </rollingPolicy>
+               <filter class="org.onap.policy.drools.utils.logging.LoggerMarkerFilter$MetricLoggerMarkerFilter" />
+               <encoder>
+                       <pattern>${metricPattern}</pattern>
+               </encoder>
+       </appender>
+
+       <appender name="AsyncMetricOut" class="ch.qos.logback.classic.AsyncAppender">
+               <appender-ref ref="MetricOut" />
+       </appender>
+
+       <appender name="TransactionOut" class="ch.qos.logback.core.rolling.RollingFileAppender">
+               <file>${logDir}/${transactionLog}.log</file>
+               <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+                       <fileNamePattern>${logDir}/${transactionLog}.%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern>
+                       <maxFileSize>50MB</maxFileSize>
+                       <maxHistory>30</maxHistory>
+                       <totalSizeCap>10GB</totalSizeCap>
+               </rollingPolicy>
+               <filter class="org.onap.policy.drools.utils.logging.LoggerMarkerFilter$TransactionLoggerMarkerFilter" />
+               <encoder>
+                       <pattern>${transactionPattern}</pattern>
+               </encoder>
+       </appender>
+
+       <appender name="AsyncTransactionOut" class="ch.qos.logback.classic.AsyncAppender">
+               <appender-ref ref="TransactionOut" />
+       </appender>
+
        <logger name="network" level="INFO" additivity="false">
                <appender-ref ref="AsyncNetworkOut" />          
        </logger>
        <root level="INFO">
                <appender-ref ref="AsyncDebugOut" />
                <appender-ref ref="AsyncErrorOut" />
+               <appender-ref ref="AsyncMetricOut" />
+               <appender-ref ref="AsyncTransactionOut" />
        </root>
 
 </configuration>
diff --git a/policy-utils/src/main/java/org/onap/policy/drools/utils/LoggerUtil.java b/policy-utils/src/main/java/org/onap/policy/drools/utils/LoggerUtil.java
deleted file mode 100644 (file)
index 681a2b2..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * ONAP
- * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ============LICENSE_END=========================================================
- */
-package org.onap.policy.drools.utils;
-
-import org.slf4j.LoggerFactory;
-
-import ch.qos.logback.classic.LoggerContext;
-
-/**
- * Loger Utils
- */
-public class LoggerUtil {
-
-  /**
-   * Root logger
-   */
-  public static final String ROOT_LOGGER = "ROOT";
-  
-  private LoggerUtil() {
-         // Empty constructor
-  }
-
-  /**
-   * set the log level of a logger
-   *
-   * @param loggerName logger name
-   * @param loggerLevel logger level
-   */
-  public static String setLevel(String loggerName, String loggerLevel) {
-    if (!(LoggerFactory.getILoggerFactory() instanceof LoggerContext))
-      throw new IllegalStateException("The SLF4J logger factory is not configured for logback");
-
-    final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
-    final ch.qos.logback.classic.Logger logger = context.getLogger(loggerName);
-    if (logger == null)
-      throw new IllegalArgumentException("no logger " + loggerName);
-
-    logger.setLevel(ch.qos.logback.classic.Level.toLevel(loggerLevel));
-    return logger.getLevel().toString();
-  }
-}
index 6734226..229927e 100644 (file)
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * ONAP
  * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -22,8 +22,10 @@ package org.onap.policy.drools.utils;
 
 import java.io.IOException;
 import java.net.ConnectException;
+import java.net.InetAddress;
 import java.net.Socket;
 
+import java.net.UnknownHostException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -32,42 +34,80 @@ import org.slf4j.LoggerFactory;
  */
 public class NetworkUtil {
 
-  public static final Logger logger = LoggerFactory.getLogger(NetworkUtil.class.getName());
-
-  /**
-   * IPv4 Wildcard IP address
-   */
-  public static final String IPv4_WILDCARD_ADDRESS = "0.0.0.0";
-
-  private NetworkUtil() {
-         // Empty constructor
-  }
-
-  /**
-   * try to connect to $host:$port $retries times while we are getting connection failures.
-   *
-   * @param host host
-   * @param port port
-   * @param retries number of attempts
-   * @return true is port is open, false otherwise
-   * @throws InterruptedException if execution has been interrupted
-   */
-  public static boolean isTcpPortOpen(String host, int port, int retries, long interval)
-      throws InterruptedException, IOException {
-    int retry = 0;
-    while (retry < retries) {
-      try (Socket s = new Socket(host, port)) {
-        logger.debug("{}:{} connected - retries={} interval={}", host, port, retries, interval);
-        return true;
-      } catch (final ConnectException e) {
-        retry++;
-        logger.trace("{}:{} connected - retries={} interval={}", host, port, retries, interval, e);
-        Thread.sleep(interval);
-      }
+    public static final Logger logger = LoggerFactory.getLogger(NetworkUtil.class.getName());
+
+    /**
+     * IPv4 Wildcard IP address
+     */
+    public static final String IPv4_WILDCARD_ADDRESS = "0.0.0.0";
+
+    private NetworkUtil() {
+        // Empty constructor
+    }
+
+    /**
+     * try to connect to $host:$port $retries times while we are getting connection failures.
+     *
+     * @param host host
+     * @param port port
+     * @param retries number of attempts
+     * @return true is port is open, false otherwise
+     * @throws InterruptedException if execution has been interrupted
+     */
+    public static boolean isTcpPortOpen(String host, int port, int retries, long interval)
+        throws InterruptedException, IOException {
+        int retry = 0;
+        while (retry < retries) {
+            try (Socket s = new Socket(host, port)) {
+                logger.debug("{}:{} connected - retries={} interval={}", host, port, retries, interval);
+                return true;
+            } catch (final ConnectException e) {
+                retry++;
+                logger.trace("{}:{} connected - retries={} interval={}", host, port, retries, interval, e);
+                Thread.sleep(interval);
+            }
+        }
+
+        logger.warn("{}:{} closed = retries={} interval={}", host, port, retries, interval);
+        return false;
+    }
+
+    /**
+     * gets host name
+     *
+     * @return host name
+     */
+    public static String getHostname() {
+
+        String hostname = System.getenv("HOSTNAME");
+        if (hostname != null && !hostname.isEmpty()) {
+            return hostname;
+        }
+
+        try {
+            return InetAddress.getLocalHost().getHostName();
+        } catch (UnknownHostException e) {
+            logger.warn("cannot resolve local hostname", e);
+            /* continue */
+        }
+
+        return "localhost";
     }
 
-    logger.warn("{}:{} closed = retries={} interval={}", host, port, retries, interval);
-    return false;
-  }
+    /**
+     * gets host's IP
+     *
+     * @return host IP
+     */
+    public static String getHostIp() {
+
+        try {
+            return InetAddress.getLocalHost().getHostAddress();
+        } catch (UnknownHostException e) {
+            logger.warn("cannot resolve local hostname", e);
+            /* continue */
+        }
 
+        return "127.0.0.1";
+    }
 }
diff --git a/policy-utils/src/main/java/org/onap/policy/drools/utils/logging/LoggerMarkerFilter.java b/policy-utils/src/main/java/org/onap/policy/drools/utils/logging/LoggerMarkerFilter.java
new file mode 100644 (file)
index 0000000..19414d3
--- /dev/null
@@ -0,0 +1,77 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.policy.drools.utils.logging;
+
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.filter.AbstractMatcherFilter;
+import ch.qos.logback.core.spi.FilterReply;
+import org.slf4j.Marker;
+
+/**
+ * Logger Marker Filters to be used in logback.xml configuration
+ * to accept/deny metric or transaction (audit) events
+ */
+public abstract class LoggerMarkerFilter extends AbstractMatcherFilter<ILoggingEvent> {
+
+    protected final Marker marker;
+
+    public LoggerMarkerFilter(Marker marker) {
+       this.marker = marker;
+    }
+
+    @Override
+    public FilterReply decide(ILoggingEvent event) {
+
+        if (this.marker == null || !isStarted()) {
+            return FilterReply.DENY;
+        }
+
+        if (event == null || event.getMarker() == null) {
+            return FilterReply.DENY;
+        }
+
+        if (event.getMarker().equals(marker)) {
+            return FilterReply.ACCEPT;
+        } else {
+            return FilterReply.DENY;
+        }
+    }
+
+    /**
+     * Metric Logger Marker Filter
+     */
+    public static class MetricLoggerMarkerFilter extends LoggerMarkerFilter {
+
+        public MetricLoggerMarkerFilter() {
+            super(LoggerUtil.METRIC_LOG_MARKER);
+        }
+
+    }
+
+    /**
+     * Transaction Logger Marker Filter
+     */
+    public static class TransactionLoggerMarkerFilter extends LoggerMarkerFilter {
+
+        public TransactionLoggerMarkerFilter() {
+            super(LoggerUtil.TRANSACTION_LOG_MARKER);
+        }
+    }
+}
diff --git a/policy-utils/src/main/java/org/onap/policy/drools/utils/logging/LoggerUtil.java b/policy-utils/src/main/java/org/onap/policy/drools/utils/logging/LoggerUtil.java
new file mode 100644 (file)
index 0000000..26b3570
--- /dev/null
@@ -0,0 +1,83 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.policy.drools.utils.logging;
+
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.LoggerContext;
+import org.slf4j.Marker;
+import org.slf4j.MarkerFactory;
+
+/**
+ * Loger Utils
+ */
+public class LoggerUtil {
+
+    /**
+     * Root logger
+     */
+    public static final String ROOT_LOGGER = "ROOT";
+
+    /**
+     * Metric Log Marker Name
+     */
+    public static final String METRIC_LOG_MARKER_NAME = "metric";
+
+    /**
+     * Transaction Log Marker Name
+     */
+    public static final String TRANSACTION_LOG_MARKER_NAME = "transaction";
+
+    /**
+     * Marks a logging record as a metric
+     */
+    public static final Marker METRIC_LOG_MARKER = MarkerFactory.getMarker(METRIC_LOG_MARKER_NAME);
+
+    /**
+     * Marks a logging record as an end-to-end transaction
+     */
+    public static final Marker TRANSACTION_LOG_MARKER = MarkerFactory.getMarker(TRANSACTION_LOG_MARKER_NAME);
+
+
+    private LoggerUtil() {
+        // Empty constructor
+    }
+
+    /**
+     * set the log level of a logger
+     *
+     * @param loggerName logger name
+     * @param loggerLevel logger level
+     */
+    public static String setLevel(String loggerName, String loggerLevel) {
+        if (!(LoggerFactory.getILoggerFactory() instanceof LoggerContext)) {
+            throw new IllegalStateException("The SLF4J logger factory is not configured for logback");
+        }
+
+        final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
+        final ch.qos.logback.classic.Logger logger = context.getLogger(loggerName);
+        if (logger == null) {
+            throw new IllegalArgumentException("no logger " + loggerName);
+        }
+
+        logger.setLevel(ch.qos.logback.classic.Level.toLevel(loggerLevel));
+        return logger.getLevel().toString();
+    }
+}
diff --git a/policy-utils/src/main/java/org/onap/policy/drools/utils/logging/MDCTransaction.java b/policy-utils/src/main/java/org/onap/policy/drools/utils/logging/MDCTransaction.java
new file mode 100644 (file)
index 0000000..1a27dde
--- /dev/null
@@ -0,0 +1,1194 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * policy-utils
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onap.policy.drools.utils.logging;
+
+import java.text.SimpleDateFormat;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Date;
+import java.util.UUID;
+import org.onap.policy.drools.utils.NetworkUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+
+/**
+ * MDC Transaction Utility Class.
+ *
+ * There is an implicit 2-level tree of Transactions in ONAP: transactions
+ * and subtransactions.
+ *
+ * 1. The top level transaction relates to the overarching transaction
+ *    id (ie. RequestId) and should be made available to subtransactions
+ *    for reuse in the ThreadLocal MDC structure.
+ *
+ *    This is the data to be inherited and common to all subtransactions
+ *    (not a common case but could be modified by subtransactions):
+ *
+ *    Request ID
+ *    Virtual Server Name
+ *    Partner Name
+ *    Server
+ *    Server IP Address
+ *    Server FQDN
+ *
+ * 2. The second level at the leaves is formed by subtransactions and the key
+ *    identifier is the invocation id.
+ *
+ *    Begin Timestamp
+ *    End Timestamp
+ *    Elapsed Time
+ *    Service Instance ID
+ *    Service Name
+ *    Status Code
+ *    Response Code
+ *    Response Description
+ *    Instance UUID
+ *    Severity
+ *    Target Entity
+ *    Target Service Name
+ *    Server
+ *    Server IP Address
+ *    Server FQDN
+ *    Client IP Address
+ *    Process Key
+ *    Remote Host
+ *    Alert Severity
+ *    Target Virtual Entity
+ *
+ *
+ * The naming convention for the fields must match the naming given at
+ *
+ *      https://wiki.onap.org/pages/viewpage.action?pageId=20087036
+ */
+public interface MDCTransaction {
+    /*
+     * The fields must match the naming given at
+     * https://wiki.onap.org/pages/viewpage.action?pageId=20087036
+     */
+
+    /**
+     * End to end transaction ID. Subtransactions will inherit this value from the transaction.
+     */
+    String REQUEST_ID = "RequestID";
+
+    /**
+     * Invocation ID, ie. SubTransaction ID.
+     */
+    String INVOCATION_ID = "InvocationID";
+
+    /**
+     * Service Name. Both transactions and subtransactions will have its own copy.
+     */
+    String SERVICE_NAME = "ServiceName";
+
+    /**
+     * Partner Name Subtransactions will inherit this value from the transaction.
+     */
+    String PARTNER_NAME = "PartnerName";
+
+    /**
+     * Start Timestamp. Both transactions and subtransactions will have its own copy.
+     */
+    String BEGIN_TIMESTAMP = "BeginTimestamp";
+
+    /**
+     * End Timestamp. Both transactions and subtransactions will have its own copy.
+     */
+    String END_TIMESTAMP = "EndTimestamp";
+
+    /**
+     * Elapsed Time. Both transactions and subtransactions will have its own copy.
+     */
+    String ELAPSED_TIME = "ElapsedTime";
+
+    /**
+     * Elapsed Time. Both transactions and subtransactions will have its own copy.
+     */
+    String SERVICE_INSTANCE_ID = "ServiceInstanceID";
+
+    /**
+     * Virtual Server Name. Subtransactions will inherit this value from the transaction.
+     */
+    String VIRTUAL_SERVER_NAME = "VirtualServerName";
+
+    /**
+     * Status Code Both transactions and subtransactions will have its own copy.
+     */
+    String STATUS_CODE = "StatusCode";
+
+    /**
+     * Response Code Both transactions and subtransactions will have its own copy.
+     */
+    String RESPONSE_CODE = "ResponseCode";
+
+    /**
+     * Response Description Both transactions and subtransactions will have its own copy.
+     */
+    String RESPONSE_DESCRIPTION = "ResponseDescription";
+
+    /**
+     * Instance UUID Both transactions and subtransactions will have its own copy.
+     */
+    String INSTANCE_UUID = "InstanceUUID";
+
+    /**
+     * Severity Both transactions and subtransactions will have its own copy.
+     */
+    String SEVERITY = "Severity";
+
+    /**
+     * Target Entity Both transactions and subtransactions will have its own copy.
+     */
+    String TARGET_ENTITY = "TargetEntity";
+
+    /**
+     * Target Service Name Both transactions and subtransactions will have its own copy.
+     */
+    String TARGET_SERVICE_NAME = "TargetServiceName";
+
+    /**
+     * Server Subtransactions inherit this value.    if (this.getSources().size() == 1)
+      this.getSources().get(0).getTopic();
+     */
+    String SERVER = "Server";
+
+    /**
+     * Server IP Address Subtransactions inherit this value.
+     */
+    String SERVER_IP_ADDRESS = "ServerIpAddress";
+
+    /**
+     * Server FQDN Subtransactions inherit this value.
+     */
+    String SERVER_FQDN = "ServerFQDN";
+
+    /**
+     * Client IP Address Both transactions and subtransactions will have its own copy.
+     */
+    String CLIENT_IP_ADDRESS = "ClientIPAddress";
+
+    /**
+     * Process Key Both transactions and subtransactions will have its own copy.
+     */
+    String PROCESS_KEY = "ProcessKey";
+
+    /**
+     * Remote Host Both transactions and subtransactions will have its own copy.
+     */
+    String REMOTE_HOST = "RemoteHost";
+
+    /**
+     * Alert Severity Both transactions and subtransactions will have its own copy.
+     */
+    String ALERT_SEVERITY = "AlertSeverity";
+
+    /**
+     * Target Virtual Entity Both transactions and subtransactions will have its own copy.
+     */
+    String TARGET_VIRTUAL_ENTITY = "TargetVirtualEntity";
+
+    /**
+     * Default Service Name
+     */
+    String DEFAULT_SERVICE_NAME = "PDP-D";
+
+    /**
+     * Default Host Name
+     */
+    String DEFAULT_HOSTNAME = NetworkUtil.getHostname();
+
+    /**
+     * Default Host IP
+     */
+    String DEFAULT_HOSTIP = NetworkUtil.getHostIp();
+
+    /**
+     * Status Code Complete
+     */
+    String STATUS_CODE_COMPLETE = "COMPLETE";
+
+    /**
+     * Status Code Error
+     */
+    String STATUS_CODE_FAILURE = "ERROR";
+
+    /**
+     * reset subtransaction data
+     */
+    MDCTransaction resetSubTransaction();
+
+    /**
+     * resets transaction data
+     */
+    MDCTransaction resetTransaction();
+
+    /**
+     * flush to MDC structure
+     */
+    MDCTransaction flush();
+
+    /**
+     * convenience method to log a metric.  Alternatively caller
+     * could call flush() and the logging statement directly for
+     * further granularity.
+     */
+    MDCTransaction metric();
+
+    /**
+     * convenience method to log a transaction record.  Alternatively caller
+     * could call flush() and the logging statement directly for
+     * further granularity.
+     */
+    MDCTransaction transaction();
+
+    /**
+     * get invocation id
+     */
+    MDCTransaction setInvocationId(String invocationId);
+
+    /**
+     * set start time
+     */
+    MDCTransaction setStartTime(Instant startTime);
+
+    /**
+     * set service name
+     */
+    MDCTransaction setServiceName(String serviceName);
+
+    /**
+     * set status code
+     */
+    MDCTransaction setStatusCode(String statusCode);
+
+    /**
+     * set status code
+     */
+    MDCTransaction setStatusCode(boolean success);
+
+    /**
+     * sets response code
+     */
+    MDCTransaction setResponseCode(String responseCode);
+
+    /**
+     * sets response description
+     */
+    MDCTransaction setResponseDescription(String responseDescription);
+
+    /**
+     * sets instance uuid
+     */
+    MDCTransaction setInstanceUUID(String instanceUUID);
+
+    /**
+     * set severity
+     */
+    MDCTransaction setSeverity(String severity);
+
+    /**
+     * set target entity
+     */
+    MDCTransaction setTargetEntity(String targetEntity);
+
+    /**
+     * set target service name
+     */
+    MDCTransaction setTargetServiceName(String targetServiceName);
+
+    /**
+     * set target virtual entity
+     */
+    MDCTransaction setTargetVirtualEntity(String targetVirtualEntity);
+
+    /**
+     * set request id
+     */
+    MDCTransaction setRequestId(String requestId);
+
+    /**
+     * set partner
+     */
+    MDCTransaction setPartner(String partner);
+
+    /**
+     * set server
+     */
+    MDCTransaction setServer(String server);
+
+    /**
+     * set server ip address
+     */
+    MDCTransaction setServerIpAddress(String serverIpAddress);
+
+    /**
+     * set server fqdn
+     */
+    MDCTransaction setServerFqdn(String serverFqdn);
+
+    /**
+     * set virtual server
+     */
+    MDCTransaction setVirtualServerName(String virtualServerName);
+    /**
+     * sets end time
+     */
+    MDCTransaction setEndTime(Instant endTime);
+
+    /**
+     * sets elapsed time
+     */
+    MDCTransaction setElapsedTime(Long elapsedTime);
+
+    /**
+     * sets service instance id
+     */
+    MDCTransaction setServiceInstanceId(String serviceInstanceId);
+
+    /**
+     * sets process key
+     */
+    MDCTransaction setProcessKey(String processKey);
+
+    /**
+     * sets alert severity
+     */
+    MDCTransaction setAlertSeverity(String alertSeverity);
+
+    /**
+     * sets client ip address
+     */
+    MDCTransaction setClientIpAddress(String clientIpAddress);
+
+    /**
+     * sets remote host
+     */
+    MDCTransaction setRemoteHost(String remoteHost);
+
+    /**
+     * get start time
+     */
+    Instant getStartTime();
+
+    /**
+     * get server
+     */
+    String getServer();
+
+    /**
+     * get end time
+     */
+    Instant getEndTime();
+
+    /**
+     * get elapsed time
+     */
+    Long getElapsedTime();
+
+    /**
+     * get remote host
+     */
+    String getRemoteHost();
+
+    /**
+     * get client ip address
+     */
+    String getClientIpAddress();
+
+    /**
+     * get alert severity
+     */
+    String getAlertSeverity();
+
+    /**
+     * get process key
+     */
+    String getProcessKey();
+
+    /**
+     * get service instance id
+     */
+    String getServiceInstanceId();
+
+    /**
+     * get invocation id
+     */
+    String getInvocationId();
+
+    /**
+     * get service name
+     */
+    String getServiceName();
+
+    /**
+     * get status code
+     */
+    String getStatusCode();
+
+    /**
+     * get response description
+     */
+    String getResponseDescription();
+
+    /**
+     * get instance uuid
+     */
+    String getInstanceUUID();
+
+    /**
+     * get severity
+     */
+    String getSeverity();
+
+    /**
+     * get target entity
+     */
+    String getTargetEntity();
+
+    /**
+     * get service name
+     */
+    String getTargetServiceName();
+
+    /**
+     * get target virtual entity
+     */
+    String getTargetVirtualEntity();
+
+    /**
+     * get response code
+     */
+    String getResponseCode();
+
+    /**
+     * get request id
+     */
+    String getRequestId();
+
+    /**
+     * get partner
+     */
+    String getPartner();
+
+    /**
+     * get server fqdn
+     */
+    String getServerFqdn();
+
+    /**
+     * get virtual server name
+     */
+    String getVirtualServerName();
+
+    /**
+     * get server ip
+     */
+    String getServerIpAddress();
+
+    /**
+     * generate timestamp used for logging
+     */
+    String timestamp(Instant time);
+
+    /**
+     * create new MDC Transaction
+     *
+     * @param requestId transaction Id
+     * @param partner requesting partner
+     *
+     * @return MDC Transaction
+     */
+    static MDCTransaction newTransaction(String requestId, String partner) {
+        return new MDCTransactionImpl(requestId, partner);
+    }
+
+    /**
+     * create new MDC Transaction
+     */
+    static MDCTransaction newTransaction() {
+        return new MDCTransactionImpl();
+    }
+
+    /**
+     * create new subtransaction
+     *
+     * @param invocationId sub-transaction od
+     * @return MDC Transaction
+     */
+    static MDCTransaction newSubTransaction(String invocationId) {
+        return new MDCTransactionImpl(invocationId);
+    }
+
+    /**
+     * create transaction from an existing one
+     *
+     * @param transaction transaction
+     * @return MDC Transaction
+     */
+    static MDCTransaction fromTransaction(MDCTransaction transaction) {
+        return new MDCTransactionImpl(transaction);
+    }
+
+}
+
+class MDCTransactionImpl implements MDCTransaction {
+
+    private final static Logger logger = LoggerFactory.getLogger(MDCTransactionImpl.class.getName());
+
+    /**
+     * Logging Format for Timestamps
+     */
+
+    private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS+00:00";
+
+    /* transaction inheritable fields */
+
+    private String requestId;
+    private String partner;
+
+    private String invocationId;
+    private String virtualServerName;
+    private String server;
+    private String serverIpAddress;
+    private String serverFqdn;
+
+    private String serviceName;
+
+    private Instant startTime;
+    private Instant endTime;
+    private Long elapsedTime;
+
+    private String serviceInstanceId;
+    private String instanceUUID;
+    private String processKey;
+
+    private String statusCode;
+    private String responseCode;
+    private String responseDescription;
+    private String severity;
+    private String alertSeverity;
+
+    private String targetEntity;
+    private String targetServiceName;
+    private String targetVirtualEntity;
+    private String clientIpAddress;
+    private String remoteHost;
+
+    /**
+     * Transaction with no information set
+     */
+    public MDCTransactionImpl() {
+        MDC.clear();
+    }
+
+    /**
+     * MDC Transaction
+     *
+     * @param requestId  transaction id
+     * @param partner    transaction origin
+     */
+    public MDCTransactionImpl(String requestId, String partner) {
+        MDC.clear();
+
+        this.setRequestId(requestId);
+        this.setPartner(partner);
+
+        this.setServiceName(DEFAULT_SERVICE_NAME);
+        this.setServer(DEFAULT_HOSTNAME);
+        this.setServerIpAddress(DEFAULT_HOSTIP);
+        this.setServerFqdn(DEFAULT_HOSTNAME);
+        this.setVirtualServerName(DEFAULT_HOSTNAME);
+
+        this.setStartTime(Instant.now());
+    }
+
+    /**
+     * create subtransaction
+     *
+     * @param invocationId subtransaction id
+     */
+    public MDCTransactionImpl(String invocationId) {
+        this.resetSubTransaction();
+
+        this.setRequestId(MDC.get(REQUEST_ID));
+        this.setPartner(MDC.get(PARTNER_NAME));
+        this.setServiceName(MDC.get(SERVICE_NAME));
+        this.setServer(MDC.get(SERVER));
+        this.setServerIpAddress(MDC.get(SERVER_IP_ADDRESS));
+        this.setServerFqdn(MDC.get(SERVER_FQDN));
+        this.setVirtualServerName(MDC.get(VIRTUAL_SERVER_NAME));
+
+        this.setStartTime(Instant.now());
+        this.setInvocationId(invocationId);
+    }
+
+    /**
+     * copy constructor transaction/subtransaction
+     *
+     * @param transaction
+     */
+    public MDCTransactionImpl(MDCTransaction transaction) {
+        MDC.clear();
+        this.setAlertSeverity(transaction.getAlertSeverity());
+        this.setClientIpAddress(transaction.getClientIpAddress());
+        this.setElapsedTime(transaction.getElapsedTime());
+        this.setEndTime(transaction.getEndTime());
+        this.setInstanceUUID(transaction.getInstanceUUID());
+        this.setInvocationId(transaction.getInvocationId());
+        this.setPartner(transaction.getPartner());
+        this.setProcessKey(transaction.getProcessKey());
+        this.setRemoteHost(transaction.getRemoteHost());
+        this.setRequestId(transaction.getRequestId());
+        this.setResponseCode(transaction.getResponseCode());
+        this.setResponseDescription(transaction.getResponseDescription());
+        this.setServer(transaction.getServer());
+        this.setServerFqdn(transaction.getServerFqdn());
+        this.setServerIpAddress(transaction.getServerIpAddress());
+        this.setServiceInstanceId(transaction.getServiceInstanceId());
+        this.setServiceName(transaction.getServiceName());
+        this.setSeverity(transaction.getSeverity());
+        this.setStartTime(transaction.getStartTime());
+        this.setStatusCode(transaction.getStatusCode());
+        this.setTargetEntity(transaction.getTargetEntity());
+        this.setTargetServiceName(transaction.getTargetServiceName());
+        this.setTargetVirtualEntity(transaction.getTargetVirtualEntity());
+        this.setVirtualServerName(transaction.getVirtualServerName());
+    }
+
+    /**
+     * reset subtransaction portion
+     *
+     * @return MDCTransaction
+     */
+    @Override
+    public MDCTransaction resetSubTransaction() {
+       MDC.remove(INVOCATION_ID);
+       MDC.remove(BEGIN_TIMESTAMP);
+       MDC.remove(END_TIMESTAMP);
+       MDC.remove(ELAPSED_TIME);
+       MDC.remove(SERVICE_INSTANCE_ID);
+       MDC.remove(STATUS_CODE);
+       MDC.remove(RESPONSE_CODE);
+       MDC.remove(RESPONSE_DESCRIPTION);
+       MDC.remove(INSTANCE_UUID);
+       MDC.remove(TARGET_ENTITY);
+       MDC.remove(TARGET_SERVICE_NAME);
+       MDC.remove(PROCESS_KEY);
+       MDC.remove(CLIENT_IP_ADDRESS);
+       MDC.remove(REMOTE_HOST);
+       MDC.remove(ALERT_SEVERITY);
+       MDC.remove(TARGET_VIRTUAL_ENTITY);
+
+       return this;
+    }
+
+    @Override
+    public MDCTransaction resetTransaction() {
+        MDC.clear();
+        return this;
+    }
+
+    /**
+     * flush transaction to MDC
+     */
+    @Override
+    public MDCTransaction flush() {
+        if (this.requestId != null && !this.requestId.isEmpty())
+            MDC.put(REQUEST_ID, this.requestId);
+
+        if (this.invocationId != null && !this.invocationId.isEmpty())
+            MDC.put(INVOCATION_ID, this.invocationId);
+
+        if (this.partner != null)
+            MDC.put(PARTNER_NAME, this.partner);
+
+        if (this.virtualServerName != null)
+            MDC.put(VIRTUAL_SERVER_NAME, this.virtualServerName);
+
+        if (this.server != null)
+            MDC.put(SERVER, this.server);
+
+        if (this.serverIpAddress != null)
+            MDC.put(SERVER_IP_ADDRESS, this.serverIpAddress);
+
+        if (this.serverFqdn != null)
+            MDC.put(SERVER_FQDN, this.serverFqdn);
+
+        if (this.serviceName != null)
+            MDC.put(SERVICE_NAME, this.serviceName);
+
+        if (this.startTime != null)
+            MDC.put(BEGIN_TIMESTAMP, timestamp(this.startTime));
+
+        if (this.endTime != null) {
+            MDC.put(END_TIMESTAMP, timestamp(this.endTime));
+        } else {
+            this.setEndTime(null);
+            MDC.put(END_TIMESTAMP, timestamp(this.endTime));
+        }
+
+        if (this.elapsedTime != null) {
+            MDC.put(ELAPSED_TIME, String.valueOf(this.elapsedTime));
+        } else {
+            if (endTime != null && startTime != null) {
+                 this.elapsedTime = Duration.between(startTime, endTime).toMillis();
+                MDC.put(ELAPSED_TIME, String.valueOf(this.elapsedTime));
+            }
+        }
+
+        if (this.serviceInstanceId != null)
+            MDC.put(SERVICE_INSTANCE_ID, this.serviceInstanceId);
+
+        if (this.instanceUUID != null)
+            MDC.put(INSTANCE_UUID, this.instanceUUID);
+
+        if (this.processKey != null)
+            MDC.put(PROCESS_KEY, this.processKey);
+
+        if (this.statusCode != null)
+            MDC.put(STATUS_CODE, this.statusCode);
+
+        if (this.responseCode != null)
+            MDC.put(RESPONSE_CODE, this.responseCode);
+
+        if (this.responseDescription != null)
+            MDC.put(RESPONSE_DESCRIPTION, this.responseDescription);
+
+        if (this.severity != null)
+            MDC.put(SEVERITY, this.severity);
+
+        if (this.alertSeverity != null)
+            MDC.put(ALERT_SEVERITY, this.alertSeverity);
+
+        if (this.targetEntity != null)
+            MDC.put(TARGET_ENTITY, this.targetEntity);
+
+        if (this.targetServiceName != null)
+            MDC.put(TARGET_SERVICE_NAME, this.targetServiceName);
+
+        if (this.targetVirtualEntity != null)
+            MDC.put(TARGET_VIRTUAL_ENTITY, this.targetVirtualEntity);
+
+        if (this.clientIpAddress != null)
+            MDC.put(CLIENT_IP_ADDRESS, this.clientIpAddress);
+
+        if (this.remoteHost != null)
+            MDC.put(REMOTE_HOST, this.remoteHost);
+
+        return this;
+    }
+
+    @Override
+    public MDCTransaction metric() {
+        this.flush();
+        logger.info(LoggerUtil.METRIC_LOG_MARKER, "");
+        return this;
+    }
+
+    @Override
+    public MDCTransaction transaction() {
+        this.flush();
+        logger.info(LoggerUtil.TRANSACTION_LOG_MARKER, "");
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setEndTime(Instant endTime) {
+        if (endTime == null) {
+            this.endTime = Instant.now();
+        } else {
+            this.endTime = endTime;
+        }
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setElapsedTime(Long elapsedTime) {
+        this.elapsedTime = elapsedTime;
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setServiceInstanceId(String serviceInstanceId) {
+        this.serviceInstanceId = serviceInstanceId;
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setProcessKey(String processKey) {
+        this.processKey = processKey;
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setAlertSeverity(String alertSeverity) {
+        this.alertSeverity = alertSeverity;
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setClientIpAddress(String clientIpAddress) {
+        this.clientIpAddress = clientIpAddress;
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setRemoteHost(String remoteHost) {
+        this.remoteHost = remoteHost;
+        return this;
+    }
+
+    @Override
+    public Instant getStartTime() {
+        return this.startTime;
+    }
+
+    @Override
+    public String getServer() {
+        return this.server;
+    }
+
+    @Override
+    public Instant getEndTime() {
+        return this.endTime;
+    }
+
+    @Override
+    public Long getElapsedTime() {
+        return this.elapsedTime;
+    }
+
+    @Override
+    public String getRemoteHost() {
+        return this.remoteHost;
+    }
+
+    @Override
+    public String getClientIpAddress() {
+        return this.clientIpAddress;
+    }
+
+    @Override
+    public String getAlertSeverity() {
+        return this.alertSeverity;
+    }
+
+    @Override
+    public String getProcessKey() {
+        return this.processKey;
+    }
+
+    @Override
+    public String getServiceInstanceId() {
+        return this.serviceInstanceId;
+    }
+
+    /* transaction and subtransaction fields */
+
+    @Override
+    public MDCTransaction setInvocationId(String invocationId) {
+        if (invocationId == null) {
+            this.invocationId = UUID.randomUUID().toString();
+        } else {
+            this.invocationId = invocationId;
+        }
+
+        MDC.put(INVOCATION_ID, this.invocationId);
+
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setStartTime(Instant startTime) {
+        if (startTime == null) {
+            this.startTime = Instant.now();
+        } else {
+            this.startTime = startTime;
+        }
+
+        MDC.put(BEGIN_TIMESTAMP, this.timestamp(this.startTime));
+
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setServiceName(String serviceName) {
+        if (serviceName == null || serviceName.isEmpty()) {
+            this.serviceName = DEFAULT_SERVICE_NAME;
+        } else {
+            this.serviceName = serviceName;
+        }
+
+        MDC.put(SERVICE_NAME, this.serviceName);
+
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setStatusCode(String statusCode) {
+        this.statusCode = statusCode;
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setStatusCode(boolean success) {
+        if (success) {
+            this.statusCode = STATUS_CODE_COMPLETE;
+        } else {
+            this.statusCode = STATUS_CODE_FAILURE;
+        }
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setResponseCode(String responseCode) {
+        this.responseCode = responseCode;
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setResponseDescription(String responseDescription) {
+        this.responseDescription = responseDescription;
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setInstanceUUID(String instanceUUID) {
+        if (instanceUUID == null) {
+            this.instanceUUID = UUID.randomUUID().toString();
+        } else {
+            this.instanceUUID = instanceUUID;
+        }
+
+        MDC.put(INSTANCE_UUID, this.instanceUUID);
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setSeverity(String severity) {
+        this.severity = severity;
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setTargetEntity(String targetEntity) {
+        this.targetEntity = targetEntity;
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setTargetServiceName(String targetServiceName) {
+        this.targetServiceName = targetServiceName;
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setTargetVirtualEntity(String targetVirtualEntity) {
+        this.targetVirtualEntity = targetVirtualEntity;
+        return this;
+    }
+
+    @Override
+    public String getInvocationId() {
+        return invocationId;
+    }
+
+    @Override
+    public String getServiceName() {
+        return serviceName;
+    }
+
+    @Override
+    public String getStatusCode() {
+        return statusCode;
+    }
+
+    @Override
+    public String getResponseDescription() {
+        return responseDescription;
+    }
+
+    @Override
+    public String getInstanceUUID() {
+        return instanceUUID;
+    }
+
+    @Override
+    public String getSeverity() {
+        return severity;
+    }
+
+    @Override
+    public String getTargetEntity() {
+        return targetEntity;
+    }
+
+    @Override
+    public String getTargetServiceName() {
+        return targetServiceName;
+    }
+
+    @Override
+    public String getTargetVirtualEntity() {
+        return targetVirtualEntity;
+    }
+
+    @Override
+    public String getResponseCode() {
+        return responseCode;
+    }
+
+    /* inheritable fields by subtransactions via MDC */
+
+    @Override
+    public MDCTransaction setRequestId(String requestId) {
+        if (requestId == null || requestId.isEmpty()) {
+            this.requestId = UUID.randomUUID().toString();
+        } else {
+            this.requestId = requestId;
+        }
+
+        MDC.put(REQUEST_ID, this.requestId);
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setPartner(String partner) {
+        if (partner == null || partner.isEmpty()) {
+            this.partner = DEFAULT_SERVICE_NAME;
+        } else {
+            this.partner = partner;
+        }
+
+        MDC.put(PARTNER_NAME, this.partner);
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setServer(String server) {
+        if (server == null || server.isEmpty()) {
+            this.server = DEFAULT_HOSTNAME;
+        } else {
+            this.server = server;
+        }
+
+        MDC.put(SERVER, this.server);
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setServerIpAddress(String serverIpAddress) {
+        if (serverIpAddress == null || serverIpAddress.isEmpty()) {
+            this.serverIpAddress = DEFAULT_HOSTIP;
+        } else {
+            this.serverIpAddress = serverIpAddress;
+        }
+
+        MDC.put(SERVER_IP_ADDRESS, this.serverIpAddress);
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setServerFqdn(String serverFqdn) {
+        if (serverFqdn == null || serverFqdn.isEmpty()) {
+            this.serverFqdn = DEFAULT_HOSTNAME;
+        } else {
+            this.serverFqdn = serverFqdn;
+        }
+
+        MDC.put(SERVER_FQDN, this.serverFqdn);
+        return this;
+    }
+
+    @Override
+    public MDCTransaction setVirtualServerName(String virtualServerName) {
+        if (virtualServerName == null || virtualServerName.isEmpty()) {
+            this.virtualServerName = DEFAULT_HOSTNAME;
+        } else {
+            this.virtualServerName = virtualServerName;
+        }
+
+        MDC.put(VIRTUAL_SERVER_NAME, this.virtualServerName);
+        return this;
+    }
+
+    @Override
+    public String getRequestId() {
+        return requestId;
+    }
+
+    @Override
+    public String getPartner() {
+        return partner;
+    }
+
+    @Override
+    public String getServerFqdn() {
+        return serverFqdn;
+    }
+
+    @Override
+    public String getVirtualServerName() {
+        return virtualServerName;
+    }
+
+    @Override
+    public String getServerIpAddress() {
+        return serverIpAddress;
+    }
+
+    @Override
+    public String timestamp(Instant time) {
+        return new SimpleDateFormat(DATE_FORMAT).format(Date.from(time));
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("MDCTransaction{");
+        sb.append("requestId='").append(requestId).append('\'');
+        sb.append(", partner='").append(partner).append('\'');
+        sb.append(", invocationId='").append(invocationId).append('\'');
+        sb.append(", virtualServerName='").append(virtualServerName).append('\'');
+        sb.append(", server='").append(server).append('\'');
+        sb.append(", serverIpAddress='").append(serverIpAddress).append('\'');
+        sb.append(", serverFqdn='").append(serverFqdn).append('\'');
+        sb.append(", serviceName='").append(serviceName).append('\'');
+        sb.append(", startTime=").append(startTime);
+        sb.append(", endTime=").append(endTime);
+        sb.append(", elapsedTime=").append(elapsedTime);
+        sb.append(", serviceInstanceId='").append(serviceInstanceId).append('\'');
+        sb.append(", instanceUUID='").append(instanceUUID).append('\'');
+        sb.append(", processKey='").append(processKey).append('\'');
+        sb.append(", statusCode='").append(statusCode).append('\'');
+        sb.append(", responseCode='").append(responseCode).append('\'');
+        sb.append(", responseDescription='").append(responseDescription).append('\'');
+        sb.append(", severity='").append(severity).append('\'');
+        sb.append(", alertSeverity='").append(alertSeverity).append('\'');
+        sb.append(", targetEntity='").append(targetEntity).append('\'');
+        sb.append(", targetServiceName='").append(targetServiceName).append('\'');
+        sb.append(", targetVirtualEntity='").append(targetVirtualEntity).append('\'');
+        sb.append(", clientIpAddress='").append(clientIpAddress).append('\'');
+        sb.append(", remoteHost='").append(remoteHost).append('\'');
+        sb.append('}');
+        return sb.toString();
+    }
+
+}
index c8b7735..406cdae 100644 (file)
@@ -32,6 +32,8 @@ public class NetworkUtilTest {
        public void test() throws InterruptedException, IOException {
                assertNotNull(NetworkUtil.IPv4_WILDCARD_ADDRESS);
                assertFalse(NetworkUtil.isTcpPortOpen("localhost", 8080, 1, 5));
+               assertNotNull(NetworkUtil.getHostname());
+               assertNotNull(NetworkUtil.getHostIp());
        }
 
 }
  * limitations under the License.
  * ============LICENSE_END=========================================================
  */
-package org.onap.policy.drools.utils;
+package org.onap.policy.drools.utils.logging;
 
 import static org.junit.Assert.*;
 
 import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class LoggerUtilTest {
 
        @Test
        public void test() {
-               assertNotNull(LoggerUtil.setLevel("foo", "warn"));
+
+               Logger logger = LoggerFactory.getLogger(LoggerUtilTest.class);
+
+               assertTrue(logger.isInfoEnabled());
+
+           logger.info("line 1");
+               logger.info(LoggerUtil.METRIC_LOG_MARKER, "line 1 Metric");
+               logger.info(LoggerUtil.TRANSACTION_LOG_MARKER, "line 1 Transaction");
+
+               LoggerUtil.setLevel(LoggerUtil.ROOT_LOGGER, "warn");
+               logger.info("line 2");
+               logger.info(LoggerUtil.METRIC_LOG_MARKER, "line 2 Metric");
+               logger.info(LoggerUtil.TRANSACTION_LOG_MARKER, "line 2 Transaction");
+
+               assertFalse(logger.isInfoEnabled());
+
+               LoggerUtil.setLevel(LoggerUtil.ROOT_LOGGER, "debug");
+               logger.debug("line 3");
+               logger.debug(LoggerUtil.METRIC_LOG_MARKER, "line 3 Metric");
+               logger.debug(LoggerUtil.TRANSACTION_LOG_MARKER, "line 3 Transaction");
+
+               assertTrue(logger.isDebugEnabled());
        }
 
 }
diff --git a/policy-utils/src/test/java/org/onap/policy/drools/utils/logging/MDCTransactionTest.java b/policy-utils/src/test/java/org/onap/policy/drools/utils/logging/MDCTransactionTest.java
new file mode 100644 (file)
index 0000000..f6c48da
--- /dev/null
@@ -0,0 +1,265 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * policy-utils
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onap.policy.drools.utils.logging;
+
+import static org.junit.Assert.*;
+
+import java.time.Duration;
+import java.time.Instant;
+import org.junit.Test;
+import org.slf4j.MDC;
+
+public class MDCTransactionTest {
+
+    @Test
+    public void resetSubTransaction() {
+        MDCTransaction trans =
+            MDCTransaction.newTransaction(null, null).resetSubTransaction();
+
+        assertNotNull(trans.getRequestId());
+        assertNotNull(trans.getPartner());
+        assertNotNull(trans.getServiceName());
+        assertNotNull(trans.getServer());
+        assertNotNull(trans.getServerIpAddress());
+        assertNotNull(trans.getServerFqdn());
+        assertNotNull(trans.getVirtualServerName());
+        assertNotNull(trans.getStartTime());
+
+        assertNullSubTransactionFields(trans);
+
+        assertNotNull(MDC.get(MDCTransaction.REQUEST_ID));
+        assertNotNull(MDC.get(MDCTransaction.PARTNER_NAME));
+        assertNotNull(MDC.get(MDCTransaction.VIRTUAL_SERVER_NAME));
+        assertNotNull(MDC.get(MDCTransaction.SERVER));
+        assertNotNull(MDC.get(MDCTransaction.SERVER_IP_ADDRESS));
+        assertNotNull(MDC.get(MDCTransaction.SERVER_FQDN));
+        assertNotNull(MDC.get(MDCTransaction.SERVICE_NAME));
+
+        assertNull(MDC.get(MDCTransaction.INVOCATION_ID));
+        assertNull(MDC.get(MDCTransaction.BEGIN_TIMESTAMP));
+        assertNull(MDC.get(MDCTransaction.END_TIMESTAMP));
+        assertNull(MDC.get(MDCTransaction.ELAPSED_TIME));
+        assertNull(MDC.get(MDCTransaction.SERVICE_INSTANCE_ID));
+        assertNull(MDC.get(MDCTransaction.INSTANCE_UUID));
+        assertNull(MDC.get(MDCTransaction.PROCESS_KEY));
+        assertNull(MDC.get(MDCTransaction.STATUS_CODE));
+        assertNull(MDC.get(MDCTransaction.RESPONSE_CODE));
+        assertNull(MDC.get(MDCTransaction.RESPONSE_DESCRIPTION));
+        assertNull(MDC.get(MDCTransaction.SEVERITY));
+        assertNull(MDC.get(MDCTransaction.ALERT_SEVERITY));
+        assertNull(MDC.get(MDCTransaction.TARGET_ENTITY));
+        assertNull(MDC.get(MDCTransaction.TARGET_SERVICE_NAME));
+        assertNull(MDC.get(MDCTransaction.TARGET_VIRTUAL_ENTITY));
+        assertNull(MDC.get(MDCTransaction.CLIENT_IP_ADDRESS));
+        assertNull(MDC.get(MDCTransaction.REMOTE_HOST));
+
+        assertEquals(trans.getRequestId(), MDC.get(MDCTransaction.REQUEST_ID));
+        assertEquals(trans.getPartner(), MDC.get(MDCTransaction.PARTNER_NAME));
+        assertEquals(trans.getVirtualServerName(), MDC.get(MDCTransaction.VIRTUAL_SERVER_NAME));
+        assertEquals(trans.getServer(), MDC.get(MDCTransaction.SERVER));
+        assertEquals(trans.getServerIpAddress(), MDC.get(MDCTransaction.SERVER_IP_ADDRESS));
+        assertEquals(trans.getServerFqdn(), MDC.get(MDCTransaction.SERVER_FQDN));
+        assertEquals(trans.getServiceName(), MDC.get(MDCTransaction.SERVICE_NAME));
+    }
+
+    private void assertNullSubTransactionFields(MDCTransaction trans) {
+        assertNull(trans.getInvocationId());
+        assertNullSubTransactionFieldsButInvocationId(trans);
+    }
+
+    private void assertNullSubTransactionFieldsButInvocationId(MDCTransaction trans) {
+        assertNull(trans.getEndTime());
+        assertNull(trans.getElapsedTime());
+        assertNull(trans.getServiceInstanceId());
+        assertNull(trans.getStatusCode());
+        assertNull(trans.getResponseCode());
+        assertNull(trans.getResponseDescription());
+        assertNull(trans.getInstanceUUID());
+        assertNull(trans.getTargetEntity());
+        assertNull(trans.getTargetServiceName());
+        assertNull(trans.getProcessKey());
+        assertNull(trans.getClientIpAddress());
+        assertNull(trans.getRemoteHost());
+        assertNull(trans.getAlertSeverity());
+        assertNull(trans.getTargetVirtualEntity());
+    }
+
+    protected void assertTransactionFields(MDCTransaction trans) {
+        assertEquals(trans.getRequestId(), MDC.get(MDCTransaction.REQUEST_ID));
+        assertEquals(trans.getPartner(), MDC.get(MDCTransaction.PARTNER_NAME));
+        assertEquals(trans.getVirtualServerName(), MDC.get(MDCTransaction.VIRTUAL_SERVER_NAME));
+        assertEquals(trans.getServer(), MDC.get(MDCTransaction.SERVER));
+        assertEquals(trans.getServerIpAddress(), MDC.get(MDCTransaction.SERVER_IP_ADDRESS));
+        assertEquals(trans.getServerFqdn(), MDC.get(MDCTransaction.SERVER_FQDN));
+        assertEquals(trans.getServiceName(), MDC.get(MDCTransaction.SERVICE_NAME));
+
+    }
+
+    @Test
+    public void flush() {
+        MDCTransaction trans =
+            MDCTransaction.newTransaction().
+                setRequestId(null).
+                setInvocationId(null).
+                setPartner(null).
+                setVirtualServerName(null).
+                setServer(null).
+                setServerIpAddress(null).
+                setServerFqdn(null).
+                setServiceName(null).
+                setStartTime(null).
+                setEndTime(null).
+                setServiceInstanceId("service-instance-id").
+                setInstanceUUID(null).
+                setProcessKey("process-key").
+                setStatusCode("status-code").
+                setResponseCode("response-code").
+                setResponseDescription("response-description").
+                setSeverity("severity").
+                setAlertSeverity("alert-severity").
+                setTargetEntity("target-entity").
+                setTargetServiceName("target-service-name").
+                setTargetVirtualEntity("target-virtual-entity").
+                setClientIpAddress("client-ip-address").
+                setRemoteHost("remote-host").
+                flush();
+
+        assertTransactionFields(trans);
+
+        assertNotNull(MDC.get(MDCTransaction.INVOCATION_ID));
+        assertNotNull(MDC.get(MDCTransaction.BEGIN_TIMESTAMP));
+        assertNotNull(MDC.get(MDCTransaction.END_TIMESTAMP));
+        assertNotNull(MDC.get(MDCTransaction.ELAPSED_TIME));
+        assertNotNull(MDC.get(MDCTransaction.SERVICE_INSTANCE_ID));
+        assertNotNull(MDC.get(MDCTransaction.INSTANCE_UUID));
+        assertNotNull(MDC.get(MDCTransaction.PROCESS_KEY));
+        assertNotNull(MDC.get(MDCTransaction.STATUS_CODE));
+        assertNotNull(MDC.get(MDCTransaction.RESPONSE_CODE));
+        assertNotNull(MDC.get(MDCTransaction.RESPONSE_DESCRIPTION));
+        assertNotNull(MDC.get(MDCTransaction.SEVERITY));
+        assertNotNull(MDC.get(MDCTransaction.ALERT_SEVERITY));
+        assertNotNull(MDC.get(MDCTransaction.TARGET_ENTITY));
+        assertNotNull(MDC.get(MDCTransaction.TARGET_SERVICE_NAME));
+        assertNotNull(MDC.get(MDCTransaction.TARGET_VIRTUAL_ENTITY));
+        assertNotNull(MDC.get(MDCTransaction.CLIENT_IP_ADDRESS));
+        assertNotNull(MDC.get(MDCTransaction.REMOTE_HOST));
+
+        assertEquals(trans.getInvocationId(), MDC.get(MDCTransaction.INVOCATION_ID));
+        assertEquals(trans.timestamp(trans.getStartTime()), MDC.get(MDCTransaction.BEGIN_TIMESTAMP));
+        assertEquals(trans.timestamp(trans.getEndTime()), MDC.get(MDCTransaction.END_TIMESTAMP));
+        assertNotEquals(trans.getElapsedTime(), MDC.get(MDCTransaction.ELAPSED_TIME));
+        assertEquals(String.valueOf(Duration.between(trans.getStartTime(), trans.getEndTime()).toMillis()),
+            MDC.get(MDCTransaction.ELAPSED_TIME));
+        assertEquals(trans.getServiceInstanceId(), MDC.get(MDCTransaction.SERVICE_INSTANCE_ID));
+        assertEquals(trans.getInstanceUUID(), MDC.get(MDCTransaction.INSTANCE_UUID));
+        assertEquals(trans.getProcessKey(),MDC.get(MDCTransaction.PROCESS_KEY));
+        assertEquals(trans.getStatusCode(), MDC.get(MDCTransaction.STATUS_CODE));
+        assertEquals(trans.getResponseCode(), MDC.get(MDCTransaction.RESPONSE_CODE));
+        assertEquals(trans.getResponseDescription(), MDC.get(MDCTransaction.RESPONSE_DESCRIPTION));
+        assertEquals(trans.getSeverity(), MDC.get(MDCTransaction.SEVERITY));
+        assertEquals(trans.getAlertSeverity(), MDC.get(MDCTransaction.ALERT_SEVERITY));
+        assertEquals(trans.getTargetEntity(), MDC.get(MDCTransaction.TARGET_ENTITY));
+        assertEquals(trans.getTargetServiceName(), MDC.get(MDCTransaction.TARGET_SERVICE_NAME));
+        assertEquals(trans.getTargetVirtualEntity(), MDC.get(MDCTransaction.TARGET_VIRTUAL_ENTITY));
+        assertEquals(trans.getClientIpAddress(), MDC.get(MDCTransaction.CLIENT_IP_ADDRESS));
+        assertEquals(trans.getRemoteHost(), MDC.get(MDCTransaction.REMOTE_HOST));
+
+        assertEquals(trans.getServiceInstanceId(),"service-instance-id");
+        assertEquals(trans.getProcessKey(),"process-key");
+        assertEquals(trans.getStatusCode(),"status-code");
+        assertEquals(trans.getResponseCode(),"response-code");
+        assertEquals(trans.getResponseDescription(),"response-description");
+        assertEquals(trans.getSeverity(),"severity");
+        assertEquals(trans.getAlertSeverity(),"alert-severity");
+        assertEquals(trans.getTargetEntity(),"target-entity");
+        assertEquals(trans.getTargetServiceName(),"target-service-name");
+        assertEquals(trans.getTargetVirtualEntity(),"target-virtual-entity");
+        assertEquals(trans.getClientIpAddress(),"client-ip-address");
+        assertEquals(trans.getRemoteHost(),"remote-host");
+    }
+
+    @Test
+    public void metric() {
+        MDCTransaction trans =
+            MDCTransaction.newTransaction(null, null).metric();
+
+        assertTransactionFields(trans);
+    }
+
+    @Test
+    public void transaction() {
+        MDCTransaction trans =
+            MDCTransaction.newTransaction(null, null).transaction();
+
+        assertTransactionFields(trans);
+    }
+
+    @Test
+    public void subTransaction() {
+        MDCTransaction trans =
+            MDCTransaction.newTransaction(null, "partner");
+
+        MDCTransaction subTrans = MDCTransaction.newSubTransaction(null);
+
+        assertTransactionFields(trans);
+        assertTransactionFields(subTrans);
+
+        assertEquals(trans.getRequestId(), trans.getRequestId());
+        assertEquals(trans.getPartner(), trans.getPartner());
+        assertEquals(trans.getVirtualServerName(), trans.getVirtualServerName());
+        assertEquals(trans.getServer(), trans.getServer());
+        assertEquals(trans.getServerIpAddress(), trans.getServerIpAddress());
+        assertEquals(trans.getServerFqdn(), trans.getServerFqdn());
+        assertEquals(trans.getServiceName(), trans.getServiceName());
+
+        assertNotEquals(trans.getInvocationId(), subTrans.getInvocationId());
+        assertNull(trans.getInvocationId());
+        assertNotNull(subTrans.getInvocationId());
+
+        assertNotNull(subTrans.getStartTime());
+        assertNullSubTransactionFieldsButInvocationId(trans);
+
+        subTrans.setServiceInstanceId("service-instance-id").
+            setInstanceUUID(null).
+            setProcessKey("process-key").
+            setStatusCode("status-code").
+            setResponseCode("response-code").
+            setResponseDescription("response-description").
+            setSeverity("severity").
+            setAlertSeverity("alert-severity").
+            setTargetEntity("target-entity").
+            setTargetServiceName("target-service-name").
+            setTargetVirtualEntity("target-virtual-entity").
+            setClientIpAddress("client-ip-address").
+            setRemoteHost("remote-host").
+            setEndTime(Instant.now());
+
+        subTrans.setStatusCode(false).setResponseCode("400");
+
+        MDCTransaction subTrans2 = MDCTransaction.fromTransaction(subTrans);
+
+        assertEquals(subTrans.toString(), subTrans2.toString());
+
+        subTrans.metric();
+        subTrans2.setStatusCode("202").setProcessKey("junit").metric();
+
+        trans.resetSubTransaction().setStatusCode(true).setResponseCode("200").metric();
+    }
+
+}
\ No newline at end of file
diff --git a/policy-utils/src/test/resources/logback-test.xml b/policy-utils/src/test/resources/logback-test.xml
new file mode 100644 (file)
index 0000000..366a5f6
--- /dev/null
@@ -0,0 +1,36 @@
+<!--
+  ============LICENSE_START=======================================================
+  ONAP
+  ================================================================================
+  Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ============LICENSE_END=========================================================
+-->
+
+<configuration>
+
+    <property name="pattern" value="%X{RequestID}|%X{InvocationID}|%X{ServiceName}|%X{PartnerName}|%X{BeginTimestamp}|%X{EndTimestamp}|%X{ElapsedTime}|%X{ServiceInstanceID}|%X{VirtualServerName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%X{Severity}|%X{TargetEntity}|%X{TargetServiceName}|%X{Server}|%X{ServerIPAddress}|%X{ServerFQDN}|%X{ClientIPAddress}|%X{ProcessKey}|%X{RemoteHost}|%X{AlertSeverity}|%X{TargetVirtualEntity}|%level|%logger{0}|%thread| %msg%n"/>
+
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <filter class="org.onap.policy.drools.utils.logging.LoggerMarkerFilter$MetricLoggerMarkerFilter" />
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <Pattern>${pattern}</Pattern>
+        </encoder>
+    </appender>
+    
+    <root level="INFO">
+        <appender-ref ref="STDOUT"/>
+    </root>
+
+</configuration>