diff options
author | olegb <olegb@amdocs.com> | 2018-02-19 16:19:17 +0200 |
---|---|---|
committer | Vitaly Emporopulo <Vitaliy.Emporopulo@amdocs.com> | 2018-03-15 08:27:59 +0000 |
commit | 9c40f569b817e0886d95ad8b1ac235d8644873da (patch) | |
tree | 8613cc536ab0b30b2e96a70d94bdff52944295e7 | |
parent | 5979cf87e450fc2b47360cdfced44808dc2d82bf (diff) |
Changed logging context API
Issue-ID: SDC-772
Change-Id: I9dce63f3a1bb7df067cf06a96158afa7d799319e
Signed-off-by: olegb <olegb@amdocs.com>
15 files changed, 571 insertions, 279 deletions
diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggingContext.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggingContext.java index f827fec50f..879d9cf098 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggingContext.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggingContext.java @@ -1,5 +1,5 @@ /* - * Copyright © 2016-2017 European Support Limited + * Copyright © 2016-2018 European Support Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,37 +22,38 @@ import java.util.Objects; import java.util.concurrent.Callable; /** - * <a>Factory to hide a concrete, framework-specific implementation of diagnostic context.</a> - * <p>The service used by this factory must implement {@link LoggingContextService}. If no - * implementation has been configured or could be instantiated, a <b>no-op context service</b> will be - * used, and <b>no context</b> will be stored or propagated. No errors will be generated, so that the application can - * still work (albeit without proper logging).</p> + * <p>Factory to hide a concrete, framework-specific implementation of diagnostic context.</p> * - * @author evitaliy - * @since 07/01/2018. + * <p>The service used by this factory must implement {@link LoggingContextService}. If no implementation has been + * configured or could be instantiated, a <b>no-op context service</b> will be used, and <b>no context</b> will be + * stored or propagated. No errors will be generated, so that the application can still work (albeit without proper + * logging).</p> * + * @author evitaliy * @see ServiceBinder * @see LoggingContextService + * @since 07 Jan 2018 */ public class LoggingContext { - private static final LoggingContextService SERVICE = ServiceBinder.getContextServiceBinding().orElse( + private static final LoggingContextService SERVICE = + ServiceBinder.getContextServiceBinding().orElse( new NoOpLoggingContextService()); private LoggingContext() { // prevent instantiation } - public static void put(String key, String value) { - SERVICE.put(key, value); + public static void putRequestId(String requestId) { + SERVICE.putRequestId(requestId); } - public static String get(String key) { - return SERVICE.get(key); + public static void putServiceName(String serviceName) { + SERVICE.putServiceName(serviceName); } - public static void remove(String key) { - SERVICE.remove(key); + public static void putPartnerName(String partnerName) { + SERVICE.putPartnerName(partnerName); } public static void clear() { @@ -69,24 +70,19 @@ public class LoggingContext { private static class NoOpLoggingContextService implements LoggingContextService { - private static final String KEY_CANNOT_BE_NULL = "Key cannot be null"; - @Override - public void put(String key, String value) { - Objects.requireNonNull(key, KEY_CANNOT_BE_NULL); - // no-op + public void putRequestId(String requestId) { + Objects.requireNonNull(requestId, "Request ID cannot be null"); } @Override - public String get(String key) { - Objects.requireNonNull(key, KEY_CANNOT_BE_NULL); - return null; + public void putServiceName(String serviceName) { + Objects.requireNonNull(serviceName, "Service name cannot be null"); } @Override - public void remove(String key) { - Objects.requireNonNull(key, KEY_CANNOT_BE_NULL); - // no-op + public void putPartnerName(String partnerName) { + Objects.requireNonNull(partnerName, "Partner name cannot be null"); } @Override diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/spi/LoggingContextService.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/spi/LoggingContextService.java index 7aed0fc7dc..07b93c1468 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/spi/LoggingContextService.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/spi/LoggingContextService.java @@ -1,12 +1,12 @@ /* - * Copyright © 2016-2017 European Support Limited + * Copyright © 2016-2018 European Support Limited * * 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. @@ -19,37 +19,25 @@ package org.openecomp.sdc.logging.spi; import java.util.concurrent.Callable; /** - * Should be used to implement a framework-specific mechanism of managing a per-thread diagnostic context - * (for instance <a href="http://www.slf4j.org/manual.html#mdc">MDC</a>), and propagating it to child threads if needed. - * Context propagation should be used when creating a child thread directly, or submitting tasks for potentially - * postponed execution via an - * <a href="http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html">Executor</a> (including any of - * the - * <a href="http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html">executor services</a> - * and <a href="http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ForkJoinPool.html">ForkJoinPool</a>). + * Should be used to implement a framework-specific mechanism of managing a per-thread diagnostic context (for instance + * <a href="http://www.slf4j.org/manual.html#mdc">MDC</a>), and propagating it to child threads if needed. Context + * propagation should be used when creating a child thread directly, or submitting tasks for potentially postponed + * execution via an <a href="http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html">Executor</a> + * (including any of the <a href="http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html"> + * executor services</a> and <a href="http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ForkJoinPool.html"> + * ForkJoinPool</a>). * * @author evitaliy - * @since 07/01/2018. + * @since 07 Jan 2018 */ public interface LoggingContextService { - /** - * Allows to store a key-value pair on thread context - */ - void put(String key, String value); + void putRequestId(String requestId); - /** - * Returns the value associated with a key stored on thread context - * - * @return value or <code>null</code> if the key does not exits - */ - String get(String key); + void putServiceName(String serviceName); - /** - * Removes a particular key from thread context - */ - void remove(String key); + void putPartnerName(String partnerName); /** * Clear logging thread context @@ -57,14 +45,14 @@ public interface LoggingContextService { void clear(); /** - * Copies logging context of current thread onto a {@link Runnable}, so that the context is available - * when this {@link Runnable} runs in another thread. + * Copies logging context of current thread onto a {@link Runnable}, so that the context is available when this + * {@link Runnable} runs in another thread. */ Runnable copyToRunnable(Runnable runnable); /** - * Copies logging context of current thread onto a {@link Callable}, so that the context is available - * when this {@link Callable} runs in another thread + * Copies logging context of current thread onto a {@link Callable}, so that the context is available when this + * {@link Callable} runs in another thread */ <V> Callable<V> copyToCallable(Callable<V> callable); } diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/LoggingContextTest.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/LoggingContextTest.java index 79252cde0b..bfc53a3146 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/LoggingContextTest.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/LoggingContextTest.java @@ -16,14 +16,12 @@ package org.openecomp.sdc.logging.api; -import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; import java.lang.reflect.Field; import java.util.concurrent.Callable; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; +import org.testng.annotations.Test; /** * @author EVITALIY @@ -40,36 +38,19 @@ public class LoggingContextTest { "org.openecomp.sdc.logging.api.LoggingContext$NoOpLoggingContextService"); } - @Test - public void putDoesNotHaveEffectWhenNoBinding() { - final String key = "Key"; - LoggingContext.put(key, "Dummy"); - assertNull(LoggingContext.get(key)); - } - @Test(expectedExceptions = NullPointerException.class) - public void throwNpeWhenPutWithKeyNull() { - LoggingContext.put(null, "value"); - } - - @Test - public void getAlwaysReturnsNull() { - assertNull(LoggingContext.get("GetKey")); + public void throwNpeWhenPartnerNameIsNull() { + LoggingContext.putPartnerName(null); } @Test(expectedExceptions = NullPointerException.class) - public void throwNpeWhenGetWithKeyNull() { - LoggingContext.get(null); - } - - @Test - public void removeDoesNotFail() { - LoggingContext.remove("RemoveKey"); + public void throwNpeWhenServiceNameIsNull() { + LoggingContext.putServiceName(null); } @Test(expectedExceptions = NullPointerException.class) - public void throwNpWhenRemoveWithKeyNull() { - LoggingContext.remove(null); + public void throwNpeWhenRequestIdIsNull() { + LoggingContext.putRequestId(null); } @Test diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/GlobalLoggingContext.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/GlobalLoggingContext.java new file mode 100644 index 0000000000..95dc52c85c --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/GlobalLoggingContext.java @@ -0,0 +1,185 @@ +/* + * Copyright © 2016-2017 European Support Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openecomp.sdc.logging; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.nio.charset.StandardCharsets; +import java.util.Properties; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicLong; +import java.util.prefs.BackingStoreException; +import java.util.prefs.Preferences; + +/** + * Collect information the is required for logging, but should not concern the business code of an application. For + * example, host name and IP address. + * + * @author evitaliy + * @since 04 Mar 2018 + */ +@SuppressWarnings({"UseOfSystemOutOrSystemErr", "CallToPrintStackTrace", "squid:S106", "squid:S1148"}) +public class GlobalLoggingContext { + + private static final String APPLICATION_ID_KEY = "ApplicationId"; + + private static final String CONFIGURATION_RESOURCE = "META-INF/logging/logger.properties"; + + @SuppressWarnings("squid:S1075") + private static final String ID_PREFERENCES_PATH = "/logging/instance/uuid"; + + private static final String APP_DISTINGUISHER_KEY = "app.distinguisher"; + + // 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 DISTINGUISHER; + + private static final String APPLICATION_ID; + + private static final String INSTANCE_ID; + + static { + APPLICATION_ID = System.getProperty(APPLICATION_ID_KEY); + DISTINGUISHER = readDistinguisher(); + INSTANCE_ID = readInstanceId(); + } + + private GlobalLoggingContext() { /* prevent instantiation */ } + + public static String getApplicationId() { + return APPLICATION_ID; + } + + /** + * A distinguisher to allow separation of logs created by applications running with the same configuration, but + * different class-loaders. For instance, when multiple web application are running in the same container and their + * logger configuration is passed at the JVM level. + * + * @return application distinguisher defined in a properties file + */ + public static String getDistinguisher() { + return DISTINGUISHER; + } + + /** + * A unique ID of the logging entity. Is useful to distinguish between different nodes of the same application. It + * is assumed, that the node can be re-started, in which case the unique ID must be retained. + * + * @return unique logging entity ID + */ + public static String getInstanceId() { + return INSTANCE_ID; + } + + /** + * Local host address as returned by Java runtime. A value of host address will be cached for the interval specified + * in {@link HostAddressCache#REFRESH_TIME} + * + * @return local host address, may be null if could not be read for some reason + */ + public static InetAddress getHostAddress() { + return HOST_ADDRESS.get(); + } + + private static String readInstanceId() { + + String appId = System.getProperty(APPLICATION_ID_KEY); + String key = ID_PREFERENCES_PATH + (appId == null ? "" : "/" + appId); + + try { + + // By default, this will be ~/.java/.userPrefs/prefs.xml + final Preferences preferences = Preferences.userRoot(); + String existingId = preferences.get(key, null); + if (existingId != null) { + return existingId; + } + + String newId = UUID.randomUUID().toString(); + preferences.put(key, newId); + preferences.flush(); + return newId; + + } catch (BackingStoreException e) { + e.printStackTrace(); + // don't fail if there's a problem to use the store for some unexpected reason + return UUID.randomUUID().toString(); + } + } + + private static String readDistinguisher() { + + try { + Properties properties = loadConfiguration(); + return properties.getProperty(APP_DISTINGUISHER_KEY, ""); + } catch (IOException e) { + e.printStackTrace(); // can't write to a log + return ""; + } + } + + private static Properties loadConfiguration() throws IOException { + + Properties properties = new Properties(); + + try (InputStream is = Thread.currentThread().getContextClassLoader() + .getResourceAsStream(CONFIGURATION_RESOURCE)) { + + if (is == null) { + return properties; + } + + try (InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) { + properties.load(reader); + return properties; + } + } + } + + private static class HostAddressCache { + + private static final long REFRESH_TIME = 60000L; + + private final AtomicLong lastUpdated = new AtomicLong(0L); + private InetAddress hostAddress; + + public InetAddress get() { + + long current = System.currentTimeMillis(); + if (current - lastUpdated.get() > REFRESH_TIME) { + + synchronized (this) { + + try { + // set now to register the attempt even if failed + lastUpdated.set(current); + hostAddress = InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + e.printStackTrace(); // can't really use logging + hostAddress = null; + } + } + } + + return hostAddress; + } + } +} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/BaseMDCCopyingWrapper.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/BaseMDCCopyingWrapper.java index a963542906..d667ff769c 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/BaseMDCCopyingWrapper.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/BaseMDCCopyingWrapper.java @@ -16,38 +16,58 @@ package org.openecomp.sdc.logging.slf4j; -import org.slf4j.MDC; - +import java.util.EnumMap; import java.util.Map; +import org.openecomp.sdc.logging.slf4j.SLF4JLoggingServiceProvider.ContextField; +import org.slf4j.MDC; /** - * @author EVITALIY - * @since 08 Jan 18 + * Because we don't know which information should be carried over from MDC, and which shouldn't, copy just the keys that + * the logging service uses. + * + * @author evitaliy + * @since 08 Jan 2018 */ abstract class BaseMDCCopyingWrapper { - private final Map<String, String> context; + private final Map<ContextField, String> context; BaseMDCCopyingWrapper() { - this.context = MDC.getCopyOfContextMap(); + this.context = fromMdc(); } - final Map<String, String> replace() { - Map<String, String> old = MDC.getCopyOfContextMap(); - replaceMDC(this.context); + final Map<ContextField, String> replace() { + Map<ContextField, String> old = fromMdc(); + toMdc(this.context); return old; } - final void revert(Map<String, String> old) { - replaceMDC(old); + final void revert(Map<ContextField, String> old) { + toMdc(old); + } + + private Map<ContextField, String> fromMdc() { + + Map<ContextField, String> copy = new EnumMap<>(ContextField.class); + for (ContextField k : ContextField.values()) { + String v = MDC.get(k.asKey()); + if (v != null) { + copy.put(k, v); + } + } + + return copy; } - private static void replaceMDC(Map<String, String> context) { + private static void toMdc(Map<ContextField, String> context) { - if (context == null) { - MDC.clear(); - } else { - MDC.setContextMap(context); + for (ContextField k : ContextField.values()) { + String v = context.get(k); + if (v != null) { + MDC.put(k.asKey(), v); + } else { + MDC.remove(k.asKey()); + } } } } diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/MDCCallableWrapper.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/MDCCallableWrapper.java index 9cb67dee4c..07d0f935f7 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/MDCCallableWrapper.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/MDCCallableWrapper.java @@ -18,6 +18,7 @@ package org.openecomp.sdc.logging.slf4j; import java.util.Map; import java.util.concurrent.Callable; +import org.openecomp.sdc.logging.slf4j.SLF4JLoggingServiceProvider.ContextField; /** * @author EVITALIY @@ -35,7 +36,7 @@ class MDCCallableWrapper<V> extends BaseMDCCopyingWrapper implements Callable<V> @Override public V call() throws Exception { - Map<String, String> oldContext = replace(); + Map<ContextField, String> oldContext = replace(); try { return task.call(); diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/MDCRunnableWrapper.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/MDCRunnableWrapper.java index f1a6986fec..e1b8f1e5c5 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/MDCRunnableWrapper.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/MDCRunnableWrapper.java @@ -17,6 +17,7 @@ package org.openecomp.sdc.logging.slf4j; import java.util.Map; +import org.openecomp.sdc.logging.slf4j.SLF4JLoggingServiceProvider.ContextField; /** * @author EVITALIY @@ -34,7 +35,7 @@ class MDCRunnableWrapper extends BaseMDCCopyingWrapper implements Runnable { @Override public void run() { - Map<String, String> oldContext = replace(); + Map<ContextField, String> oldContext = replace(); try { task.run(); diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/SLF4JLoggerWrapper.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/SLF4JLoggerWrapper.java index a8ada8777f..783dac4ed4 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/SLF4JLoggerWrapper.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/SLF4JLoggerWrapper.java @@ -16,6 +16,14 @@ package org.openecomp.sdc.logging.slf4j; +import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.BEGIN_TIMESTAMP; +import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.CLIENT_IP_ADDRESS; +import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.ELAPSED_TIME; +import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.END_TIMESTAMP; +import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.RESPONSE_CODE; +import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.RESPONSE_DESCRIPTION; +import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.STATUS_CODE; + import java.text.Format; import java.text.SimpleDateFormat; import org.openecomp.sdc.logging.api.AuditData; @@ -24,28 +32,36 @@ import org.slf4j.LoggerFactory; import org.slf4j.MDC; /** - * @author EVITALIY + * @author evitaliy * @since 08 Jan 18 */ class SLF4JLoggerWrapper implements Logger { //The specified format presents time in UTC formatted per ISO 8601, as required by ONAP logging guidelines - private static final String DATE_TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"; + private static final String PREFIX = ""; - static final String BEGIN_TIMESTAMP = PREFIX + "BeginTimestamp"; - static final String END_TIMESTAMP = PREFIX + "EndTimestamp"; - static final String ELAPSED_TIME = PREFIX + "ElapsedTime"; - static final String STATUS_CODE = PREFIX + "StatusCode"; - static final String RESPONSE_CODE = PREFIX + "ResponseCode"; - static final String RESPONSE_DESCRIPTION = PREFIX + "ResponseDescription"; - static final String CLIENT_IP_ADDRESS = PREFIX + "ClientIpAddress"; + enum AuditField { + + BEGIN_TIMESTAMP(PREFIX + "BeginTimestamp"), + END_TIMESTAMP(PREFIX + "EndTimestamp"), + ELAPSED_TIME(PREFIX + "ElapsedTime"), + STATUS_CODE(PREFIX + "StatusCode"), + RESPONSE_CODE(PREFIX + "ResponseCode"), + RESPONSE_DESCRIPTION(PREFIX + "ResponseDescription"), + CLIENT_IP_ADDRESS(PREFIX + "ClientIpAddress"); + + private final String key; - private static final String[] ALL_MDC_FIELDS = { - BEGIN_TIMESTAMP, END_TIMESTAMP, ELAPSED_TIME, STATUS_CODE, - RESPONSE_CODE, RESPONSE_DESCRIPTION, CLIENT_IP_ADDRESS - }; + AuditField(String key) { + this.key = key; + } + + public String asKey() { + return key; + } + } private final org.slf4j.Logger logger; @@ -110,19 +126,19 @@ class SLF4JLoggerWrapper implements Logger { } putTimes(data); - putIfNotNull(RESPONSE_CODE, data.getResponseCode()); - putIfNotNull(RESPONSE_DESCRIPTION, data.getResponseDescription()); - putIfNotNull(CLIENT_IP_ADDRESS, data.getClientIpAddress()); + putIfNotNull(RESPONSE_CODE.key, data.getResponseCode()); + putIfNotNull(RESPONSE_DESCRIPTION.key, data.getResponseDescription()); + putIfNotNull(CLIENT_IP_ADDRESS.key, data.getClientIpAddress()); if (data.getStatusCode() != null) { - MDC.put(STATUS_CODE, data.getStatusCode().name()); + MDC.put(STATUS_CODE.key, data.getStatusCode().name()); } try { logger.info(Markers.AUDIT, ""); } finally { - for (String k : ALL_MDC_FIELDS) { - MDC.remove(k); + for (AuditField f : AuditField.values()) { + MDC.remove(f.key); } } } @@ -136,9 +152,9 @@ class SLF4JLoggerWrapper implements Logger { private void putTimes(AuditData data) { // SimpleDateFormat is not thread-safe and cannot be a constant Format dateTimeFormat = new SimpleDateFormat(DATE_TIME_PATTERN); - MDC.put(BEGIN_TIMESTAMP, dateTimeFormat.format(data.getStartTime())); - MDC.put(END_TIMESTAMP, dateTimeFormat.format(data.getEndTime())); - MDC.put(ELAPSED_TIME, String.valueOf(data.getEndTime() - data.getStartTime())); + MDC.put(BEGIN_TIMESTAMP.key, dateTimeFormat.format(data.getStartTime())); + MDC.put(END_TIMESTAMP.key, dateTimeFormat.format(data.getEndTime())); + MDC.put(ELAPSED_TIME.key, String.valueOf(data.getEndTime() - data.getStartTime())); } @Override diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/SLF4JLoggingServiceProvider.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/SLF4JLoggingServiceProvider.java index fbda93cf61..6f69aae1b6 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/SLF4JLoggingServiceProvider.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/SLF4JLoggingServiceProvider.java @@ -16,6 +16,10 @@ package org.openecomp.sdc.logging.slf4j; +import static org.openecomp.sdc.logging.slf4j.SLF4JLoggingServiceProvider.ContextField.PARTNER_NAME; +import static org.openecomp.sdc.logging.slf4j.SLF4JLoggingServiceProvider.ContextField.REQUEST_ID; +import static org.openecomp.sdc.logging.slf4j.SLF4JLoggingServiceProvider.ContextField.SERVICE_NAME; + import java.util.Objects; import java.util.concurrent.Callable; import org.openecomp.sdc.logging.api.Logger; @@ -24,11 +28,26 @@ import org.slf4j.MDC; /** * @author evitaliy - * @since 13/09/2016. + * @since 13 Sep 2016 */ public class SLF4JLoggingServiceProvider implements LoggingServiceProvider { - private static final String KEY_CANNOT_BE_NULL = "Key cannot be null"; + enum ContextField { + + REQUEST_ID("RequestId"), + SERVICE_NAME("ServiceName"), + PARTNER_NAME("PartnerName"); + + private final String key; + + ContextField(String key) { + this.key = key; + } + + String asKey() { + return key; + } + } @Override public Logger getLogger(String className) { @@ -43,26 +62,29 @@ public class SLF4JLoggingServiceProvider implements LoggingServiceProvider { } @Override - public void put(String key, String value) { - Objects.requireNonNull(key, KEY_CANNOT_BE_NULL); - MDC.put(key, value); + public void putRequestId(String requestId) { + put(REQUEST_ID.key, requestId); } @Override - public String get(String key) { - Objects.requireNonNull(key, KEY_CANNOT_BE_NULL); - return MDC.get(key); + public void putServiceName(String serviceName) { + put(SERVICE_NAME.key, serviceName); } @Override - public void remove(String key) { - Objects.requireNonNull(key, KEY_CANNOT_BE_NULL); - MDC.remove(key); + public void putPartnerName(String partnerName) { + put(PARTNER_NAME.key, partnerName); } @Override public void clear() { - MDC.clear(); + for (ContextField s : ContextField.values()) { + MDC.remove(s.key); + } + } + + private void put(String key, String value) { + MDC.put(key, Objects.requireNonNull(value, key)); } @Override diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/BaseContextPropagationTest.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/BaseContextPropagationTest.java index 636ff94a39..52a794f937 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/BaseContextPropagationTest.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/BaseContextPropagationTest.java @@ -1,5 +1,5 @@ /* - * Copyright © 2016-2017 European Support Limited + * Copyright © 2016-2018 European Support Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,18 +23,17 @@ import org.testng.annotations.DataProvider; import java.util.concurrent.Callable; /** - * @author EVITALIY + * @author evitaliy * @since 08 Jan 18 */ public abstract class BaseContextPropagationTest { - // Disable if an old version of ctx implementation is being used. - // ctxPropagationFactory should be used when ctx is not propagated to child threads. + // Disable if an old version of logback implementation is being used. + // Context propagation should be used when ctx is not propagated to child threads. // See https://jira.qos.ch/browse/LOGBACK-422 and https://jira.qos.ch/browse/LOGBACK-624 static final boolean ENABLED = false; static final String PROVIDER = "context"; - static final String KEY = "test-data"; static final String EXPECT_PROPAGATED_TO_CHILD = "Expected the data to be propagated to the child thread's context"; static final String EXPECT_RETAINED_IN_CURRENT = "Expected the data to be retained in this thread"; @@ -52,27 +51,27 @@ public abstract class BaseContextPropagationTest { @DataProvider(name = PROVIDER) public static Object[][] contextServices() { // try both directly call the implementation and get it via the binding - return new Object[][] { - { new SLF4JLoggingServiceProvider() }, - { new LoggingContextAdaptor() } + return new Object[][]{ + {new SLF4JLoggingServiceProvider()}, + {new LoggingContextAdaptor()} }; } private static class LoggingContextAdaptor implements LoggingContextService { @Override - public void put(String key, String value) { - LoggingContext.put(key, value); + public void putRequestId(String requestId) { + LoggingContext.putRequestId(requestId); } @Override - public String get(String key) { - return LoggingContext.get(key); + public void putServiceName(String serviceName) { + LoggingContext.putServiceName(serviceName); } @Override - public void remove(String key) { - LoggingContext.remove(key); + public void putPartnerName(String partnerName) { + LoggingContext.putPartnerName(partnerName); } @Override diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/CallableContextPropagationTest.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/CallableContextPropagationTest.java index 0c8de97e1a..58d52bfa0f 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/CallableContextPropagationTest.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/CallableContextPropagationTest.java @@ -16,23 +16,24 @@ package org.openecomp.sdc.logging.slf4j; -import org.openecomp.sdc.logging.spi.LoggingContextService; -import org.testng.annotations.Test; +import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.assertContextEmpty; +import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.assertContextFields; +import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.putUniqueValues; +import static org.testng.Assert.assertTrue; -import java.util.UUID; +import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; +import org.openecomp.sdc.logging.slf4j.SLF4JLoggingServiceProvider.ContextField; +import org.openecomp.sdc.logging.spi.LoggingContextService; +import org.testng.annotations.Test; /** - * @author EVITALIY + * @author evitaliy * @since 08 Jan 18 */ public class CallableContextPropagationTest extends BaseContextPropagationTest { @@ -40,33 +41,29 @@ public class CallableContextPropagationTest extends BaseContextPropagationTest { @Test(enabled = ENABLED, dataProvider = PROVIDER) public void testContextPropagated(LoggingContextService ctx) throws Exception { - String uuid = UUID.randomUUID().toString(); - ctx.put(KEY, uuid); - + Map<ContextField, String> values = putUniqueValues(ctx); AtomicBoolean complete = new AtomicBoolean(false); // pass the callable to the context service first execute(ctx.copyToCallable(() -> { - assertEquals(ctx.get(KEY), uuid, EXPECT_PROPAGATED_TO_CHILD); + assertContextFields(values, EXPECT_PROPAGATED_TO_CHILD); complete.set(true); return null; })); - assertEquals(ctx.get(KEY), uuid, EXPECT_RETAINED_IN_CURRENT); + assertContextFields(values, EXPECT_RETAINED_IN_CURRENT); assertTrue(complete.get(), EXPECT_INNER_RUN); } @Test(enabled = ENABLED, dataProvider = PROVIDER) public void testContextReplacement(LoggingContextService ctx) throws Exception { - String innerRandom = UUID.randomUUID().toString(); - ctx.put(KEY, innerRandom); - + Map<ContextField, String> innerValues = putUniqueValues(ctx); AtomicBoolean innerComplete = new AtomicBoolean(false); // should run with the context of main thread Callable inner = ctx.copyToCallable(() -> { - assertEquals(ctx.get(KEY), innerRandom, EXPECT_PROPAGATED_TO_CHILD); + assertContextFields(innerValues, EXPECT_PROPAGATED_TO_CHILD); innerComplete.set(true); return null; }); @@ -74,15 +71,14 @@ public class CallableContextPropagationTest extends BaseContextPropagationTest { // pushes its own context, but the inner must run with its own context AtomicBoolean outerComplete = new AtomicBoolean(false); execute(() -> { - String outerUuid = UUID.randomUUID().toString(); - ctx.put(KEY, outerUuid); + Map<ContextField, String> outerValues = putUniqueValues(ctx); inner.call(); - assertEquals(ctx.get(KEY), outerUuid, EXPECT_REPLACED_WITH_STORED); + assertContextFields(outerValues, EXPECT_REPLACED_WITH_STORED); outerComplete.set(true); return null; }); - assertEquals(ctx.get(KEY), innerRandom, EXPECT_RETAINED_IN_CURRENT); + assertContextFields(innerValues, EXPECT_RETAINED_IN_CURRENT); assertTrue(outerComplete.get(), EXPECT_OUTER_RUN); assertTrue(innerComplete.get(), EXPECT_INNER_RUN); } @@ -90,30 +86,29 @@ public class CallableContextPropagationTest extends BaseContextPropagationTest { @Test(enabled = ENABLED, dataProvider = PROVIDER) public void testContextRemainsEmpty(LoggingContextService ctx) throws Exception { - ctx.remove(KEY); - assertNull(ctx.get(KEY), EXPECT_EMPTY); + ctx.clear(); + assertContextEmpty(EXPECT_EMPTY); final AtomicBoolean complete = new AtomicBoolean(false); execute(ctx.copyToCallable(() -> { - assertNull(ctx.get(KEY), EXPECT_EMPTY); + assertContextEmpty(EXPECT_EMPTY); complete.set(true); return null; })); - assertNull(ctx.get(KEY), EXPECT_EMPTY); + assertContextEmpty(EXPECT_EMPTY); assertTrue(complete.get(), EXPECT_INNER_RUN); } @Test(enabled = ENABLED, dataProvider = PROVIDER) public void testContextCleanedUp(LoggingContextService ctx) throws Exception { - String innerRandom = UUID.randomUUID().toString(); - ctx.put(KEY, innerRandom); + Map<ContextField, String> innerValues = putUniqueValues(ctx); AtomicBoolean innerComplete = new AtomicBoolean(false); // should run with the context of main thread Callable inner = ctx.copyToCallable((() -> { - assertEquals(ctx.get(KEY), innerRandom, EXPECT_PROPAGATED_TO_CHILD); + assertContextFields(innerValues, EXPECT_PROPAGATED_TO_CHILD); innerComplete.set(true); return null; })); @@ -121,14 +116,14 @@ public class CallableContextPropagationTest extends BaseContextPropagationTest { // pushes its own context, but runs the inner AtomicBoolean outerComplete = new AtomicBoolean(false); execute(() -> { - assertNull(ctx.get(KEY), EXPECT_NOT_COPIED); + assertContextEmpty(EXPECT_NOT_COPIED); inner.call(); - assertNull(ctx.get(KEY), EXPECT_REMAIN_EMPTY); + assertContextEmpty(EXPECT_REMAIN_EMPTY); outerComplete.set(true); return null; }); - assertEquals(ctx.get(KEY), innerRandom, EXPECT_RETAINED_IN_PARENT); + assertContextFields(innerValues, EXPECT_RETAINED_IN_PARENT); assertTrue(outerComplete.get(), EXPECT_OUTER_RUN); assertTrue(innerComplete.get(), EXPECT_INNER_RUN); } @@ -136,13 +131,12 @@ public class CallableContextPropagationTest extends BaseContextPropagationTest { @Test(enabled = ENABLED, dataProvider = PROVIDER) public void testCleanupAfterError(LoggingContextService ctx) throws Exception { - String innerRandom = UUID.randomUUID().toString(); - ctx.put(KEY, innerRandom); + Map<ContextField, String> innerValues = putUniqueValues(ctx); // should run with the context of main thread AtomicBoolean innerComplete = new AtomicBoolean(false); Callable inner = ctx.copyToCallable(() -> { - assertEquals(ctx.get(KEY), innerRandom, EXPECT_PROPAGATED_TO_CHILD); + assertContextFields(innerValues, EXPECT_PROPAGATED_TO_CHILD); innerComplete.set(true); throw new IllegalArgumentException(); }); @@ -152,23 +146,22 @@ public class CallableContextPropagationTest extends BaseContextPropagationTest { AtomicBoolean exceptionThrown = new AtomicBoolean(false); execute(() -> { - String outerUuid = UUID.randomUUID().toString(); - ctx.put(KEY, outerUuid); - assertEquals(ctx.get(KEY), outerUuid, EXPECT_POPULATED); + Map<ContextField, String> outerValues = putUniqueValues(ctx); + assertContextFields(outerValues, EXPECT_POPULATED); try { inner.call(); } catch (IllegalArgumentException e) { exceptionThrown.set(true); } finally { - assertEquals(ctx.get(KEY), outerUuid, EXPECT_REVERTED_ON_EXCEPTION); + assertContextFields(outerValues, EXPECT_REVERTED_ON_EXCEPTION); outerComplete.set(true); } return null; }); - assertEquals(ctx.get(KEY), innerRandom, EXPECT_RETAINED_IN_PARENT); + assertContextFields(innerValues, EXPECT_RETAINED_IN_PARENT); assertTrue(outerComplete.get(), EXPECT_OUTER_RUN); assertTrue(innerComplete.get(), EXPECT_INNER_RUN); assertTrue(exceptionThrown.get(), EXPECT_EXCEPTION_FROM_INNER); diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/ContextPropagationTestHelper.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/ContextPropagationTestHelper.java new file mode 100644 index 0000000000..5112d37ac5 --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/ContextPropagationTestHelper.java @@ -0,0 +1,67 @@ +/* + * Copyright © 2016-2017 European Support Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openecomp.sdc.logging.slf4j; + +import static org.testng.Assert.assertEquals; + +import java.util.Collections; +import java.util.EnumMap; +import java.util.Map; +import java.util.UUID; +import org.openecomp.sdc.logging.slf4j.SLF4JLoggingServiceProvider.ContextField; +import org.openecomp.sdc.logging.spi.LoggingContextService; +import org.slf4j.MDC; + +/** + * @author evitaliy + * @since 08 Mar 18 + */ +class ContextPropagationTestHelper { + + private static final Map<ContextField, String> EMPTY_CONTEXT = + Collections.unmodifiableMap(new EnumMap<>(ContextField.class)); + + static Map<ContextField, String> putUniqueValues(LoggingContextService ctx) { + + Map<ContextField, String> values = new EnumMap<>(ContextField.class); + + String service = UUID.randomUUID().toString(); + ctx.putServiceName(service); + values.put(ContextField.SERVICE_NAME, service); + + String partner = UUID.randomUUID().toString(); + ctx.putPartnerName(partner); + values.put(ContextField.PARTNER_NAME, partner); + + String request = UUID.randomUUID().toString(); + ctx.putRequestId(request); + values.put(ContextField.REQUEST_ID, request); + + return values; + } + + static void assertContextFields(Map<ContextField, String> values, String error) { + + for (ContextField f : ContextField.values()) { + assertEquals(MDC.get(f.asKey()), values.get(f), error); + } + } + + static void assertContextEmpty(String error) { + assertContextFields(EMPTY_CONTEXT, error); + } +} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/LoggingContextTest.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/LoggingContextTest.java index e93c114193..430d4d4c54 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/LoggingContextTest.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/LoggingContextTest.java @@ -17,6 +17,7 @@ package org.openecomp.sdc.logging.slf4j; import org.openecomp.sdc.logging.api.LoggingContext; +import org.openecomp.sdc.logging.slf4j.SLF4JLoggingServiceProvider.ContextField; import org.slf4j.MDC; import org.testng.annotations.Test; @@ -27,7 +28,7 @@ import static org.testng.Assert.assertNull; /** * @author evitaliy - * @since 12/09/2016. + * @since 12 Sep 2016 */ public class LoggingContextTest { @@ -52,61 +53,93 @@ public class LoggingContextTest { } @Test - public void clearContextWhenClearCalled() { + public void keysClearedWhenContextCleared() { - String random = UUID.randomUUID().toString(); + String value = UUID.randomUUID().toString(); try { - LoggingContext.put(random, random); + LoggingContext.putPartnerName(value); + LoggingContext.putServiceName(value); + LoggingContext.putRequestId(value); LoggingContext.clear(); - assertNull(MDC.get(random)); - assertNull(LoggingContext.get(random)); + + for (ContextField field : ContextField.values()) { + assertNull(MDC.get(field.asKey())); + } + } finally { - MDC.remove(random); + MDC.clear(); } } @Test - public void returnContextWhenGetCalled() { + public void unrelatedKeysRemainWhenContextCleared() { - String random = UUID.randomUUID().toString(); + String randomValue = UUID.randomUUID().toString(); + String randomKey = "Key-" + randomValue; try { - LoggingContext.put(random, random); - assertEquals(random, MDC.get(random)); - assertEquals(random, LoggingContext.get(random)); + + MDC.put(randomKey, randomValue); + LoggingContext.clear(); + assertEquals(MDC.get(randomKey), randomValue); + } finally { - MDC.remove(random); + MDC.clear(); } } @Test - public void removeContextWhenRemoveCalled() { + public void contextHasServiceNameWhenPut() { String random = UUID.randomUUID().toString(); try { - LoggingContext.put(random, random); - LoggingContext.remove(random); - assertNull(MDC.get(random)); - assertNull(LoggingContext.get(random)); + LoggingContext.putServiceName(random); + assertEquals(random, MDC.get(ContextField.SERVICE_NAME.asKey())); } finally { - MDC.remove(random); + MDC.clear(); } } @Test(expectedExceptions = NullPointerException.class) - public void throwNpeWhenPutWithKeyNull() { - LoggingContext.put(null, "---"); + public void throwNpeWhenServiceNameNull() { + LoggingContext.putServiceName(null); + } + + @Test + public void contextHasRequestIdWhenPut() { + + String random = UUID.randomUUID().toString(); + + try { + LoggingContext.putRequestId(random); + assertEquals(random, MDC.get(ContextField.REQUEST_ID.asKey())); + } finally { + MDC.clear(); + } } @Test(expectedExceptions = NullPointerException.class) - public void throwNpeWhenGetWithKeyNull() { - LoggingContext.get(null); + public void throwNpeWhenRequestIdNull() { + LoggingContext.putRequestId(null); + } + + @Test + public void contextHasPartnerNameWhenPut() { + + String random = UUID.randomUUID().toString(); + + try { + LoggingContext.putPartnerName(random); + assertEquals(random, MDC.get(ContextField.PARTNER_NAME.asKey())); + } finally { + MDC.clear(); + } } @Test(expectedExceptions = NullPointerException.class) - public void throwNpeWhenRemoveWithKeyNull() { - LoggingContext.remove(null); + public void throwNpeWhenPartnerNameNull() { + LoggingContext.putPartnerName(null); } } diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/RunnableContextPropagationTest.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/RunnableContextPropagationTest.java index 90d6cda52a..fcd1a56252 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/RunnableContextPropagationTest.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/RunnableContextPropagationTest.java @@ -16,18 +16,19 @@ package org.openecomp.sdc.logging.slf4j; -import org.openecomp.sdc.logging.spi.LoggingContextService; -import org.testng.annotations.Test; +import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.assertContextEmpty; +import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.assertContextFields; +import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.putUniqueValues; +import static org.testng.Assert.assertTrue; -import java.util.UUID; +import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; +import org.openecomp.sdc.logging.slf4j.SLF4JLoggingServiceProvider.ContextField; +import org.openecomp.sdc.logging.spi.LoggingContextService; +import org.testng.annotations.Test; /** - * @author EVITALIY + * @author evitaliy * @since 08 Jan 18 */ public class RunnableContextPropagationTest extends BaseContextPropagationTest { @@ -36,14 +37,12 @@ public class RunnableContextPropagationTest extends BaseContextPropagationTest { public void contextNotCopiedToChildThreadByDefault(LoggingContextService ctx) throws InterruptedException { - String random = UUID.randomUUID().toString(); - ctx.put(KEY, random); - + Map<ContextField, String> values = putUniqueValues(ctx); AtomicBoolean complete = new AtomicBoolean(false); // create thread right away without copying context Thread thread = new Thread(() -> { - assertNull(ctx.get(KEY), "Data unexpectedly copied to a child thread. " + + assertContextEmpty("Data unexpectedly copied to a child thread. " + "Are you using an old version of SLF4J diagnostic context implementation (e.g. logback)?"); complete.set(true); }); @@ -51,7 +50,7 @@ public class RunnableContextPropagationTest extends BaseContextPropagationTest { thread.start(); thread.join(); - assertEquals(ctx.get(KEY), random, EXPECT_RETAINED_IN_CURRENT); + assertContextFields(values, EXPECT_RETAINED_IN_CURRENT); assertTrue(complete.get(), EXPECT_INNER_RUN); } @@ -59,21 +58,19 @@ public class RunnableContextPropagationTest extends BaseContextPropagationTest { public void contextCopiedWhenToRunnableCalled(LoggingContextService ctx) throws InterruptedException { - String uuid = UUID.randomUUID().toString(); - ctx.put(KEY, uuid); - + Map<ContextField, String> values = putUniqueValues(ctx); AtomicBoolean complete = new AtomicBoolean(false); // pass the runnable to the context service first Thread thread = new Thread(ctx.copyToRunnable(() -> { - assertEquals(ctx.get(KEY), uuid, EXPECT_PROPAGATED_TO_CHILD); + assertContextFields(values, EXPECT_PROPAGATED_TO_CHILD); complete.set(true); })); thread.start(); thread.join(); - assertEquals(ctx.get(KEY), uuid, EXPECT_RETAINED_IN_CURRENT); + assertContextFields(values, EXPECT_RETAINED_IN_CURRENT); assertTrue(complete.get(), EXPECT_INNER_RUN); } @@ -81,31 +78,28 @@ public class RunnableContextPropagationTest extends BaseContextPropagationTest { public void copiedContextRetainedEvenWhenAnotherPushed(LoggingContextService ctx) throws InterruptedException { - String innerRandom = UUID.randomUUID().toString(); - ctx.put(KEY, innerRandom); - + Map<ContextField, String> innerValues = putUniqueValues(ctx); AtomicBoolean innerComplete = new AtomicBoolean(false); // should run with the context of main thread Runnable inner = ctx.copyToRunnable(() -> { - assertEquals(ctx.get(KEY), innerRandom, EXPECT_PROPAGATED_TO_CHILD); + assertContextFields(innerValues, EXPECT_PROPAGATED_TO_CHILD); innerComplete.set(true); }); // pushes its context, but the inner must run with its own context AtomicBoolean outerComplete = new AtomicBoolean(false); Thread outer = new Thread(() -> { - String outerUuid = UUID.randomUUID().toString(); - ctx.put(KEY, outerUuid); + Map<ContextField, String> outerValues = putUniqueValues(ctx); inner.run(); - assertEquals(ctx.get(KEY), outerUuid, EXPECT_REPLACED_WITH_STORED); + assertContextFields(outerValues, EXPECT_REPLACED_WITH_STORED); outerComplete.set(true); }); outer.start(); outer.join(); - assertEquals(ctx.get(KEY), innerRandom, EXPECT_RETAINED_IN_CURRENT); + assertContextFields(innerValues, EXPECT_RETAINED_IN_CURRENT); assertTrue(outerComplete.get(), EXPECT_OUTER_RUN); assertTrue(innerComplete.get(), EXPECT_INNER_RUN); } @@ -114,12 +108,12 @@ public class RunnableContextPropagationTest extends BaseContextPropagationTest { public void contextRemainsEmptyWhenParentWasEmpty(LoggingContextService ctx) throws InterruptedException { - ctx.remove(KEY); - assertNull(ctx.get(KEY), EXPECT_EMPTY); + ctx.clear(); + assertContextEmpty(EXPECT_EMPTY); final AtomicBoolean complete = new AtomicBoolean(false); Runnable runnable = ctx.copyToRunnable(() -> { - assertNull(ctx.get(KEY), EXPECT_EMPTY); + assertContextEmpty(EXPECT_EMPTY); complete.set(true); }); @@ -127,7 +121,7 @@ public class RunnableContextPropagationTest extends BaseContextPropagationTest { thread.start(); thread.join(); - assertNull(ctx.get(KEY), EXPECT_EMPTY); + assertContextEmpty(EXPECT_EMPTY); assertTrue(complete.get(), EXPECT_INNER_RUN); } @@ -135,29 +129,27 @@ public class RunnableContextPropagationTest extends BaseContextPropagationTest { public void childThreadCleanedUpAfterRunnableRuns(LoggingContextService ctx) throws Exception { - String innerRandom = UUID.randomUUID().toString(); - ctx.put(KEY, innerRandom); - + Map<ContextField, String> innerValues = putUniqueValues(ctx); AtomicBoolean innerComplete = new AtomicBoolean(false); // should run with the context of main thread Runnable inner = ctx.copyToRunnable(() -> { - assertEquals(ctx.get(KEY), innerRandom, EXPECT_PROPAGATED_TO_CHILD); + assertContextFields(innerValues, EXPECT_PROPAGATED_TO_CHILD); innerComplete.set(true); }); // pushes its own context, but runs the inner AtomicBoolean outerComplete = new AtomicBoolean(false); Thread outer = new Thread(() -> { - assertNull(ctx.get(KEY), EXPECT_NOT_COPIED); + assertContextEmpty(EXPECT_NOT_COPIED); inner.run(); - assertNull(ctx.get(KEY), EXPECT_REMAIN_EMPTY); + assertContextEmpty(EXPECT_REMAIN_EMPTY); outerComplete.set(true); }); outer.start(); outer.join(); - assertEquals(ctx.get(KEY), innerRandom, EXPECT_RETAINED_IN_PARENT); + assertContextFields(innerValues, EXPECT_RETAINED_IN_PARENT); assertTrue(outerComplete.get(), EXPECT_OUTER_RUN); assertTrue(innerComplete.get(), EXPECT_INNER_RUN); } @@ -166,13 +158,12 @@ public class RunnableContextPropagationTest extends BaseContextPropagationTest { public void childThreadCleanedUpAfterException(LoggingContextService ctx) throws Exception { - String innerRandom = UUID.randomUUID().toString(); - ctx.put(KEY, innerRandom); + Map<ContextField, String> innerValues = putUniqueValues(ctx); // should run with the context of main thread AtomicBoolean innerComplete = new AtomicBoolean(false); Runnable inner = ctx.copyToRunnable(() -> { - assertEquals(ctx.get(KEY), innerRandom, EXPECT_PROPAGATED_TO_CHILD); + assertContextFields(innerValues, EXPECT_PROPAGATED_TO_CHILD); innerComplete.set(true); throw new IllegalArgumentException(); }); @@ -182,16 +173,15 @@ public class RunnableContextPropagationTest extends BaseContextPropagationTest { AtomicBoolean exceptionThrown = new AtomicBoolean(false); Thread outer = new Thread(() -> { - String outerUuid = UUID.randomUUID().toString(); - ctx.put(KEY, outerUuid); - assertEquals(ctx.get(KEY), outerUuid, EXPECT_POPULATED); + Map<ContextField, String> outerValues = putUniqueValues(ctx); + assertContextFields(outerValues, EXPECT_POPULATED); try { inner.run(); } catch (IllegalArgumentException e) { exceptionThrown.set(true); } finally { - assertEquals(ctx.get(KEY), outerUuid, EXPECT_REVERTED_ON_EXCEPTION); + assertContextFields(outerValues, EXPECT_REVERTED_ON_EXCEPTION); outerComplete.set(true); } }); @@ -199,7 +189,7 @@ public class RunnableContextPropagationTest extends BaseContextPropagationTest { outer.start(); outer.join(); - assertEquals(ctx.get(KEY), innerRandom, EXPECT_RETAINED_IN_PARENT); + assertContextFields(innerValues, EXPECT_RETAINED_IN_PARENT); assertTrue(outerComplete.get(), EXPECT_OUTER_RUN); assertTrue(innerComplete.get(), EXPECT_INNER_RUN); assertTrue(exceptionThrown.get(), EXPECT_EXCEPTION_FROM_INNER); diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/SLF4JLoggerWrapperTest.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/SLF4JLoggerWrapperTest.java index a4a5e5c72c..9093f7d066 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/SLF4JLoggerWrapperTest.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/SLF4JLoggerWrapperTest.java @@ -16,13 +16,13 @@ package org.openecomp.sdc.logging.slf4j; -import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.BEGIN_TIMESTAMP; -import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.CLIENT_IP_ADDRESS; -import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.ELAPSED_TIME; -import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.END_TIMESTAMP; -import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.RESPONSE_CODE; -import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.RESPONSE_DESCRIPTION; -import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.STATUS_CODE; +import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.BEGIN_TIMESTAMP; +import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.CLIENT_IP_ADDRESS; +import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.ELAPSED_TIME; +import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.END_TIMESTAMP; +import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.RESPONSE_CODE; +import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.RESPONSE_DESCRIPTION; +import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.STATUS_CODE; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; @@ -39,7 +39,7 @@ import org.slf4j.MDC; import org.testng.annotations.Test; /** - * @author EVITALIY + * @author evitaliy * @since 05 Mar 18 */ public class SLF4JLoggerWrapperTest { @@ -54,7 +54,7 @@ public class SLF4JLoggerWrapperTest { SpyLogger spy = createSpy(); long start = System.currentTimeMillis(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder().startTime(start).build()); - assertNotNull(spy.mdc().get(BEGIN_TIMESTAMP)); + assertNotNull(spy.mdc().get(BEGIN_TIMESTAMP.asKey())); } @Test @@ -62,7 +62,7 @@ public class SLF4JLoggerWrapperTest { SpyLogger spy = createSpy(); long end = System.currentTimeMillis(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder().endTime(end).build()); - assertNotNull(spy.mdc().get(END_TIMESTAMP)); + assertNotNull(spy.mdc().get(END_TIMESTAMP.asKey())); } @Test @@ -71,21 +71,21 @@ public class SLF4JLoggerWrapperTest { long start = System.currentTimeMillis(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder() .startTime(start).endTime(start).build()); - assertNotNull(spy.mdc().get(ELAPSED_TIME)); + assertNotNull(spy.mdc().get(ELAPSED_TIME.asKey())); } @Test public void statusCodeAvailableWhenPassed() { SpyLogger spy = createSpy(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder().statusCode(StatusCode.COMPLETE).build()); - assertEquals(spy.mdc().get(STATUS_CODE), StatusCode.COMPLETE.name()); + assertEquals(spy.mdc().get(STATUS_CODE.asKey()), StatusCode.COMPLETE.name()); } @Test public void statusCodeEmptyWhenNotPassed() { SpyLogger spy = createSpy(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder().build()); - assertNull(spy.mdc().get(STATUS_CODE)); + assertNull(spy.mdc().get(STATUS_CODE.asKey())); } @Test @@ -93,14 +93,14 @@ public class SLF4JLoggerWrapperTest { final String responseCode = "SpyResponse"; SpyLogger spy = createSpy(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder().responseCode(responseCode).build()); - assertEquals(spy.mdc().get(RESPONSE_CODE), responseCode); + assertEquals(spy.mdc().get(RESPONSE_CODE.asKey()), responseCode); } @Test public void responseCodeEmptyWhenNotPassed() { SpyLogger spy = createSpy(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder().build()); - assertNull(spy.mdc().get(RESPONSE_CODE)); + assertNull(spy.mdc().get(RESPONSE_CODE.asKey())); } @Test @@ -108,14 +108,14 @@ public class SLF4JLoggerWrapperTest { final String responseDescription = "SpyDescription"; SpyLogger spy = createSpy(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder().responseDescription(responseDescription).build()); - assertEquals(spy.mdc().get(RESPONSE_DESCRIPTION), responseDescription); + assertEquals(spy.mdc().get(RESPONSE_DESCRIPTION.asKey()), responseDescription); } @Test public void responseDescriptionEmptyWhenNotPassed() { SpyLogger spy = createSpy(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder().build()); - assertNull(spy.mdc().get(RESPONSE_DESCRIPTION)); + assertNull(spy.mdc().get(RESPONSE_DESCRIPTION.asKey())); } @Test @@ -123,14 +123,14 @@ public class SLF4JLoggerWrapperTest { final String ipAddress = "10.56.20.20"; SpyLogger spy = createSpy(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder().clientIpAddress(ipAddress).build()); - assertEquals(spy.mdc().get(CLIENT_IP_ADDRESS), ipAddress); + assertEquals(spy.mdc().get(CLIENT_IP_ADDRESS.asKey()), ipAddress); } @Test public void clientIpAddressEmptyWhenNotPassed() { SpyLogger spy = createSpy(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder().build()); - assertNull(spy.mdc().get(CLIENT_IP_ADDRESS)); + assertNull(spy.mdc().get(CLIENT_IP_ADDRESS.asKey())); } @Test @@ -140,7 +140,7 @@ public class SLF4JLoggerWrapperTest { long start = System.currentTimeMillis(); long end = start + diff; new SLF4JLoggerWrapper(spy).audit(AuditData.builder().startTime(start).endTime(end).build()); - assertEquals(spy.mdc().get(ELAPSED_TIME), Long.toString(diff)); + assertEquals(spy.mdc().get(ELAPSED_TIME.asKey()), Long.toString(diff)); } interface SpyLogger extends Logger { |