Skip to content

Commit 32a2a9d

Browse files
committed
Organize internal logging around SLF4J and JUL #100
1 parent e84abb0 commit 32a2a9d

14 files changed

Lines changed: 117 additions & 91 deletions

File tree

RELEASE-NOTES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
* #90 Deprecate Ivy artifact syntax for %maven magic
2020
* #93 Extensions / kernel lifecycle
2121
* #99 Get rid of SLF4J transitive dependency
22+
* #100 Organize internal logging around SLF4J and JUL
2223

2324
## 1.0-a5
2425

jjava-distro/src/main/java/org/dflib/jjava/distro/JJava.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package org.dflib.jjava.distro;
22

33
import org.dflib.jjava.jupyter.channels.JupyterConnection;
4-
import org.dflib.jjava.jupyter.channels.JupyterSocket;
54
import org.dflib.jjava.jupyter.kernel.KernelConnectionProperties;
65
import org.dflib.jjava.kernel.JavaKernel;
76
import org.dflib.jjava.kernel.magics.ClasspathMagic;
@@ -20,16 +19,19 @@
2019
import java.nio.file.Path;
2120
import java.nio.file.Paths;
2221
import java.util.Properties;
23-
import java.util.logging.Level;
2422

2523
/**
2624
* The main class launching Jupyter Java kernel.
2725
*/
2826
public class JJava {
2927

28+
// single-line JUL logging that mimics the default Jupyter format for the label:
29+
// [I 2025-10-19 16:15:41.181 ServerApp]
30+
private static final String JUL_JUPYTER_LOG_FORMAT = "[%4$.1s %1$tF %1$tT.%1$tL %3$s] %5$s%n";
3031
private static final String POM_PROPERTIES = "META-INF/maven/org.dflib.jjava/jjava-distro/pom.properties";
3132

3233
public static void main(String[] args) throws Exception {
34+
3335
if (args.length < 1) {
3436
throw new IllegalArgumentException("Missing connection file argument");
3537
}
@@ -39,7 +41,7 @@ public static void main(String[] args) throws Exception {
3941
throw new IllegalArgumentException("Connection file '" + connectionFile + "' isn't a file.");
4042
}
4143

42-
JupyterSocket.JUPYTER_LOGGER.setLevel(Level.WARNING);
44+
System.setProperty("java.util.logging.SimpleFormatter.format", JUL_JUPYTER_LOG_FORMAT);
4345

4446
KernelConnectionProperties connProps = KernelConnectionProperties.parse(Files.readString(connectionFile));
4547
JupyterConnection connection = new JupyterConnection(connProps);

jjava-jupyter/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
<groupId>org.zeromq</groupId>
2323
<artifactId>jeromq</artifactId>
2424
</dependency>
25+
<dependency>
26+
<groupId>org.slf4j</groupId>
27+
<artifactId>slf4j-api</artifactId>
28+
</dependency>
2529

2630
<dependency>
2731
<groupId>org.junit.jupiter</groupId>

jjava-jupyter/src/main/java/org/dflib/jjava/jupyter/channels/HeartbeatChannel.java

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,23 @@
22

33
import org.dflib.jjava.jupyter.kernel.KernelConnectionProperties;
44
import org.dflib.jjava.jupyter.messages.HMACGenerator;
5+
import org.slf4j.LoggerFactory;
56
import org.zeromq.SocketType;
67
import org.zeromq.ZMQ;
78

89
import java.util.concurrent.atomic.AtomicInteger;
9-
import java.util.logging.Level;
10-
import java.util.logging.Logger;
10+
1111

1212
public class HeartbeatChannel extends JupyterSocket {
13-
private static final long HB_DEFAULT_SLEEP_MS = 500;
1413

14+
private static final long HB_DEFAULT_SLEEP_MS = 500;
1515
private static final AtomicInteger HEARTBEAT_ID = new AtomicInteger();
1616

1717
private final long sleep;
1818
private volatile Loop pulse;
1919

2020
public HeartbeatChannel(ZMQ.Context context, HMACGenerator hmacGenerator, long sleep) {
21-
super(context, SocketType.REP, hmacGenerator, Logger.getLogger("HeartbeatChannel"));
21+
super(context, SocketType.REP, hmacGenerator, LoggerFactory.getLogger("HeartbeatChannel"));
2222
this.sleep = sleep;
2323
}
2424

@@ -38,7 +38,7 @@ public void bind(KernelConnectionProperties connProps) {
3838
String channelThreadName = "Heartbeat-" + HEARTBEAT_ID.getAndIncrement();
3939
String addr = formatAddress(connProps.getTransport(), connProps.getIp(), connProps.getHbPort());
4040

41-
logger.log(Level.INFO, String.format("Binding %s to %s.", channelThreadName, addr));
41+
logger.debug("Binding {} to {}.", channelThreadName, addr);
4242
super.bind(addr);
4343

4444
ZMQ.Poller poller = super.ctx.poller(1);
@@ -49,22 +49,24 @@ public void bind(KernelConnectionProperties connProps) {
4949
if (events > 0) {
5050
byte[] msg = this.recv();
5151
if (msg == null) {
52-
//Error during receive, just continue
53-
super.logger.log(Level.SEVERE, "Poll returned 1 event but could not read the echo string");
52+
// Error during receive, just continue
53+
logger.warn("Poll returned 1 event but could not read the echo string");
5454
return;
5555
}
56+
5657
if (!this.send(msg)) {
57-
super.logger.log(Level.SEVERE, "Could not send heartbeat reply");
58+
logger.warn("Could not send heartbeat reply");
5859
}
59-
super.logger.log(Level.FINEST, "Heartbeat pulse");
60+
61+
logger.trace("Heartbeat pulse");
6062
}
6163
});
6264
this.pulse.onClose(() -> {
63-
logger.log(Level.INFO, channelThreadName + " shutdown.");
65+
logger.debug( "{} shutdown.", channelThreadName);
6466
this.pulse = null;
6567
});
6668
this.pulse.start();
67-
logger.log(Level.INFO, "Polling on " + channelThreadName);
69+
logger.debug("Polling on {}", channelThreadName);
6870
}
6971

7072
@Override
@@ -80,7 +82,8 @@ public void waitUntilClose() {
8082
if (this.pulse != null) {
8183
try {
8284
this.pulse.join();
83-
} catch (InterruptedException ignored) { }
85+
} catch (InterruptedException ignored) {
86+
}
8487
}
8588
}
8689
}

