From 280f8015d06af1f41a3ef12e8300801c7a5e0d54 Mon Sep 17 00:00:00 2001 From: AviZi Date: Fri, 9 Jun 2017 02:39:56 +0300 Subject: [SDC-29] Amdocs OnBoard 1707 initial commit. Change-Id: Ie4d12a3f574008b792899b368a0902a8b46b5370 Signed-off-by: AviZi --- .../openecomp-logging-api/pom.xml | 18 + .../openecomp/core/logging/api/BaseFactory.java | 54 +++ .../org/openecomp/core/logging/api/Logger.java | 103 +++++ .../core/logging/api/LoggerCreationService.java | 11 + .../openecomp/core/logging/api/LoggerFactory.java | 232 +++++++++++ .../core/logging/api/annotations/Metrics.java | 15 + .../api/context/ContextPropagationService.java | 10 + .../core/logging/api/context/TaskFactory.java | 73 ++++ .../core/logging/api/LoggerFactoryTest.java | 74 ++++ .../core/logging/api/context/TaskFactoryTest.java | 30 ++ .../openecomp-logging-core/README | 29 ++ .../openecomp-logging-core/pom.xml | 72 ++++ .../java/org/openecomp/core/logging/Markers.java | 21 + .../core/logging/Slf4JLoggerCreationService.java | 236 +++++++++++ .../core/logging/aspects/MetricsAspect.java | 72 ++++ .../logging/context/MdcPropagationService.java | 71 ++++ .../core/logging/logback/DispatchingAppender.java | 142 +++++++ .../logging/logback/EventTypeDiscriminator.java | 121 ++++++ .../core/logging/servlet/LoggingFilter.java | 135 ++++++ ...penecomp.core.logging.api.LoggerCreationService | 1 + ...e.logging.api.context.ContextPropagationService | 1 + .../openecomp/core/logging/LoggerFactoryTest.java | 25 ++ .../org/openecomp/core/logging/RoutingTest.java | 155 +++++++ .../org/openecomp/core/logging/api/LoggerTest.java | 65 +++ .../core/logging/aspects/MetricsAspectTest.java | 452 +++++++++++++++++++++ .../logging/context/MDCPropagationFactoryTest.java | 216 ++++++++++ .../core/logging/context/TaskFactoryTest.java | 26 ++ .../logback/EventTypeDiscriminatorTest.java | 220 ++++++++++ .../core/logging/servlet/LoggingFilterTest.java | 314 ++++++++++++++ .../src/test/resources/README | 8 + .../src/test/resources/dispatching-logback.xml | 335 +++++++++++++++ .../src/test/resources/logback.xml | 41 ++ .../src/test/resources/sifting-logback.xml | 42 ++ common/openecomp-logging-lib/pom.xml | 34 ++ 34 files changed, 3454 insertions(+) create mode 100644 common/openecomp-logging-lib/openecomp-logging-api/pom.xml create mode 100644 common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/BaseFactory.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/Logger.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/LoggerCreationService.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/LoggerFactory.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/annotations/Metrics.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/context/ContextPropagationService.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-api/src/main/java/org/openecomp/core/logging/api/context/TaskFactory.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-api/src/test/java/org/openecomp/core/logging/api/LoggerFactoryTest.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-api/src/test/java/org/openecomp/core/logging/api/context/TaskFactoryTest.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/README create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/pom.xml create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/Markers.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/Slf4JLoggerCreationService.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/aspects/MetricsAspect.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/context/MdcPropagationService.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/logback/DispatchingAppender.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/logback/EventTypeDiscriminator.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/servlet/LoggingFilter.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/main/resources/META-INF/services/org.openecomp.core.logging.api.LoggerCreationService create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/main/resources/META-INF/services/org.openecomp.core.logging.api.context.ContextPropagationService create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/LoggerFactoryTest.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/RoutingTest.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/api/LoggerTest.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/aspects/MetricsAspectTest.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/context/MDCPropagationFactoryTest.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/context/TaskFactoryTest.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/logback/EventTypeDiscriminatorTest.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/servlet/LoggingFilterTest.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/README create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/dispatching-logback.xml create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/logback.xml create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/sifting-logback.xml create mode 100644 common/openecomp-logging-lib/pom.xml (limited to 'common/openecomp-logging-lib') 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 @@ + + + 4.0.0 + + openecomp-configuration-management-test + org.openecomp.sdc.common + openecomp-logging-api + + + openecomp-logging-lib + org.openecomp.sdc.common + 1.1.0-SNAPSHOT + .. + + + 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.

