Skip to content

Commit

Permalink
+ changed configuration refresh and service shutdown API
Browse files Browse the repository at this point in the history
  • Loading branch information
q3769 committed Mar 31, 2023
1 parent 4a32925 commit 1b409f8
Show file tree
Hide file tree
Showing 11 changed files with 164 additions and 64 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

<groupId>io.github.elf4j</groupId>
<artifactId>elf4j-engine</artifactId>
<version>2.0.11</version>
<version>3.0.0</version>
<packaging>jar</packaging>
<name>elf4j-engine</name>
<description>A stand-alone Java log engine implementing the ELF4J (Easy Logging Facade for Java) API</description>
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/elf4j/engine/NativeLoggerFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@
import elf4j.engine.NativeLogger;
import elf4j.engine.writer.LogWriter;

import javax.annotation.Nullable;
import java.util.Properties;

/**
*
*/
Expand All @@ -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 <code>null</code>, 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);
}
49 changes: 49 additions & 0 deletions src/main/java/elf4j/engine/configuration/Refreshable.java
Original file line number Diff line number Diff line change
@@ -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 <code>null</code>, 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -40,7 +41,7 @@
*
*/
@ToString
public class DefaultLogServiceConfiguration implements LogServiceConfiguration {
public class RefreshableLogServiceConfiguration implements LogServiceConfiguration, Refreshable {
private final Map<NativeLogger, Boolean> loggerConfigurationCache = new ConcurrentHashMap<>();
private final PropertiesLoader propertiesLoader;
private boolean noop;
Expand All @@ -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;
Expand Down
47 changes: 36 additions & 11 deletions src/main/java/elf4j/engine/service/LogServiceManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<Refreshable> refreshables = new HashSet<>();
private final Set<Stoppable> 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);
}
}
36 changes: 36 additions & 0 deletions src/main/java/elf4j/engine/service/Stoppable.java
Original file line number Diff line number Diff line change
@@ -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();
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -99,6 +91,11 @@ public void log(NativeLogger nativeLogger,
writerThread.execute(() -> logServiceConfiguration.getLogServiceWriter().write(logEntryBuilder.build()));
}

@Override
public void stop() {
this.writerThread.shutdown();
}

/**
*
*/
Expand All @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/elf4j/engine/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
Expand All @@ -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);
}
}
}
Loading

0 comments on commit 1b409f8

Please sign in to comment.