Skip to content

Adds a connection id to an incoming request that is included in all log messages from code handling that request - #97

Merged
Tyreviel merged 8 commits into
mainfrom
95-ConnectionID
Feb 23, 2026
Merged

Adds a connection id to an incoming request that is included in all log messages from code handling that request#97
Tyreviel merged 8 commits into
mainfrom
95-ConnectionID

Conversation

@Tyreviel

@Tyreviel Tyreviel commented Feb 19, 2026

Copy link
Copy Markdown

closes #95

Summary by CodeRabbit

  • New Features

    • Per-request connection ID tracking added to logs; context is cleared after each request.
    • Log entries now include timestamps, severity, and optional connection identifiers.
  • Refactor

    • Replaced ad-hoc console prints with structured Java logging and a custom log formatter.
  • Tests

    • Added/updated tests to verify structured log output and connection ID inclusion.

@Tyreviel Tyreviel changed the title Ads a connection id to an incoming request that is included in all log messages from code handling that request Adds a connection id to an incoming request that is included in all log messages from code handling that request Feb 19, 2026
@coderabbitai

coderabbitai Bot commented Feb 19, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Generates an 8-character connection ID per request in ConnectionHandler, stores it in a ThreadLocal via LogContext, uses ServerLogFormatter to include the connection ID in log lines, replaces println logging with java.util.logging in LoggingFilter, and clears the LogContext after request processing.

Changes

Cohort / File(s) Summary
New Logging Utilities
src/main/java/org/juv25d/logging/LogContext.java, src/main/java/org/juv25d/logging/ServerLogFormatter.java
Adds ThreadLocal-backed LogContext (set/get/clear) and a Formatter that prepends timestamp, level and optional [connectionId] to log messages and includes throwable stack traces.
Logging Integration
src/main/java/org/juv25d/ConnectionHandler.java, src/main/java/org/juv25d/filter/LoggingFilter.java, src/main/java/org/juv25d/logging/ServerLogging.java
ConnectionHandler generates and sets an 8-char connectionId at request start and clears it in finally; LoggingFilter now uses java.util.logging.Logger instead of System.out.println; ServerLogging replaces SimpleFormatter with ServerLogFormatter.
Tests
src/test/java/org/juv25d/filter/LoggingFilterTest.java, src/test/java/org/juv25d/logging/ConnectionIdLoggingTest.java
Updated test to capture LogRecords via a custom Handler; added ConnectionIdLoggingTest to assert formatted output contains the connection ID.

Sequence Diagram

sequenceDiagram
    participant Client
    participant ConnectionHandler
    participant LogContext
    participant LoggingFilter
    participant Logger
    participant ServerLogFormatter

    Client->>ConnectionHandler: send request
    ConnectionHandler->>ConnectionHandler: generate 8-char id
    ConnectionHandler->>LogContext: setConnectionId(id)
    ConnectionHandler->>LoggingFilter: forward request
    LoggingFilter->>Logger: logger.info(method + " " + path)
    Logger->>ServerLogFormatter: format(LogRecord)
    ServerLogFormatter->>LogContext: getConnectionId()
    LogContext-->>ServerLogFormatter: return id
    ServerLogFormatter-->>Logger: formatted message (timestamp, level, [id], msg)
    Logger-->>LoggingFilter: emit log
    LoggingFilter-->>ConnectionHandler: processing done
    ConnectionHandler->>LogContext: clear()
    ConnectionHandler-->>Client: respond
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • PR #28: Modifies ConnectionHandler and logging foundations; directly related due to overlapping changes to connection-id handling and logging formatter.

Suggested reviewers

  • bamsemats
  • simonforsberg
  • fmazmz

Poem

🐰 A tiny id hops on each request today,
Thread-local burrow where it safely will stay,
From handler to logger, it skips with delight,
Tags every message by morning and night,
A rabbit's small mark making logs feel right.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main change: adding a connection ID to incoming requests and including it in all log messages.
Linked Issues check ✅ Passed The code changes fully implement the requirement in #95: LogContext stores connection IDs per-thread, ConnectionHandler generates and sets them, ServerLogFormatter includes them in logs, and tests verify the functionality.
Out of Scope Changes check ✅ Passed All changes are directly related to #95 requirements. LogContext, ServerLogFormatter, and ServerLogging updates support the connection ID feature; filter and handler updates implement it; tests verify it. No unrelated changes detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 95-ConnectionID

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/org/juv25d/logging/ServerLogging.java (1)

8-8: ⚠️ Potential issue | 🔴 Critical

Remove unused SimpleFormatter import — Spotless CI failure.

SimpleFormatter is no longer referenced after the formatter was replaced with ServerLogFormatter, causing the pipeline to fail. Run mvn spotless:apply to clean up.