In order to use the + * factory, a particular (e.g. framework-specific) implementation of a service must be configured as + * described in java.util.ServiceLoader).

+ * + * @see java.util.ServiceLoader + */ +public class BaseFactory { + + protected static T locateService(Class clazz) throws Exception { + + T service; + ServiceLoader loader = ServiceLoader.load(clazz); + Iterator 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; + +/** + *

This interface defines logging as specified by OPENECOMP logging requirements.

Formatted + * messages must follow the Factory to hide a concrete, framework-specific implementation of logger creation.

The + * service used by this factory must implement {@link LoggerCreationService}. If no implementation + * has been configured or could not be instantiated, a no-op logger will be used, and no + * events will be logged. This is done to prevent recursion if attempts are being made to log + * exceptions that resulted from logger initialization.

+ * + * @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; + +/** + *

Should be used to propagate a diagnostic context (for instance MDC) to other threads.

Applicable when + * creating a child thread directly, or submitting tasks for potentially postponed execution via an + * Executor + * (including any of the executor + * services and ForkJoinPool).

+ *

The service used by this factory must implement {@link ContextPropagationService}.

+ * + * @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 @@ + + + 4.0.0 + + openecomp-configuration-management-test + org.openecomp.sdc.common + openecomp-logging-core + + + openecomp-logging-lib + org.openecomp.sdc.common + 1.1.0-SNAPSHOT + .. + + + + 1.1.7 + 1.6.5 + 3.4 + + + + + org.aspectj + aspectjrt + + + org.openecomp.sdc.common + openecomp-logging-api + ${project.version} + + + ch.qos.logback + logback-classic + ${logback.version} + + + ch.qos.logback + logback-core + ${logback.version} + + + + + org.easymock + easymock + ${easymock.version} + test + + + org.powermock + powermock-api-easymock + ${powermock.version} + test + + + org.powermock + powermock-core + ${powermock.version} + test + + + org.powermock + powermock-module-testng + ${powermock.version} + test + + + + 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; + +/** + *

The list of markers that can be used for special logging such as metrics, audit, etc.

+ *

Although markers can be easily instantiated whenever needed, having constants for them helps + * eliminate mistakes - misspelling, using a marker that is not handled, etc.

Usage:

+ *
+ *     Logger log = LogFactory.getLogger(this.getClass());
+ *     log.info(Markers.AUDIT, "User '{}' logged out", user);
+ * 
+ * + * @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; + +/** + *

Wraps around any method annotated with {@link Metrics} to measure and log its execution time + * in milliseconds.

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.

See, for example, Aspect + * Oriented Programming with Spring.

+ * + * @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 SLF4J Mapped Diagnostic Context + * (MDC) 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 context; + + private MdcCopyingWrapper(Runnable task) { + this.task = task; + this.context = MDC.getCopyOfContextMap(); + } + + private static void replaceMdc(Map context) { + + if (context == null) { + MDC.clear(); + } else { + MDC.setContextMap(context); + } + } + + @Override + public void run() { + + Map 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; + +/** + *

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.

Changes that must be made + * in logback.xml supplied with EELF:

+ *
+ *     <appender name="DISPATCHER" class="DispatchingAppender">
+ *          <discriminator class="EventTypeDiscriminator"/>
+ *          <appenderNamePattern>asyncEELF%s</appenderNamePattern>
+ *     </appender>
+ *     <root level="INFO" additivity="false">
+ *          <appender-ref ref="DISPATCHER" />
+ *      </root>
+ * 
+ */ +public class DispatchingAppender extends AppenderBase { + + // "magic" appender to indicate a missing appender + private static final Appender NO_APPENDER = new DispatchingAppender(); + + private Map> appenders = new ConcurrentHashMap<>(); + + private Discriminator discriminator; + private String appenderNamePattern; + + public Discriminator getDiscriminator() { + return this.discriminator; + } + + @DefaultClass(MDCBasedDiscriminator.class) + public void setDiscriminator(Discriminator 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 appender = this.lookupAppender(appenderName); + if (appender == NO_APPENDER) { + this.addError(String.format("Appender %s does not exist", appenderName)); + } else { + appender.doAppend(event); + } + } + } + + private Appender lookupAppender(String key) { + + Appender appender = appenders.get(key); + if (appender != null) { + return appender; + } + + LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + for (Logger log : context.getLoggerList()) { + + Iterator> iterator = log.iteratorForAppenders(); + while (iterator.hasNext()) { + + Appender 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, + *
+ *     <configuration>
+ *         <appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
+ *             <discriminator class="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="INFO">
+ *             <appender-ref ref="SIFT" />
+ *         </root>
+ *     </configuration>
+ * 
+ */ +public class EventTypeDiscriminator extends AbstractDiscriminator { + + 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; + +/** + *

Pushes information required by EELF onto MDC (Mapped Diagnostic Context).

This is + * servlet filter that should be configured in web.xml to be used. Example:

+ *
+ *  <filter>
+ *      <filter-name>LoggingServletFilter</filter-name>
+ *      <filter-class>LoggingFilter</filter-class>
+ *  </filter>
+ *  <filter-mapping>
+ *      <filter-name>LoggingServletFilter</filter-name>
+ *      <url-pattern>/*</url-pattern>
+ *  </filter-mapping>
+ * 
+ */ +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 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 { + + private List events = Collections.synchronizedList(new ArrayList<>(10)); + + @Override + protected void append(ILoggingEvent event) { + this.events.add(event); + } + + public boolean contains(Predicate 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 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 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=/dispatching-logback.xml + +or + +-Dlogback.configurationFile=/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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${defaultPattern} + + + + + + + + + + + + ${logDirectory}/${generalLogName}.log + + ${logDirectory}/${generalLogName}.%i.log.zip + + 1 + 9 + + + 5MB + + + ${defaultPattern} + + + + + 256 + + + + + + ${logDirectory}/${securityLogName}.log + + ${logDirectory}/${securityLogName}.%i.log.zip + + 1 + 9 + + + 5MB + + + ${defaultPattern} + + + + + 256 + 0 + + + + + + ${logDirectory}/${performanceLogName}.log + + ${logDirectory}/${performanceLogName}.%i.log.zip + + 1 + 9 + + + 5MB + + + true + ${defaultPattern} + + + + 256 + + + + + + ${logDirectory}/${serverLogName}.log + + ${logDirectory}/${serverLogName}.%i.log.zip + + 1 + 9 + + + 5MB + + + ${defaultPattern} + + + + 256 + + + + + + + ${logDirectory}/${policyLogName}.log + + ${logDirectory}/${policyLogName}.%i.log.zip + + 1 + 9 + + + 5MB + + + ${defaultPattern} + + + + 256 + + + + + + + + ${logDirectory}/${auditLogName}.log + + ${logDirectory}/${auditLogName}.%i.log.zip + + 1 + 9 + + + 5MB + + + ${defaultPattern} + + + + 256 + + + + + ${logDirectory}/${metricsLogName}.log + + ${logDirectory}/${metricsLogName}.%i.log.zip + + 1 + 9 + + + 5MB + + + + ${defaultPattern} + + + + + + 256 + + + + + ${logDirectory}/${errorLogName}.log + + ${logDirectory}/${errorLogName}.%i.log.zip + + 1 + 9 + + + 5MB + + + ${defaultPattern} + + + + + 256 + + + + + ${debugLogDirectory}/${debugLogName}.log + + ${debugLogDirectory}/${debugLogName}.%i.log.zip + + 1 + 9 + + + 5MB + + + ${debugLoggerPattern} + + + + + 256 + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + asyncEELF%s + + + + + + + \ 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 @@ + + + + + + + + + + + + ${defaultPattern} + + + + + + + + ${logDirectory}/${eventType}.log + + ${logDirectory}/${eventType}.%i.log.zip + 1 + 9 + + + 5MB + + + ${defaultPattern} + + + + + + + + + + \ 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 @@ + + + + + + + + + + + + + + ${defaultPattern} + + + + + + + + ${logDirectory}/${eventType}.log + + ${logDirectory}/${eventType}.%i.log.zip + 1 + 9 + + + 5MB + + + ${defaultPattern} + + + + + + + + + + \ 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 @@ + + + 4.0.0 + + org.openecomp.sdc.common + openecomp-logging-lib + pom + + + openecomp-common-lib + org.openecomp.sdc.common + 1.1.0-SNAPSHOT + .. + + + + openecomp-logging-api + openecomp-logging-core + + + + + org.slf4j + slf4j-api + + + javax.servlet + servlet-api + + + + -- cgit 1.2.3-korg