Skip to content

Commit

Permalink
refactor: log4j-api to slf4j-api
Browse files Browse the repository at this point in the history
brenoepics committed Apr 30, 2024
1 parent 088360b commit 97cb23f
Showing 16 changed files with 251 additions and 551 deletions.
5 changes: 0 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -102,11 +102,6 @@ libraryDependencies += "io.github.brenoepics" % "at4j" % "1.0.0"

**A:** You can access your Azure Translator Keys through your Azure portal. Remember to keep your keys secure and refrain from sharing them publicly. If you suspect a key has been compromised, it's crucial to regenerate it promptly. For detailed instructions on generating your own keys, refer to [this guide](https://brenoepics.github.io/at4j/guide/azure-subscription.html#azure-subscription). Additionally, you can explore the [Azure Free Tier](https://brenoepics.github.io/at4j/guide/azure-subscription.html#azure-free-tier) for more information.

Optional Logger Dependency
**Q:** Is there a recommended logger dependency for the project?

**A:** While our project is compatible with any Log4j-2-compatible logging framework, integrating one can enhance your logging experience significantly. This allows you to configure log format, log targets (console, file, database, etc.), log levels per class, and more. For further details, please visit our [Docs](https://brenoepics.github.io/at4j/guide/installation.html#logger-dependency).

## 🤝 Thank You!
- **Microsoft Azure**: Supporting our project with a generous grant of $10,000+ in Azure credits, enabling us to use virtual machines, document translation and other essential cloud resources for our development needs.
- We extend our sincere thanks to all contributors for their invaluable contributions.
47 changes: 0 additions & 47 deletions docs/src/guide/installation.md
Original file line number Diff line number Diff line change
@@ -25,50 +25,3 @@ implementation group: 'io.github.brenoepics', name: 'at4j', version: 'AT4J-VERSI
libraryDependencies += "io.github.brenoepics" % "at4j" % "AT4J-VERSION"
```
:::

## Optional Logger Dependency {#logger-dependency}

In addition to AT4J, it is also recommended to install a Log4j-2-compatible logging framework.
A logging framework can be used to provide a more sophisticated logging experience with being able to configure log format,
log targets (console, file, database, Discord direct message, ...), log levels per class, and much more.

For example, Log4j Core:

::: code-group
```groovy [Gradle]
dependencies { runtimeOnly 'org.apache.logging.log4j:log4j-core:2.17.0' }
```

```xml [Maven]
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.0</version>
</dependency>
```

```scala [Sbt]
libraryDependencies ++= Seq("org.apache.logging.log4j" % "log4j-core" % "2.17.0")
```
:::

Or Log4j to Slf4j:

::: code-group
```groovy [Gradle]
dependencies { runtimeOnly 'org.apache.logging.log4j:log4j-to-slf4j:2.22.1' }
```

```xml [Maven]
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.22.1</version>
</dependency>
```
```scala [Sbt]
libraryDependencies ++= Seq("org.apache.logging.log4j" % "log4j-to-slf4j" % "2.22.1")
```
:::

Take a look at the logger configuration doc for further information.
6 changes: 3 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -52,9 +52,9 @@
</properties>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.23.1</version>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.13</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
4 changes: 2 additions & 2 deletions src/main/java/io/github/brenoepics/at4j/AzureApiBuilder.java
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

import io.github.brenoepics.at4j.azure.BaseURL;
import io.github.brenoepics.at4j.core.AzureApiImpl;
import io.github.brenoepics.at4j.util.logging.PrivacyProtectionLogger;
import io.github.brenoepics.at4j.util.logging.ProtectedLogger;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
@@ -52,7 +52,7 @@ public AzureApiBuilder baseURL(BaseURL baseURL) {
*/
public AzureApiBuilder setKey(String subscriptionKey) {
this.subscriptionKey = subscriptionKey;
PrivacyProtectionLogger.addPrivateData(subscriptionKey);
ProtectedLogger.addPrivateData(subscriptionKey);
return this;
}

Original file line number Diff line number Diff line change
@@ -7,6 +7,8 @@
import io.github.brenoepics.at4j.util.rest.RestRequestHandler;
import io.github.brenoepics.at4j.util.rest.RestRequestResponseInfoImpl;
import io.github.brenoepics.at4j.util.rest.RestRequestResult;
import org.slf4j.Logger;

import java.net.http.HttpHeaders;
import java.net.http.HttpResponse;
import java.util.HashSet;
@@ -15,7 +17,6 @@
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import org.apache.logging.log4j.Logger;

/** This class manages rate-limits and keeps track of them. */
public class RateLimitManager<T, T3, T4> {

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,81 +1,31 @@
package io.github.brenoepics.at4j.util.logging;

import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.simple.SimpleLogger;
import org.apache.logging.log4j.util.PropertiesUtil;
import org.apache.logging.log4j.util.ProviderUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** This class is used to get a {@link Logger} instance. */
public class LoggerUtil {
LoggerUtil() {
throw new UnsupportedOperationException();
}

private static final AtomicReference<Boolean> initialized = new AtomicReference<>(false);
private static final AtomicBoolean noLogger = new AtomicBoolean();
private static final Map<String, Logger> loggers = new ConcurrentHashMap<>();

/**
* Get or create a logger with the given name.
*
* @param name The name of the logger.
* @return The logger with the given name.
*/
public static Logger getLogger(String name) {
AtomicBoolean logWarning = new AtomicBoolean(false);
initialized.updateAndGet(
initialized -> {
if (Boolean.TRUE.equals(!initialized) && !ProviderUtil.hasProviders()) {
noLogger.set(true);
logWarning.set(true);
}
return true;
});
LoggerUtil() {
throw new UnsupportedOperationException();
}

if (noLogger.get()) {
return loggers.computeIfAbsent(
name,
key -> {
Level debugLevel =
FallbackLoggerConfiguration.isDebugEnabled() ? Level.DEBUG : Level.INFO;
Level level = FallbackLoggerConfiguration.isTraceEnabled() ? Level.TRACE : debugLevel;
Logger logger =
new SimpleLogger(
name,
level,
true,
false,
true,
true,
"yyyy-MM-dd HH:mm:ss.SSSZ",
null,
new PropertiesUtil(new Properties()),
System.out);
if (logWarning.get()) {
logger.info(
"No Log4j2 compatible logger was found. Using default AT4J implementation!");
}
return new PrivacyProtectionLogger(logger);
});
} else {
return new PrivacyProtectionLogger(LogManager.getLogger(name));
/**
* Get or create a logger with the given name.
*
* @param name The name of the logger.
* @return The logger with the given name.
*/
public static Logger getLogger(String name) {
return LoggerFactory.getLogger(name);
}
}

/**
* Gets or creates a logger for the given name.
*
* @param clazz The class of the logger.
* @return A logger for the given class.
*/
public static Logger getLogger(Class<?> clazz) {
return getLogger(clazz.getName());
}
}
/**
* Gets or creates a logger for the given class.
*
* @param clazz The class of the logger.
* @return A logger for the given class.
*/
public static Logger getLogger(Class<?> clazz) {
return LoggerFactory.getLogger(clazz);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package io.github.brenoepics.at4j.util.logging;

import java.util.HashSet;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.Marker;
import org.slf4j.event.Level;
import org.slf4j.helpers.AbstractLogger;

/**
* This logger is used to wrap another logger and replace configured sensitive data by asterisks.
*/
public class ProtectedLogger extends AbstractLogger {
private static final long serialVersionUID = 91095837261631L;
private static final String PRIVATE_DATA_REPLACEMENT = "**********";
private static final Set<String> privateDataSet = new HashSet<>();

private final transient Logger delegate;

/**
* Class constructor. It's recommended to use {@link LoggerUtil#getLogger(String)}.
*
* @param delegate The delegate logger that gets the cleaned messages.
*/
ProtectedLogger(Logger delegate) {
this.delegate = delegate;
}

/**
* Adds private data to be asterisked out in log messages. A {@code null} argument is simply
* ignored.
*
* @param privateData The private data.
*/
public static void addPrivateData(String privateData) {
if (privateData != null && !privateData.trim().isEmpty()) {
privateDataSet.add(privateData);
}
}

@Override
public String getName() {
return delegate.getName();
}

@Override
public boolean isTraceEnabled() {
return delegate.isTraceEnabled();
}

@Override
public boolean isTraceEnabled(Marker marker) {
return delegate.isTraceEnabled(marker);
}

@Override
public boolean isDebugEnabled() {
return delegate.isDebugEnabled();
}

@Override
public boolean isDebugEnabled(Marker marker) {
return delegate.isDebugEnabled(marker);
}

@Override
public boolean isInfoEnabled() {
return delegate.isInfoEnabled();
}

@Override
public boolean isInfoEnabled(Marker marker) {
return delegate.isInfoEnabled(marker);
}

@Override
public boolean isWarnEnabled() {
return delegate.isWarnEnabled();
}

@Override
public boolean isWarnEnabled(Marker marker) {
return delegate.isWarnEnabled(marker);
}

@Override
public boolean isErrorEnabled() {
return delegate.isErrorEnabled();
}

@Override
public boolean isErrorEnabled(Marker marker) {
return delegate.isErrorEnabled(marker);
}

@Override
protected String getFullyQualifiedCallerName() {
return delegate.getName();
}

@Override
protected void handleNormalizedLoggingCall(
Level level, Marker marker, String message, Object[] objects, Throwable t) {
if (privateDataSet.stream().noneMatch(message::contains)) {
log(level, marker, objects, t, message);
return;
}

String replacedMessage = message;
for (String privateData : privateDataSet) {
if (message.contains(privateData)) {
replacedMessage = replacedMessage.replace(privateData, PRIVATE_DATA_REPLACEMENT);
}
}

log(level, marker, objects, t, replacedMessage);
}

private void log(Level level, Marker marker, Object[] objects, Throwable t, String message) {
switch (level) {
case TRACE:
delegate.trace(marker, message, objects, t);
break;
case DEBUG:
delegate.debug(marker, message, objects, t);
break;
case INFO:
delegate.info(marker, message, objects, t);
break;
case WARN:
delegate.warn(marker, message, objects, t);
break;
case ERROR:
delegate.error(marker, message, objects, t);
break;
}
}
}
Original file line number Diff line number Diff line change
@@ -5,6 +5,8 @@
import io.github.brenoepics.at4j.AzureApi;
import io.github.brenoepics.at4j.core.exceptions.AzureException;
import io.github.brenoepics.at4j.util.logging.LoggerUtil;
import org.slf4j.Logger;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
@@ -15,8 +17,6 @@
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;

import org.apache.logging.log4j.Logger;

/** This class is used to wrap a rest request. */
public class RestRequest {

Original file line number Diff line number Diff line change
@@ -5,11 +5,11 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.NullNode;
import io.github.brenoepics.at4j.util.logging.LoggerUtil;
import org.slf4j.Logger;

import java.io.IOException;
import java.net.http.HttpResponse;
import java.util.Optional;
import org.apache.logging.log4j.Logger;

/** The result of a {@link RestRequest}. */
public class RestRequestResult {

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package io.github.brenoepics.at4j.util.logging;

import static org.mockito.Mockito.*;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.Marker;
import org.slf4j.event.Level;

class ProtectedLoggerTest {
private Logger delegate;
private ProtectedLogger protectedLogger;

@BeforeEach
public void setup() {
delegate = Mockito.mock(Logger.class);
protectedLogger = new ProtectedLogger(delegate);
}

@Test
void logMessageTest() {
String privateData = "secret";
ProtectedLogger.addPrivateData(privateData);
String message = "This is a secret message";
Marker marker = Mockito.mock(Marker.class);
protectedLogger.handleNormalizedLoggingCall(Level.INFO, marker, message, null, null);
verify(delegate).info(eq(marker), eq("This is a ********** message"), isNull(), isNull());
}

@Test
void logTraceMessageTest() {
String privateData = "secret";
ProtectedLogger.addPrivateData(privateData);
String message = "This is a secret trace message";
Marker marker = Mockito.mock(Marker.class);
protectedLogger.handleNormalizedLoggingCall(Level.TRACE, marker, message, null, null);
verify(delegate).trace(eq(marker), eq("This is a ********** trace message"), isNull(), isNull());
}

@Test
void logDebugMessageTest() {
String privateData = "secret";
ProtectedLogger.addPrivateData(privateData);
String message = "This is a secret debug message";
Marker marker = Mockito.mock(Marker.class);
protectedLogger.handleNormalizedLoggingCall(Level.DEBUG, marker, message, null, null);
verify(delegate).debug(eq(marker), eq("This is a ********** debug message"), isNull(), isNull());
}

@Test
void logWarnMessageTest() {
String privateData = "secret";
ProtectedLogger.addPrivateData(privateData);
String message = "This is a secret warn message";
Marker marker = Mockito.mock(Marker.class);
protectedLogger.handleNormalizedLoggingCall(Level.WARN, marker, message, null, null);
verify(delegate).warn(eq(marker), eq("This is a ********** warn message"), isNull(), isNull());
}

@Test
void logErrorMessageTest() {
String privateData = "secret";
ProtectedLogger.addPrivateData(privateData);
String message = "This is a secret error message";
Marker marker = Mockito.mock(Marker.class);
protectedLogger.handleNormalizedLoggingCall(Level.ERROR, marker, message, null, null);
verify(delegate).error(eq(marker), eq("This is a ********** error message"), isNull(), isNull());
}

@Test
void logMessageWithoutPrivateDataTest() {
String message = "This is a regular message";
Marker marker = Mockito.mock(Marker.class);
protectedLogger.handleNormalizedLoggingCall(Level.INFO, marker, message, null, null);
verify(delegate).info(eq(marker), eq("This is a regular message"), isNull(), isNull());
}
}

0 comments on commit 97cb23f

Please sign in to comment.