diff --git a/pom.xml b/pom.xml
index 990e38e..26c05fe 100644
--- a/pom.xml
+++ b/pom.xml
@@ -31,7 +31,7 @@
io.github.elf4j
elf4j-engine
- 2.0.11
+ 3.0.0
jar
elf4j-engine
A stand-alone Java log engine implementing the ELF4J (Easy Logging Facade for Java) API
diff --git a/src/main/java/elf4j/engine/NativeLoggerFactory.java b/src/main/java/elf4j/engine/NativeLoggerFactory.java
index 4512698..edcc710 100644
--- a/src/main/java/elf4j/engine/NativeLoggerFactory.java
+++ b/src/main/java/elf4j/engine/NativeLoggerFactory.java
@@ -27,8 +27,8 @@
import elf4j.Level;
import elf4j.Logger;
-import elf4j.engine.service.DefaultLogService;
import elf4j.engine.service.LogService;
+import elf4j.engine.service.StoppableLogService;
import elf4j.engine.util.StackTraceUtils;
import elf4j.spi.LoggerFactory;
import lombok.NonNull;
@@ -76,7 +76,7 @@ public NativeLoggerFactory() {
* the class that the API client uses to obtain access to a logger instance
*/
public NativeLoggerFactory(@NonNull Class> serviceAccessClass) {
- this(DEFAULT_LOGGER_SEVERITY_LEVEL, serviceAccessClass, new DefaultLogService());
+ this(DEFAULT_LOGGER_SEVERITY_LEVEL, serviceAccessClass, new StoppableLogService());
}
NativeLoggerFactory(@NonNull Level defaultLoggerLevel,
diff --git a/src/main/java/elf4j/engine/configuration/LogServiceConfiguration.java b/src/main/java/elf4j/engine/configuration/LogServiceConfiguration.java
index ec0f5ce..90bfb02 100644
--- a/src/main/java/elf4j/engine/configuration/LogServiceConfiguration.java
+++ b/src/main/java/elf4j/engine/configuration/LogServiceConfiguration.java
@@ -28,9 +28,6 @@
import elf4j.engine.NativeLogger;
import elf4j.engine.writer.LogWriter;
-import javax.annotation.Nullable;
-import java.util.Properties;
-
/**
*
*/
@@ -47,12 +44,4 @@ public interface LogServiceConfiguration {
* writer and that configured for the logger's caller/owner class; otherwise, false.
*/
boolean isEnabled(NativeLogger nativeLogger);
-
- /**
- * @param properties
- * used to refresh the logging configuration. If null
, only properties reloaded from the
- * configuration file will be used. Otherwise, the specified properties will replace all current properties
- * and configuration file is ignored.
- */
- void refresh(@Nullable Properties properties);
}
diff --git a/src/main/java/elf4j/engine/configuration/Refreshable.java b/src/main/java/elf4j/engine/configuration/Refreshable.java
new file mode 100644
index 0000000..938d555
--- /dev/null
+++ b/src/main/java/elf4j/engine/configuration/Refreshable.java
@@ -0,0 +1,49 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2023 Qingtian Wang
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+package elf4j.engine.configuration;
+
+import javax.annotation.Nullable;
+import java.util.Properties;
+
+/**
+ *
+ */
+public interface Refreshable {
+ /**
+ * @param properties
+ * used to refresh the logging configuration. If null
, only properties reloaded from the
+ * configuration file will be used. Otherwise, the specified properties will replace all current properties
+ * and configuration file is ignored.
+ */
+ void refresh(@Nullable Properties properties);
+
+ /**
+ * reloads from original source of properties
+ */
+ default void refresh() {
+ this.refresh(null);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/elf4j/engine/configuration/DefaultLogServiceConfiguration.java b/src/main/java/elf4j/engine/configuration/RefreshableLogServiceConfiguration.java
similarity index 90%
rename from src/main/java/elf4j/engine/configuration/DefaultLogServiceConfiguration.java
rename to src/main/java/elf4j/engine/configuration/RefreshableLogServiceConfiguration.java
index af2e882..c5facd4 100644
--- a/src/main/java/elf4j/engine/configuration/DefaultLogServiceConfiguration.java
+++ b/src/main/java/elf4j/engine/configuration/RefreshableLogServiceConfiguration.java
@@ -27,6 +27,7 @@
import elf4j.Level;
import elf4j.engine.NativeLogger;
+import elf4j.engine.service.LogServiceManager;
import elf4j.engine.writer.LogWriter;
import elf4j.util.InternalLogger;
import lombok.ToString;
@@ -40,7 +41,7 @@
*
*/
@ToString
-public class DefaultLogServiceConfiguration implements LogServiceConfiguration {
+public class RefreshableLogServiceConfiguration implements LogServiceConfiguration, Refreshable {
private final Map loggerConfigurationCache = new ConcurrentHashMap<>();
private final PropertiesLoader propertiesLoader;
private boolean noop;
@@ -50,12 +51,13 @@ public class DefaultLogServiceConfiguration implements LogServiceConfiguration {
/**
*
*/
- public DefaultLogServiceConfiguration() {
+ public RefreshableLogServiceConfiguration() {
this.propertiesLoader = new PropertiesLoader();
setRepositories(this.propertiesLoader.load());
+ LogServiceManager.INSTANCE.register(this);
}
- DefaultLogServiceConfiguration(CallerLevelRepository callerLevelRepository, WriterRepository writerRepository) {
+ RefreshableLogServiceConfiguration(CallerLevelRepository callerLevelRepository, WriterRepository writerRepository) {
this.propertiesLoader = new PropertiesLoader();
this.callerLevelRepository = callerLevelRepository;
this.writerRepository = writerRepository;
diff --git a/src/main/java/elf4j/engine/service/LogServiceManager.java b/src/main/java/elf4j/engine/service/LogServiceManager.java
index 5699796..ea6a9c5 100644
--- a/src/main/java/elf4j/engine/service/LogServiceManager.java
+++ b/src/main/java/elf4j/engine/service/LogServiceManager.java
@@ -25,35 +25,60 @@
package elf4j.engine.service;
+import elf4j.engine.configuration.Refreshable;
+
+import java.util.HashSet;
import java.util.Properties;
+import java.util.Set;
/**
*
*/
-public class LogServiceManager {
- private LogServiceManager() {
+public enum LogServiceManager {
+ /**
+ *
+ */
+ INSTANCE;
+
+ private final Set refreshables = new HashSet<>();
+ private final Set stoppables = new HashSet<>();
+
+ /**
+ * @param refreshable
+ * added to be accessible for management
+ */
+ public void register(Refreshable refreshable) {
+ this.refreshables.add(refreshable);
}
/**
- *
+ * @param stoppable
+ * added to be accessible for management
+ */
+ public void register(Stoppable stoppable) {
+ this.stoppables.add(stoppable);
+ }
+
+ /**
+ * reloads properties source for each refreshable
*/
- public static void refreshConfiguration() {
- refreshConfiguration(null);
+ public void refreshAll() {
+ refreshables.forEach(Refreshable::refresh);
}
/**
* @param properties
- * overriding properties for the new configuration, in addition to the reloaded properties from the
- * configuration file
+ * if non-null, replaces current configuration with the specified properties, instead of reloading from the
+ * original properties source; otherwise, reloads the original properties source for each refreshable.
*/
- public static void refreshConfiguration(Properties properties) {
- DefaultLogService.refreshConfiguration(properties);
+ public void refreshAll(Properties properties) {
+ refreshables.forEach(refreshable -> refreshable.refresh(properties));
}
/**
*
*/
- public static void shutdown() {
- DefaultLogService.shutdown();
+ public void shutdownAll() {
+ stoppables.forEach(Stoppable::stop);
}
}
diff --git a/src/main/java/elf4j/engine/service/Stoppable.java b/src/main/java/elf4j/engine/service/Stoppable.java
new file mode 100644
index 0000000..9159b9f
--- /dev/null
+++ b/src/main/java/elf4j/engine/service/Stoppable.java
@@ -0,0 +1,36 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2023 Qingtian Wang
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+package elf4j.engine.service;
+
+/**
+ *
+ */
+public interface Stoppable {
+ /**
+ *
+ */
+ void stop();
+}
diff --git a/src/main/java/elf4j/engine/service/DefaultLogService.java b/src/main/java/elf4j/engine/service/StoppableLogService.java
similarity index 89%
rename from src/main/java/elf4j/engine/service/DefaultLogService.java
rename to src/main/java/elf4j/engine/service/StoppableLogService.java
index b6d811f..15c2046 100644
--- a/src/main/java/elf4j/engine/service/DefaultLogService.java
+++ b/src/main/java/elf4j/engine/service/StoppableLogService.java
@@ -26,41 +26,33 @@
package elf4j.engine.service;
import elf4j.engine.NativeLogger;
-import elf4j.engine.configuration.DefaultLogServiceConfiguration;
import elf4j.engine.configuration.LogServiceConfiguration;
+import elf4j.engine.configuration.RefreshableLogServiceConfiguration;
import elf4j.engine.util.StackTraceUtils;
import lombok.NonNull;
import java.util.Objects;
-import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
*
*/
-public class DefaultLogService implements LogService {
+public class StoppableLogService implements LogService, Stoppable {
private final LogServiceConfiguration logServiceConfiguration;
private final WriterThread writerThread;
/**
*
*/
- public DefaultLogService() {
+ public StoppableLogService() {
this(ServiceConfigurationHolder.INSTANCE, WriterThreadHolder.INSTANCE);
}
- DefaultLogService(LogServiceConfiguration logServiceConfiguration, WriterThread writerThread) {
+ StoppableLogService(LogServiceConfiguration logServiceConfiguration, WriterThread writerThread) {
this.logServiceConfiguration = logServiceConfiguration;
this.writerThread = writerThread;
- }
-
- static void refreshConfiguration(Properties properties) {
- ServiceConfigurationHolder.INSTANCE.refresh(properties);
- }
-
- static void shutdown() {
- WriterThreadHolder.INSTANCE.shutdown();
+ LogServiceManager.INSTANCE.register(this);
}
@Override
@@ -99,6 +91,11 @@ public void log(NativeLogger nativeLogger,
writerThread.execute(() -> logServiceConfiguration.getLogServiceWriter().write(logEntryBuilder.build()));
}
+ @Override
+ public void stop() {
+ this.writerThread.shutdown();
+ }
+
/**
*
*/
@@ -125,7 +122,7 @@ public void execute(@NonNull Runnable command) {
}
private static class ServiceConfigurationHolder {
- private static final LogServiceConfiguration INSTANCE = new DefaultLogServiceConfiguration();
+ private static final LogServiceConfiguration INSTANCE = new RefreshableLogServiceConfiguration();
}
private static class WriterThreadHolder {
diff --git a/src/test/java/elf4j/engine/Main.java b/src/test/java/elf4j/engine/Main.java
index 0e5867b..6680e3f 100644
--- a/src/test/java/elf4j/engine/Main.java
+++ b/src/test/java/elf4j/engine/Main.java
@@ -77,6 +77,6 @@ public static void main(String[] args) {
.log("Not a practical example but the severity level is INFO");
MoreAwaitility.block(Duration.ofMillis(200), "Making sure console streams show up");
- LogServiceManager.shutdown();
+ LogServiceManager.INSTANCE.shutdownAll();
}
}
diff --git a/src/test/java/elf4j/engine/configuration/DefaultLogServiceConfigurationTest.java b/src/test/java/elf4j/engine/configuration/StoppableLogServiceConfigurationTest.java
similarity index 74%
rename from src/test/java/elf4j/engine/configuration/DefaultLogServiceConfigurationTest.java
rename to src/test/java/elf4j/engine/configuration/StoppableLogServiceConfigurationTest.java
index d0dee0a..1574552 100644
--- a/src/test/java/elf4j/engine/configuration/DefaultLogServiceConfigurationTest.java
+++ b/src/test/java/elf4j/engine/configuration/StoppableLogServiceConfigurationTest.java
@@ -45,7 +45,7 @@
import static org.mockito.BDDMockito.then;
@ExtendWith(MockitoExtension.class)
-class DefaultLogServiceConfigurationTest {
+class StoppableLogServiceConfigurationTest {
@Mock CallerLevelRepository mockCallerLevelRepository;
@Mock WriterRepository mockWriterRepository;
@Mock LogWriter stubLogWriter;
@@ -55,19 +55,19 @@ class DefaultLogServiceConfigurationTest {
class isEnabled {
@Test
void cacheLoadFromReposOnlyOnce() {
- DefaultLogServiceConfiguration defaultLoggingConfiguration =
- new DefaultLogServiceConfiguration(mockCallerLevelRepository, mockWriterRepository);
+ RefreshableLogServiceConfiguration refreshableLogServiceConfiguration =
+ new RefreshableLogServiceConfiguration(mockCallerLevelRepository, mockWriterRepository);
NativeLogger nativeLogger = new NativeLogger("test.owner.class.Name", Level.OFF, mockLogService);
given(mockWriterRepository.getLogServiceWriter()).willReturn(stubLogWriter);
given(stubLogWriter.getMinimumOutputLevel()).willReturn(Level.TRACE);
given(mockCallerLevelRepository.getMinimumOutputLevel(nativeLogger)).willReturn(Level.TRACE);
- defaultLoggingConfiguration.isEnabled(nativeLogger);
+ refreshableLogServiceConfiguration.isEnabled(nativeLogger);
assertSame(stubLogWriter, mockWriterRepository.getLogServiceWriter());
then(mockCallerLevelRepository).should().getMinimumOutputLevel(nativeLogger);
- defaultLoggingConfiguration.isEnabled(nativeLogger);
+ refreshableLogServiceConfiguration.isEnabled(nativeLogger);
then(mockWriterRepository).shouldHaveNoMoreInteractions();
then(mockCallerLevelRepository).shouldHaveNoMoreInteractions();
@@ -78,20 +78,22 @@ void cacheLoadFromReposOnlyOnce() {
class refresh {
@Test
void reload() {
- DefaultLogServiceConfiguration defaultServiceConfiguration = new DefaultLogServiceConfiguration();
+ RefreshableLogServiceConfiguration refreshableLogServiceConfiguration =
+ new RefreshableLogServiceConfiguration();
- defaultServiceConfiguration.refresh(null);
+ refreshableLogServiceConfiguration.refresh(null);
- assertTrue(defaultServiceConfiguration.getLogServiceWriter() instanceof WriterGroup);
+ assertTrue(refreshableLogServiceConfiguration.getLogServiceWriter() instanceof WriterGroup);
}
@Test
void replace() {
- DefaultLogServiceConfiguration defaultServiceConfiguration = new DefaultLogServiceConfiguration();
+ RefreshableLogServiceConfiguration refreshableLogServiceConfiguration =
+ new RefreshableLogServiceConfiguration();
- defaultServiceConfiguration.refresh(new Properties());
+ refreshableLogServiceConfiguration.refresh(new Properties());
- assertTrue(defaultServiceConfiguration.getLogServiceWriter() instanceof StandardStreamsWriter);
+ assertTrue(refreshableLogServiceConfiguration.getLogServiceWriter() instanceof StandardStreamsWriter);
}
}
}
\ No newline at end of file
diff --git a/src/test/java/elf4j/engine/service/DefaultLogServiceTest.java b/src/test/java/elf4j/engine/service/StoppableLogServiceTest.java
similarity index 88%
rename from src/test/java/elf4j/engine/service/DefaultLogServiceTest.java
rename to src/test/java/elf4j/engine/service/StoppableLogServiceTest.java
index 6cbae5c..ed924ad 100644
--- a/src/test/java/elf4j/engine/service/DefaultLogServiceTest.java
+++ b/src/test/java/elf4j/engine/service/StoppableLogServiceTest.java
@@ -46,7 +46,7 @@
import static org.mockito.Mockito.never;
@ExtendWith(MockitoExtension.class)
-class DefaultLogServiceTest {
+class StoppableLogServiceTest {
private static class StubWriterThread implements WriterThread {
@Override
@@ -62,13 +62,13 @@ public void execute(Runnable command) {
@Nested
class isEnabled {
NativeLogger stubLogger;
- DefaultLogService logService;
+ StoppableLogService logService;
@Mock LogServiceConfiguration mockLogServiceConfiguration;
@Mock WriterThread mockWriterThread;
@Test
void delegateToConfiguration() {
- logService = new DefaultLogService(mockLogServiceConfiguration, mockWriterThread);
+ logService = new StoppableLogService(mockLogServiceConfiguration, mockWriterThread);
stubLogger = new NativeLogger(this.getClass().getName(), Level.TRACE, logService);
logService.isEnabled(stubLogger);
@@ -80,7 +80,7 @@ void delegateToConfiguration() {
@Nested
class log {
NativeLogger stubLogger;
- DefaultLogService logService;
+ StoppableLogService logService;
@Mock LogServiceConfiguration mockLogServiceConfiguration;
@Mock LogWriter mockLogWriter;
@Mock WriterThread mockWriterThread;
@@ -88,7 +88,7 @@ class log {
@Test
void async() {
- logService = new DefaultLogService(mockLogServiceConfiguration, mockWriterThread);
+ logService = new StoppableLogService(mockLogServiceConfiguration, mockWriterThread);
stubLogger = new NativeLogger(this.getClass().getName(), Level.TRACE, logService);
given(mockLogServiceConfiguration.isEnabled(any(NativeLogger.class))).willReturn(true);
given(mockLogServiceConfiguration.getLogServiceWriter()).willReturn(mockLogWriter);
@@ -100,7 +100,7 @@ void async() {
@Test
void callThreadRequired() {
- logService = new DefaultLogService(mockLogServiceConfiguration, new StubWriterThread());
+ logService = new StoppableLogService(mockLogServiceConfiguration, new StubWriterThread());
stubLogger = new NativeLogger(this.getClass().getName(), Level.TRACE, logService);
given(mockLogWriter.includeCallerThread()).willReturn(true);
given(mockLogServiceConfiguration.isEnabled(any(NativeLogger.class))).willReturn(true);
@@ -116,7 +116,7 @@ void callThreadRequired() {
@Test
void callThreadNotRequired() {
- logService = new DefaultLogService(mockLogServiceConfiguration, new StubWriterThread());
+ logService = new StoppableLogService(mockLogServiceConfiguration, new StubWriterThread());
stubLogger = new NativeLogger(this.getClass().getName(), Level.TRACE, logService);
given(mockLogWriter.includeCallerThread()).willReturn(false);
given(mockLogServiceConfiguration.isEnabled(any(NativeLogger.class))).willReturn(true);
@@ -130,7 +130,7 @@ void callThreadNotRequired() {
@Test
void callerDetailRequired() {
- logService = new DefaultLogService(mockLogServiceConfiguration, new StubWriterThread());
+ logService = new StoppableLogService(mockLogServiceConfiguration, new StubWriterThread());
stubLogger = new NativeLogger(this.getClass().getName(), Level.TRACE, logService);
given(mockLogServiceConfiguration.isEnabled(any(NativeLogger.class))).willReturn(true);
given(mockLogServiceConfiguration.getLogServiceWriter()).willReturn(mockLogWriter);
@@ -144,7 +144,7 @@ void callerDetailRequired() {
@Test
void callDetailNotRequired() {
- logService = new DefaultLogService(mockLogServiceConfiguration, new StubWriterThread());
+ logService = new StoppableLogService(mockLogServiceConfiguration, new StubWriterThread());
stubLogger = new NativeLogger(this.getClass().getName(), Level.TRACE, logService);
given(mockLogServiceConfiguration.isEnabled(any(NativeLogger.class))).willReturn(true);
given(mockLogWriter.includeCallerDetail()).willReturn(false);
@@ -158,7 +158,7 @@ void callDetailNotRequired() {
@Test
void onlyLogWhenEnabled() {
- logService = new DefaultLogService(mockLogServiceConfiguration, new StubWriterThread());
+ logService = new StoppableLogService(mockLogServiceConfiguration, new StubWriterThread());
stubLogger = new NativeLogger(this.getClass().getName(), Level.TRACE, logService);
given(mockLogServiceConfiguration.isEnabled(any(NativeLogger.class))).willReturn(false);