Skip to content

Commit

Permalink
Refactor/#112 Property File 파싱 로직 변경 (#114)
Browse files Browse the repository at this point in the history
* init: 의존 추가

- SnakeYAML 의존을 추가했습니다.
- 기존 의존 버전을 최신화했습니다.

* style: AppKeyTest 스타일 변경

- 테스트 스타일을 변경했습니다.

* chore: 클래스 이름 변경

- LogbatOptions -> LogBatOptions 이름 변경

* refactor: LogBatOptions 생성 로직 변경

- 생성 로직을 Config을 전달받아 구현하는 방식으로 수정했습니다.
- LogBatconfig -> LogBatConfig 클래스 명 변경을 진행했습니다.
- 이에 따른 테스트를 수정했습니다.

* refactor: LogBatConfig 로직 변경

- Map<String, String>을 관리하도록 수정했습니다.
  - 이에 따른 테스트를 수정했습니다.

* chore: 클래스 명 변경 및 docs 추가

- InvalidAppKeyException -> InvalidOptionException
- LogBatConfig docs 추

* docs: AppKey 주석 작성

- AppKey에 대한 주석을 작성했습니다.

* refactor: LogBatFactory 로직 변경

- 싱글턴 보장을 위한 VarHandler 사용 로직을 적용했습니다.
- javadoc을 추가했습니다.

* chore: 클래스 이름 변경

- LogbatAppender -> LogBatAppender

* refactor: LogSender 로직 변경

- 생성자에서 LogBatOptions으로만 생성이 가능하게 수정했습니다.
- 내부 메서드에 대한 리팩토링을 진행했습니다.
- LogSenderTest를 수정했습니다.

* refactor: LogBatConfigLoader 로직 변경

- .yml, .yaml 파일 로드시 SnakeYAML 의존을 사용하도록 수정했습니다.
- java-doc을 추가했습니다.

* chore: 클래스 이름 변경

- logBat -> LogBat 클래스 이름을 변경했습니다.
- Java-Doc에 저자를 추가했습니다.

* docs: LogProcessScheduler

- Java-Doc을 추가했습니다.

* chore: 로직 수정

- null -> .loadConfig()

* refactor: VarHandle 변수명 변경

- INSTANCES -> INSTANCE

* refactor: instance volatile 적용

* refactor: `compareAndSet` 을 사용한 객체 할당

- `synchronized` 키워드 제거
- `compareAndSet` 를 통해서 하나의 객체만 반환될것을 보장

* feat: 다중 값 허용하지 않도록 변경

* refactor: filename 에 final 키워드 적용

* refactor: 매개변수의 filename 제거

- 매개변수의 filename 없이 객체 내부의 값을 참조하도록 변경

* fix: 여러 설정파일로 부터 값을 불러올 수 있도록 변경

* style: 코드 위치 변경

- VarHandle 부분을 코드 최하단으로 옮겼습니다.
- docs를 수정했습니다.

* chore: LogBatConfigLoader

- 일부 로직 수정
- docs 수정

* style: LogBufferTest

- 테스트 형식을 이전 테스트와 동일하게 맞췄습니다.

---------

Co-authored-by: luizy <[email protected]>
  • Loading branch information
tidavid1 and LuizyHub authored Aug 25, 2024
1 parent f380ff3 commit 47a3234
Show file tree
Hide file tree
Showing 24 changed files with 818 additions and 561 deletions.
32 changes: 16 additions & 16 deletions sdk/java/logbat-sdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,23 @@ publishing {
}

dependencies {
// logback
implementation 'ch.qos.logback:logback-classic:1.4.14'

// slf4j
implementation 'org.slf4j:slf4j-api:1.7.36'

// objectMapper
implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'

// Logback Classic
implementation 'ch.qos.logback:logback-classic:1.5.7'
// Slf4j API
implementation 'org.slf4j:slf4j-api:2.0.16'
// Jackson ObjectMapper
implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2'
// SnakeYAML
implementation 'org.yaml:snakeyaml:2.2'

// Junit5
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
testImplementation 'org.assertj:assertj-core:3.24.2'

// mockito
testImplementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.15.3'
testImplementation 'org.mockito:mockito-core:5.6.0'
testImplementation 'org.junit.jupiter:junit-jupiter:5.11.0'
// AssertJ
testImplementation 'org.assertj:assertj-core:3.26.3'
// Jackson JSR310
testImplementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.17.2'
// Mockito
testImplementation 'org.mockito:mockito-core:5.12.0'
}

