Skip to content

Commit 00ceea5

Browse files
Enable JUL logging for fat jar and update logging documentation (#1168)
## Description <!-- Provide a brief summary of the changes made and the issue they aim to address.--> Replace Log4j2 dependencies with the SLF4J-to-JUL bridge (slf4j-jdk14) so that the fat jar can emit SDK and Apache HTTP client logs via Java Util Logging (JUL) without requiring users to supply additional logging libraries. - Simplify JulLogger implementation to delegate directly to java.util.logging - Remove log4j-core, log4j-api, and log4j-slf4j2-impl test dependencies - Remove Log4j2 shade plugin transformers from pom.xml - Restructure docs/LOGGING.md with a fat jar vs thin jar quick-reference table, JUL configuration examples, and SLF4J/Log4j2/Logback integration guides - Simplify logging section in README.md to point to detailed docs ## Testing <!-- Describe how the changes have been tested--> - Unit tests - E2e tests ## Additional Notes to the Reviewer <!-- Share any additional context or insights that may help the reviewer understand the changes better. This could include challenges faced, limitations, or compromises made during the development process. Also, mention any areas of the code that you would like the reviewer to focus on specifically. -->
1 parent 10c59d5 commit 00ceea5

8 files changed

Lines changed: 148 additions & 169 deletions

File tree

NEXT_CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
- Added connection property `OAuthWebServerTimeout` to configure the OAuth browser authentication timeout for U2M (user-to-machine) flows, and also updated hardcoded 1-hour timeout to default 120 seconds timeout.
77

88
### Updated
9+
- Fat jar now routes SDK and Apache HTTP client logs through Java Util Logging (JUL), removing the need for external logging libraries.
910

1011
### Fixed
1112
- Fixed `rollback()` to throw `SQLException` when called in auto-commit mode (no active transaction), aligning with JDBC spec. Previously it silently sent a ROLLBACK command to the server.

README.md

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,7 @@ Optional parameters:
9595

9696
### Logging
9797

98-
The driver supports both SLF4J and Java Util Logging (JUL) frameworks:
99-
100-
- **SLF4J**: Enable with `-Dcom.databricks.jdbc.loggerImpl=SLF4JLOGGER`
101-
- **JUL**: Enable with `-Dcom.databricks.jdbc.loggerImpl=JDKLOGGER` (default)
102-
103-
For detailed logging configuration options, see [Logging Documentation](./docs/LOGGING.md).
98+
The driver supports logging configuration via JDBC URL parameters or system properties. For detailed configuration options, see [Logging Documentation](./docs/LOGGING.md).
10499

105100
## Running Tests
106101

docs/LOGGING.md

Lines changed: 125 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,156 @@
11
# Logging Configuration
22

3-
The Databricks JDBC driver supports both [SLF4J](https://www.slf4j.org/) and [JUL](https://docs.oracle.com/javase/8/docs/api/java/util/logging/package-summary.html) logging frameworks.
3+
The Databricks JDBC driver supports Java Util Logging (JUL) and SLF4J logging frameworks. The available options depend on whether you use the fat JAR or thin JAR.
44

5-
## SLF4J Logging
5+
## Quick Reference
6+
7+
| JAR Type | JUL | SLF4J (native) | SLF4J (via bridge) |
8+
|----------|-----|----------------|-------------------|
9+
| Fat JAR (`databricks-jdbc-X.Y.Z.jar`) | Supported | Not supported | Supported |
10+
| Thin JAR (`databricks-jdbc-X.Y.Z-thin.jar`) | Supported | Supported | N/A |
11+
12+
---
13+
14+
## Fat JAR Logging
15+
16+
The fat JAR bundles all dependencies with shading. **Only JUL logging is natively supported.** The fat JAR includes an SLF4J-to-JUL bridge, so logs from internal libraries (Databricks SDK, Apache HTTP client, etc.) are automatically routed to JUL and will appear in your configured log output.
17+
18+
### Configuration via JDBC URL
619

7-
SLF4J logging can be enabled by setting the system property:
820
```
9-
-Dcom.databricks.jdbc.loggerImpl=SLF4JLOGGER
21+
jdbc:databricks://<host>:443;HttpPath=<path>;LogLevel=5;LogPath=/var/log/databricks
22+
```
23+
24+
### Configuration via Properties
25+
26+
```java
27+
Properties props = new Properties();
28+
props.setProperty("LogLevel", "5"); // DEBUG
29+
props.setProperty("LogPath", "/var/log"); // Directory for log files
30+
props.setProperty("LogFileSize", "10"); // Max file size in MB
31+
props.setProperty("LogFileCount", "5"); // Number of rotating files
32+
33+
Connection conn = DriverManager.getConnection(url, props);
1034
```
1135

12-
You need to provide an SLF4J binding implementation and corresponding configuration file in the classpath. This gives you the freedom to adapt the JDBC logging to your specific needs.
36+
### Log Level Values
37+
38+
| Value | Level |
39+
|-------|-------|
40+
| 0 | OFF |
41+
| 1 | FATAL |
42+
| 2 | ERROR |
43+
| 3 | WARN |
44+
| 4 | INFO |
45+
| 5 | DEBUG |
46+
| 6 | TRACE |
47+
48+
### Note on SLF4JLOGGER Mode
49+
50+
Setting `-Dcom.databricks.jdbc.loggerImpl=SLF4JLOGGER` with the fat JAR will **not** produce any log output. The fat JAR is designed for out-of-the-box use with BI tools and applications that cannot manage dependencies. SLF4J is bundled because the Databricks SDK requires it at runtime, and it is shaded to avoid conflicts with user environments. As a result, the shaded SLF4J does not connect to user-provided bindings.
51+
52+
---
1353

14-
### Example: Using SLF4J with Log4j2
54+
## Thin JAR Logging
1555

16-
Add the following dependencies to your `pom.xml`:
56+
The thin JAR does not bundle dependencies, giving you full control over logging configuration. Both JUL and SLF4J are supported.
57+
58+
### Using JUL (Default)
59+
60+
Configure via JDBC URL parameters as shown above, or use a `logging.properties` file:
61+
62+
```properties
63+
handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler
64+
.level=INFO
65+
java.util.logging.FileHandler.pattern=/var/log/databricks-jdbc.log
66+
java.util.logging.FileHandler.limit=10000000
67+
java.util.logging.FileHandler.count=5
68+
java.util.logging.ConsoleHandler.level=ALL
69+
```
70+
71+
### Using SLF4J
72+
73+
Enable SLF4J logging:
74+
75+
```
76+
-Dcom.databricks.jdbc.loggerImpl=SLF4JLOGGER
77+
```
78+
79+
Add an SLF4J binding to your project (e.g., Logback):
1780

1881
```xml
1982
<dependency>
20-
<groupId>org.apache.logging.log4j</groupId>
21-
<artifactId>log4j-slf4j2-impl</artifactId>
22-
<version>${log4j.version}</version>
23-
</dependency>
24-
<dependency>
25-
<groupId>org.apache.logging.log4j</groupId>
26-
<artifactId>log4j-core</artifactId>
27-
<version>${log4j.version}</version>
28-
</dependency>
29-
<dependency>
30-
<groupId>org.apache.logging.log4j</groupId>
31-
<artifactId>log4j-api</artifactId>
32-
<version>${log4j.version}</version>
83+
<groupId>ch.qos.logback</groupId>
84+
<artifactId>logback-classic</artifactId>
85+
<version>1.4.14</version>
3386
</dependency>
3487
```
3588

36-
Create a `log4j2.xml` configuration file:
89+
Optionally exclude the driver's SLF4J version to use your own:
3790

3891
```xml
39-
<?xml version="1.0" encoding="UTF-8"?>
40-
<Configuration status="WARN">
41-
<Appenders>
42-
<!-- Console appender for default logging -->
43-
<Console name="Console" target="SYSTEM_OUT">
44-
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n"/>
45-
</Console>
46-
</Appenders>
47-
48-
<Loggers>
49-
<!-- Root logger to catch any logs that don't match other loggers -->
50-
<Root level="info">
51-
<AppenderRef ref="Console"/>
52-
</Root>
53-
</Loggers>
54-
</Configuration>
92+
<dependency>
93+
<groupId>com.databricks</groupId>
94+
<artifactId>databricks-jdbc</artifactId>
95+
<version>3.0.7</version>
96+
<classifier>thin</classifier>
97+
<exclusions>
98+
<exclusion>
99+
<groupId>org.slf4j</groupId>
100+
<artifactId>slf4j-api</artifactId>
101+
</exclusion>
102+
</exclusions>
103+
</dependency>
55104
```
56105

57-
## Java Util Logging (JUL)
106+
---
58107

59-
JUL logging is enabled by default, or can be explicitly set with:
60-
```
61-
-Dcom.databricks.jdbc.loggerImpl=JDKLOGGER
108+
## Integrating with SLF4J (Fat JAR)
109+
110+
Fat JAR users can integrate driver logs into their SLF4J/Logback setup using the JUL-to-SLF4J bridge.
111+
112+
### Step 1: Add Dependency
113+
114+
```xml
115+
<dependency>
116+
<groupId>org.slf4j</groupId>
117+
<artifactId>jul-to-slf4j</artifactId>
118+
<version>2.0.13</version>
119+
</dependency>
62120
```
63121

64-
There are two ways to configure JUL logging:
122+
### Step 2: Create `logging.properties`
65123

66-
### 1. JDBC URL Parameters
124+
```properties
125+
handlers = org.slf4j.bridge.SLF4JBridgeHandler
126+
.level = FINEST
127+
```
67128

68-
Standard logging parameters can be passed in the JDBC URL:
129+
### Step 3: Pass JVM Argument
69130

70131
```
71-
jdbc:databricks://your-databricks-host:443;transportMode=http;ssl=1;AuthMech=3;httpPath=/sql/1.0/warehouses/your-warehouse-id;UID=token;logLevel=DEBUG;logPath=/path/to/dir;logFileSize=10;logFileCount=5
132+
-Djava.util.logging.config.file=/path/to/logging.properties
72133
```
73134

74-
Available parameters:
75-
- `logLevel`: Logging level (e.g., DEBUG, INFO)
76-
- `logPath`: Directory path for log files
77-
- `logFileSize`: Maximum size of each log file in MB
78-
- `logFileCount`: Maximum number of log files to keep
135+
This argument is required to bypass the driver's internal JUL configuration and allow logs to propagate to the SLF4J bridge.
79136

80-
### 2. Configuration File
137+
### Step 4: Configure Logback
81138

82-
Logging properties can also be set in a `logging.properties` file in the classpath:
83-
84-
```properties
85-
handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler
86-
.level=INFO
87-
java.util.logging.FileHandler.level=ALL
88-
java.util.logging.FileHandler.pattern=/path/to/dir/databricks-jdbc.log
89-
java.util.logging.FileHandler.limit=10000000
90-
java.util.logging.FileHandler.count=5
91-
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
92-
java.util.logging.ConsoleHandler.level=ALL
93-
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
139+
```xml
140+
<configuration>
141+
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
142+
<encoder>
143+
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
144+
</encoder>
145+
</appender>
146+
147+
<!-- Databricks JDBC Driver logs (includes SDK, HTTP client, etc.) -->
148+
<logger name="com.databricks" level="DEBUG"/>
149+
150+
<root level="INFO">
151+
<appender-ref ref="CONSOLE"/>
152+
</root>
153+
</configuration>
94154
```
155+
156+
The `com.databricks` logger captures all driver logs including shaded internal libraries (Databricks SDK, Apache HTTP client, etc.).

pom.xml

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
<maven.compiler.target>11</maven.compiler.target>
4949
<mockito.version>5.2.0</mockito.version>
5050
<jackson.version>2.18.3</jackson.version>
51-
<log4j.version>2.25.3</log4j.version>
5251
<slf4j.version>2.0.13</slf4j.version>
5352
<google.guava.version>33.0.0-jre</google.guava.version>
5453
<junit.jupiter.version>5.9.2</junit.jupiter.version>
@@ -136,23 +135,11 @@
136135
<artifactId>slf4j-api</artifactId>
137136
<version>${slf4j.version}</version>
138137
</dependency>
138+
<!-- SLF4J to JUL bridge - shaded into fat JAR so internal logging works -->
139139
<dependency>
140-
<groupId>org.apache.logging.log4j</groupId>
141-
<artifactId>log4j-slf4j2-impl</artifactId>
142-
<version>${log4j.version}</version>
143-
<scope>test</scope>
144-
</dependency>
145-
<dependency>
146-
<groupId>org.apache.logging.log4j</groupId>
147-
<artifactId>log4j-core</artifactId>
148-
<version>${log4j.version}</version>
149-
<scope>test</scope>
150-
</dependency>
151-
<dependency>
152-
<groupId>org.apache.logging.log4j</groupId>
153-
<artifactId>log4j-api</artifactId>
154-
<version>${log4j.version}</version>
155-
<scope>test</scope>
140+
<groupId>org.slf4j</groupId>
141+
<artifactId>slf4j-jdk14</artifactId>
142+
<version>${slf4j.version}</version>
156143
</dependency>
157144
<dependency>
158145
<groupId>commons-io</groupId>
@@ -356,10 +343,6 @@
356343
--add-opens=java.base/java.nio=ALL-UNNAMED
357344
-Dnet.bytebuddy.experimental=true
358345
</argLine>
359-
<systemPropertyVariables>
360-
<com.databricks.jdbc.loggerImpl>JDKLOGGER</com.databricks.jdbc.loggerImpl>
361-
<java.util.logging.config.file>${project.basedir}/src/test/resources/logging.properties</java.util.logging.config.file>
362-
</systemPropertyVariables>
363346
</configuration>
364347
</plugin>
365348
<plugin>
@@ -480,13 +463,6 @@
480463
<groupId>org.apache.maven.plugins</groupId>
481464
<artifactId>maven-shade-plugin</artifactId>
482465
<version>3.5.0</version>
483-
<dependencies>
484-
<dependency>
485-
<groupId>org.apache.logging.log4j</groupId>
486-
<artifactId>log4j-transform-maven-shade-plugin-extensions</artifactId>
487-
<version>0.1.0</version>
488-
</dependency>
489-
</dependencies>
490466
<executions>
491467
<execution>
492468
<id>shade and package jars</id>
@@ -582,7 +558,6 @@
582558
</filter>
583559
</filters>
584560
<transformers>
585-
<transformer implementation="org.apache.logging.log4j.maven.plugins.shade.transformer.Log4j2PluginCacheFileTransformer"/>
586561
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
587562
<mainClass>com.databricks.client.jdbc.Driver</mainClass>
588563
<manifestEntries>

0 commit comments

Comments
 (0)