Subchapter 49.1
references/android.mdMarkdown10 KBView on GitHub
The PostHog Android SDK has built-in support for capturing structured Logs from Android apps. The SDK handles the OTLP encoding, batching, on-disk persistence across app restarts, and lifecycle integration. You just call PostHog.logger.{trace,debug,info,warn,error,fatal}(...).
Manual capture only. Logs are emitted by your code. The SDK does not autocapture system log streams (Log.d, Logcat, Timber).
Minimum version:
com.posthog:posthog-android@3.46.0or later. Bump the dependency in yourbuild.gradle(orbuild.gradle.kts) and re-sync.
1
Required
If you haven’t installed posthog-android yet, follow the steps below. For full details, see the Android SDK guide (opens in a new tab).
The best way to install the PostHog Android library is with a build system like Gradle (opens in a new tab). This ensures you can easily upgrade to the latest versions.
All you need to do is add the posthog-android module to your App’s build.gradle or build.gradle.kts:
PostHog AI
dependencies {
implementation 'com.posthog:posthog-android:3.+'
}dependencies {
implementation("com.posthog:posthog-android:3.+")
}The best place to initialize the client is in your Application subclass.
Kotlin
PostHog AI
import android.app.Application
import com.posthog.android.PostHogAndroid
import com.posthog.android.PostHogAndroidConfig
class SampleApp : Application() {
companion object {
const val POSTHOG_API_KEY = "<ph_project_token>"
// usually 'https://us.i.posthog.com' or 'https://eu.i.posthog.com'
const val POSTHOG_HOST = "https://us.i.posthog.com"
}
2
Required
Configure Logs through config.logs before calling PostHogAndroid.setup(...). All fields are optional; defaults are tuned for mobile (cellular bandwidth, battery, app lifecycle).
Kotlin
PostHog AI
import com.posthog.android.PostHogAndroid
import com.posthog.android.PostHogAndroidConfig
class SampleApp : Application() {
override fun
3
Required
Use PostHog.logger for the per-level convenience API.
Kotlin
PostHog AI
import com.posthog.PostHog
import com.posthog.logs.PostHogLogSeverity
// Per-level convenience methods
PostHog.logger.info("checkout completed", mapOf("order_id" to "ord_789",
4
Recommended
Capture a test log from your app:
Kotlin
PostHog AI
PostHog.logger.info("hello from Android")
PostHog.flush()Open the PostHog Logs UI (opens in a new tab).
Filter by service.name = 'my-app' (or whatever value you set above).
You should see your record arrive within a few seconds.
5
Optional
The logs config has knobs for high-volume apps:
Kotlin
PostHog AI
val config = PostHogAndroidConfig(apiKey = "<ph_project_token>").apply {
logs.serviceName = "my-app"
logs.flushIntervalSeconds =
6
Optional
beforeSend runs synchronously before the rate cap, so dropped records don’t consume the per-window budget. Use it for redaction, sampling, or filtering by level. Each hook receives an immutable PostHogLogRecord and returns either a (possibly modified) record or null to drop it.
Kotlin
PostHog AI
config.logs.addBeforeSend { record ->
// Drop debug logs in production
if (record.level == PostHogLogSeverity.DEBUG) return@addBeforeSend null
// Redact secrets in the body
record.
Checkpoint
What you can do with your logs
| Action | Description |
|---|---|
| Why you need logs (opens in a new tab) | What logs show you that nothing else does |
| Search logs (opens in a new tab) | Use the search interface to find specific log entries |
| Filter by level | Filter by INFO, WARN, ERROR, etc. |
| Link session replay |
Ask a question
HelpfulCould be better
These resource attributes are captured at setup(...) and apply to every batch. Mutating config.logs.serviceName, environment, serviceVersion, or resourceAttributes after setup has no effect.
Available severity levels: TRACE, DEBUG, INFO, WARN, ERROR, FATAL.
Records are buffered, batched, persisted to disk, and flushed automatically – every 30 seconds, when the buffer hits the threshold, when the app moves to the background, or on PostHog.flush(). flush() drains events, Session Replay, and Logs together.
Each record is automatically tagged with the current distinct ID, session ID, current screen, app foreground/background state, and active Feature Flags at the moment of capture.
From Java:
Java
PostHog AI
import com.posthog.PostHog;
import com.posthog.logs.PostHogLogSeverity;
import java.util.Map;
PostHog.Companion.getLogger().info("checkout opened", null);
PostHog.Companion.getLogger().error(
"payment failed",
Map.of("amount_cents", 1999, "currency", "USD")
);Full configuration reference:
| Field | Default | What it does |
|---|---|---|
| serviceName | app package id | OTLP service.name resource attribute |
| serviceVersion | BuildConfig.VERSION_NAME | OTLP service.version resource attribute |
| environment | null | OTLP deployment.environment resource attribute |
| resourceAttributes | {} | Extra OTLP resource attributes (SDK keys win on collision) |
| flushIntervalSeconds | 30 | Periodic flush interval |
| flushAt | 20 | Buffer threshold that triggers an automatic flush |
| maxBatchSize | 50 | Max records per outbound POST (halved on 413) |
| maxBufferSize | 1000 | Max records held on disk before FIFO eviction |
| rateCapMaxLogs | 500 | Max records per rateCapWindowSeconds window. Set to 0 to disable. |
| rateCapWindowSeconds | 10 | Rate-cap tumbling window length |
serviceName, serviceVersion, environment, resourceAttributes, flushAt, and maxBatchSize are captured at setup(...); mutating them later has no effect. flushIntervalSeconds, maxBufferSize, and rate-cap fields are re-read at runtime. Defaults are tuned for cellular-aware mobile apps. Raise rateCapMaxLogs and maxBufferSize for high-volume scenarios.
Call addBeforeSend multiple times to compose a chain – hooks are evaluated left-to-right (registration order). Returning null from any hook short-circuits and drops the record. A hook that throws is treated the same as returning null (the record is dropped, the exception is logged via the SDK’s internal debug logger). Returning a record with a blank body also drops the record.
addBeforeSend and removeBeforeSend are live – added or removed hooks take effect on the next captureLog call.
From Java, register a PostHogBeforeSendLog SAM:
Java
PostHog AI
config.getLogs().addBeforeSend(record ->
record.getBody().contains("secret") ? null : record
);| Connect logs to users and session replays by passing posthogDistinctId and sessionId |
| Link logs to a person (opens in a new tab) | Surface every log emitted on behalf of a user on their PostHog person profile |
| Logging best practices (opens in a new tab) | Learn what to log, how to structure logs, and patterns that make logs useful in production |