🐛 Proposed fix
-import java.util.logging.SimpleFormatter;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/juv25d/logging/ServerLogging.java` at line 8, Remove the
unused import of SimpleFormatter from the top of the ServerLogging class: delete
the line importing java.util.logging.SimpleFormatter, verify there are no
remaining references to SimpleFormatter in ServerLogging (the class now uses
ServerLogFormatter), then run mvn spotless:apply to reformat and ensure the
Spotless CI failure is resolved.
🧹 Nitpick comments (2)
src/main/java/org/juv25d/logging/LogContext.java (1)

3-16: Add a private constructor to prevent instantiation of this utility class.

All members are static; allowing new LogContext() is misleading.

♻️ Proposed fix
 public class LogContext {
     private static final ThreadLocal<String> connectionId = new ThreadLocal<>();
+
+    private LogContext() {}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/juv25d/logging/LogContext.java` around lines 3 - 16, This
utility class LogContext is instantiable but only exposes static members
(connectionId, setConnectionId, getConnectionId, clear); add a private no-arg
constructor to prevent creating instances by declaring "private LogContext() {
}" in the class so it cannot be instantiated while preserving existing static
ThreadLocal connectionId and static methods.
src/main/java/org/juv25d/ConnectionHandler.java (1)

28-29: Prefer imports over fully-qualified class names.

java.util.UUID and org.juv25d.logging.LogContext are used inline rather than imported at the top of the file.

♻️ Proposed cleanup
+import java.util.UUID;
+import org.juv25d.logging.LogContext;
 ...
-        String connectionId = java.util.UUID.randomUUID().toString().substring(0, 8);
-        org.juv25d.logging.LogContext.setConnectionId(connectionId);
+        String connectionId = UUID.randomUUID().toString().substring(0, 8);
+        LogContext.setConnectionId(connectionId);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/juv25d/ConnectionHandler.java` around lines 28 - 29,
Replace the inline fully-qualified usages with imports: add import
java.util.UUID and import org.juv25d.logging.LogContext at the top of
ConnectionHandler.java, then change the lines that create connectionId and set
the context to use UUID.randomUUID() and
LogContext.setConnectionId(connectionId) (and update any other occurrences of
the fully-qualified names in this class) to improve readability and consistency.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/java/org/juv25d/logging/ServerLogFormatter.java`:
- Around line 12-22: The formatter ServerLogFormatter.format currently returns
only formatMessage(record) and drops any attached Throwable; update the method
(in ServerLogFormatter.format) to call record.getThrown(), and if non-null
capture its stack trace into a string (e.g., via StringWriter/PrintWriter) and
append that stack-trace text to the returned message (after the formatted
message and a newline) so exceptions logged with logger.log(..., e) are
rendered; keep using formatMessage(record) for the main message and only append
the stack trace when record.getThrown() is present.

