Skip to content

Commit e517038

Browse files
SNOW-1229142: Improve commons logging wrapping (#2036)
1 parent 9aaaa10 commit e517038

File tree

5 files changed

+206
-0
lines changed

5 files changed

+206
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,6 @@ wss*.config
7171
wss-unified-agent.jar
7272
whitesource/
7373
*.swp
74+
75+
#created in some tests
76+
placeholder
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright (c) 2025 Snowflake Computing Inc. All rights reserved.
3+
*/
4+
package net.snowflake.client.log;
5+
6+
import net.snowflake.client.core.SnowflakeJdbcInternalApi;
7+
import org.apache.commons.logging.Log;
8+
9+
/**
10+
* This is a wrapper class of apache commons logging which uses SFLogger to use driver configuration
11+
* (via java.util.logging or SLF4J) and mask secrets. Wrapper does not hide trace and debug
12+
* messages.
13+
*/
14+
@SnowflakeJdbcInternalApi
15+
public class CommonsLoggingWrapper implements Log {
16+
private final SFLogger logger;
17+
18+
public CommonsLoggingWrapper(String className) {
19+
this.logger = SFLoggerFactory.getLogger(className);
20+
}
21+
22+
public void debug(Object msg) {
23+
logger.debug(String.valueOf(msg), true);
24+
}
25+
26+
public void debug(Object msg, Throwable t) {
27+
logger.debug(String.valueOf(msg), t);
28+
}
29+
30+
public void error(Object msg) {
31+
logger.error(String.valueOf(msg), true);
32+
}
33+
34+
public void error(Object msg, Throwable t) {
35+
logger.error(String.valueOf(msg), t);
36+
}
37+
38+
public void fatal(Object msg) {
39+
this.error(msg);
40+
}
41+
42+
public void fatal(Object msg, Throwable t) {
43+
this.error(msg, t);
44+
}
45+
46+
public void info(Object msg) {
47+
logger.info(String.valueOf(msg), true);
48+
}
49+
50+
public void info(Object msg, Throwable t) {
51+
logger.info(String.valueOf(msg), t);
52+
}
53+
54+
public boolean isDebugEnabled() {
55+
return logger.isDebugEnabled();
56+
}
57+
58+
public boolean isErrorEnabled() {
59+
return logger.isErrorEnabled();
60+
}
61+
62+
public boolean isFatalEnabled() {
63+
return logger.isErrorEnabled();
64+
}
65+
66+
public boolean isInfoEnabled() {
67+
return logger.isInfoEnabled();
68+
}
69+
70+
public boolean isTraceEnabled() {
71+
return logger.isTraceEnabled();
72+
}
73+
74+
public boolean isWarnEnabled() {
75+
return logger.isWarnEnabled();
76+
}
77+
78+
public void trace(Object msg) {
79+
logger.debug(String.valueOf(msg), true);
80+
}
81+
82+
public void trace(Object msg, Throwable t) {
83+
logger.trace(String.valueOf(msg), t);
84+
}
85+
86+
public void warn(Object msg) {
87+
logger.warn(String.valueOf(msg));
88+
}
89+
90+
public void warn(Object msg, Throwable t) {
91+
logger.warn(String.valueOf(msg), t);
92+
}
93+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright (c) 2025 Snowflake Computing Inc. All rights reserved.
3+
*/
4+
package net.snowflake.client.log;
5+
6+
import static net.snowflake.client.jdbc.SnowflakeUtil.systemGetProperty;
7+
8+
import java.util.stream.Collectors;
9+
import java.util.stream.Stream;
10+
11+
enum CommonsLoggingWrapperMode {
12+
/** All logs from commons logging are passed to SFLogger (check {@link CommonsLoggingWrapper}) */
13+
ALL,
14+
/**
15+
* The default behaviour is forwarding all logs to java.util.logging from commons logging (check
16+
* {@link JDK14JCLWrapper}), no logs are forwarded to SLF4J logger (check {@link SLF4JJCLWrapper})
17+
*/
18+
DEFAULT,
19+
/**
20+
* Logs from commons logging are not forwarded and commons logging is not reconfigured - may be
21+
* the option when if you need to replace commons logging with the SLF4J bridge when thin jar is
22+
* used
23+
*/
24+
OFF;
25+
26+
static final String JAVA_PROPERTY = "net.snowflake.jdbc.commons_logging_wrapper";
27+
28+
static CommonsLoggingWrapperMode detect() {
29+
String value = systemGetProperty(JAVA_PROPERTY);
30+
if (value == null) {
31+
return DEFAULT;
32+
}
33+
try {
34+
return CommonsLoggingWrapperMode.valueOf(value);
35+
} catch (Exception e) {
36+
throw new IllegalArgumentException(
37+
"Unknown commons logging wrapper value '"
38+
+ value
39+
+ "', expected one of: "
40+
+ Stream.of(CommonsLoggingWrapperMode.values())
41+
.map(Enum::name)
42+
.collect(Collectors.joining(", ")));
43+
}
44+
}
45+
}

src/main/java/net/snowflake/client/log/SFLoggerUtil.java

+10
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,19 @@ public static void initializeSnowflakeLogger() {
2020
loggerImplementation = SFLoggerFactory.LoggerImpl.JDK14LOGGER;
2121
}
2222

23+
CommonsLoggingWrapperMode commonsLoggingWrapperMode = CommonsLoggingWrapperMode.detect();
24+
if (commonsLoggingWrapperMode == CommonsLoggingWrapperMode.OFF) {
25+
return;
26+
}
27+
2328
System.setProperty(
2429
"org.apache.commons.logging.LogFactory", "org.apache.commons.logging.impl.LogFactoryImpl");
2530
LogFactory logFactory = LogFactory.getFactory();
31+
if (commonsLoggingWrapperMode == CommonsLoggingWrapperMode.ALL) {
32+
logFactory.setAttribute(
33+
"org.apache.commons.logging.Log", CommonsLoggingWrapper.class.getName());
34+
return;
35+
}
2636
switch (loggerImplementation) {
2737
case SLF4JLOGGER:
2838
logFactory.setAttribute(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (c) 2025 Snowflake Computing Inc. All rights reserved.
3+
*/
4+
package net.snowflake.client.log;
5+
6+
import static org.junit.jupiter.api.Assertions.assertEquals;
7+
import static org.junit.jupiter.api.Assertions.assertThrows;
8+
9+
import org.junit.jupiter.api.AfterEach;
10+
import org.junit.jupiter.api.BeforeEach;
11+
import org.junit.jupiter.api.Test;
12+
import org.junit.jupiter.params.ParameterizedTest;
13+
import org.junit.jupiter.params.provider.EnumSource;
14+
15+
public class CommonsLoggingWrapperModeTest {
16+
17+
private String propertyValue;
18+
19+
@BeforeEach
20+
public void setUp() {
21+
propertyValue = System.getProperty(CommonsLoggingWrapperMode.JAVA_PROPERTY);
22+
}
23+
24+
@AfterEach
25+
public void tearDown() {
26+
if (propertyValue != null) {
27+
System.setProperty(CommonsLoggingWrapperMode.JAVA_PROPERTY, propertyValue);
28+
} else {
29+
System.clearProperty(CommonsLoggingWrapperMode.JAVA_PROPERTY);
30+
}
31+
}
32+
33+
@ParameterizedTest
34+
@EnumSource(CommonsLoggingWrapperMode.class)
35+
public void shouldDetectMode(CommonsLoggingWrapperMode value) {
36+
System.setProperty(CommonsLoggingWrapperMode.JAVA_PROPERTY, value.name());
37+
assertEquals(value, CommonsLoggingWrapperMode.detect());
38+
}
39+
40+
@Test
41+
public void shouldPickDefaultMode() {
42+
System.clearProperty(CommonsLoggingWrapperMode.JAVA_PROPERTY);
43+
assertEquals(CommonsLoggingWrapperMode.DEFAULT, CommonsLoggingWrapperMode.detect());
44+
}
45+
46+
@Test
47+
public void shouldThrowOnUnknownMode() {
48+
System.setProperty(CommonsLoggingWrapperMode.JAVA_PROPERTY, "invalid");
49+
IllegalArgumentException illegalArgumentException =
50+
assertThrows(IllegalArgumentException.class, CommonsLoggingWrapperMode::detect);
51+
assertEquals(
52+
"Unknown commons logging wrapper value 'invalid', expected one of: ALL, DEFAULT, OFF",
53+
illegalArgumentException.getMessage());
54+
}
55+
}

0 commit comments

Comments
 (0)