From 1c1edf2e7b1ddef504d8b075b2763e0b0d83a2aa Mon Sep 17 00:00:00 2001 From: vempo Date: Mon, 8 Jan 2018 20:59:19 +0200 Subject: Added logging context service, refactoring Change-Id: Ib040d4579107b60c8da2c7a6da829f49c1cd8dd4 Issue-ID: SDC-772 Signed-off-by: vempo --- .../sdc/logging/api/LoggerCreationService.java | 31 -- .../openecomp/sdc/logging/api/LoggerFactory.java | 447 ++++++++++----------- .../openecomp/sdc/logging/api/LoggingContext.java | 109 +++++ .../openecomp/sdc/logging/api/ServiceBinder.java | 93 +++++ .../api/context/ContextPropagationService.java | 30 -- .../sdc/logging/api/context/TaskFactory.java | 71 ---- .../logging/provider/LoggerCreationService.java | 34 ++ .../logging/provider/LoggingContextService.java | 70 ++++ .../logging/provider/LoggingServiceProvider.java | 30 ++ .../sdc/logging/api/LoggerFactoryTest.java | 74 ++-- .../sdc/logging/api/LoggingContextTest.java | 101 +++++ .../sdc/logging/api/ServiceBinderTest.java | 38 ++ .../sdc/logging/api/context/TaskFactoryTest.java | 32 -- 13 files changed, 738 insertions(+), 422 deletions(-) delete mode 100644 openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggerCreationService.java create mode 100644 openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggingContext.java create mode 100644 openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/ServiceBinder.java delete mode 100644 openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/context/ContextPropagationService.java delete mode 100644 openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/context/TaskFactory.java create mode 100644 openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/provider/LoggerCreationService.java create mode 100644 openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/provider/LoggingContextService.java create mode 100644 openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/provider/LoggingServiceProvider.java create mode 100644 openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/LoggingContextTest.java create mode 100644 openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/ServiceBinderTest.java delete mode 100644 openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/context/TaskFactoryTest.java (limited to 'openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src') diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggerCreationService.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggerCreationService.java deleted file mode 100644 index 1d8eda255e..0000000000 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggerCreationService.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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.api; - -/** - * - * Implements a framework-specific logging, to be used by {@link LoggerFactory}. - * - * @author evitaliy - * @since 13/09/2016. - */ -public interface LoggerCreationService { - - Logger getLogger(String className); - - Logger getLogger(Class clazz); -} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggerFactory.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggerFactory.java index 1be2fa21dc..b790a02042 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggerFactory.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggerFactory.java @@ -4,9 +4,9 @@ * 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. @@ -16,245 +16,244 @@ package org.openecomp.sdc.logging.api; +import org.openecomp.sdc.logging.provider.LoggerCreationService; + +import java.util.Objects; /** * 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 + * implementation has been configured or could 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.

* * @author evitaliy - * @see BaseFactory - * @see LoggerCreationService * @since 13/09/2016. + * + * @see ServiceBinder + * @see LoggerCreationService */ -@SuppressWarnings("ThrowableInstanceNeverThrown") -public class LoggerFactory extends BaseFactory { - - private static final LoggerCreationService SERVICE; +public class LoggerFactory { - static { - LoggerCreationService service; + // 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 + private static final LoggerCreationService SERVICE = ServiceBinder.getCreationServiceBinding().orElse( + new NoOpLoggerCreationService()); - try { - service = locateService(LoggerCreationService.class); - } catch (Exception ex) { - new RuntimeException("Failed to instantiate logger factory", ex).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(); + private LoggerFactory() { + // prevent instantiation } - 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 NoOpLogger(); - - private static class NoOpLogger implements Logger { - @Override - public String getName() { - return "No-Op Logger"; - } - - @Override - public boolean isMetricsEnabled() { - return false; - } - - @Override - public void metrics(String msg) { - //this is no_op_method - } - - @Override - public void metrics(String msg, Object arg) { - //this is no_op_method - } - - @Override - public void metrics(String msg, Object arg1, Object arg2) { - //this is no_op_method - } - - @Override - public void metrics(String msg, Object... arguments) { - //this is no_op_method - } - - @Override - public void metrics(String msg, Throwable t) { - //this is no_op_method - } - - @Override - public boolean isAuditEnabled() { - return false; - } - - @Override - public void audit(String msg) { - //this is no_op_method - } - - @Override - public void audit(String msg, Object arg) { - //this is no_op_method - } - - @Override - public void audit(String msg, Object arg1, Object arg2) { - //this is no_op_method - } - - @Override - public void audit(String msg, Object... arguments) { - //this is no_op_method - } - - @Override - public void audit(String msg, Throwable t) { - //this is no_op_method - } - - @Override - public boolean isDebugEnabled() { - return false; - } - - @Override - public void debug(String msg) { - //this is no_op_method - } - - @Override - public void debug(String msg, Object arg) { - //this is no_op_method - } - - @Override - public void debug(String msg, Object arg1, Object arg2) { - //this is no_op_method - } - - @Override - public void debug(String msg, Object... arguments) { - //this is no_op_method - } - - @Override - public void debug(String msg, Throwable t) { - //this is no_op_method - } - - @Override - public boolean isInfoEnabled() { - return false; - } - - @Override - public void info(String msg) { - //this is no_op_method - } - - @Override - public void info(String msg, Object arg) { - //this is no_op_method - } - - @Override - public void info(String msg, Object arg1, Object arg2) { - //this is no_op_method - } - - @Override - public void info(String msg, Object... arguments) { - //this is no_op_method - } - - @Override - public void info(String msg, Throwable t) { - //this is no_op_method - } - - @Override - public boolean isWarnEnabled() { - return false; - } - - @Override - public void warn(String msg) { - //this is no_op_method - } - - @Override - public void warn(String msg, Object arg) { - //this is no_op_method - } - - @Override - public void warn(String msg, Object... arguments) { - //this is no_op_method - } - - @Override - public void warn(String msg, Object arg1, Object arg2) { - //this is no_op_method - } - - @Override - public void warn(String msg, Throwable t) { - //this is no_op_method - } - - @Override - public boolean isErrorEnabled() { - return false; - } - - @Override - public void error(String msg) { - //this is no_op_method - } - - @Override - public void error(String msg, Object arg) { - //this is no_op_method - } - - @Override - public void error(String msg, Object arg1, Object arg2) { - //this is no_op_method - } - - @Override - public void error(String msg, Object... arguments) { - //this is no_op_method - } - - @Override - public void error(String msg, Throwable t) { - //this is no_op_method - } + public static Logger getLogger(String clazzName) { + return SERVICE.getLogger(clazzName); } - @Override - public Logger getLogger(String className) { - return NO_OP_LOGGER; + public static Logger getLogger(Class clazz) { + return SERVICE.getLogger(clazz); } - @Override - public Logger getLogger(Class clazz) { - return NO_OP_LOGGER; + private static class NoOpLoggerCreationService implements LoggerCreationService { + + private static final Logger NO_OP_LOGGER = new NoOpLogger(); + + private static class NoOpLogger implements Logger { + + @Override + public String getName() { + return "No-Op Logger"; + } + + @Override + public boolean isMetricsEnabled() { + return false; + } + + @Override + public void metrics(String msg) { + // no-op + } + + @Override + public void metrics(String msg, Object arg) { + // no-op + } + + @Override + public void metrics(String msg, Object arg1, Object arg2) { + // no-op + } + + @Override + public void metrics(String msg, Object... arguments) { + // no-op + } + + @Override + public void metrics(String msg, Throwable t) { + // no-op + } + + @Override + public boolean isAuditEnabled() { + return false; + } + + @Override + public void audit(String msg) { + // no-op + } + + @Override + public void audit(String msg, Object arg) { + // no-op + } + + @Override + public void audit(String msg, Object arg1, Object arg2) { + // no-op + } + + @Override + public void audit(String msg, Object... arguments) { + // no-op + } + + @Override + public void audit(String msg, Throwable t) { + // no-op + } + + @Override + public boolean isDebugEnabled() { + return false; + } + + @Override + public void debug(String msg) { + // no-op + } + + @Override + public void debug(String msg, Object arg) { + // no-op + } + + @Override + public void debug(String msg, Object arg1, Object arg2) { + // no-op + } + + @Override + public void debug(String msg, Object... arguments) { + // no-op + } + + @Override + public void debug(String msg, Throwable t) { + // no-op + } + + @Override + public boolean isInfoEnabled() { + return false; + } + + @Override + public void info(String msg) { + // no-op + } + + @Override + public void info(String msg, Object arg) { + // no-op + } + + @Override + public void info(String msg, Object arg1, Object arg2) { + // no-op + } + + @Override + public void info(String msg, Object... arguments) { + // no-op + } + + @Override + public void info(String msg, Throwable t) { + // no-op + } + + @Override + public boolean isWarnEnabled() { + return false; + } + + @Override + public void warn(String msg) { + // no-op + } + + @Override + public void warn(String msg, Object arg) { + // no-op + } + + @Override + public void warn(String msg, Object... arguments) { + // no-op + } + + @Override + public void warn(String msg, Object arg1, Object arg2) { + // no-op + } + + @Override + public void warn(String msg, Throwable t) { + // no-op + } + + @Override + public boolean isErrorEnabled() { + return false; + } + + @Override + public void error(String msg) { + // no-op + } + + @Override + public void error(String msg, Object arg) { + // no-op + } + + @Override + public void error(String msg, Object arg1, Object arg2) { + // no-op + } + + @Override + public void error(String msg, Object... arguments) { + // no-op + } + + @Override + public void error(String msg, Throwable t) { + // no-op + } + } + + @Override + public Logger getLogger(String className) { + Objects.requireNonNull(className, "Name cannot be null"); + return NO_OP_LOGGER; + } + + @Override + public Logger getLogger(Class clazz) { + Objects.requireNonNull(clazz, "Class cannot be null"); + return NO_OP_LOGGER; + } } - } } 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 new file mode 100644 index 0000000000..542f709074 --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggingContext.java @@ -0,0 +1,109 @@ +/* + * 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.api; + +import org.openecomp.sdc.logging.provider.LoggingContextService; + +import java.util.Objects; +import java.util.concurrent.Callable; + +/** + * Factory to hide a concrete, framework-specific implementation of diagnostic context. + *

The service used by this factory must implement {@link LoggingContextService}. If no + * implementation has been configured or could be instantiated, a no-op context service will be + * used, and no context will be stored or propagated. No errors will be generated, so that the application can + * still work (albeit without proper logging).

+ * + * @author evitaliy + * @since 07/01/2018. + * + * @see ServiceBinder + * @see LoggingContextService + */ +public class LoggingContext { + + 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 String get(String key) { + return SERVICE.get(key); + } + + public static void remove(String key) { + SERVICE.remove(key); + } + + public static void clear() { + SERVICE.clear(); + } + + public static Runnable toRunnable(Runnable runnable) { + return SERVICE.toRunnable(runnable); + } + + public static Callable toCallable(Callable callable) { + return SERVICE.toCallable(callable); + } + + 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 + } + + @Override + public String get(String key) { + Objects.requireNonNull(key, KEY_CANNOT_BE_NULL); + return null; + } + + @Override + public void remove(String key) { + Objects.requireNonNull(key, KEY_CANNOT_BE_NULL); + // no-op + } + + @Override + public void clear() { + // no-op + } + + @Override + public Runnable toRunnable(Runnable runnable) { + Objects.requireNonNull(runnable, "Runnable cannot be null"); + return runnable; + } + + @Override + public Callable toCallable(Callable callable) { + Objects.requireNonNull(callable, "Callable cannot be null"); + return callable; + } + } +} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/ServiceBinder.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/ServiceBinder.java new file mode 100644 index 0000000000..b16f3944e9 --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/ServiceBinder.java @@ -0,0 +1,93 @@ +/* + * 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.api; + +import org.openecomp.sdc.logging.provider.LoggerCreationService; +import org.openecomp.sdc.logging.provider.LoggingContextService; +import org.openecomp.sdc.logging.provider.LoggingServiceProvider; + +import java.util.Iterator; +import java.util.Optional; +import java.util.ServiceLoader; + +/** + *

Binds to a concrete implementation of logging services.

+ * + *

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).

+ * + * @author evitaliy + * @since 13/09/2016. + * + * @see ServiceLoader + */ + +// No advanced logging can be used here because we don't know +// which underlying implementation will be used +@SuppressWarnings({"UseOfSystemOutOrSystemErr", "squid:S106"}) +class ServiceBinder { + + private static final LoggingServiceProvider PROVIDER = lookupProvider(); + + private ServiceBinder () { + // prevent instantiation + } + + private static LoggingServiceProvider lookupProvider() { + + ServiceLoader loader = ServiceLoader.load(LoggingServiceProvider.class); + Iterator iterator = loader.iterator(); + + if (!iterator.hasNext()) { + System.err.printf("[ERROR] No provider configured for logging services %s. " + + "Default implementation will be used.\n", + LoggingServiceProvider.class.getName()); + return null; + } + + try { + + LoggingServiceProvider provider = iterator.next(); + if (!iterator.hasNext()) { + return provider; + } + + Logger logger = provider.getLogger(ServiceBinder.class); + if (logger.isWarnEnabled()) { + logger.warn("More than one provider for logging services {} found", + LoggingServiceProvider.class.getName()); + } + + return provider; + + } catch (Exception e) { + // don't fail if the provider cannot be instantiated + e.printStackTrace(System.err); + return null; + } + } + + static Optional getContextServiceBinding() { + return Optional.ofNullable(PROVIDER); + } + + static Optional getCreationServiceBinding() { + return Optional.ofNullable(PROVIDER); + } +} + diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/context/ContextPropagationService.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/context/ContextPropagationService.java deleted file mode 100644 index 7207ea7610..0000000000 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/context/ContextPropagationService.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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.api.context; - -/** - * Should be used to implement a framework-specific mechanism of propagation of a diagnostic context to child threads. - * - * @author evitaliy - * @since 12/09/2016. - */ - -@FunctionalInterface -public interface ContextPropagationService { - - Runnable create(Runnable task); -} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/context/TaskFactory.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/context/TaskFactory.java deleted file mode 100644 index 8621638460..0000000000 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/context/TaskFactory.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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.api.context; - -import org.openecomp.sdc.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}.

- * - * @author evitaliy - * @see ContextPropagationService - * @since 12/09/2016. - */ -@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 (Exception ex) { - error = new RuntimeException("Failed to instantiate task factory", ex); - } - - 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/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/provider/LoggerCreationService.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/provider/LoggerCreationService.java new file mode 100644 index 0000000000..344d23688e --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/provider/LoggerCreationService.java @@ -0,0 +1,34 @@ +/* + * 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.provider; + +import org.openecomp.sdc.logging.api.Logger; +import org.openecomp.sdc.logging.api.LoggerFactory; + +/** + * + * Implements a framework-specific logging, to be used by {@link LoggerFactory}. + * + * @author evitaliy + * @since 13/09/2016. + */ +public interface LoggerCreationService { + + Logger getLogger(String className); + + Logger getLogger(Class clazz); +} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/provider/LoggingContextService.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/provider/LoggingContextService.java new file mode 100644 index 0000000000..8e725e7cc5 --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/provider/LoggingContextService.java @@ -0,0 +1,70 @@ +/* + * 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.provider; + +import java.util.concurrent.Callable; + +/** + * Should be used to implement a framework-specific mechanism of managing a per-thread diagnostic context + * (for instance MDC), 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 + * Executor (including any of + * the + * executor services + * and ForkJoinPool). + * + * @author evitaliy + * @since 07/01/2018. + */ + +public interface LoggingContextService { + + /** + * Allows to store a key-value pair on thread context + */ + void put(String key, String value); + + /** + * Returns the value associated with a key stored on thread context + * + * @return value or null if the key does not exits + */ + String get(String key); + + /** + * Removes a particular key from thread context + */ + void remove(String key); + + /** + * Clear logging thread context + */ + 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. + */ + Runnable toRunnable(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 + */ + Callable toCallable(Callable callable); +} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/provider/LoggingServiceProvider.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/provider/LoggingServiceProvider.java new file mode 100644 index 0000000000..baf99f0e55 --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/provider/LoggingServiceProvider.java @@ -0,0 +1,30 @@ +/* + * 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.provider; + +/** + *

From the application code (consumer) perspective, logger creation (factory) and logging context are independent + * services. From the service provider perspective, however, these services are related and must be implemented together + * using the same underlying mechanism. Therefore, the service provider-facing interface combines the two services + * — to eliminate the chance that their implementations don't work well together.

+ * + * @author EVITALIY + * @since 07 Jan 18 + */ +public interface LoggingServiceProvider extends LoggerCreationService, LoggingContextService { + // single provider must implement two separate consumer services +} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/LoggerFactoryTest.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/LoggerFactoryTest.java index 4b3a1ba7c7..9fde4e5e6c 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/LoggerFactoryTest.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/LoggerFactoryTest.java @@ -4,9 +4,9 @@ * 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,10 +19,8 @@ package org.openecomp.sdc.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; /** @@ -31,40 +29,48 @@ import static org.testng.Assert.assertNotNull; */ public class LoggerFactoryTest { - @Test - public void testNoOpLoggerService() throws Exception { + @Test + public void shouldHoldNoOpWhenNoBinding() throws Exception { + + // set up to access the private static field + Field factory = LoggerFactory.class.getDeclaredField("SERVICE"); + factory.setAccessible(true); + Object impl = factory.get(null); - assertFalse(ServiceLoader.load(LoggerCreationService.class).iterator().hasNext()); + assertEquals(impl.getClass().getName(), + "org.openecomp.sdc.logging.api.LoggerFactory$NoOpLoggerCreationService"); + } - LoggerFactory.getLogger(LoggerFactoryTest.class); - Field factory = LoggerFactory.class.getDeclaredField("SERVICE"); - factory.setAccessible(true); - Object impl = factory.get(null); - assertEquals("org.openecomp.sdc.logging.api.LoggerFactory$NoOpLoggerCreationService", - impl.getClass().getName()); - } + @Test + public void verifyNoOpLoggerWorksWhenGotByClass() { + Logger logger = LoggerFactory.getLogger(LoggerFactoryTest.class); + verifyLoggerWorks(logger); + } - @Test - public void testNoOpLoggerByClass() throws Exception { - Logger logger = LoggerFactory.getLogger(LoggerFactoryTest.class); - verifyLogger(logger); - } + @Test + public void verifyNoOpLoggerWorksWhenGotByName() { + Logger logger = LoggerFactory.getLogger(LoggerFactoryTest.class.getName()); + verifyLoggerWorks(logger); + } - @Test - public void testNoOpLoggerByName() throws Exception { - Logger logger = LoggerFactory.getLogger(LoggerFactoryTest.class.getName()); - verifyLogger(logger); - } + @Test(expectedExceptions = NullPointerException.class) + public void throwNpeWhenGetByNameWithNull() { + LoggerFactory.getLogger((String) null); + } - private void verifyLogger(Logger logger) { - assertNotNull(logger); + @Test(expectedExceptions = NullPointerException.class) + public void throwNpeWhenGetByClassWithNull() { + LoggerFactory.getLogger((Class) null); + } - // make sure no exceptions are thrown - logger.error(""); - logger.warn(""); - logger.info(""); - logger.debug(""); - logger.audit(""); - logger.metrics(""); - } + private void verifyLoggerWorks(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/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 new file mode 100644 index 0000000000..7899eebd51 --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/LoggingContextTest.java @@ -0,0 +1,101 @@ +/* + * 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.api; + +import org.testng.annotations.Test; + +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; + +/** + * @author EVITALIY + * @since 08 Jan 18 + */ +public class LoggingContextTest { + + @Test + public void shouldHoldNoOpWhenNoBinding() throws Exception { + Field factory = LoggingContext.class.getDeclaredField("SERVICE"); + factory.setAccessible(true); + Object impl = factory.get(null); + assertEquals(impl.getClass().getName(), + "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")); + } + + @Test(expectedExceptions = NullPointerException.class) + public void throwNpeWhenGetWithKeyNull() { + LoggingContext.get(null); + } + + @Test + public void removeDoesNotFail() { + LoggingContext.remove("RemoveKey"); + } + + @Test(expectedExceptions = NullPointerException.class) + public void throwNpWhenRemoveWithKeyNull() { + LoggingContext.remove(null); + } + + @Test + public void clearDoesNotFail() { + LoggingContext.clear(); + } + + @Test + public void toRunnableReturnsSameInstance() { + Runnable test = () -> { /* do nothing */ }; + assertTrue(test == LoggingContext.toRunnable(test)); + } + + @Test(expectedExceptions = NullPointerException.class) + public void throwNpeWhenToRunnableWithNull() { + LoggingContext.toRunnable(null); + } + + @Test + public void toCallableReturnsSameInstance() { + Callable test = () -> ""; + assertTrue(test == LoggingContext.toCallable(test)); + } + + @Test(expectedExceptions = NullPointerException.class) + public void throwNpeWhenToCallableWithNull() { + LoggingContext.toCallable(null); + } +} \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/ServiceBinderTest.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/ServiceBinderTest.java new file mode 100644 index 0000000000..1a5c81d90d --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/ServiceBinderTest.java @@ -0,0 +1,38 @@ +/* + * 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.api; + +import org.testng.annotations.Test; + +import static org.testng.Assert.*; + +/** + * @author EVITALIY + * @since 08 Jan 18 + */ +public class ServiceBinderTest { + + @Test + public void makeSureNoContextServiceBinding() { + assertFalse(ServiceBinder.getContextServiceBinding().isPresent()); + } + + @Test + public void makeSureNoCreationServiceBinding() { + assertFalse(ServiceBinder.getCreationServiceBinding().isPresent()); + } +} \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/context/TaskFactoryTest.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/context/TaskFactoryTest.java deleted file mode 100644 index f5c2187024..0000000000 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/context/TaskFactoryTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.openecomp.sdc.logging.api.context; - -import org.testng.annotations.Test; - -import java.util.ServiceLoader; - -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; - -/** - * @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 -- cgit 1.2.3-korg