jjava-jupyter/src/main/java/org/dflib/jjava/jupyter/channels/IOPubChannel.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,20 @@
22

33
import org.dflib.jjava.jupyter.kernel.KernelConnectionProperties;
44
import org.dflib.jjava.jupyter.messages.HMACGenerator;
5+
import org.slf4j.LoggerFactory;
56
import org.zeromq.SocketType;
67
import org.zeromq.ZMQ;
78

8-
import java.util.logging.Level;
9-
import java.util.logging.Logger;
10-
119
public class IOPubChannel extends JupyterSocket {
1210
public IOPubChannel(ZMQ.Context context, HMACGenerator hmacGenerator) {
13-
super(context, SocketType.PUB, hmacGenerator, Logger.getLogger("IOPubChannel"));
11+
super(context, SocketType.PUB, hmacGenerator, LoggerFactory.getLogger("IOPubChannel"));
1412
}
1513

1614
@Override
1715
public void bind(KernelConnectionProperties connProps) {
1816
String addr = formatAddress(connProps.getTransport(), connProps.getIp(), connProps.getIopubPort());
1917

20-
logger.log(Level.INFO, String.format("Binding iopub to %s.", addr));
18+
logger.debug("Binding iopub to {}.", addr);
2119
super.bind(addr);
2220
}
2321
}

jjava-jupyter/src/main/java/org/dflib/jjava/jupyter/channels/JupyterSocket.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.dflib.jjava.jupyter.messages.publish.PublishStatus;
2626
import org.dflib.jjava.jupyter.messages.reply.ErrorReply;
2727
import org.dflib.jjava.jupyter.messages.request.HistoryRequest;
28+
import org.slf4j.Logger;
2829
import org.zeromq.SocketType;
2930
import org.zeromq.ZMQ;
3031

@@ -35,33 +36,33 @@
3536
import java.util.Iterator;
3637
import java.util.List;
3738
import java.util.Map;
38-
import java.util.logging.Logger;
3939