test {
Expand All @@ -62,7 +62,7 @@ jar {
)
}
duplicatesStrategy = DuplicatesStrategy.EXCLUDE // 중복된 파일 무시

from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
Expand Down
121 changes: 121 additions & 0 deletions sdk/java/logbat-sdk/src/main/java/info/logbat/LogBatFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package info.logbat;

import info.logbat.application.LogBat;
import info.logbat.application.LogSendRequestFactory;
import info.logbat.config.LogBatConfigLoader;
import info.logbat.domain.options.LogBatOptions;
import info.logbat.exception.InvalidOptionException;
import info.logbat.infrastructure.AsyncLogWriter;
import info.logbat.infrastructure.LogBuffer;
import info.logbat.infrastructure.LogSender;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;

/**
* LogBatFactory is a factory class that creates and manages a single instance of the LogBat class.
* <p>
* This class implements the singleton pattern to ensure that only one LogBat instance is created
* and shared across the application. It uses VarHandle for thread-safe lazy initialization.
* </p>
* <p>
* The LogBat instance is created with its required dependencies such as {@link LogBuffer},
* {@link LogSender}, {@link LogSendRequestFactory}, and {@link AsyncLogWriter}.
* </p>
* <p>
* The Logbat instance is initialized with default configuration options. Custom configuration can
* be set using the {@link LogBatOptions} class.
* </p>
*
* @author KyungMin Lee <a href="https://github.com/tidavid1">GitHub</a>, JungJae Park <a
* href="https://github.com/LuizyHub">GitHub</a>
* @version 0.1.2
* @since 0.1.0
*/
public final class LogBatFactory {

private static volatile LogBat instance;

/**
* Returns the singleton instance of LogBat.
* <p>
* This method provides thread-safe lazy initialization of the LogBat instance. If the instance
* hasn't been created yet, it calls {@link #getDelayedInstance()} to create and initialize it.
* </p>
*
* @return the singleton LogBat instance
*/
public static LogBat getInstance() {
LogBat logbat = instance;
if (logbat != null) {
return logbat;
}
return getDelayedInstance();
}

/**
* Creates and initializes the LogBat instance if it hasn't been created yet.
* <p>
* This method is synchronized to ensure thread safety during the initialization process. It
* double-checks if the instance has already been created to prevent unnecessary synchronization
* after the first initialization.
* </p>
*
* @return the initialized LogBat instance
* @throws RuntimeException if the LogBat instance creation fails
*/
private static LogBat getDelayedInstance() {
try {
LogBat logbat = createLogbat();
if (!INSTANCE.compareAndSet(null, logbat)) {
logbat = instance;
}
return logbat;
} catch (InvalidOptionException e) {
System.err.println("Failed to create LogBat instance: " + e.getMessage());
System.exit(100);
}
// Should never reach this point
return null;
}

/**
* Creates a new LogBat instance with all necessary dependencies.
* <p>
* This method initializes and configures all required components for the LogBat instance,
* including LogBatOptions, LogSendRequestFactory, and AsyncLogWriter.
* </p>
*
* @return a new LogBat instance
* @throws InvalidOptionException if there's an issue with the LogBatOptions configuration
*/
private static LogBat createLogbat() throws InvalidOptionException {
LogBatOptions logbatOptions = new LogBatOptions(LogBatConfigLoader.loadConfig());
LogSendRequestFactory logSendRequestFactory = new LogSendRequestFactory();
AsyncLogWriter asyncLogWriter = new AsyncLogWriter(new LogBuffer(),
new LogSender(logbatOptions));
return new LogBat(asyncLogWriter, logSendRequestFactory);
}

/**
* Private constructor to prevent instantiation of this utility class.
*
* @throws UnsupportedOperationException always, as this class should not be instantiated
*/
private LogBatFactory() {
throw new UnsupportedOperationException("LogBatFactory cannot be instantiated");
}

/**
* VarHandle for the LogBat instance, used for thread-safe lazy initialization.
*/
private static final VarHandle INSTANCE;

static {
try {
INSTANCE = MethodHandles.lookup()
.findStaticVarHandle(LogBatFactory.class, "instance", LogBat.class);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new ExceptionInInitializerError(e);
}
}
}
68 changes: 0 additions & 68 deletions sdk/java/logbat-sdk/src/main/java/info/logbat/LogbatFactory.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.UnsynchronizedAppenderBase;
import info.logbat.LogbatFactory;
import info.logbat.application.Logbat;
import info.logbat.LogBatFactory;
import info.logbat.application.LogBat;

