Skip to content

Commit b430501

Browse files
committed
feat(logback): add 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
1 parent 5052ac5 commit b430501

14 files changed

Lines changed: 772 additions & 0 deletions

File tree

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'posthog-server-logback': minor
3+
---
4+
5+
Initial `0.x` release of `com.posthog:posthog-server-logback` — a Logback appender that reports logged errors to PostHog Error Tracking through the server SDK. This module is pre-1.0; its public API may change between minor versions.
6+
7+
- `PostHogAppender` (`ch.qos.logback.core.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.
8+
- Register a configured server client once at startup with `PostHogAppender.setPostHog(client)`; events logged before registration are dropped. Alternatively self-configure from `logback.xml` via `<apiKey>`/`<host>` (each self-configuring appender owns its client and closes it on `stop()`, so a Logback config reload keeps capturing). An application-registered client always wins.
9+
- Events from `com.posthog…` loggers are always skipped (recursion guard), events without a throwable are skipped (no message-only synthesis in v1), and captured events carry `$exception_level` (`error`, or `warning` when the threshold is lowered), `logger_name`, and the log message under `log_message` when it differs from the throwable message.
10+
- Depends on `com.posthog:posthog-server` (transitive `api`); Logback is `compileOnly` — provide `logback-classic` yourself (1.3.x line for Java 8 compatibility).

Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ dryReleaseSurveysCompose:
3535
dryReleaseServer:
3636
./gradlew :posthog-server:publishToMavenLocal
3737

38+
dryReleaseServerLogback:
39+
./gradlew :posthog-server-logback:publishToMavenLocal
40+
3841
dryReleaseAndroidPlugin:
3942
./gradlew :posthog-android-gradle-plugin:publishToMavenLocal
4043

@@ -53,6 +56,9 @@ releaseSurveysCompose:
5356
releaseServer:
5457
./gradlew :posthog-server:publishToSonatype closeAndReleaseSonatypeStagingRepository
5558

59+
releaseServerLogback:
60+
./gradlew :posthog-server-logback:publishToSonatype closeAndReleaseSonatypeStagingRepository
61+
5662
releaseAndroidPlugin:
5763
./gradlew :posthog-android-gradle-plugin:publishToSonatype :posthog-android-gradle-plugin:closeAndReleaseSonatypeStagingRepository
5864

buildSrc/src/main/java/PosthogBuildConfig.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ object PosthogBuildConfig {
6565
val GSON = "2.10.1"
6666

6767
val OKHTTP = "4.12.0"
68+
69+
// Logback appender: 1.3.x is the last line targeting Java 8 (1.4.x+ requires Java 11).
70+
val LOGBACK = "1.3.14"
6871
val CURTAINS = "1.2.5"
6972
val ANDROIDX_CORE = "1.5.0"
7073
val ANDROIDX_COMPOSE = "1.0.0"

gradle.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ coreVersion=6.29.0
2626
androidVersion=3.58.0
2727
surveysComposeVersion=0.1.0
2828
serverVersion=2.9.0
29+
serverLogbackVersion=0.1.0
2930

3031
# Shared build versions (single source of truth for buildSrc, PosthogBuildConfig, and gradle plugin)
3132
kotlinVersion=2.1.10

pnpm-lock.yaml

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ packages:
33
- "posthog-android"
44
- "posthog-android-surveys-compose"
55
- "posthog-server"
6+
- "posthog-server-logback"
67
- "posthog-android-gradle-plugin"
78

89
minimumReleaseAge: 10080
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# posthog-server-logback
2+
3+
## Next
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
public final class com/posthog/server/logback/PostHogAppender : ch/qos/logback/core/AppenderBase {
2+
public static final field Companion Lcom/posthog/server/logback/PostHogAppender$Companion;
3+
public fun <init> ()V
4+
public synthetic fun append (Ljava/lang/Object;)V
5+
public static final fun clearPostHog ()V
6+
public final fun getApiKey ()Ljava/lang/String;
7+
public final fun getHost ()Ljava/lang/String;
8+
public final fun getMinimumCaptureLevel ()Lch/qos/logback/classic/Level;
9+
public final fun setApiKey (Ljava/lang/String;)V
10+
public final fun setHost (Ljava/lang/String;)V
11+
public final fun setMinimumCaptureLevel (Lch/qos/logback/classic/Level;)V
12+
public static final fun setPostHog (Lcom/posthog/server/PostHogInterface;)V
13+
public fun start ()V
14+
public fun stop ()V
15+
}
16+
17+
public final class com/posthog/server/logback/PostHogAppender$Companion {
18+
public final fun clearPostHog ()V
19+
public final fun setPostHog (Lcom/posthog/server/PostHogInterface;)V
20+
}
21+
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
@file:Suppress("ktlint:standard:max-line-length")
2+
3+
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
4+
5+
version = properties["serverLogbackVersion"].toString()
6+
7+
plugins {
8+
`java-library`
9+
kotlin("jvm")
10+
id("com.android.lint")
11+
12+
// publish
13+
`maven-publish`
14+
signing
15+
id("org.jetbrains.dokka")
16+
17+
// plugins
18+
id("com.github.gmazzo.buildconfig")
19+
20+
// tests
21+
id("org.jetbrains.kotlinx.kover")
22+
23+
// compatibility
24+
id("ru.vyarus.animalsniffer")
25+
}
26+
27+
buildConfig {
28+
useKotlinOutput()
29+
packageName("com.posthog.server.logback")
30+
buildConfigField("String", "SDK_NAME", "\"posthog-server-logback\"")
31+
buildConfigField("String", "VERSION_NAME", "\"${project.version}\"")
32+
}
33+
34+
java {
35+
withSourcesJar()
36+
sourceCompatibility = PosthogBuildConfig.Build.JAVA_VERSION
37+
targetCompatibility = PosthogBuildConfig.Build.JAVA_VERSION
38+
}
39+
40+
val dokkaJavadocJar by tasks.register<Jar>("dokkaJavadocJar") {
41+
dependsOn(tasks.dokkaJavadoc)
42+
from(tasks.dokkaJavadoc.flatMap { it.outputDirectory })
43+
archiveClassifier.set("javadoc")
44+
}
45+
46+
val dokkaHtmlJar by tasks.register<Jar>("dokkaHtmlJar") {
47+
dependsOn(tasks.dokkaHtml)
48+
from(tasks.dokkaHtml.flatMap { it.outputDirectory })
49+
archiveClassifier.set("html-doc")
50+
}
51+
52+
publishing {
53+
publications {
54+
create<MavenPublication>("maven") {
55+
from(components["java"])
56+
artifact(dokkaJavadocJar)
57+
artifact(dokkaHtmlJar)
58+
59+
postHogConfig(project.name, project.version.toString())
60+
pom.postHogConfig(
61+
project.name,
62+
moduleDescription = "Logback appender that reports errors to PostHog via the server SDK",
63+
)
64+
}
65+
}
66+
signing.postHogConfig("maven", this)
67+
}
68+
69+
tasks.withType<KotlinCompile>().configureEach {
70+
compilerOptions.postHogConfig()
71+
}
72+
73+
kotlin {
74+
explicitApi()
75+
}
76+
77+
configure<SourceSetContainer> {
78+
test {
79+
java.srcDir("src/test/java")
80+
}
81+
}
82+
83+
dependencies {
84+
// Expose the server SDK transitively: consumers configure and use a PostHog server client
85+
// alongside the appender, so it belongs on the compile classpath of anything depending on this.
86+
api(project(":posthog-server"))
87+
88+
implementation(kotlin("stdlib-jdk8", PosthogBuildConfig.Kotlin.KOTLIN))
89+
90+
// Logback is provided by the host application; keep it off our runtime classpath and pin a
91+
// conservative Java 8-compatible floor (the 1.3.x line; 1.4.x+ requires Java 11).
92+
compileOnly("ch.qos.logback:logback-classic:${PosthogBuildConfig.Dependencies.LOGBACK}")
93+
compileOnly("org.codehaus.mojo:animal-sniffer-annotations:${PosthogBuildConfig.Plugins.ANIMAL_SNIFFER_SDK_ANNOTATION}")
94+
95+
// compatibility
96+
signature("org.codehaus.mojo.signature:java18:${PosthogBuildConfig.Plugins.SIGNATURE_JAVA18}@signature")
97+
98+
// tests
99+
testImplementation("ch.qos.logback:logback-classic:${PosthogBuildConfig.Dependencies.LOGBACK}")
100+
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:${PosthogBuildConfig.Kotlin.KOTLIN}")
101+
testImplementation("com.squareup.okhttp3:mockwebserver:${PosthogBuildConfig.Dependencies.OKHTTP}")
102+
testImplementation("com.google.code.gson:gson:${PosthogBuildConfig.Dependencies.GSON}")
103+
}
104+
105+
tasks.javadoc {
106+
if (JavaVersion.current().isJava9Compatible) {
107+
(options as StandardJavadocDocletOptions).addBooleanOption("html5", true)
108+
}
109+
}

0 commit comments

Comments
 (0)