# How to Integrate spdlog with Android's logcat: Complete Implementation Guide

> Easily integrate spdlog with Android logcat using the built-in android_sink. Route messages directly to Android's logging system with our complete implementation guide.

- Repository: [Gabi Melman/spdlog](https://github.com/gabime/spdlog)
- Tags: how-to-guide
- Published: 2026-07-19

---

**Use spdlog's built-in `android_sink` in [`include/spdlog/sinks/android_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/android_sink.h) to route messages directly to Android's logging system via `__android_log_write`, accessible through the `android_logger_mt()` and `android_logger_st()` factory functions.**

The **gabime/spdlog** library provides a dedicated Android sink that seamlessly bridges C++ applications to Android's native logging infrastructure. When you integrate spdlog with Android's logcat, the library automatically handles platform detection, log level translation, and resilient write operations. The implementation is conditionally compiled only when the `__ANDROID__` macro is present, ensuring zero overhead on non-Android platforms.

## Android Sink Architecture

The core integration lives in [`include/spdlog/sinks/android_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/android_sink.h), where the template class `android_sink` inherits from `base_sink` and overrides the `sink_it_` method to forward formatted messages to Android's log daemon.

### Platform Detection and Compilation

The Android sink activates automatically when your build defines the `__ANDROID__` preprocessor macro (standard for Android NDK projects). The header encapsulates all Android-specific APIs, ensuring that code including spdlog on Linux, Windows, or macOS never encounters undefined Android symbols.

### Log Level Translation

Inside `sink_it_`, the static method `convert_to_android_` maps spdlog severity levels to Android log priorities. According to the source code at lines 88-105 of [`include/spdlog/sinks/android_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/android_sink.h), the conversion follows this mapping:

- `spdlog::level::debug` → `ANDROID_LOG_DEBUG`
- `spdlog::level::info` → `ANDROID_LOG_INFO`
- `spdlog::level::err` → `ANDROID_LOG_ERROR`
- `spdlog::level::critical` → `ANDROID_LOG_FATAL`

This translation preserves severity semantics across the boundary between your C++ application and Android Studio's logcat view.

### Resilient Write Handling

The implementation handles transient failures gracefully. If `__android_log_write` returns `EAGAIN`, the sink retries the operation up to `SPDLOG_ANDROID_RETRIES` times (defaulting to 2 attempts) using millisecond delays via `sleep_for_millis` from [`include/spdlog/details/os.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/os.h). If the write fails with `-EPERM` (permission denied), the sink silently returns without throwing, respecting Android's loggable property restrictions on specific buffers.

## Creating Android Loggers

spdlog provides convenient factory functions that eliminate boilerplate when instantiating Android-specific loggers.

### Multi-Threaded Logger

Use `android_logger_mt` to create a thread-safe logger backed by `android_sink_mt`:

```cpp
auto logger = spdlog::android_logger_mt("my_logger", "MyAppTag");
logger->set_level(spdlog::level::debug);
logger->info("Hello from spdlog on Android!");

```

The first argument registers the logger in spdlog's registry; the second sets the Android log tag visible in `adb logcat` filters.

### Single-Threaded Optimization

For low-overhead scenarios where logging occurs from a single thread, use `android_logger_st` which creates a lock-free `android_sink_st`:

```cpp
auto logger_st = spdlog::android_logger_st("render_logger", "Render");
logger_st->trace("Frame time: {} ms", elapsed);

```

### Custom Formatting and Raw Messages

You can customize output patterns or send raw payloads without spdlog's default formatting:

```cpp
auto raw_logger = spdlog::android_logger_mt("raw_logger", "RawTag");
raw_logger->set_formatter(std::make_unique<spdlog::pattern_formatter>("%v"));
raw_logger->info("Message without timestamps or metadata");

```

### Alternative Log Buffers

To write to non-default Android buffers (e.g., `LOG_ID_RADIO`), instantiate the `android_sink` template directly:

```cpp
using radio_sink_mt = spdlog::sinks::android_sink<std::mutex, log_id::LOG_ID_RADIO>;
auto radio_logger = spdlog::synchronous_factory::create<radio_sink_mt>("radio_logger", "RadioTag");
radio_logger->warn("Baseband message");

```

## Build Configuration

When compiling for Android, ensure your build system links against the Android logging library. In **CMake**, add:

```cmake
find_library(ANDROID_LOG log)
target_link_libraries(your_target spdlog::spdlog ${ANDROID_LOG})

```

No additional `target_compile_definitions` are required; the headers in [`include/spdlog/sinks/android_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/android_sink.h) automatically detect the Android environment via the `__ANDROID__` macro set by the NDK toolchain.

## Summary

- **Conditional compilation**: The `android_sink` activates only when `__ANDROID__` is defined, ensuring portable codebases.
- **Automatic translation**: The `convert_to_android_` method maps spdlog levels to Android priorities without manual intervention.
- **Factory functions**: `android_logger_mt()` provides thread-safe access, while `android_logger_st()` optimizes single-threaded performance.
- **Resilient delivery**: Retries up to `SPDLOG_ANDROID_RETRIES` times on `EAGAIN` failures.
- **Flexible targeting**: Support for custom tags, formatters, and alternative Android log buffers via template parameters.

## Frequently Asked Questions

### How does spdlog map its log levels to Android priorities?

The `android_sink` class implements a static `convert_to_android_` method that translates spdlog severity levels to Android native priorities. Debug messages become `ANDROID_LOG_DEBUG`, errors become `ANDROID_LOG_ERROR`, and critical levels map to `ANDROID_LOG_FATAL`. This happens automatically inside `sink_it_` before calling `__android_log_write`.

### Can I use spdlog with logcat in a multi-threaded application?

Yes. Call `spdlog::android_logger_mt()` to obtain a thread-safe logger that uses `android_sink_mt`. This sink inherits locking behavior from `base_sink` in [`include/spdlog/sinks/base_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/base_sink.h), ensuring that concurrent calls to `__android_log_write` are properly synchronized when multiple threads log simultaneously.

### What happens if Android's log daemon rejects a message?

The `android_sink` implementation retries failed writes up to `SPDLOG_ANDROID_RETRIES` (default 2) when receiving `EAGAIN` errors. If the system returns `-EPERM` (indicating the process lacks permission for that log level or buffer), the sink silently drops the message rather than throwing an exception, preventing application crashes due to logging restrictions.

### Do I need to modify spdlog's source code to enable Android support?

No. Android support ships with the main repository in [`include/spdlog/sinks/android_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/android_sink.h). Simply ensure your NDK build defines `__ANDROID__` (standard for Android builds) and links against `liblog.so`. The headers automatically expose `android_logger_mt` and `android_logger_st` factory functions when building for the Android platform.