public class LogbatAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {
public class LogBatAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {

private Logbat logbat;
private LogBat logbat;

@Override
public void start() {
super.start();
this.logbat = LogbatFactory.getInstance();
this.logbat = LogBatFactory.getInstance();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package info.logbat.application;

import ch.qos.logback.classic.spi.ILoggingEvent;
import info.logbat.infrastructure.AsyncLogWriter;
import info.logbat.infrastructure.payload.LogSendRequest;

/**
* The LogBat class is responsible for writing log events asynchronously. It uses an AsyncLogWriter
* to send log requests and a LogSendRequestFactory to create log send requests from logging
* events.
*
* @author KyungMin Lee <a href="https://github.com/tidavid1">GitHub</a>
* @version 0.1.0
* @see AsyncLogWriter
* @see LogSendRequestFactory
* @since 0.1.0
*/
public class LogBat {

private final AsyncLogWriter asyncLogWriter;
private final LogSendRequestFactory logSendRequestFactory;

/**
* Constructs a new LogBat instance.
*
* @param asyncLogWriter The AsyncLogWriter used to send log requests asynchronously.
* @param logSendRequestFactory The factory used to create LogSendRequest objects from logging
* events.
*/
public LogBat(AsyncLogWriter asyncLogWriter, LogSendRequestFactory logSendRequestFactory) {
this.asyncLogWriter = asyncLogWriter;
this.logSendRequestFactory = logSendRequestFactory;
}

/**
* Writes a log event asynchronously. This method creates a LogSendRequest from the given
* logging event and sends it using the AsyncLogWriter.
*
* @param eventObject The ILoggingEvent to be written as a log.
*/
public void writeLog(ILoggingEvent eventObject) {
LogSendRequest logSendRequest = logSendRequestFactory.createLogSendRequest(eventObject);
asyncLogWriter.sendLog(logSendRequest);
}

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package info.logbat.config;

import info.logbat.exception.InvalidOptionException;
import java.util.Map;
import java.util.Optional;

/**
* Configuration class for LogBat.
* <p>
* This class is used to store the configuration options for LogBat. The configuration options are
* stored in a map, where the key is the option name and the value is the option value. The
* configuration options can be accessed using the {@link #getValue(String)} method. If the option
* is not found, an {@link InvalidOptionException} is thrown.
* </p>
*
* @author KyungMin Lee <a href="https://github.com/tidavid1">GitHub</a>
* @version 0.1.1
* @see InvalidOptionException
* @see info.logbat.config.LogBatConfig#getValue(String)
* @see info.logbat.config.LogBatConfig#LogBatConfig(Map)
* @since 0.1.1
*/
public class LogBatConfig {

// The configuration options
private final Map<String, String> options;

/**
* Constructs a new LogBatConfig object with the given options.
*
* @param options the configuration options
*/
public LogBatConfig(Map<String, String> options) {
this.options = options;
}

/**
* Returns the value of the option with the given key.
*
* @param key the key of the option
* @return the value of the option
* @throws InvalidOptionException if the option is not found
*/
public String getValue(String key) throws InvalidOptionException {
return Optional.ofNullable(options.get(key))
.orElseThrow(() -> new InvalidOptionException("Key not found: " + key));
}

}
Loading

0 comments on commit 47a3234

Please sign in to comment.