Skip to content

feat(logback): add posthog-server-logback appender module - #672

Draft
cat-ph wants to merge 1 commit into
cat/java-et-uncaughtfrom
cat/java-et-logback
Draft

feat(logback): add posthog-server-logback appender module#672
cat-ph wants to merge 1 commit into
cat/java-et-uncaughtfrom
cat/java-et-logback

Conversation

@cat-ph

@cat-ph cat-ph commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

🚨 Before merge / release

posthog-server-logback is not wired into the release workflow. The version-sync step and the publish matrix in .github/workflows still need an entry for the new module (and the module needs its Sonatype coordinates confirmed). That was deliberately left out of this PR — no workflow files are touched here — so the repo owner can wire it up. Merging as-is is safe: nothing publishes the module yet.

💡 Motivation and Context

Fourth and last PR in the JVM error-tracking stack: a new posthog-server-logback module (com.posthog:posthog-server-logback, 0.1.0) with a Logback appender that reports logged errors to PostHog Error Tracking through the server SDK.

  • PostHogAppender (AppenderBase<ILoggingEvent>, package com.posthog.server.logback) captures events at or above minimumCaptureLevel (default ERROR) that carry a Throwable, sending them through the server SDK's captureException so request-context distinct-id resolution and in-app frame config apply automatically (the appender runs on the logging thread, inside any active PostHogRequestContext scope).
  • Wiring: register a client you already configure with PostHogAppender.setPostHog(client) once at startup (events logged before registration are dropped — documented), or let the appender self-configure from logback.xml via <apiKey>/<host>, in which case it owns and closes that client on stop(). An explicitly registered client always wins.
  • Events from com.posthog… loggers are always skipped (recursion guard), events without a throwable are skipped (no message-only synthesis in this first version), and captured events carry $exception_level, logger_name, and log_message when the log message differs from the throwable message.
  • Uses the PostHogCapturedThrowables guard from PR 3, so an exception already reported by the uncaught handler is not re-reported when a log mirror sees the same instance.
  • Build wiring is additive: settings.gradle.kts, pnpm-workspace.yaml, gradle.properties (serverLogbackVersion=0.1.0), Makefile dry/release targets, and a LOGBACK version constant in buildSrc. Logback is compileOnly (consumers bring logback-classic; the 1.3.x line is the last one targeting Java 8), and posthog-server is an api dependency.

The module is explicitly pre-1.0: the changeset says the public API may change between minor versions.

💚 How did you test it?

  • New PostHogAppenderTest (8 tests): an error with a throwable becomes exactly one $exception event with the expected properties, below-threshold events ignored, WARN captured with warning level once the threshold is lowered, com.posthog logger names skipped for recursion, a logger merely sharing that string prefix still captured, throwable-less events ignored, events logged before a client is registered dropped, and the same throwable instance logged twice captured once.
  • ./gradlew :posthog-server-logback:test :posthog-server-logback:apiCheck pass; spotlessCheck clean. The module's gradle.lockfile was regenerated so it matches the repo's current kover/animalsniffer versions.
  • Not covered here: publishing. See the note at the top.

📝 Checklist

  • I reviewed the submitted code.
  • I added tests to verify the changes.
  • I updated the docs if needed.
  • No breaking change or entry added to the changelog.

If releasing new changes

  • Ran pnpm changeset to generate a changeset file
  • Added the "release" label to the PR to indicate we're publishing new versions for the affected packages

🔗 Stacked PR

Position 4 of 4 (top of the stack). Base: cat/java-et-uncaught (PR #671).

  1. PR feat(error-tracking): complete exception chain metadata and in-app classification #669 — core exception chain metadata + in-app classification
  2. PR feat(server): expose error tracking config and captureException options #670 — server error-tracking config and captureException options
  3. PR feat(server): opt-in uncaught exception capture #671 — opt-in server uncaught-exception capture
  4. this PR — new posthog-server-logback appender module

New pure-JVM module publishing com.posthog:posthog-server-logback — a Logback
appender that mirrors qualifying log events into PostHog error tracking.

- PostHogAppender (AppenderBase<ILoggingEvent>): captures events at
  minimumCaptureLevel (default ERROR) that carry a real Throwable; maps log
  level to $exception_level; attaches logger name and the log message when it
  differs from the throwable message; never throws from append.
- Client wiring via static PostHogAppender.setPostHog(...); events before
  registration are dropped by design. Runs on the logging thread, so
  PostHogRequestContext scopes resolve the distinct id automatically.
- Recursion guard: com.posthog.* loggers are never captured.
- Dedup: consults the core PostHogCapturedThrowables identity marker so the
  appender and the uncaught handler don't double-report the same Throwable.
- logback-classic is compileOnly (1.3.x line, Java 8); animalsniffer and
  apiCheck pass. release.yml publish matrix / version-sync intentionally not
  updated (workflow edits out of scope) — human follow-up before release.

# Conflicts:
#	gradle.properties
@cat-ph
cat-ph force-pushed the cat/java-et-uncaught branch from 29a1276 to c9db1af Compare August 3, 2026 23:03
@cat-ph
cat-ph force-pushed the cat/java-et-logback branch from b168168 to 1df4118 Compare August 3, 2026 23:03
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.

1 participant