aboutsummaryrefslogtreecommitdiffstats
path: root/common/openecomp-logging-lib
diff options
context:
space:
mode:
authorAviZi <avi.ziv@amdocs.com>2017-06-09 02:39:56 +0300
committerAviZi <avi.ziv@amdocs.com>2017-06-09 02:39:56 +0300
commit280f8015d06af1f41a3ef12e8300801c7a5e0d54 (patch)
tree9c1d3978c04cd28068f02073038c936bb49ca9e0 /common/openecomp-logging-lib
parentfd3821dad11780d33c5373d74c957c442489945e (diff)
[SDC-29] Amdocs OnBoard 1707 initial commit.
Change-Id: Ie4d12a3f574008b792899b368a0902a8b46b5370 Signed-off-by: AviZi <avi.ziv@amdocs.com>
Diffstat (limited to 'common/openecomp-logging-lib')
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-api/pom.xml18
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/BaseFactory.java54
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/Logger.java103
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/LoggerCreationService.java11
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/LoggerFactory.java232
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/annotations/Metrics.java15
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/context/ContextPropagationService.java10
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/context/TaskFactory.java73
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-api/src/test/java/org/openecomp/core/logging/api/LoggerFactoryTest.java74
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-api/src/test/java/org/openecomp/core/logging/api/context/TaskFactoryTest.java30
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/README29
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/pom.xml72
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/Markers.java21
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/Slf4JLoggerCreationService.java236
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/aspects/MetricsAspect.java72
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/context/MdcPropagationService.java71
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/logback/DispatchingAppender.java142
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/logback/EventTypeDiscriminator.java121
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/servlet/LoggingFilter.java135
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/src/main/resources/META-INF/services/org.openecomp.core.logging.api.LoggerCreationService1
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/src/main/resources/META-INF/services/org.openecomp.core.logging.api.context.ContextPropagationService1
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/LoggerFactoryTest.java25
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/RoutingTest.java155
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/api/LoggerTest.java65
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/aspects/MetricsAspectTest.java452
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/context/MDCPropagationFactoryTest.java216
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/context/TaskFactoryTest.java26
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/logback/EventTypeDiscriminatorTest.java220
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/servlet/LoggingFilterTest.java314
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/README8
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/dispatching-logback.xml335
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/logback.xml41
-rw-r--r--common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/sifting-logback.xml42
-rw-r--r--common/openecomp-logging-lib/pom.xml34
34 files changed, 3454 insertions, 0 deletions
diff --git a/common/openecomp-logging-lib/openecomp-logging-api/pom.xml b/common/openecomp-logging-lib/openecomp-logging-api/pom.xml
new file mode 100644
index 0000000000..96129557f4
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-api/pom.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <name>openecomp-configuration-management-test</name>
+ <groupId>org.openecomp.sdc.common</groupId>
+ <artifactId>openecomp-logging-api</artifactId>
+
+ <parent>
+ <artifactId>openecomp-logging-lib</artifactId>
+ <groupId>org.openecomp.sdc.common</groupId>
+ <version>1.1.0-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+
+</project>
diff --git a/common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/BaseFactory.java b/common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/BaseFactory.java
new file mode 100644
index 0000000000..14943805cc
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/BaseFactory.java
@@ -0,0 +1,54 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * 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.openecomp.core.logging.api;
+
+import java.util.Iterator;
+import java.util.ServiceLoader;
+
+/**
+ * Contains common functionality for factories used in the logging framework. <p>In order to use the
+ * factory, a particular (e.g. framework-specific) implementation of a service must be configured as
+ * described in <a href="http://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html">java.util.ServiceLoader</a>).</p>
+ *
+ * @see java.util.ServiceLoader
+ */
+public class BaseFactory {
+
+ protected static <T> T locateService(Class<T> clazz) throws Exception {
+
+ T service;
+ ServiceLoader<T> loader = ServiceLoader.load(clazz);
+ Iterator<T> iterator = loader.iterator();
+ if (iterator.hasNext()) {
+
+ service = iterator.next();
+ if (iterator.hasNext()) {
+ System.err.println(String.format("Warning! Configured more than one implementation of %s",
+ clazz.getName()));
+ }
+
+ return service;
+ }
+
+ throw new IllegalArgumentException(
+ (String.format("No implementations configured for %s", clazz.getName())));
+ }
+}
diff --git a/common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/Logger.java b/common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/Logger.java
new file mode 100644
index 0000000000..0fe3d8f230
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/Logger.java
@@ -0,0 +1,103 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * 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.openecomp.core.logging.api;
+
+/**
+ * <p>This interface defines logging as specified by OPENECOMP logging requirements.</p> <p>Formatted
+ * messages must follow the <a href="http://www.slf4j.org/api/org/slf4j/helpers/MessageFormatter.html>SLF4J
+ * format</a>.</p>
+ */
+public interface Logger {
+
+ String getName();
+
+ boolean isMetricsEnabled();
+
+ void metrics(String msg);
+
+ void metrics(String msg, Object arg);
+
+ void metrics(String msg, Object arg1, Object arg2);
+
+ void metrics(String msg, Object... arguments);
+
+ void metrics(String msg, Throwable throwable);
+
+ boolean isAuditEnabled();
+
+ void audit(String msg);
+
+ void audit(String msg, Object arg);
+
+ void audit(String msg, Object arg1, Object arg2);
+
+ void audit(String msg, Object... arguments);
+
+ void audit(String msg, Throwable throwable);
+
+ boolean isDebugEnabled();
+
+ void debug(String msg);
+
+ void debug(String msg, Object arg);
+
+ void debug(String msg, Object arg1, Object arg2);
+
+ void debug(String msg, Object... arguments);
+
+ void debug(String msg, Throwable throwable);
+
+ boolean isInfoEnabled();
+
+ void info(String msg);
+
+ void info(String msg, Object arg);
+
+ void info(String msg, Object arg1, Object arg2);
+
+ void info(String msg, Object... arguments);
+
+ void info(String msg, Throwable throwable);
+
+ boolean isWarnEnabled();
+
+ void warn(String msg);
+
+ void warn(String msg, Object arg);
+
+ void warn(String msg, Object... arguments);
+
+ void warn(String msg, Object arg1, Object arg2);
+
+ void warn(String msg, Throwable throwable);
+
+ boolean isErrorEnabled();
+
+ void error(String msg);
+
+ void error(String msg, Object arg);
+
+ void error(String msg, Object arg1, Object arg2);
+
+ void error(String msg, Object... arguments);
+
+ void error(String msg, Throwable throwable);
+}
diff --git a/common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/LoggerCreationService.java b/common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/LoggerCreationService.java
new file mode 100644
index 0000000000..298f8f0267
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/LoggerCreationService.java
@@ -0,0 +1,11 @@
+package org.openecomp.core.logging.api;
+
+/**
+ * Implements a framework-specific logging, to be used by {@link LoggerFactory}.
+ */
+public interface LoggerCreationService {
+
+ Logger getLogger(String className);
+
+ Logger getLogger(Class<?> clazz);
+}
diff --git a/common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/LoggerFactory.java b/common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/LoggerFactory.java
new file mode 100644
index 0000000000..e6f4aa3707
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/LoggerFactory.java
@@ -0,0 +1,232 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * 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.openecomp.core.logging.api;
+
+/**
+ * <a>Factory to hide a concrete, framework-specific implementation of logger creation.</a> <p>The
+ * service used by this factory must implement {@link LoggerCreationService}. If no implementation
+ * has been configured or could not be instantiated, a <b>no-op logger</b> will be used, and <b>no
+ * events</b> will be logged. This is done to prevent recursion if attempts are being made to log
+ * exceptions that resulted from logger initialization. </p>
+ *
+ * @see BaseFactory
+ * @see LoggerCreationService
+ */
+@SuppressWarnings("ThrowableInstanceNeverThrown")
+public class LoggerFactory extends BaseFactory {
+
+ private static final LoggerCreationService SERVICE;
+
+ static {
+
+ LoggerCreationService service;
+
+ try {
+ service = locateService(LoggerCreationService.class);
+ } catch (Throwable throwable) {
+ new RuntimeException("Failed to instantiate logger factory", throwable).printStackTrace();
+ // use the no-op service to prevent recursion in case of an attempt to log an exception as a
+ // result of a logger initialization error
+ service = new NoOpLoggerCreationService();
+ }
+
+ SERVICE = service;
+ }
+
+ public static Logger getLogger(String clazzName) {
+ return SERVICE.getLogger(clazzName);
+ }
+
+ public static Logger getLogger(Class<?> clazz) {
+ return SERVICE.getLogger(clazz);
+ }
+
+ private static class NoOpLoggerCreationService implements LoggerCreationService {
+
+ private static final Logger NO_OP_LOGGER = new Logger() {
+
+ @Override
+ public String getName() {
+ return "No-Op Logger";
+ }
+
+ @Override
+ public boolean isMetricsEnabled() {
+ return false;
+ }
+
+ @Override
+ public void metrics(String msg) {
+ }
+
+ @Override
+ public void metrics(String msg, Object arg) {
+ }
+
+ @Override
+ public void metrics(String msg, Object arg1, Object arg2) {
+ }
+
+ @Override
+ public void metrics(String msg, Object... arguments) {
+ }
+
+ @Override
+ public void metrics(String msg, Throwable throwable) {
+ }
+
+ @Override
+ public boolean isAuditEnabled() {
+ return false;
+ }
+
+ @Override
+ public void audit(String msg) {
+ }
+
+ @Override
+ public void audit(String msg, Object arg) {
+ }
+
+ @Override
+ public void audit(String msg, Object arg1, Object arg2) {
+ }
+
+ @Override
+ public void audit(String msg, Object... arguments) {
+ }
+
+ @Override
+ public void audit(String msg, Throwable throwable) {
+ }
+
+ @Override
+ public boolean isDebugEnabled() {
+ return false;
+ }
+
+ @Override
+ public void debug(String msg) {
+ }
+
+ @Override
+ public void debug(String msg, Object arg) {
+ }
+
+ @Override
+ public void debug(String msg, Object arg1, Object arg2) {
+ }
+
+ @Override
+ public void debug(String msg, Object... arguments) {
+ }
+
+ @Override
+ public void debug(String msg, Throwable throwable) {
+ }
+
+ @Override
+ public boolean isInfoEnabled() {
+ return false;
+ }
+
+ @Override
+ public void info(String msg) {
+ }
+
+ @Override
+ public void info(String msg, Object arg) {
+ }
+
+ @Override
+ public void info(String msg, Object arg1, Object arg2) {
+ }
+
+ @Override
+ public void info(String msg, Object... arguments) {
+ }
+
+ @Override
+ public void info(String msg, Throwable throwable) {
+ }
+
+ @Override
+ public boolean isWarnEnabled() {
+ return false;
+ }
+
+ @Override
+ public void warn(String msg) {
+ }
+
+ @Override
+ public void warn(String msg, Object arg) {
+ }
+
+ @Override
+ public void warn(String msg, Object... arguments) {
+ }
+
+ @Override
+ public void warn(String msg, Object arg1, Object arg2) {
+ }
+
+ @Override
+ public void warn(String msg, Throwable throwable) {
+ }
+
+ @Override
+ public boolean isErrorEnabled() {
+ return false;
+ }
+
+ @Override
+ public void error(String msg) {
+ }
+
+ @Override
+ public void error(String msg, Object arg) {
+ }
+
+ @Override
+ public void error(String msg, Object arg1, Object arg2) {
+ }
+
+ @Override
+ public void error(String msg, Object... arguments) {
+ }
+
+ @Override
+ public void error(String msg, Throwable throwable) {
+ }
+ };
+
+ @Override
+ public Logger getLogger(String className) {
+ return NO_OP_LOGGER;
+ }
+
+ @Override
+ public Logger getLogger(Class<?> clazz) {
+ return NO_OP_LOGGER;
+ }
+ }
+}
diff --git a/common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/annotations/Metrics.java b/common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/annotations/Metrics.java
new file mode 100644
index 0000000000..1588bcafc0
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/annotations/Metrics.java
@@ -0,0 +1,15 @@
+package org.openecomp.core.logging.api.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates a method whose execution time should be measured and logged as required for OPENECOMP
+ * metrics.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Metrics {
+}
diff --git a/common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/context/ContextPropagationService.java b/common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/context/ContextPropagationService.java
new file mode 100644
index 0000000000..8e9c2dfa28
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/context/ContextPropagationService.java
@@ -0,0 +1,10 @@
+package org.openecomp.core.logging.api.context;
+
+/**
+ * Should be used to implement a framework-specific mechanism of propagation of a diagnostic context
+ * to child threads.
+ */
+public interface ContextPropagationService {
+
+ Runnable create(Runnable task);
+}
diff --git a/common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/context/TaskFactory.java b/common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/context/TaskFactory.java
new file mode 100644
index 0000000000..b358a77573
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/context/TaskFactory.java
@@ -0,0 +1,73 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * 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.openecomp.core.logging.api.context;
+
+import org.openecomp.core.logging.api.BaseFactory;
+
+/**
+ * <p>Should be used to propagate a diagnostic context (for instance <a
+ * href="http://www.slf4j.org/manual.html#mdc">MDC</a>) to other threads.</p> <p>Applicable when
+ * creating a child thread directly, or submitting tasks for potentially postponed execution via an
+ * <a href="http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html">Executor</a>
+ * (including any of the <a href="http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html">executor
+ * services</a> and <a href="http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ForkJoinPool.html">ForkJoinPool</a>).</p>
+ * <p>The service used by this factory must implement {@link ContextPropagationService}.</p>
+ *
+ * @see ContextPropagationService
+ */
+@SuppressWarnings("ThrowableInstanceNeverThrown")
+public class TaskFactory extends BaseFactory {
+
+ private static final ContextPropagationService SERVICE;
+ private static final RuntimeException ERROR;
+
+ static {
+
+ ContextPropagationService service = null;
+ RuntimeException error = null;
+
+ try {
+ service = locateService(ContextPropagationService.class);
+ } catch (Throwable throwable) {
+ error = new RuntimeException("Failed to instantiate task factory", throwable);
+ }
+
+ SERVICE = service;
+ ERROR = error;
+ }
+
+ /**
+ * Modify a task so that a diagnostic context is propagated to the thread when the task runs. Done
+ * in a logging-framework specific way.
+ *
+ * @param task any Runnable that will run in a thread
+ * @return modified (wrapped) original task that runs the same business logic, but also takes care
+ of copying the diagnostic context for logging.
+ */
+ public static Runnable create(Runnable task) {
+
+ if (SERVICE == null) {
+ throw ERROR;
+ }
+
+ return SERVICE.create(task);
+ }
+}
diff --git a/common/openecomp-logging-lib/openecomp-logging-api/src/test/java/org/openecomp/core/logging/api/LoggerFactoryTest.java b/common/openecomp-logging-lib/openecomp-logging-api/src/test/java/org/openecomp/core/logging/api/LoggerFactoryTest.java
new file mode 100644
index 0000000000..7158db7ab4
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-api/src/test/java/org/openecomp/core/logging/api/LoggerFactoryTest.java
@@ -0,0 +1,74 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * 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.openecomp.core.logging.api;
+
+import org.testng.annotations.Test;
+
+import java.lang.reflect.Field;
+import java.util.ServiceLoader;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+
+/**
+ * @author evitaliy
+ * @since 14/09/2016.
+ */
+public class LoggerFactoryTest {
+
+ @Test
+ public void testNoOpLoggerService() throws Exception {
+
+ assertFalse(ServiceLoader.load(LoggerCreationService.class).iterator().hasNext());
+
+ LoggerFactory.getLogger(LoggerFactoryTest.class);
+ Field factory = LoggerFactory.class.getDeclaredField("SERVICE");
+ factory.setAccessible(true);
+ Object impl = factory.get(null);
+ assertEquals("org.openecomp.core.logging.api.LoggerFactory$NoOpLoggerCreationService",
+ impl.getClass().getName());
+ }
+
+ @Test
+ public void testNoOpLoggerByClass() throws Exception {
+ Logger logger = LoggerFactory.getLogger(LoggerFactoryTest.class);
+ verifyLogger(logger);
+ }
+
+ @Test
+ public void testNoOpLoggerByName() throws Exception {
+ Logger logger = LoggerFactory.getLogger(LoggerFactoryTest.class.getName());
+ verifyLogger(logger);
+ }
+
+ private void verifyLogger(Logger logger) {
+ assertNotNull(logger);
+
+ // make sure no exceptions are thrown
+ logger.error("");
+ logger.warn("");
+ logger.info("");
+ logger.debug("");
+ logger.audit("");
+ logger.metrics("");
+ }
+}
diff --git a/common/openecomp-logging-lib/openecomp-logging-api/src/test/java/org/openecomp/core/logging/api/context/TaskFactoryTest.java b/common/openecomp-logging-lib/openecomp-logging-api/src/test/java/org/openecomp/core/logging/api/context/TaskFactoryTest.java
new file mode 100644
index 0000000000..111a30de1a
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-api/src/test/java/org/openecomp/core/logging/api/context/TaskFactoryTest.java
@@ -0,0 +1,30 @@
+package org.openecomp.core.logging.api.context;
+
+import org.testng.annotations.Test;
+
+import java.util.ServiceLoader;
+
+import static org.testng.Assert.*;
+
+/**
+ * @author evitaliy
+ * @since 14/09/2016.
+ */
+public class TaskFactoryTest {
+
+ @Test(expectedExceptions = RuntimeException.class)
+ public void testNoImplementation() throws Exception {
+
+ assertFalse(ServiceLoader.load(ContextPropagationService.class).iterator().hasNext());
+
+ try {
+ TaskFactory.create(() -> {
+ });
+ } catch (RuntimeException e) {
+ Throwable cause = e.getCause();
+ assertNotNull(cause);
+ assertTrue(cause.getMessage().contains(ContextPropagationService.class.getName()));
+ throw e;
+ }
+ }
+} \ No newline at end of file
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/README b/common/openecomp-logging-lib/openecomp-logging-core/README
new file mode 100644
index 0000000000..779c5d99df
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/README
@@ -0,0 +1,29 @@
+The purpose of this module is to make a Web application meet the OPENECOMP logging requirements described in
+OPENECOMP platform application logging guidelines.
+
+The default out-of-the box solution is based on SLF4J.
+
+It introduces three major areas of functionality as follows:
+
+1. Routing of logging messages for the Logback library, so that all logging events are written to separate files
+according to their type.
+
+2. An AOP aspect for measuring execution time and logging it, so that the application code is not contaminated with
+this type of logging.
+
+3. Collecting and populating the context of a Web API request and propagating it to every logging event.
+
+TODO:
+
+1. MetricsAspect
+ - Configurable metrics message
+ - Make sure there are no exceptions but applicative ones
+
+2. EventTypeDiscriminator
+ - Make event types configurable to make the names of log files easily customizable
+
+3. DispatchingAppender
+ - Read appenders from configuration, so that there is no need in EELF loggers
+ - Simpler use of discriminator or an entirely different mechanism
+ - Better appender name pattern, or mapping between a discriminating value and an appender name
+ - Discard the appenders cache on configuration changes
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/pom.xml b/common/openecomp-logging-lib/openecomp-logging-core/pom.xml
new file mode 100644
index 0000000000..636595bc45
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/pom.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <name>openecomp-configuration-management-test</name>
+ <groupId>org.openecomp.sdc.common</groupId>
+ <artifactId>openecomp-logging-core</artifactId>
+
+ <parent>
+ <artifactId>openecomp-logging-lib</artifactId>
+ <groupId>org.openecomp.sdc.common</groupId>
+ <version>1.1.0-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+
+ <properties>
+ <logback.version>1.1.7</logback.version>
+ <powermock.version>1.6.5</powermock.version>
+ <easymock.version>3.4</easymock.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.aspectj</groupId>
+ <artifactId>aspectjrt</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.openecomp.sdc.common</groupId>
+ <artifactId>openecomp-logging-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>${logback.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <version>${logback.version}</version>
+ </dependency>
+
+ <!-- for testing -->
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymock</artifactId>
+ <version>${easymock.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock-api-easymock</artifactId>
+ <version>${powermock.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock-core</artifactId>
+ <version>${powermock.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock-module-testng</artifactId>
+ <version>${powermock.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/Markers.java b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/Markers.java
new file mode 100644
index 0000000000..dc2ae367b3
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/Markers.java
@@ -0,0 +1,21 @@
+package org.openecomp.core.logging;
+
+import org.slf4j.Marker;
+import org.slf4j.MarkerFactory;
+
+/**
+ * <p>The list of markers that can be used for special logging such as metrics, audit, etc.</p>
+ * <p>Although markers can be easily instantiated whenever needed, having constants for them helps
+ * eliminate mistakes - misspelling, using a marker that is not handled, etc.</p> <p>Usage:</p>
+ * <pre>
+ * Logger log = LogFactory.getLogger(this.getClass());
+ * log.info(Markers.AUDIT, "User '{}' logged out", user);
+ * </pre>
+ *
+ * @see org.slf4j.Marker
+ */
+public class Markers {
+
+ public static final Marker AUDIT = MarkerFactory.getMarker("AUDIT");
+ public static final Marker METRICS = MarkerFactory.getMarker("METRICS");
+}
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/Slf4JLoggerCreationService.java b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/Slf4JLoggerCreationService.java
new file mode 100644
index 0000000000..3238e75f8e
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/Slf4JLoggerCreationService.java
@@ -0,0 +1,236 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * 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.openecomp.core.logging;
+
+import org.openecomp.core.logging.api.Logger;
+import org.openecomp.core.logging.api.LoggerCreationService;
+import org.slf4j.LoggerFactory;
+
+public class Slf4JLoggerCreationService implements LoggerCreationService {
+
+ @Override
+ public Logger getLogger(String className) {
+ return new Slf4JWrapper(className);
+ }
+
+ @Override
+ public Logger getLogger(Class<?> clazz) {
+ return new Slf4JWrapper(clazz);
+ }
+
+ private class Slf4JWrapper implements Logger {
+
+ private final org.slf4j.Logger logger;
+
+ public Slf4JWrapper(Class<?> clazz) {
+ logger = LoggerFactory.getLogger(clazz);
+ }
+
+ public Slf4JWrapper(String className) {
+ logger = LoggerFactory.getLogger(className);
+ }
+
+ @Override
+ public String getName() {
+ return logger.getName();
+ }
+
+ @Override
+ public boolean isMetricsEnabled() {
+ return logger.isInfoEnabled(Markers.METRICS);
+ }
+
+ @Override
+ public void metrics(String msg) {
+ logger.info(Markers.METRICS, msg);
+ }
+
+ @Override
+ public void metrics(String msg, Object arg) {
+ logger.info(Markers.METRICS, msg, arg);
+ }
+
+ @Override
+ public void metrics(String msg, Object arg1, Object arg2) {
+ logger.info(Markers.METRICS, msg, arg1, arg2);
+ }
+
+ @Override
+ public void metrics(String msg, Object... arguments) {
+ logger.info(Markers.METRICS, msg, arguments);
+ }
+
+ @Override
+ public void metrics(String msg, Throwable throwable) {
+ logger.info(Markers.METRICS, msg, throwable);
+ }
+
+ @Override
+ public boolean isAuditEnabled() {
+ return logger.isInfoEnabled(Markers.AUDIT);
+ }
+
+ @Override
+ public void audit(String msg) {
+ logger.info(Markers.AUDIT, msg);
+ }
+
+ @Override
+ public void audit(String msg, Object arg) {
+ logger.info(Markers.AUDIT, msg, arg);
+ }
+
+ @Override
+ public void audit(String msg, Object arg1, Object arg2) {
+ logger.info(Markers.AUDIT, msg, arg1, arg2);
+ }
+
+ @Override
+ public void audit(String msg, Object... arguments) {
+ logger.info(Markers.AUDIT, msg, arguments);
+ }
+
+ @Override
+ public void audit(String msg, Throwable throwable) {
+ logger.info(Markers.AUDIT, msg, throwable);
+ }
+
+ @Override
+ public boolean isDebugEnabled() {
+ return logger.isDebugEnabled();
+ }
+
+ @Override
+ public void debug(String msg) {
+ logger.debug(msg);
+ }
+
+ @Override
+ public void debug(String format, Object arg) {
+ logger.debug(format, arg);
+ }
+
+ @Override
+ public void debug(String format, Object arg1, Object arg2) {
+ logger.debug(format, arg1, arg2);
+ }
+
+ @Override
+ public void debug(String format, Object... arguments) {
+ logger.debug(format, arguments);
+ }
+
+ @Override
+ public void debug(String msg, Throwable throwable) {
+ logger.debug(msg, throwable);
+ }
+
+ @Override
+ public boolean isInfoEnabled() {
+ return logger.isInfoEnabled();
+ }
+
+ @Override
+ public void info(String msg) {
+ logger.info(msg);
+ }
+
+ @Override
+ public void info(String format, Object arg) {
+ logger.info(format, arg);
+ }
+
+ @Override
+ public void info(String format, Object arg1, Object arg2) {
+ logger.info(format, arg1, arg2);
+ }
+
+ @Override
+ public void info(String format, Object... arguments) {
+ logger.info(format, arguments);
+ }
+
+ @Override
+ public void info(String msg, Throwable throwable) {
+ logger.info(msg, throwable);
+ }
+
+ @Override
+ public boolean isWarnEnabled() {
+ return logger.isWarnEnabled();
+ }
+
+ @Override
+ public void warn(String msg) {
+ logger.warn(msg);
+ }
+
+ @Override
+ public void warn(String format, Object arg) {
+ logger.warn(format, arg);
+ }
+
+ @Override
+ public void warn(String format, Object... arguments) {
+ logger.warn(format, arguments);
+ }
+
+ @Override
+ public void warn(String format, Object arg1, Object arg2) {
+ logger.warn(format, arg1, arg2);
+ }
+
+ @Override
+ public void warn(String msg, Throwable throwable) {
+ logger.warn(msg, throwable);
+ }
+
+ @Override
+ public boolean isErrorEnabled() {
+ return logger.isErrorEnabled();
+ }
+
+ @Override
+ public void error(String msg) {
+ logger.error(msg);
+ }
+
+ @Override
+ public void error(String format, Object arg) {
+ logger.error(format, arg);
+ }
+
+ @Override
+ public void error(String format, Object arg1, Object arg2) {
+ logger.error(format, arg1, arg2);
+ }
+
+ @Override
+ public void error(String format, Object... arguments) {
+ logger.error(format, arguments);
+ }
+
+ @Override
+ public void error(String msg, Throwable throwable) {
+ logger.error(msg, throwable);
+ }
+ }
+}
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/aspects/MetricsAspect.java b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/aspects/MetricsAspect.java
new file mode 100644
index 0000000000..9e8c7f0aa8
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/aspects/MetricsAspect.java
@@ -0,0 +1,72 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * 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.openecomp.core.logging.aspects;
+
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.openecomp.core.logging.api.Logger;
+import org.openecomp.core.logging.api.LoggerFactory;
+import org.openecomp.core.logging.api.annotations.Metrics;
+
+/**
+ * <p>Wraps around any method annotated with {@link Metrics} to measure and log its execution time
+ * in milliseconds.</p> <p>In order for the aspect to be used, AspectJ annotation processing must be
+ * tuned on and this particular aspect enabled. Conversely, it can be disabled completely if the
+ * application does not need to log metrics.</p> <p>See, for example, <a
+ * href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html"> Aspect
+ * Oriented Programming with Spring</a>.</p>
+ *
+ * @see Metrics
+ */
+@Aspect
+public class MetricsAspect {
+
+ private static final String MESSAGE_TEMPLATE = "'{}' took {} milliseconds";
+
+ /**
+ * Log execution time object.
+ *
+ * @param pjp the pjp
+ * @return the object
+ * @throws Throwable the throwable
+ */
+ @Around("@annotation(org.openecomp.core.logging.api.annotations.Metrics)")
+ public Object logExecutionTime(ProceedingJoinPoint pjp) throws Throwable {
+
+ final Logger logger = LoggerFactory.getLogger(pjp.getSignature().getDeclaringTypeName());
+ // measure and log only if the logger for this class is enabled
+ if (logger.isMetricsEnabled()) {
+
+ final String method = pjp.getSignature().getName();
+ final long start = System.currentTimeMillis();
+
+ try {
+ return pjp.proceed();
+ } finally {
+ logger.metrics(MESSAGE_TEMPLATE, method, System.currentTimeMillis() - start);
+ }
+
+ } else {
+ return pjp.proceed();
+ }
+ }
+}
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/context/MdcPropagationService.java b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/context/MdcPropagationService.java
new file mode 100644
index 0000000000..94ad1b9717
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/context/MdcPropagationService.java
@@ -0,0 +1,71 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * 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.openecomp.core.logging.context;
+
+import org.openecomp.core.logging.api.context.ContextPropagationService;
+import org.slf4j.MDC;
+
+import java.util.Map;
+
+/**
+ * Propagates the <a href="http://www.slf4j.org/manual.html#mdc">SLF4J Mapped Diagnostic Context
+ * (MDC)</a> of a thread onto a runnable created by that thread, so that the context is available
+ * when the runnable is executed in a new thread.
+ */
+public class MdcPropagationService implements ContextPropagationService {
+
+ public Runnable create(Runnable task) {
+ return new MdcCopyingWrapper(task);
+ }
+
+ private static class MdcCopyingWrapper implements Runnable {
+
+ private final Runnable task;
+ private final Map<String, String> context;
+
+ private MdcCopyingWrapper(Runnable task) {
+ this.task = task;
+ this.context = MDC.getCopyOfContextMap();
+ }
+
+ private static void replaceMdc(Map<String, String> context) {
+
+ if (context == null) {
+ MDC.clear();
+ } else {
+ MDC.setContextMap(context);
+ }
+ }
+
+ @Override
+ public void run() {
+
+ Map<String, String> oldContext = MDC.getCopyOfContextMap();
+ replaceMdc(this.context);
+
+ try {
+ task.run();
+ } finally {
+ replaceMdc(oldContext);
+ }
+ }
+ }
+}
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/logback/DispatchingAppender.java b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/logback/DispatchingAppender.java
new file mode 100644
index 0000000000..6d5642e374
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/logback/DispatchingAppender.java
@@ -0,0 +1,142 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * 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.openecomp.core.logging.logback;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.sift.MDCBasedDiscriminator;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.Appender;
+import ch.qos.logback.core.AppenderBase;
+import ch.qos.logback.core.joran.spi.DefaultClass;
+import ch.qos.logback.core.sift.Discriminator;
+import org.slf4j.LoggerFactory;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * <p>Allows to use EELF logging configuration almost as is, by using a custom routing function, but
+ * pre-configured appenders attached to the standard EELF loggers.</p> <p>Changes that must be made
+ * in <i>logback.xml</i> supplied with EELF:</p>
+ * <pre>
+ * &lt;appender name="DISPATCHER" class="DispatchingAppender"&gt;
+ * &lt;discriminator class="EventTypeDiscriminator"/&gt;
+ * &lt;appenderNamePattern&gt;asyncEELF%s&lt;/appenderNamePattern&gt;
+ * &lt;/appender&gt;
+ * &lt;root level="INFO" additivity="false"&gt;
+ * &lt;appender-ref ref="DISPATCHER" /&gt;
+ * &lt;/root&gt;
+ * </pre>
+ */
+public class DispatchingAppender extends AppenderBase<ILoggingEvent> {
+
+ // "magic" appender to indicate a missing appender
+ private static final Appender<ILoggingEvent> NO_APPENDER = new DispatchingAppender();
+
+ private Map<String, Appender<ILoggingEvent>> appenders = new ConcurrentHashMap<>();
+
+ private Discriminator<ILoggingEvent> discriminator;
+ private String appenderNamePattern;
+
+ public Discriminator<ILoggingEvent> getDiscriminator() {
+ return this.discriminator;
+ }
+
+ @DefaultClass(MDCBasedDiscriminator.class)
+ public void setDiscriminator(Discriminator<ILoggingEvent> discriminator) {
+ this.discriminator = discriminator;
+ }
+
+ public String getAppenderNamePattern() {
+ return this.appenderNamePattern;
+ }
+
+ public void setAppenderNamePattern(String pattern) {
+ this.appenderNamePattern = pattern;
+ }
+
+ @Override
+ protected void append(ILoggingEvent event) {
+
+ if (this.isStarted()) {
+
+ String discriminatingValue = this.discriminator.getDiscriminatingValue(event);
+ String appenderName = String.format(this.appenderNamePattern, discriminatingValue);
+ Appender<ILoggingEvent> appender = this.lookupAppender(appenderName);
+ if (appender == NO_APPENDER) {
+ this.addError(String.format("Appender %s does not exist", appenderName));
+ } else {
+ appender.doAppend(event);
+ }
+ }
+ }
+
+ private Appender<ILoggingEvent> lookupAppender(String key) {
+
+ Appender<ILoggingEvent> appender = appenders.get(key);
+ if (appender != null) {
+ return appender;
+ }
+
+ LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
+ for (Logger log : context.getLoggerList()) {
+
+ Iterator<Appender<ILoggingEvent>> iterator = log.iteratorForAppenders();
+ while (iterator.hasNext()) {
+
+ Appender<ILoggingEvent> element = iterator.next();
+ if (key.equals(element.getName())) {
+ this.appenders.putIfAbsent(key, element);
+ return element;
+ }
+ }
+ }
+
+ // to avoid consecutive lookups if the required appender does not exist
+ this.appenders.putIfAbsent(key, NO_APPENDER);
+ return NO_APPENDER;
+ }
+
+ @Override
+ public void start() {
+
+ int errors = 0;
+ if (this.discriminator == null) {
+ this.addError("Missing discriminator. Aborting");
+ }
+
+ if (!this.discriminator.isStarted()) {
+ this.addError("Discriminator has not started successfully. Aborting");
+ ++errors;
+ }
+
+ if (this.appenderNamePattern == null) {
+ this.addError("Missing name pattern. Aborting");
+ ++errors;
+ }
+
+ if (errors == 0) {
+ super.start();
+ }
+ }
+}
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/logback/EventTypeDiscriminator.java b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/logback/EventTypeDiscriminator.java
new file mode 100644
index 0000000000..107f6728d7
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/logback/EventTypeDiscriminator.java
@@ -0,0 +1,121 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * 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.openecomp.core.logging.logback;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.sift.AbstractDiscriminator;
+import org.openecomp.core.logging.Markers;
+import org.slf4j.Marker;
+
+/**
+ * Can be used with {@link ch.qos.logback.classic.sift.SiftingAppender} to route events of different
+ * types to separate log files. For example,
+ * <pre>
+ * &lt;configuration&gt;
+ * &lt;appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender"&gt;
+ * &lt;discriminator class="EventTypeDiscriminator"/&gt;
+ * &lt;sift&gt;
+ * &lt;appender name="{EventType}"
+ * class="ch.qos.logback.core.rolling.RollingFileAppender"&gt;
+ * &lt;file&gt;${logDirectory}/${eventType}.log&lt;/file&gt;
+ * &lt;rollingPolicy class="ch.
+ * qos.logback.core.rolling.FixedWindowRollingPolicy"&gt;
+ * &lt;fileNamePattern&gt;
+ * ${logDirectory}/${eventType}.
+ * %i.log.zip&lt;/fileNamePattern&gt;
+ * &lt;minIndex&gt;1&lt;/minIndex&gt;
+ * &lt;maxIndex&gt;9&lt;/maxIndex&gt;
+ * &lt;/rollingPolicy&gt;
+ * &lt;triggeringPolicy
+ * class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"&gt;
+ * &lt;maxFileSize&gt;5MB&lt;/maxFileSize&gt;
+ * &lt;/triggeringPolicy&gt;
+ * &lt;encoder&gt;
+ * &lt;pattern&gt;${defaultPattern}&lt;/pattern&gt;
+ * &lt;/encoder&gt;
+ * &lt;/appender&gt;
+ * &lt;/sift&gt;
+ * &lt;/appender&gt;
+ * &lt;root level="INFO"&gt;
+ * &lt;appender-ref ref="SIFT" /&gt;
+ * &lt;/root&gt;
+ * &lt;/configuration&gt;
+ * </pre>
+ */
+public class EventTypeDiscriminator extends AbstractDiscriminator<ILoggingEvent> {
+
+ private static final String KEY = "eventType";
+
+ private static final String AUDIT = "Audit";
+ private static final String METRICS = "Metrics";
+ private static final String ERROR = "Error";
+ private static final String DEBUG = "Debug";
+ private static final String DEFAULT = DEBUG;
+
+ private static final int MIN_ERROR_LEVEL = Level.WARN_INT;
+ private static final int MAX_ERROR_LEVEL = Level.ERROR_INT;
+ private static final int DEFAULT_LEVEL = Level.DEBUG_INT;
+
+ @Override
+ public String getDiscriminatingValue(ILoggingEvent event) {
+
+ Level level = event.getLevel();
+ final int levelInt = level == null ? DEFAULT_LEVEL : level.toInt();
+ if ((levelInt > MIN_ERROR_LEVEL - 1) && (levelInt < MAX_ERROR_LEVEL + 1)) {
+ return ERROR;
+ }
+
+ if (levelInt == Level.DEBUG_INT) {
+ return DEBUG;
+ }
+
+ /*
+ * After DEBUG, ERROR, and WARNING have been filtered out,
+ * only TRACE and INFO are left. TRACE is less than DEBUG
+ * and therefore cannot be used. So, INFO should be used for
+ * custom routing like AUDIT and METRICS
+ */
+ if (levelInt == Level.INFO_INT) {
+
+ final Marker marker = event.getMarker();
+ if (marker != null) {
+
+ if (marker.contains(Markers.AUDIT)) {
+ return AUDIT;
+ }
+
+ if (marker.contains(Markers.METRICS)) {
+ return METRICS;
+ }
+ }
+
+ return ERROR;
+ }
+
+ return DEFAULT;
+ }
+
+ @Override
+ public String getKey() {
+ return KEY;
+ }
+}
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/servlet/LoggingFilter.java b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/servlet/LoggingFilter.java
new file mode 100644
index 0000000000..53923d7784
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/servlet/LoggingFilter.java
@@ -0,0 +1,135 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * 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.openecomp.core.logging.servlet;
+
+import org.slf4j.MDC;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicLong;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+/**
+ * <p>Pushes information required by EELF onto MDC (Mapped Diagnostic Context).</p> <p>This is
+ * servlet filter that should be configured in <i>web.xml</i> to be used. Example:</p>
+ * <pre>
+ * &lt;filter&gt;
+ * &lt;filter-name&gt;LoggingServletFilter&lt;/filter-name&gt;
+ * &lt;filter-class&gt;LoggingFilter&lt;/filter-class&gt;
+ * &lt;/filter&gt;
+ * &lt;filter-mapping&gt;
+ * &lt;filter-name&gt;LoggingServletFilter&lt;/filter-name&gt;
+ * &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
+ * &lt;/filter-mapping&gt;
+ * </pre>
+ */
+public class LoggingFilter implements Filter {
+
+ // should be cashed to avoid low-level call, but with a timeout to account for IP or FQDN changes
+ private static final HostAddressCache HOST_ADDRESS = new HostAddressCache();
+ private static final String UNKNOWN = "UNKNOWN";
+
+ public void destroy() {
+ }
+
+ /**
+ * Do Filter.
+ *
+ * @param request the request
+ */
+ public void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain chain) throws IOException, ServletException {
+
+ try {
+
+ MDC.clear();
+
+ MDC.put("RequestId", UUID.randomUUID().toString());
+ MDC.put("ServiceInstanceId", "N/A"); // not applicable
+ MDC.put("ServiceName", "SDC");
+ MDC.put("InstanceUUID", "N/A");
+
+ // For some reason chooses IPv4 or IPv6 in a random way
+ MDC.put("RemoteHost", request.getRemoteHost());
+
+ InetAddress host = HOST_ADDRESS.get();
+
+ String ipAddress;
+ String hostName;
+ if (host == null) {
+ ipAddress = UNKNOWN;
+ hostName = UNKNOWN;
+ } else {
+ ipAddress = host.getHostAddress();
+ hostName = host.getHostName();
+ }
+
+ MDC.put("ServerIPAddress", ipAddress);
+ MDC.put("ServerFQDN", hostName);
+
+ // TODO: Clarify what these stand for
+ // MDC.put("AlertSeverity", );
+ // MDC.put("Timer", );
+
+ chain.doFilter(request, response);
+
+ } finally {
+ MDC.clear();
+ }
+ }
+
+ public void init(FilterConfig config) throws ServletException {
+ }
+
+ private static class HostAddressCache {
+
+ private static final long REFRESH_TIME = 1000L;
+
+ private AtomicLong lastUpdated = new AtomicLong(0L);
+ private InetAddress hostAddress;
+
+ public InetAddress get() {
+
+ long current = System.currentTimeMillis();
+ if (current - lastUpdated.get() > REFRESH_TIME) {
+
+ synchronized (this) {
+
+ try {
+ lastUpdated.set(current); // set now to register the attempt even if failed
+ hostAddress = InetAddress.getLocalHost();
+ } catch (UnknownHostException unknownHostException) {
+ hostAddress = null;
+ }
+ }
+ }
+
+ return hostAddress;
+ }
+ }
+}
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/main/resources/META-INF/services/org.openecomp.core.logging.api.LoggerCreationService b/common/openecomp-logging-lib/openecomp-logging-core/src/main/resources/META-INF/services/org.openecomp.core.logging.api.LoggerCreationService
new file mode 100644
index 0000000000..ecbf5e8fbe
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/src/main/resources/META-INF/services/org.openecomp.core.logging.api.LoggerCreationService
@@ -0,0 +1 @@
+org.openecomp.core.logging.Slf4JLoggerCreationService \ No newline at end of file
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/main/resources/META-INF/services/org.openecomp.core.logging.api.context.ContextPropagationService b/common/openecomp-logging-lib/openecomp-logging-core/src/main/resources/META-INF/services/org.openecomp.core.logging.api.context.ContextPropagationService
new file mode 100644
index 0000000000..91297681ec
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/src/main/resources/META-INF/services/org.openecomp.core.logging.api.context.ContextPropagationService
@@ -0,0 +1 @@
+org.openecomp.core.logging.context.MdcPropagationService \ No newline at end of file
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/LoggerFactoryTest.java b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/LoggerFactoryTest.java
new file mode 100644
index 0000000000..6fcc134957
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/LoggerFactoryTest.java
@@ -0,0 +1,25 @@
+package org.openecomp.core.logging;
+
+import org.openecomp.core.logging.api.LoggerFactory;
+import org.testng.annotations.Test;
+
+import java.lang.reflect.Field;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * @author evitaliy
+ * @since 12/09/2016.
+ */
+public class LoggerFactoryTest {
+
+ @Test
+ public void testCreate() throws Exception {
+ // test that the service loader loads the right implementation
+ LoggerFactory.getLogger(LoggerFactoryTest.class);
+ Field factory = LoggerFactory.class.getDeclaredField("SERVICE");
+ factory.setAccessible(true);
+ Object implementation = factory.get(null);
+ assertEquals(Slf4JLoggerCreationService.class, implementation.getClass());
+ }
+} \ No newline at end of file
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/RoutingTest.java b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/RoutingTest.java
new file mode 100644
index 0000000000..c0a418a31e
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/RoutingTest.java
@@ -0,0 +1,155 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * 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.openecomp.core.logging;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.sift.SiftingAppender;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.AppenderBase;
+import org.openecomp.core.logging.logback.EventTypeDiscriminator;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Predicate;
+
+/**
+ * TODO: Add more negative tests
+ *
+ * @author EVITALIY
+ * @since 17/08/2016.
+ */
+public class RoutingTest {
+
+ private static final String ERROR = "Error";
+ private static final String DEBUG = "Debug";
+ private static final String AUDIT = "Audit";
+ private static final String METRICS = "Metrics";
+
+ private Logger logger;
+ private Map<String, TestAppender> result = new ConcurrentHashMap<>();
+
+ @BeforeClass
+ public void setUp() {
+
+ SiftingAppender appender = new SiftingAppender();
+
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ discriminator.start();
+
+ appender.setDiscriminator(discriminator);
+ appender.setAppenderFactory((context, discriminatingValue) ->
+ result.computeIfAbsent(discriminatingValue, f -> {
+ TestAppender tmp = new TestAppender();
+ tmp.start();
+ return tmp;
+ }));
+
+ appender.start();
+
+ logger = (Logger) LoggerFactory.getLogger(RoutingTest.class.getName());
+ // prevent from writing into appenders attached via parent loggers
+ logger.setAdditive(false);
+ logger.addAppender(appender);
+ logger.setLevel(Level.DEBUG);
+ }
+
+ @Test
+ public void testWarning() {
+ String msg = "This is a test warning";
+ logger.warn(msg);
+ TestAppender appender = result.get(ERROR);
+ Assert.assertTrue(appender.contains((event) ->
+ Level.WARN.equals(event.getLevel()) && msg.equals(event.getFormattedMessage())));
+ }
+
+ @Test
+ public void testError() {
+ String msg = "This is a test error";
+ logger.error(msg);
+ TestAppender appender = result.get(ERROR);
+ Assert.assertTrue(appender.contains((event) ->
+ Level.ERROR.equals(event.getLevel()) && msg.equals(event.getFormattedMessage())));
+ }
+
+ @Test
+ public void testDebug() {
+ String msg = "This is a test debug";
+ logger.debug(msg);
+ TestAppender appender = result.get(DEBUG);
+ Assert.assertTrue(appender.contains((event) ->
+ Level.DEBUG.equals(event.getLevel()) && msg.equals(event.getFormattedMessage())));
+ }
+
+ @Test
+ public void testInfo() {
+ String msg = "This is a test info";
+ logger.info(msg);
+ TestAppender appender = result.get(ERROR);
+ Assert.assertTrue(appender.contains((event) ->
+ Level.INFO.equals(event.getLevel()) && msg.equals(event.getFormattedMessage())));
+ }
+
+ @Test
+ public void testAudit() {
+ String msg = "This is a test audit";
+ logger.info(Markers.AUDIT, msg);
+ TestAppender appender = result.get(AUDIT);
+ Assert.assertTrue(appender.contains((event) ->
+ Level.INFO.equals(event.getLevel()) && msg.equals(event.getFormattedMessage())));
+ }
+
+ @Test
+ public void testMetrics() {
+ String msg = "This is a test metrics";
+ logger.info(Markers.METRICS, msg);
+ TestAppender appender = result.get(METRICS);
+ Assert.assertTrue(appender.contains((event) ->
+ Level.INFO.equals(event.getLevel()) && msg.equals(event.getFormattedMessage())));
+ }
+
+ /**
+ * An appender that just accumulates messages in a list and enables to inspect them
+ *
+ * @author EVITALIY
+ * @since 17/08/2016.
+ */
+ private static class TestAppender extends AppenderBase<ILoggingEvent> {
+
+ private List<ILoggingEvent> events = Collections.synchronizedList(new ArrayList<>(10));
+
+ @Override
+ protected void append(ILoggingEvent event) {
+ this.events.add(event);
+ }
+
+ public boolean contains(Predicate<ILoggingEvent> predicate) {
+ return events.stream().anyMatch(predicate);
+ }
+ }
+}
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/api/LoggerTest.java b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/api/LoggerTest.java
new file mode 100644
index 0000000000..b154f0d71c
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/api/LoggerTest.java
@@ -0,0 +1,65 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * 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.openecomp.core.logging.api;
+
+import org.testng.annotations.Test;
+
+/**
+ * This is only for manual testing - change ENABLE to 'true'
+ *
+ * @author evitaliy
+ * @since 13/09/2016.
+ */
+public class LoggerTest {
+
+ private static final boolean ENABLED = false;
+ private static final Logger LOGGER = LoggerFactory.getLogger(LoggerTest.class);
+
+ @Test(enabled = ENABLED)
+ public void testMetrics() throws Exception {
+ LOGGER.metrics("This is metrics");
+ }
+
+ @Test(enabled = ENABLED)
+ public void testAudit() throws Exception {
+ LOGGER.audit("This is audit");
+ }
+
+ @Test(enabled = ENABLED)
+ public void testDebug() throws Exception {
+ LOGGER.debug("This is debug");
+ }
+
+ @Test(enabled = ENABLED)
+ public void testInfo() throws Exception {
+ LOGGER.info("This is info");
+ }
+
+ @Test(enabled = ENABLED)
+ public void testWarn() throws Exception {
+ LOGGER.warn("This is warning");
+ }
+
+ @Test(enabled = ENABLED)
+ public void testError() throws Exception {
+ LOGGER.error("This is error");
+ }
+}
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/aspects/MetricsAspectTest.java b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/aspects/MetricsAspectTest.java
new file mode 100644
index 0000000000..68d255c9c3
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/aspects/MetricsAspectTest.java
@@ -0,0 +1,452 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * 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.openecomp.core.logging.aspects;
+
+import org.openecomp.core.logging.api.Logger;
+import org.openecomp.core.logging.api.LoggerFactory;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.Signature;
+import org.aspectj.lang.reflect.SourceLocation;
+import org.aspectj.runtime.internal.AroundClosure;
+import org.easymock.EasyMock;
+import org.powermock.api.easymock.PowerMock;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.testng.PowerMockTestCase;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+import sun.reflect.generics.reflectiveObjects.NotImplementedException;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Predicate;
+
+/**
+ * @author EVITALIY
+ * @since 17/08/2016.
+ */
+@PrepareForTest(LoggerFactory.class)
+public class MetricsAspectTest extends PowerMockTestCase {
+
+ private static final Object OBJ_TO_RETURN = new Object();
+ private static final String EXPECTED_MESSAGE = "'{}' took {} milliseconds";
+
+ @Test
+ public void testLogExecutionTime() throws Throwable {
+
+ String className = UUID.randomUUID().toString();
+ String methodName = UUID.randomUUID().toString();
+
+ TestLogger logger = initLogging(className, true);
+
+ MetricsAspect aspect = new MetricsAspect();
+ MockProceedingJoinPoint pjp = new MockProceedingJoinPoint(className, methodName);
+ Object returned = aspect.logExecutionTime(pjp);
+
+ Assert.assertEquals(OBJ_TO_RETURN, returned);
+ assertExecution(methodName, pjp, logger);
+ }
+
+ @Test
+ public void testMetricsDisabled() throws Throwable {
+
+ String className = UUID.randomUUID().toString();
+ String methodName = UUID.randomUUID().toString();
+
+ TestLogger logger = initLogging(className, false);
+
+ MetricsAspect aspect = new MetricsAspect();
+ MockProceedingJoinPoint pjp = new MockProceedingJoinPoint(className, methodName);
+ Object returned = aspect.logExecutionTime(pjp);
+
+ Assert.assertEquals(OBJ_TO_RETURN, returned);
+ Assert.assertEquals(1, pjp.getCount());
+ // return any event - must be empty
+ Assert.assertFalse(logger.contains((event) -> true));
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void testThrowingError() throws Throwable {
+
+ String className = UUID.randomUUID().toString();
+ String methodName = UUID.randomUUID().toString();
+
+ final TestLogger logger = initLogging(className, true);
+
+ MetricsAspect aspect = new MetricsAspect();
+ MockProceedingJoinPoint pjp = new MockProceedingJoinPointWithException(className, methodName);
+
+ try {
+ aspect.logExecutionTime(pjp);
+ } finally {
+ assertExecution(methodName, pjp, logger);
+ }
+ }
+
+ private TestLogger initLogging(String className, boolean enabled) {
+ TestLogger logger = new TestLogger(enabled);
+ PowerMock.mockStatic(LoggerFactory.class);
+ EasyMock.expect(LoggerFactory.getLogger(className)).andReturn(logger);
+ PowerMock.replay(LoggerFactory.class);
+ return logger;
+ }
+
+ private void assertExecution(String methodName, MockProceedingJoinPoint pjp, TestLogger logger) {
+
+ Assert.assertEquals(1, pjp.getCount());
+ Assert.assertTrue(logger.contains((event) ->
+ (event != null) && (event.length == 3) && EXPECTED_MESSAGE.equals(event[0])
+ && methodName.equals(event[1]) && (event[2] instanceof Long)));
+ }
+
+ private static class MockSignature implements Signature {
+
+ private final String className;
+ private final String methodName;
+
+ private MockSignature(String className, String methodName) {
+ this.className = className;
+ this.methodName = methodName;
+ }
+
+ @Override
+ public String toShortString() {
+ return null;
+ }
+
+ @Override
+ public String toLongString() {
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ return methodName;
+ }
+
+ @Override
+ public int getModifiers() {
+ return 0;
+ }
+
+ @Override
+ public Class getDeclaringType() {
+ return null;
+ }
+
+ @Override
+ public String getDeclaringTypeName() {
+ return className;
+ }
+ }
+
+ private static class MockProceedingJoinPoint implements ProceedingJoinPoint {
+
+ private AtomicInteger count = new AtomicInteger(0);
+ private Signature signature;
+
+ MockProceedingJoinPoint(String className, String methodName) {
+ this.signature = new MockSignature(className, methodName);
+ }
+
+ int getCount() {
+ return count.get();
+ }
+
+ @Override
+ public Object proceed() throws Throwable {
+ count.incrementAndGet();
+ return OBJ_TO_RETURN;
+ }
+
+ @Override
+ public void set$AroundClosure(AroundClosure aroundClosure) {
+
+ }
+
+ @Override
+ public Object proceed(Object[] objects) throws Throwable {
+ return null;
+ }
+
+ @Override
+ public String toShortString() {
+ return null;
+ }
+
+ @Override
+ public String toLongString() {
+ return null;
+ }
+
+ @Override
+ public Object getThis() {
+ return null;
+ }
+
+ @Override
+ public Object getTarget() {
+ return null;
+ }
+
+ @Override
+ public Object[] getArgs() {
+ return new Object[0];
+ }
+
+ @Override
+ public Signature getSignature() {
+ return this.signature;
+ }
+
+ @Override
+ public SourceLocation getSourceLocation() {
+ return null;
+ }
+
+ @Override
+ public String getKind() {
+ return null;
+ }
+
+ @Override
+ public StaticPart getStaticPart() {
+ return null;
+ }
+ }
+
+ private static class MockProceedingJoinPointWithException extends MockProceedingJoinPoint {
+
+ MockProceedingJoinPointWithException(String className, String methodName) {
+ super(className, methodName);
+ }
+
+ @Override
+ public Object proceed() throws Throwable {
+ super.proceed();
+ throw new IllegalArgumentException();
+ }
+ }
+
+ private class TestLogger implements Logger {
+
+ private final boolean enabled;
+ private List<Object[]> events = Collections.synchronizedList(new ArrayList<>(10));
+
+ public TestLogger(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ @Override
+ public String getName() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public boolean isMetricsEnabled() {
+ return this.enabled;
+ }
+
+ @Override
+ public void metrics(String var1) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void metrics(String var1, Object var2) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void metrics(String var1, Object var2, Object var3) {
+
+ if (this.enabled) {
+ events.add(new Object[]{var1, var2, var3});
+ }
+ }
+
+ @Override
+ public void metrics(String var1, Object... var2) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void metrics(String var1, Throwable throwable) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public boolean isAuditEnabled() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void audit(String var1) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void audit(String var1, Object var2) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void audit(String var1, Object var2, Object var3) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void audit(String var1, Object... var2) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void audit(String var1, Throwable throwable) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public boolean isDebugEnabled() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void debug(String var1) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void debug(String var1, Object var2) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void debug(String var1, Object var2, Object var3) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void debug(String var1, Object... var2) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void debug(String var1, Throwable throwable) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public boolean isInfoEnabled() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void info(String var1) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void info(String var1, Object var2) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void info(String var1, Object var2, Object var3) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void info(String var1, Object... var2) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void info(String var1, Throwable throwable) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public boolean isWarnEnabled() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void warn(String var1) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void warn(String var1, Object var2) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void warn(String var1, Object... var2) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void warn(String var1, Object var2, Object var3) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void warn(String var1, Throwable throwable) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public boolean isErrorEnabled() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void error(String var1) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void error(String var1, Object var2) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void error(String var1, Object var2, Object var3) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void error(String var1, Object... var2) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void error(String var1, Throwable throwable) {
+ throw new NotImplementedException();
+ }
+
+ public boolean contains(Predicate<Object[]> predicate) {
+ return events.stream().anyMatch(predicate);
+ }
+ }
+}
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/context/MDCPropagationFactoryTest.java b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/context/MDCPropagationFactoryTest.java
new file mode 100644
index 0000000000..f2a6549a2a
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/context/MDCPropagationFactoryTest.java
@@ -0,0 +1,216 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * 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.openecomp.core.logging.context;
+
+import org.slf4j.MDC;
+import org.testng.annotations.Test;
+
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static org.testng.Assert.*;
+
+/**
+ * @author evitaliy
+ * @since 12/09/2016.
+ */
+public class MDCPropagationFactoryTest {
+
+ @Test
+ public void testNoPropagation() throws InterruptedException {
+
+ String uuid = UUID.randomUUID().toString();
+ AtomicBoolean complete = new AtomicBoolean(false);
+ MDC.put("data", uuid);
+
+ Runnable runnable = () -> {
+ assertNull(MDC.get("data"));
+ complete.set(true);
+ };
+
+ Thread thread = new Thread(runnable);
+ thread.start();
+ thread.join();
+
+ assertEquals(MDC.get("data"), uuid);
+ assertTrue(complete.get());
+ }
+
+ @Test
+ public void testPropagation() throws InterruptedException {
+
+ String uuid = UUID.randomUUID().toString();
+ AtomicBoolean complete = new AtomicBoolean(false);
+ MDC.put("data", uuid);
+
+ MdcPropagationService factory = new MdcPropagationService();
+ Runnable runnable = factory.create(() -> {
+ assertEquals(MDC.get("data"), uuid);
+ complete.set(true);
+ });
+
+ Thread thread = new Thread(runnable);
+ thread.start();
+ thread.join();
+
+ assertEquals(MDC.get("data"), uuid);
+ assertTrue(complete.get());
+ }
+
+ @Test
+ public void testReplacement() throws InterruptedException {
+
+ String innerUuid = UUID.randomUUID().toString();
+ AtomicBoolean innerComplete = new AtomicBoolean(false);
+ AtomicBoolean outerComplete = new AtomicBoolean(false);
+
+ MDC.put("data", innerUuid);
+
+ MdcPropagationService factory = new MdcPropagationService();
+
+ // should run with the context of main thread
+ Runnable inner = factory.create(() -> {
+ assertEquals(MDC.get("data"), innerUuid);
+ innerComplete.set(true);
+ });
+
+ // pushes its own context, but runs the inner runnable
+ Runnable outer = () -> {
+ String outerUuid = UUID.randomUUID().toString();
+ MDC.put("data", outerUuid);
+ inner.run();
+ assertEquals(MDC.get("data"), outerUuid);
+ outerComplete.set(true);
+ };
+
+
+ Thread thread = new Thread(outer);
+ thread.start();
+ thread.join();
+
+ assertEquals(MDC.get("data"), innerUuid);
+ assertTrue(outerComplete.get());
+ assertTrue(innerComplete.get());
+ }
+
+ @Test
+ public void testEmpty() throws InterruptedException {
+
+ final AtomicBoolean complete = new AtomicBoolean(false);
+
+ MDC.remove("data");
+ assertNull(MDC.get("data"));
+
+ MdcPropagationService factory = new MdcPropagationService();
+ Runnable runnable = factory.create(() -> {
+ assertNull(MDC.get("data"));
+ complete.set(true);
+ });
+
+ Thread thread = new Thread(runnable);
+ thread.start();
+ thread.join();
+
+ assertNull(MDC.get("data"));
+ assertTrue(complete.get());
+ }
+
+ @Test
+ public void testCleanup() throws Exception {
+
+ String innerUuid = UUID.randomUUID().toString();
+ AtomicBoolean innerComplete = new AtomicBoolean(false);
+ AtomicBoolean outerComplete = new AtomicBoolean(false);
+
+ MDC.put("data", innerUuid);
+
+ MdcPropagationService factory = new MdcPropagationService();
+
+ // should run with the context of main thread
+ Runnable inner = factory.create(() -> {
+ assertEquals(MDC.get("data"), innerUuid);
+ innerComplete.set(true);
+ });
+
+ // pushes its own context, but runs the inner runnable
+ Runnable outer = () -> {
+ assertNull(MDC.get("data"));
+ inner.run();
+ assertNull(MDC.get("data"));
+ outerComplete.set(true);
+ };
+
+ Thread thread = new Thread(outer);
+ thread.start();
+ thread.join();
+
+ assertEquals(MDC.get("data"), innerUuid);
+ assertTrue(outerComplete.get());
+ assertTrue(innerComplete.get());
+ }
+
+ @Test
+ public void testCleanupAfterError() throws Exception {
+
+ String innerUuid = UUID.randomUUID().toString();
+ AtomicBoolean innerComplete = new AtomicBoolean(false);
+ AtomicBoolean outerComplete = new AtomicBoolean(false);
+ AtomicBoolean exceptionThrown = new AtomicBoolean(false);
+
+ MDC.put("data", innerUuid);
+
+ MdcPropagationService factory = new MdcPropagationService();
+
+ // should run with the context of main thread
+ Runnable inner = factory.create(() -> {
+ assertEquals(MDC.get("data"), innerUuid);
+ innerComplete.set(true);
+ throw new RuntimeException();
+ });
+
+ // pushes its own context, but runs the inner runnable
+ Runnable outer = () -> {
+
+ String outerUuid = UUID.randomUUID().toString();
+ MDC.put("data", outerUuid);
+ assertEquals(MDC.get("data"), outerUuid);
+
+ try {
+ inner.run();
+ } catch (RuntimeException e) {
+ exceptionThrown.set(true);
+ } finally {
+ assertEquals(MDC.get("data"), outerUuid);
+ outerComplete.set(true);
+ }
+ };
+
+ Thread thread = new Thread(outer);
+ thread.start();
+ thread.join();
+
+ assertEquals(MDC.get("data"), innerUuid);
+ assertTrue(outerComplete.get());
+ assertTrue(innerComplete.get());
+ assertTrue(exceptionThrown.get());
+ }
+
+}
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/context/TaskFactoryTest.java b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/context/TaskFactoryTest.java
new file mode 100644
index 0000000000..1649302056
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/context/TaskFactoryTest.java
@@ -0,0 +1,26 @@
+package org.openecomp.core.logging.context;
+
+import org.openecomp.core.logging.api.context.TaskFactory;
+import org.testng.annotations.Test;
+
+import java.lang.reflect.Field;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * @author evitaliy
+ * @since 12/09/2016.
+ */
+public class TaskFactoryTest {
+
+ @Test
+ public void testCreate() throws Exception {
+ // test that the service loader loads the right implementation
+ TaskFactory.create(() -> {
+ });
+ Field factory = TaskFactory.class.getDeclaredField("SERVICE");
+ factory.setAccessible(true);
+ Object implementation = factory.get(null);
+ assertEquals(MdcPropagationService.class, implementation.getClass());
+ }
+} \ No newline at end of file
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/logback/EventTypeDiscriminatorTest.java b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/logback/EventTypeDiscriminatorTest.java
new file mode 100644
index 0000000000..e2293b1761
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/logback/EventTypeDiscriminatorTest.java
@@ -0,0 +1,220 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * 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.openecomp.core.logging.logback;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.spi.LoggingEvent;
+import org.openecomp.core.logging.Markers;
+import org.slf4j.MarkerFactory;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * @author EVITALIY
+ * @since 17/08/2016.
+ */
+public class EventTypeDiscriminatorTest {
+
+ private static final String DEBUG = "Debug";
+ private static final String ERROR = "Error";
+
+ @Test
+ public void testGetDefaultDiscriminatingValue() throws Exception {
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ LoggingEvent event = new LoggingEvent();
+ assertEquals(discriminator.getDiscriminatingValue(event), DEBUG);
+ }
+
+ @Test
+ public void testGetErrorDiscriminatingValue() throws Exception {
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ LoggingEvent event = new LoggingEvent();
+ event.setLevel(Level.ERROR);
+ assertEquals(discriminator.getDiscriminatingValue(event), ERROR);
+ }
+
+ @Test
+ public void testGetWarnDiscriminatingValue() throws Exception {
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ LoggingEvent event = new LoggingEvent();
+ event.setLevel(Level.WARN);
+ assertEquals(discriminator.getDiscriminatingValue(event), ERROR);
+ }
+
+ @Test
+ public void testGetInfoDiscriminatingValue() throws Exception {
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ LoggingEvent event = new LoggingEvent();
+ event.setLevel(Level.INFO);
+ assertEquals(discriminator.getDiscriminatingValue(event), ERROR);
+ }
+
+ @Test
+ public void testGetTraceDiscriminatingValue() throws Exception {
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ LoggingEvent event = new LoggingEvent();
+ event.setLevel(Level.TRACE);
+ assertEquals(discriminator.getDiscriminatingValue(event), DEBUG);
+ }
+
+ @Test
+ public void testGetErrorWithAuditDiscriminatingValue() throws Exception {
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ LoggingEvent event = new LoggingEvent();
+ event.setLevel(Level.ERROR);
+ event.setMarker(Markers.AUDIT);
+ assertEquals(discriminator.getDiscriminatingValue(event), ERROR);
+ }
+
+ @Test
+ public void testGetErrorWithMetricsDiscriminatingValue() throws Exception {
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ LoggingEvent event = new LoggingEvent();
+ event.setLevel(Level.ERROR);
+ event.setMarker(Markers.METRICS);
+ assertEquals(discriminator.getDiscriminatingValue(event), ERROR);
+ }
+
+ @Test
+ public void testGetWarnWithAuditDiscriminatingValue() throws Exception {
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ LoggingEvent event = new LoggingEvent();
+ event.setLevel(Level.WARN);
+ event.setMarker(Markers.AUDIT);
+ assertEquals(discriminator.getDiscriminatingValue(event), ERROR);
+ }
+
+ @Test
+ public void testGetWarnWithMetricsDiscriminatingValue() throws Exception {
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ LoggingEvent event = new LoggingEvent();
+ event.setLevel(Level.WARN);
+ event.setMarker(Markers.METRICS);
+ assertEquals(discriminator.getDiscriminatingValue(event), ERROR);
+ }
+
+ @Test
+ public void testGetDebugWithAuditDiscriminatingValue() throws Exception {
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ LoggingEvent event = new LoggingEvent();
+ event.setLevel(Level.DEBUG);
+ event.setMarker(Markers.AUDIT);
+ assertEquals(discriminator.getDiscriminatingValue(event), DEBUG);
+ }
+
+ @Test
+ public void testGetDebugWithMetricsDiscriminatingValue() throws Exception {
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ LoggingEvent event = new LoggingEvent();
+ event.setLevel(Level.DEBUG);
+ event.setMarker(Markers.METRICS);
+ assertEquals(discriminator.getDiscriminatingValue(event), DEBUG);
+ }
+
+ @Test
+ public void testGetTraceWithAuditDiscriminatingValue() throws Exception {
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ LoggingEvent event = new LoggingEvent();
+ event.setLevel(Level.TRACE);
+ event.setMarker(Markers.AUDIT);
+ assertEquals(discriminator.getDiscriminatingValue(event), DEBUG);
+ }
+
+ @Test
+ public void testGetTraceWithMetricsDiscriminatingValue() throws Exception {
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ LoggingEvent event = new LoggingEvent();
+ event.setLevel(Level.TRACE);
+ event.setMarker(Markers.METRICS);
+ assertEquals(discriminator.getDiscriminatingValue(event), DEBUG);
+ }
+
+ @Test
+ public void testGetErrorWithMarkerDiscriminatingValue() throws Exception {
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ LoggingEvent event = new LoggingEvent();
+ event.setLevel(Level.ERROR);
+ event.setMarker(MarkerFactory.getMarker("Dummy"));
+ assertEquals(discriminator.getDiscriminatingValue(event), ERROR);
+ }
+
+ @Test
+ public void testGetWarnWithMarkerDiscriminatingValue() throws Exception {
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ LoggingEvent event = new LoggingEvent();
+ event.setLevel(Level.WARN);
+ event.setMarker(MarkerFactory.getMarker("Dummy"));
+ assertEquals(discriminator.getDiscriminatingValue(event), ERROR);
+ }
+
+ @Test
+ public void testGetDebugWithMarkerDiscriminatingValue() throws Exception {
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ LoggingEvent event = new LoggingEvent();
+ event.setLevel(Level.DEBUG);
+ event.setMarker(MarkerFactory.getMarker("Dummy"));
+ assertEquals(discriminator.getDiscriminatingValue(event), DEBUG);
+ }
+
+ @Test
+ public void testGetTraceWithMarkerDiscriminatingValue() throws Exception {
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ LoggingEvent event = new LoggingEvent();
+ event.setLevel(Level.TRACE);
+ event.setMarker(MarkerFactory.getMarker("Dummy"));
+ assertEquals(discriminator.getDiscriminatingValue(event), DEBUG);
+ }
+
+ @Test
+ public void testGetInfoWithMarkerDiscriminatingValue() throws Exception {
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ LoggingEvent event = new LoggingEvent();
+ event.setLevel(Level.INFO);
+ event.setMarker(MarkerFactory.getMarker("Dummy"));
+ assertEquals(discriminator.getDiscriminatingValue(event), ERROR);
+ }
+
+ @Test
+ public void testGetAuditDiscriminatingValue() throws Exception {
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ LoggingEvent event = new LoggingEvent();
+ event.setLevel(Level.INFO);
+ event.setMarker(Markers.AUDIT);
+ assertEquals(discriminator.getDiscriminatingValue(event), "Audit");
+ }
+
+ @Test
+ public void testGetMetricsMarkerDiscriminatingValue() throws Exception {
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ LoggingEvent event = new LoggingEvent();
+ event.setLevel(Level.INFO);
+ event.setMarker(Markers.METRICS);
+ assertEquals(discriminator.getDiscriminatingValue(event), "Metrics");
+ }
+
+ @Test
+ public void testGetKey() throws Exception {
+ EventTypeDiscriminator discriminator = new EventTypeDiscriminator();
+ assertEquals("eventType", discriminator.getKey());
+ }
+
+}
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/servlet/LoggingFilterTest.java b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/servlet/LoggingFilterTest.java
new file mode 100644
index 0000000000..f1d303b234
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/servlet/LoggingFilterTest.java
@@ -0,0 +1,314 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * 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.openecomp.core.logging.servlet;
+
+import org.slf4j.MDC;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import javax.servlet.*;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.InetAddress;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+
+/**
+ * TODO: Add more tests
+ *
+ * @author EVITALIY
+ * @since 17/08/2016.
+ */
+public class LoggingFilterTest {
+
+ private static final String REMOTE_HOST = UUID.randomUUID().toString();
+
+ @Test
+ public void testDoFilter() throws Exception {
+ LoggingFilter loggingFilter = new LoggingFilter();
+ ServletRequest mockRequest = new TestServletRequest();
+ ServletResponse mockResponse = new TestServletResponse();
+ TestFilterChain mockChain = new TestFilterChain();
+ loggingFilter.doFilter(mockRequest, mockResponse, mockChain);
+ assertEquals(1, mockChain.getCount());
+ assertNull(MDC.getCopyOfContextMap());
+ }
+
+ private static class TestServletRequest implements ServletRequest {
+
+ @Override
+ public Object getAttribute(String s) {
+ return null;
+ }
+
+ @Override
+ public Enumeration getAttributeNames() {
+ return null;
+ }
+
+ @Override
+ public String getCharacterEncoding() {
+ return null;
+ }
+
+ @Override
+ public void setCharacterEncoding(String s) throws UnsupportedEncodingException {
+
+ }
+
+ @Override
+ public int getContentLength() {
+ return 0;
+ }
+
+ @Override
+ public String getContentType() {
+ return null;
+ }
+
+ @Override
+ public ServletInputStream getInputStream() throws IOException {
+ return null;
+ }
+
+ @Override
+ public String getParameter(String s) {
+ return null;
+ }
+
+ @Override
+ public Enumeration getParameterNames() {
+ return null;
+ }
+
+ @Override
+ public String[] getParameterValues(String s) {
+ return new String[0];
+ }
+
+ @Override
+ public Map getParameterMap() {
+ return null;
+ }
+
+ @Override
+ public String getProtocol() {
+ return null;
+ }
+
+ @Override
+ public String getScheme() {
+ return null;
+ }
+
+ @Override
+ public String getServerName() {
+ return null;
+ }
+
+ @Override
+ public int getServerPort() {
+ return 0;
+ }
+
+ @Override
+ public BufferedReader getReader() throws IOException {
+ return null;
+ }
+
+ @Override
+ public String getRemoteAddr() {
+ return null;
+ }
+
+ @Override
+ public String getRemoteHost() {
+ return REMOTE_HOST;
+ }
+
+ @Override
+ public void setAttribute(String s, Object o) {
+
+ }
+
+ @Override
+ public void removeAttribute(String s) {
+
+ }
+
+ @Override
+ public Locale getLocale() {
+ return null;
+ }
+
+ @Override
+ public Enumeration getLocales() {
+ return null;
+ }
+
+ @Override
+ public boolean isSecure() {
+ return false;
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(String s) {
+ return null;
+ }
+
+ @Override
+ public String getRealPath(String s) {
+ return null;
+ }
+
+ @Override
+ public int getRemotePort() {
+ return 0;
+ }
+
+ @Override
+ public String getLocalName() {
+ return null;
+ }
+
+ @Override
+ public String getLocalAddr() {
+ return null;
+ }
+
+ @Override
+ public int getLocalPort() {
+ return 0;
+ }
+ }
+
+ private static class TestFilterChain implements FilterChain {
+
+ private AtomicInteger count = new AtomicInteger(0);
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse)
+ throws IOException, ServletException {
+
+ Assert.assertNotNull(MDC.get("RequestId"));
+ Assert.assertEquals(MDC.get("ServiceInstanceId"), "N/A");
+ Assert.assertEquals(MDC.get("ServiceName"), "SDC");
+ Assert.assertEquals(MDC.get("InstanceUUID"), "N/A");
+ Assert.assertEquals(MDC.get("RemoteHost"), REMOTE_HOST);
+
+ InetAddress host = InetAddress.getLocalHost();
+ Assert.assertEquals(MDC.get("ServerIPAddress"), host.getHostAddress());
+ Assert.assertEquals(MDC.get("ServerFQDN"), host.getHostName());
+
+ count.incrementAndGet();
+ }
+
+ public int getCount() {
+ return count.get();
+ }
+ }
+
+ private static class TestServletResponse implements ServletResponse {
+
+ @Override
+ public String getCharacterEncoding() {
+ return null;
+ }
+
+ @Override
+ public void setCharacterEncoding(String s) {
+
+ }
+
+ @Override
+ public String getContentType() {
+ return null;
+ }
+
+ @Override
+ public void setContentType(String s) {
+
+ }
+
+ @Override
+ public ServletOutputStream getOutputStream() throws IOException {
+ return null;
+ }
+
+ @Override
+ public PrintWriter getWriter() throws IOException {
+ return null;
+ }
+
+ @Override
+ public void setContentLength(int i) {
+
+ }
+
+ @Override
+ public int getBufferSize() {
+ return 0;
+ }
+
+ @Override
+ public void setBufferSize(int i) {
+
+ }
+
+ @Override
+ public void flushBuffer() throws IOException {
+
+ }
+
+ @Override
+ public void resetBuffer() {
+
+ }
+
+ @Override
+ public boolean isCommitted() {
+ return false;
+ }
+
+ @Override
+ public void reset() {
+
+ }
+
+ @Override
+ public Locale getLocale() {
+ return null;
+ }
+
+ @Override
+ public void setLocale(Locale locale) {
+
+ }
+ }
+}
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/README b/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/README
new file mode 100644
index 0000000000..430f36d760
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/README
@@ -0,0 +1,8 @@
+Different routing/dispatching mechanisms can be tested using -Dlogback.configurationFile and a custom configuration
+file, for example
+
+-Dlogback.configurationFile=<path>/dispatching-logback.xml
+
+or
+
+-Dlogback.configurationFile=<path>/sifting-logback.xml \ No newline at end of file
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/dispatching-logback.xml b/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/dispatching-logback.xml
new file mode 100644
index 0000000000..d0aff70b8a
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/dispatching-logback.xml
@@ -0,0 +1,335 @@
+<configuration scan="true" scanPeriod="3 seconds">
+ <!--<jmxConfigurator /> -->
+ <!-- directory path for all other type logs -->
+ <property name="logDir" value="logs" />
+
+ <!-- directory path for debugging type logs -->
+ <property name="debugDir" value="debug-logs" />
+
+ <!-- specify the component name -->
+ <property name="componentName" value="SDC" />
+
+ <!-- log file names -->
+ <property name="generalLogName" value="application" />
+ <property name="securityLogName" value="security" />
+ <property name="performanceLogName" value="performance" />
+ <property name="serverLogName" value="server" />
+ <property name="policyLogName" value="policy" />
+ <property name="errorLogName" value="error" />
+ <property name="metricsLogName" value="metrics" />
+ <property name="auditLogName" value="audit" />
+ <property name="debugLogName" value="debug" />
+
+ <property name="defaultPattern" value="%date{ISO8601,UTC}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{VirtualServerName}|%X{ServiceName}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}|%X{Timer}| %msg%n" />
+
+ <property name="debugLoggerPattern" value="%date{ISO8601,UTC}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{VirtualServerName}|%X{ServiceName}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}|%X{Timer}|[%caller{3}]| %msg%n" />
+
+ <property name="logDirectory" value="${logDir}/${componentName}" />
+ <property name="debugLogDirectory" value="${debugDir}/${componentName}" />
+
+
+ <!-- Example evaluator filter applied against console appender -->
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>${defaultPattern}</pattern>
+ </encoder>
+ </appender>
+
+ <!-- ============================================================================ -->
+ <!-- EELF Appenders -->
+ <!-- ============================================================================ -->
+
+ <!-- The EELFAppender is used to record events to the general application
+ log -->
+
+
+ <appender name="EELF"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDirectory}/${generalLogName}.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <fileNamePattern>${logDirectory}/${generalLogName}.%i.log.zip
+ </fileNamePattern>
+ <minIndex>1</minIndex>
+ <maxIndex>9</maxIndex>
+ </rollingPolicy>
+ <triggeringPolicy
+ class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>5MB</maxFileSize>
+ </triggeringPolicy>
+ <encoder>
+ <pattern>${defaultPattern}</pattern>
+ </encoder>
+ </appender>
+
+ <appender name="asyncEELF" class="ch.qos.logback.classic.AsyncAppender">
+ <queueSize>256</queueSize>
+ <appender-ref ref="EELF" />
+ </appender>
+
+ <!-- EELF Security Appender. This appender is used to record security events
+ to the security log file. Security events are separate from other loggers
+ in EELF so that security log records can be captured and managed in a secure
+ way separate from the other logs. This appender is set to never discard any
+ events. -->
+ <appender name="EELFSecurity"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDirectory}/${securityLogName}.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <fileNamePattern>${logDirectory}/${securityLogName}.%i.log.zip
+ </fileNamePattern>
+ <minIndex>1</minIndex>
+ <maxIndex>9</maxIndex>
+ </rollingPolicy>
+ <triggeringPolicy
+ class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>5MB</maxFileSize>
+ </triggeringPolicy>
+ <encoder>
+ <pattern>${defaultPattern}</pattern>
+ </encoder>
+ </appender>
+
+ <appender name="asyncEELFSecurity" class="ch.qos.logback.classic.AsyncAppender">
+ <queueSize>256</queueSize>
+ <discardingThreshold>0</discardingThreshold>
+ <appender-ref ref="EELFSecurity" />
+ </appender>
+
+ <!-- EELF Performance Appender. This appender is used to record performance
+ records. -->
+ <appender name="EELFPerformance"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDirectory}/${performanceLogName}.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <fileNamePattern>${logDirectory}/${performanceLogName}.%i.log.zip
+ </fileNamePattern>
+ <minIndex>1</minIndex>
+ <maxIndex>9</maxIndex>
+ </rollingPolicy>
+ <triggeringPolicy
+ class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>5MB</maxFileSize>
+ </triggeringPolicy>
+ <encoder>
+ <outputPatternAsHeader>true</outputPatternAsHeader>
+ <pattern>${defaultPattern}</pattern>
+ </encoder>
+ </appender>
+ <appender name="asyncEELFPerformance" class="ch.qos.logback.classic.AsyncAppender">
+ <queueSize>256</queueSize>
+ <appender-ref ref="EELFPerformance" />
+ </appender>
+
+ <!-- EELF Server Appender. This appender is used to record Server related
+ logging events. The Server logger and appender are specializations of the
+ EELF application root logger and appender. This can be used to segregate Server
+ events from other components, or it can be eliminated to record these events
+ as part of the application root log. -->
+ <appender name="EELFServer"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDirectory}/${serverLogName}.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <fileNamePattern>${logDirectory}/${serverLogName}.%i.log.zip
+ </fileNamePattern>
+ <minIndex>1</minIndex>
+ <maxIndex>9</maxIndex>
+ </rollingPolicy>
+ <triggeringPolicy
+ class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>5MB</maxFileSize>
+ </triggeringPolicy>
+ <encoder>
+ <pattern>${defaultPattern}</pattern>
+ </encoder>
+ </appender>
+ <appender name="asyncEELFServer" class="ch.qos.logback.classic.AsyncAppender">
+ <queueSize>256</queueSize>
+ <appender-ref ref="EELFServer" />
+ </appender>
+
+
+ <!-- EELF Policy Appender. This appender is used to record Policy engine
+ related logging events. The Policy logger and appender are specializations
+ of the EELF application root logger and appender. This can be used to segregate
+ Policy engine events from other components, or it can be eliminated to record
+ these events as part of the application root log. -->
+ <appender name="EELFPolicy"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDirectory}/${policyLogName}.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <fileNamePattern>${logDirectory}/${policyLogName}.%i.log.zip
+ </fileNamePattern>
+ <minIndex>1</minIndex>
+ <maxIndex>9</maxIndex>
+ </rollingPolicy>
+ <triggeringPolicy
+ class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>5MB</maxFileSize>
+ </triggeringPolicy>
+ <encoder>
+ <pattern>${defaultPattern}</pattern>
+ </encoder>
+ </appender>
+ <appender name="asyncEELFPolicy" class="ch.qos.logback.classic.AsyncAppender">
+ <queueSize>256</queueSize>
+ <appender-ref ref="EELFPolicy" />
+ </appender>
+
+
+ <!-- EELF Audit Appender. This appender is used to record audit engine
+ related logging events. The audit logger and appender are specializations
+ of the EELF application root logger and appender. This can be used to segregate
+ Policy engine events from other components, or it can be eliminated to record
+ these events as part of the application root log. -->
+
+ <appender name="EELFAudit"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDirectory}/${auditLogName}.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <fileNamePattern>${logDirectory}/${auditLogName}.%i.log.zip
+ </fileNamePattern>
+ <minIndex>1</minIndex>
+ <maxIndex>9</maxIndex>
+ </rollingPolicy>
+ <triggeringPolicy
+ class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>5MB</maxFileSize>
+ </triggeringPolicy>
+ <encoder>
+ <pattern>${defaultPattern}</pattern>
+ </encoder>
+ </appender>
+ <appender name="asyncEELFAudit" class="ch.qos.logback.classic.AsyncAppender">
+ <queueSize>256</queueSize>
+ <appender-ref ref="EELFAudit" />
+ </appender>
+
+<appender name="EELFMetrics"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDirectory}/${metricsLogName}.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <fileNamePattern>${logDirectory}/${metricsLogName}.%i.log.zip
+ </fileNamePattern>
+ <minIndex>1</minIndex>
+ <maxIndex>9</maxIndex>
+ </rollingPolicy>
+ <triggeringPolicy
+ class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>5MB</maxFileSize>
+ </triggeringPolicy>
+ <encoder>
+ <!-- <pattern>"%d{HH:mm:ss.SSS} [%thread] %-5level %logger{1024} -
+ %msg%n"</pattern> -->
+ <pattern>${defaultPattern}</pattern>
+ </encoder>
+ </appender>
+
+
+ <appender name="asyncEELFMetrics" class="ch.qos.logback.classic.AsyncAppender">
+ <queueSize>256</queueSize>
+ <appender-ref ref="EELFMetrics"/>
+ </appender>
+
+ <appender name="EELFError"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDirectory}/${errorLogName}.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <fileNamePattern>${logDirectory}/${errorLogName}.%i.log.zip
+ </fileNamePattern>
+ <minIndex>1</minIndex>
+ <maxIndex>9</maxIndex>
+ </rollingPolicy>
+ <triggeringPolicy
+ class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>5MB</maxFileSize>
+ </triggeringPolicy>
+ <encoder>
+ <pattern>${defaultPattern}</pattern>
+ </encoder>
+ </appender>
+
+ <appender name="asyncEELFError" class="ch.qos.logback.classic.AsyncAppender">
+ <queueSize>256</queueSize>
+ <appender-ref ref="EELFError"/>
+ </appender>
+
+ <appender name="EELFDebug"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${debugLogDirectory}/${debugLogName}.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <fileNamePattern>${debugLogDirectory}/${debugLogName}.%i.log.zip
+ </fileNamePattern>
+ <minIndex>1</minIndex>
+ <maxIndex>9</maxIndex>
+ </rollingPolicy>
+ <triggeringPolicy
+ class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>5MB</maxFileSize>
+ </triggeringPolicy>
+ <encoder>
+ <pattern>${debugLoggerPattern}</pattern>
+ </encoder>
+ </appender>
+
+ <appender name="asyncEELFDebug" class="ch.qos.logback.classic.AsyncAppender">
+ <queueSize>256</queueSize>
+ <appender-ref ref="EELFDebug" />
+ <includeCallerData>true</includeCallerData>
+ </appender>
+
+
+ <!-- ============================================================================ -->
+ <!-- EELF loggers -->
+ <!-- ============================================================================ -->
+ <logger name="org.openecomp.eelf" level="info" additivity="false">
+ <appender-ref ref="asyncEELF" />
+ </logger>
+ <logger name="org.openecomp.eelf.security" level="info" additivity="false">
+ <appender-ref ref="asyncEELFSecurity" />
+ </logger>
+ <logger name="org.openecomp.eelf.perf" level="info" additivity="false">
+ <appender-ref ref="asyncEELFPerformance" />
+ </logger>
+ <logger name="org.openecomp.eelf.server" level="info" additivity="false">
+ <appender-ref ref="asyncEELFServer" />
+ </logger>
+ <logger name="org.openecomp.eelf.policy" level="info" additivity="false">
+ <appender-ref ref="asyncEELFPolicy" />
+ </logger>
+
+ <logger name="org.openecomp.eelf.audit" level="info" additivity="false">
+ <appender-ref ref="asyncEELFAudit" />
+ </logger>
+
+ <logger name="org.openecomp.eelf.metrics" level="info" additivity="false">
+ <appender-ref ref="asyncEELFMetrics" />
+ </logger>
+
+
+ <logger name="org.openecomp.eelf.error" level="error" additivity="false">
+ <appender-ref ref="asyncEELFError" />
+ </logger>
+
+ <logger name="org.openecomp.eelf.debug" level="debug" additivity="false">
+ <appender-ref ref="asyncEELFDebug" />
+ </logger>
+
+ <appender name="DISPATCHER" class="org.openecomp.core.logging.logback.DispatchingAppender">
+ <discriminator class="org.openecomp.core.logging.logback.EventTypeDiscriminator"/>
+ <appenderNamePattern>asyncEELF%s</appenderNamePattern>
+ </appender>
+
+ <root level="DEBUG" additivity="false">
+ <appender-ref ref="DISPATCHER" />
+ </root>
+
+</configuration> \ No newline at end of file
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/logback.xml b/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/logback.xml
new file mode 100644
index 0000000000..c79eca228b
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/logback.xml
@@ -0,0 +1,41 @@
+<configuration scan="true" scanPeriod="3 seconds">
+
+ <property name="logDir" value="logs" />
+ <property name="componentName" value="SDC" />
+
+ <property name="defaultPattern"
+ value="%logger|%date{ISO8601,UTC}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{VirtualServerName}|%X{ServiceName}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}|%X{Timer}| %msg%n" />
+
+ <property name="logDirectory" value="${logDir}/${componentName}" />
+
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>${defaultPattern}</pattern>
+ </encoder>
+ </appender>
+
+ <appender name="DISPATCHER" class="ch.qos.logback.classic.sift.SiftingAppender">
+ <discriminator class="org.openecomp.core.logging.logback.EventTypeDiscriminator"/>
+ <sift>
+ <appender name="${eventType}" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDirectory}/${eventType}.log</file>
+ <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <fileNamePattern>${logDirectory}/${eventType}.%i.log.zip</fileNamePattern>
+ <minIndex>1</minIndex>
+ <maxIndex>9</maxIndex>
+ </rollingPolicy>
+ <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>5MB</maxFileSize>
+ </triggeringPolicy>
+ <encoder>
+ <pattern>${defaultPattern}</pattern>
+ </encoder>
+ </appender>
+ </sift>
+ </appender>
+
+ <root level="DEBUG">
+ <appender-ref ref="DISPATCHER" />
+ </root>
+
+</configuration> \ No newline at end of file
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/sifting-logback.xml b/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/sifting-logback.xml
new file mode 100644
index 0000000000..1b50e10924
--- /dev/null
+++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/sifting-logback.xml
@@ -0,0 +1,42 @@
+<configuration scan="true" scanPeriod="3 seconds" debug="true">
+
+ <property name="logDir" value="logs" />
+ <property name="componentName" value="SDC" />
+
+ <property name="defaultPattern" value="%date{ISO8601,UTC}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{VirtualServerName}|%X{ServiceName}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}|%X{Timer}| %msg%n" />
+
+ <property name="debugPattern" value="%date{ISO8601,UTC}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{VirtualServerName}|%X{ServiceName}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}|%X{Timer}|[%caller{3}]| %msg%n" />
+
+ <property name="logDirectory" value="${logDir}/${componentName}" />
+
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>${defaultPattern}</pattern>
+ </encoder>
+ </appender>
+
+ <appender name="DISPATCHER" class="ch.qos.logback.classic.sift.SiftingAppender">
+ <discriminator class="org.openecomp.core.logging.logback.EventTypeDiscriminator"/>
+ <sift>
+ <appender name="${eventType}" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDirectory}/${eventType}.log</file>
+ <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <fileNamePattern>${logDirectory}/${eventType}.%i.log.zip</fileNamePattern>
+ <minIndex>1</minIndex>
+ <maxIndex>9</maxIndex>
+ </rollingPolicy>
+ <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>5MB</maxFileSize>
+ </triggeringPolicy>
+ <encoder>
+ <pattern>${defaultPattern}</pattern>
+ </encoder>
+ </appender>
+ </sift>
+ </appender>
+
+ <root level="DEBUG" additivity="false">
+ <appender-ref ref="DISPATCHER" />
+ </root>
+
+</configuration> \ No newline at end of file
diff --git a/common/openecomp-logging-lib/pom.xml b/common/openecomp-logging-lib/pom.xml
new file mode 100644
index 0000000000..9229d2a8a2
--- /dev/null
+++ b/common/openecomp-logging-lib/pom.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.openecomp.sdc.common</groupId>
+ <artifactId>openecomp-logging-lib</artifactId>
+ <packaging>pom</packaging>
+
+ <parent>
+ <artifactId>openecomp-common-lib</artifactId>
+ <groupId>org.openecomp.sdc.common</groupId>
+ <version>1.1.0-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+
+ <modules>
+ <module>openecomp-logging-api</module>
+ <module>openecomp-logging-core</module>
+ </modules>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ </dependency>
+ </dependencies>
+
+</project>