4040
public abstract class JupyterSocket extends ZMQ.Socket {
41+
4142
protected static String formatAddress(String transport, String ip, int port) {
4243
return transport + "://" + ip + ":" + port;
4344
}
4445

45-
private static final byte[] IDENTITY_BLOB_DELIMITER = "<IDS|MSG>".getBytes(StandardCharsets.US_ASCII); // Comes from a python bytestring
46+
// Comes from a Python bytestring
47+
private static final byte[] IDENTITY_BLOB_DELIMITER = "<IDS|MSG>".getBytes(StandardCharsets.US_ASCII);
48+
4649
private static final Gson replyGson = new GsonBuilder()
4750
.registerTypeAdapter(HistoryEntry.class, HistoryEntryAdapter.INSTANCE)
4851
.registerTypeAdapter(ExpressionValue.class, ExpressionValueAdapter.INSTANCE)
4952
.create();
53+
5054
private static final Gson gson = new GsonBuilder()
5155
.registerTypeAdapter(KernelTimestamp.class, KernelTimestampAdapter.INSTANCE)
5256
.registerTypeAdapter(Header.class, HeaderAdapter.INSTANCE)
5357
.registerTypeAdapter(MessageType.class, MessageTypeAdapter.INSTANCE)
5458
.registerTypeAdapter(PublishStatus.class, PublishStatusAdapter.INSTANCE)
5559
.registerTypeAdapter(HistoryRequest.class, HistoryRequestAdapter.INSTANCE)
5660
.registerTypeHierarchyAdapter(ReplyType.class, new ReplyTypeAdapter(replyGson))
57-
//.setPrettyPrinting()
5861
.create();
5962
private static final byte[] EMPTY_JSON_OBJECT = "{}".getBytes(StandardCharsets.UTF_8);
6063
private static final Type JSON_OBJ_AS_MAP = new TypeToken<Map<String, Object>>() {
6164
}.getType();
6265

63-
public static final Logger JUPYTER_LOGGER = Logger.getLogger("Jupyter");
64-
6566
protected final ZMQ.Context ctx;
6667
protected final HMACGenerator hmacGenerator;
6768
protected final Logger logger;
@@ -71,7 +72,6 @@ protected JupyterSocket(ZMQ.Context context, SocketType type, HMACGenerator hmac
7172
super(context, type);
7273
this.ctx = context;
7374
this.hmacGenerator = hmacGenerator;
74-
logger.setParent(JUPYTER_LOGGER);
7575
this.logger = logger;
7676
this.closed = false;
7777
}
@@ -129,7 +129,10 @@ public synchronized Message<?> readMessage() {
129129
}
130130

131131
Message<?> message = new Message(identities, header, parentHeader, metadata, content, blobs);
132-
logger.finer(() -> "Received from " + super.base().getSocketOptx(zmq.ZMQ.ZMQ_LAST_ENDPOINT) + ":\n" + gson.toJson(message));
132+
133+
if (logger.isTraceEnabled()) {
134+
logger.trace("Received from {}:\n{}", super.base().getSocketOptx(zmq.ZMQ.ZMQ_LAST_ENDPOINT), gson.toJson(message));
135+
}
133136

134137
return message;
135138
}
@@ -157,7 +160,9 @@ public synchronized void sendMessage(Message<?> message) {
157160

158161
String hmac = hmacGenerator.calculateSignature(headerRaw, parentHeaderRaw, metadata, content);
159162

160-
logger.finer(() -> "Sending to " + super.base().getSocketOptx(zmq.ZMQ.ZMQ_LAST_ENDPOINT) + ":\n" + gson.toJson(message));
163+
if (logger.isTraceEnabled()) {
164+
logger.trace("Sending to {}:\n{}", super.base().getSocketOptx(zmq.ZMQ.ZMQ_LAST_ENDPOINT), gson.toJson(message));
165+
}
161166

162167
message.getIdentities().forEach(super::sendMore);
163168
super.sendMore(IDENTITY_BLOB_DELIMITER);

jjava-jupyter/src/main/java/org/dflib/jjava/jupyter/channels/Loop.java

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
package org.dflib.jjava.jupyter.channels;
22

3+
import org.slf4j.Logger;
4+
import org.slf4j.LoggerFactory;
5+
36
import java.util.Queue;
47
import java.util.concurrent.LinkedBlockingQueue;
58
import java.util.function.LongSupplier;
69
import java.util.function.ToLongFunction;
7-
import java.util.logging.Logger;
810

911
public class Loop extends Thread {
10-
private final Logger logger;
1112

13+
private final Logger logger;
1214
private volatile boolean running = false;
1315
private final LongSupplier loopBody;
1416

@@ -25,12 +27,9 @@ public Loop(String name, long sleep, Runnable target) {
2527

2628
public Loop(String name, LongSupplier target) {
2729
super(name);
28-
2930
this.loopBody = target;
30-
3131
this.runNextQueue = new LinkedBlockingQueue<>();
32-
33-
this.logger = Logger.getLogger("Loop-" + name);
32+
this.logger = LoggerFactory.getLogger("Loop-" + name);
3433
}
3534

3635
public void onClose(Runnable callback) {
@@ -91,36 +90,37 @@ public void run() {
9190
try {
9291
Thread.sleep(sleep);
9392
} catch (InterruptedException e) {
94-
this.logger.info("Loop interrupted. Stopping...");
93+
logger.debug("Loop interrupted. Stopping...");
9594
this.running = false;
9695
}
9796
} else if (sleep < 0) {
98-
this.logger.info("Loop interrupted by a negative sleep request. Stopping...");
97+
logger.debug("Loop interrupted by a negative sleep request. Stopping...");
9998
this.running = false;
10099
}
101100
}
102101

103-
this.logger.info("Running loop shutdown callback.");
102+
logger.debug("Running loop shutdown callback.");
104103

105-
if (this.onCloseCb != null)
106-
this.onCloseCb.run();
107-
this.onCloseCb = null;
104+
if (onCloseCb != null) {
105+
onCloseCb.run();
106+
onCloseCb = null;
107+
}
108108

109-
this.logger.info("Loop stopped.");
109+
logger.info("Loop stopped.");
110110
}
111111

112112
@Override
113113
public synchronized void start() {
114-
this.logger.info("Loop starting...");
114+
logger.debug("Loop starting...");
115115

116-
this.running = true;
116+
running = true;
117117
super.start();
118118

119-
this.logger.info("Loop started.");
119+
logger.info("Loop started.");
120120
}
121121

122122
public void shutdown() {
123-
this.running = false;
124-
this.logger.info("Loop shutdown.");
123+
running = false;
124+
logger.debug("Loop shutdown.");
125125
}
126126
}

0 commit comments

Comments
 (0)