Remote Logging is a mechanism for sending logs from a mobile device to a remote server for centralized analysis and monitoring. Unlike local logging, which stores data on the device, remote collection allows seeing errors and anomalies from all user devices in real time. According to Sentry Resource Library, applications with remote logging find 92% of production bugs within the first hour after release compared to 15% when using only crash reports. This is a mandatory tool for any mobile development team: Firebase Crashlytics, Sentry and Datadog provide ready-made SDKs for iOS and Android.
Key Takeaways
Remote Logging is the process of collecting logs from remote devices and transmitting them to a central server for analysis. In the context of mobile development, remote logging includes not only crash reports but also custom events, breadcrumbs, performance metrics and user scenarios.
The main difference between remote logging and crash reporting is proactivity. Crash reporting only collects data about application crashes that have already occurred. Remote logging collects the sequence of events leading up to the crash: which screens the user opened, what requests they made, what data they entered. This makes it possible to reproduce the error scenario without communicating with the user.
Apple provides a built-in remote log collection mechanism via .logarchive, but for production applications third-party services are almost always used. The Android SDK includes Logcat, which is accessible remotely via ADB, but not for end-user devices without debugging.
The remote logging architecture consists of three components: the client SDK on the device that collects and buffers logs, the transport protocol for sending data, and the server for storage and visualization.
| Component | Role | Examples |
|---|---|---|
| Client SDK | Collection, buffering, batching | Firebase SDK, Sentry Cocoa, Timber |
| Transport | Data transmission via HTTPS | REST, gRPC, WebSocket |
| Server | Storage, indexing, alerts | Sentry, Crashlytics, Datadog |
The client SDK buffers logs in RAM and periodically flushes them to the server in batches. If the device is offline, logs are saved to a local file and sent on the next network connection. Buffer size and send interval are configurable: typical values are 50 events or 30 seconds.
HTTPS REST is the most common protocol for remote logging. The SDK serializes logs to JSON and sends them via POST requests to the server endpoint. gRPC is an alternative with binary serialization (Protocol Buffers), which is 30–40% more compact than JSON and faster on mobile devices with unstable connections. WebSocket is used for real-time logging in debugging but rarely in production due to power consumption.
Firebase Crashlytics is a free Google service for collecting crash reports and custom logs. It is built into the Firebase SDK and does not require a separate server. Crashlytics automatically collects stack traces, device state, OS version and open screens at the time of the crash.
Custom logs in Crashlytics are added via the log() method — they are not sent to the server immediately but are stored in a ring buffer and attached to the next crash report. This is a key difference from Sentry, where each log is a separate event. The maximum volume of custom logs in Crashlytics is 64 KB per crash.
// Firebase Crashlytics — custom logs on Android
import com.google.firebase.crashlytics.FirebaseCrashlytics
class CheckoutViewModel {
fun processPayment(amount: Double) {
FirebaseCrashlytics.getInstance()
.log("Payment started: amount=$amount")
try {
process(amount)
} catch (e: Exception) {
FirebaseCrashlytics.getInstance()
.recordException(e)
}
}
}
Firebase Crashlytics supports setUserIdentifier for linking crashes to specific users. This helps determine whether a bug is widespread or affects only one user. setCustomKey adds arbitrary keys to each report — A/B test version, region, pricing plan.
Sentry is an error monitoring platform that stores not only crash reports but also all custom events (breadcrumbs) as independent records. Unlike Crashlytics, Sentry allows viewing the sequence of events leading up to an error in chronological order — breadcrumbs are visible in the interface without needing to reconstruct them from the crash log.
The Sentry SDK automatically collects breadcrumbs for system events: UIViewController lifecycle changes (viewDidLoad, viewWillAppear), touches, button presses, HTTP requests via URLSession. All these events appear in the error timeline alongside custom breadcrumbs. For Android, Activity and Fragment lifecycle, onClick events and network requests via OkHttp are similarly collected.
The Sentry SDK for iOS and Android automatically collects breadcrumbs for UI events: touches, navigation, lifecycle. Developers can add custom breadcrumbs via addBreadcrumb() specifying the type, category and level. Sentry supports distributed tracing: the logger links client-side breadcrumbs with backend requests through a trace ID.
import Sentry
func trackCartEvent(action: String, itemId: String) {
let crumb = Breadcrumb()
crumb.level = .info
crumb.category = "cart"
crumb.message = "Cart \(action): \(itemId)"
crumb.data = ["action": action, "item_id": itemId]
SentrySDK.addBreadcrumb(crumb)
}
Logcat is Android’s standard logging system, accessible through the Android Debug Bridge (ADB). Logcat collects all system and application messages, organized by levels (V, D, I, W, E, F) and tags. Remote access to Logcat works via ADB over USB or Wi-Fi, but only for devices in debugging mode — production applications on devices without a USB connection are not accessible.
For remote logging in production on Android, alternatives are used: Logcat itself cannot send logs to a server. Its role is local diagnostics. However, there are wrappers (Timber, LogcatLive) that forward messages to Firebase or Sentry while preserving the familiar Log.d / Log.e API. Timber allows switching handlers without changing application code — a debug tree writes to Logcat, a release tree sends to the server with batching and compression.
Batching is grouping multiple logs into a single HTTP request to save traffic and battery. Instead of 50 individual POST requests, the SDK sends one JSON array. Typical strategies: sending on a schedule (every 30 seconds), by count (every 50 events), or by event (only on critical errors).
For applications with millions of users, log volume can reach terabytes per day. Batching reduces the number of requests by 10–50 times and lowers server load. Sentry uses gzip compression at the transport level, further reducing data volume by 60–70%.
// Simple batching implementation on Android
class LogBatcher {
private val buffer = mutableListOf<LogEvent>()
private val maxSize = 50
private val intervalMs = 30_000L
fun append(event: LogEvent) {
buffer.add(event)
if (buffer.size >= maxSize) flush()
}
suspend fun flush() {
val batch = buffer.toList()
buffer.clear()
sendToServer(batch)
}
}
gzip is the standard compression method for HTTP log transmission. The Sentry and Crashlytics SDKs automatically compress the request body before sending. Deduplication removes duplicate messages on the client side: if the same event occurs 100 times per second, the SDK sends it once with a count field = 100.
The most common mistake is logging sensitive data. Remote logging SDKs transmit data to the server, and if a developer accidentally logs a password, token or user email, this data ends up in the cloud infrastructure. Always use PII (Personally Identifiable Information) filtering at the SDK level: Sentry has a built-in beforeSend hook for cleaning data before sending.
The second common problem is excessive logging. If every finger movement is sent to the server, data volume grows exponentially, and so do server costs. Set a logging budget: no more than 1–5 events per user per minute in production. Send debug logs only with a flag that is enabled for specific devices.
The third mistake is ignoring the offline scenario. If the SDK loses logs when there is no network and does not restore them on reconnect, remote logging is useless for users with unstable connections. All SDKs (Firebase, Sentry) automatically cache logs to a local file and send them when the network becomes available, but this setting needs to be verified.
Frequently Asked Questions
Crash reporting only collects information about application crashes. Remote Logging collects all events: custom logs, breadcrumbs, performance metrics, UI events. Crash reporting is a subset of remote logging, not an alternative to it.
Crashlytics is free and sufficient for basic crash reports. Sentry is better if you need breadcrumbs, distributed tracing, custom dashboards and flexible alerts. For enterprise projects with compliance requirements, Sentry is available in a self-hosted version.
Use logging levels: send debug/info logs only from a developer’s device using the isDebuggable flag. Filter other levels (warn, error) through a beforeSend hook, removing fields containing PII. Define the maximum log size per session.
Logcat does not support remote sending to a server. For remote logging on Android, use Timber for forwarding to Firebase or Sentry, and keep Logcat for debugging via USB. Timber replaces the Android Log API and adds plantable trees.
Up to 50 events per minute per device does not noticeably affect battery consumption if batching is used (sending in batches rather than one by one). At 200+ events per minute, the Wi-Fi/modem will be constantly active — battery drains 15–25% faster.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also