In `@src/test/java/org/juv25d/logging/ConnectionIdLoggingTest.java`:
- Line 16: Spotless formatting failed in the test class ConnectionIdLoggingTest;
run the formatter and commit the changes by executing mvn spotless:apply (or
apply your project's Spotless rules in your IDE), then stage and commit the
modified files so the Spotless CI check passes.
- Around line 17-46: The test leaks handlers and can fail silently: in
ConnectionIdLoggingTest ensure you remove the temporary Handler from the Logger
in the finally block (call logger.removeHandler(handler)), explicitly set the
effective log level so the INFO record is emitted (e.g.,
logger.setLevel(Level.INFO) and handler.setLevel(Level.ALL)), and guard the list
access by asserting formattedMessages is not empty before calling
formattedMessages.get(0) (or use an assert on size/contains) so failures produce
a clear assertion rather than IndexOutOfBoundsException; keep references to
logger, handler, formattedMessages, ServerLogFormatter,
LogContext.setConnectionId and LogContext.clear when making these changes.

---

Outside diff comments:
In `@src/main/java/org/juv25d/logging/ServerLogging.java`:
- Line 8: Remove the unused import of SimpleFormatter from the top of the
ServerLogging class: delete the line importing
java.util.logging.SimpleFormatter, verify there are no remaining references to
SimpleFormatter in ServerLogging (the class now uses ServerLogFormatter), then
run mvn spotless:apply to reformat and ensure the Spotless CI failure is
resolved.

---

Nitpick comments:
In `@src/main/java/org/juv25d/ConnectionHandler.java`:
- Around line 28-29: Replace the inline fully-qualified usages with imports: add
import java.util.UUID and import org.juv25d.logging.LogContext at the top of
ConnectionHandler.java, then change the lines that create connectionId and set
the context to use UUID.randomUUID() and
LogContext.setConnectionId(connectionId) (and update any other occurrences of
the fully-qualified names in this class) to improve readability and consistency.

In `@src/main/java/org/juv25d/logging/LogContext.java`:
- Around line 3-16: This utility class LogContext is instantiable but only
exposes static members (connectionId, setConnectionId, getConnectionId, clear);
add a private no-arg constructor to prevent creating instances by declaring
"private LogContext() { }" in the class so it cannot be instantiated while
preserving existing static ThreadLocal connectionId and static methods.

Comment thread src/main/java/org/juv25d/logging/ServerLogFormatter.java
Comment thread src/test/java/org/juv25d/logging/ConnectionIdLoggingTest.java
Comment thread src/test/java/org/juv25d/logging/ConnectionIdLoggingTest.java

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/test/java/org/juv25d/logging/ConnectionIdLoggingTest.java`:
- Around line 17-47: The test leaks a Handler and can silently do nothing or
crash: ensure the test pins the logger level, removes the handler in the finally
block, and guards the list access; specifically, on the Logger instance created
in this test (logger) call logger.setLevel(Level.INFO) so logger.info(...) will
emit, register the anonymous Handler as before but ensure
logger.removeHandler(handler) is called in the finally block after
LogContext.clear(), and replace the unguarded formattedMessages.get(0) access
with a safe assertion (e.g., assertFalse(formattedMessages.isEmpty()) or
assertTrue(formattedMessages.size() > 0) then inspect formattedMessages.get(0));
also add the missing static import for assertFalse/assertTrue in the test
imports.

@Tyreviel Tyreviel self-assigned this Feb 19, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/main/java/org/juv25d/logging/ServerLogFormatter.java (1)

16-17: LogContext.getConnectionId() read on the formatter thread — breaks under async logging.

Reading the ThreadLocal here is correct for synchronous j.u.l. (formatter runs on the logging-caller thread), but if an AsyncHandler or any other off-thread dispatch is introduced later, the ThreadLocal will not carry the connection ID to the formatter thread and the field will silently be null.

An alternative is to capture the connection ID into the LogRecord at the call site (e.g. via MDC-style parameters or a custom LogRecord subclass), making the formatter purely data-driven and independent of the calling thread.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/juv25d/logging/ServerLogFormatter.java` around lines 16 -
17, The formatter currently calls LogContext.getConnectionId() on the formatter
thread (in ServerLogFormatter), which breaks when logging is handled off-thread;
instead capture the connection id at the logging call site and put it on the
LogRecord so the formatter is data-driven: modify call sites to read
LogContext.getConnectionId() before logging and attach it to the LogRecord
(e.g., via LogRecord.setParameters(...) or by creating and using a small custom
LogRecord subclass that carries a getConnectionId() field), then update
ServerLogFormatter.format(LogRecord) to read the connection id from
record.getParameters() or the custom LogRecord accessor and remove direct calls
to LogContext.getConnectionId() inside the formatter.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/java/org/juv25d/logging/ServerLogFormatter.java`:
- Line 21: The formatter currently uses ZonedDateTime.now(...) which records the
formatting time; update ServerLogFormatter to use the LogRecord's event instant
instead: replace the ZonedDateTime.now(ZoneId.systemDefault()).format(dtf) call
with ZonedDateTime.ofInstant(record.getInstant(),
ZoneId.systemDefault()).format(dtf) (use record.getInstant() from the LogRecord)
so timestamps reflect the actual event time.

---

Nitpick comments:
In `@src/main/java/org/juv25d/logging/ServerLogFormatter.java`:
- Around line 16-17: The formatter currently calls LogContext.getConnectionId()
on the formatter thread (in ServerLogFormatter), which breaks when logging is
handled off-thread; instead capture the connection id at the logging call site
and put it on the LogRecord so the formatter is data-driven: modify call sites
to read LogContext.getConnectionId() before logging and attach it to the
LogRecord (e.g., via LogRecord.setParameters(...) or by creating and using a
small custom LogRecord subclass that carries a getConnectionId() field), then
update ServerLogFormatter.format(LogRecord) to read the connection id from
record.getParameters() or the custom LogRecord accessor and remove direct calls
to LogContext.getConnectionId() inside the formatter.

Comment thread src/main/java/org/juv25d/logging/ServerLogFormatter.java

@annikaholmqvist94 annikaholmqvist94 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job! Moving to structured logging makes the logs more readable and easier to debug

@SandraNelj SandraNelj left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great addition. The logging feels more consistent now and the connection ID makes debugging clearer. Good job!

@Tyreviel
Tyreviel merged commit 0a46b1f into main Feb 23, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a connection id to an incoming request

3 participants