# How to Use `android_sink` for Android Logging with spdlog

> Integrate spdlog with Android logging using android_sink. Forward native C++ messages to logcat seamlessly with spdlog API and __android_log_write.

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

---

**The `android_sink` class forwards spdlog messages to Android's logcat system via `__android_log_write`, enabling native C++ applications to integrate with Android's logging infrastructure using the familiar spdlog API.**

The `android_sink` header provides a specialized logging backend for Android platforms in the gabime/spdlog repository. When compiling for Android (when the `__ANDROID__` macro is defined), this sink converts spdlog's formatted messages into Android log priorities and writes them to logcat buffers with configurable retry logic.

## How `android_sink` Works Under the Hood

The `android_sink` implementation resides in [`include/spdlog/sinks/android_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/android_sink.h) and derives from `spdlog::sinks::base_sink<Mutex>`. According to the source code, the template class overrides the `sink_it_` method to format messages and forward them to Android's native logging API.

The sink maps spdlog's severity levels to Android priorities through the `convert_to_android_` method (lines 88–105). For example, `spdlog::level::trace` maps to `ANDROID_LOG_VERBOSE`, while `spdlog::level::err` maps to `ANDROID_LOG_ERROR`.

If the write operation fails with `EAGAIN`, the sink implements retry logic using `SPDLOG_ANDROID_RETRIES` (lines 57–62). This ensures log messages persist even when the Android log buffer experiences temporary backpressure.

## Factory Functions for Quick Setup

To simplify logger creation, spdlog provides two factory functions in [`include/spdlog/sinks/android_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/android_sink.h) (lines 123–132):

1. **`spdlog::android_logger_mt`** – Creates a multi-threaded logger using `std::mutex` for thread safety.
2. **`spdlog::android_logger_st`** – Creates a single-threaded logger using a null-mutex for zero synchronization overhead.

Both functions accept a logger name and an optional string tag that appears in logcat output.

## Basic Multi-Threaded Setup

Use `android_logger_mt` when logging from multiple threads. The tag parameter groups messages under a specific identifier in logcat.

```cpp
#if defined(__ANDROID__)
#include "spdlog/sinks/android_sink.h"

int main() {
    // Tag that appears in logcat
    std::string tag = "my-app";

    // Create multi-threaded Android logger
    auto logger = spdlog::android_logger_mt("android_logger", tag);

    // Standard spdlog usage
    logger->info("Application started");
    logger->warn("Low memory warning");
    logger->error("Unexpected error occurred: {}", 42);
}
#endif

```

## Single-Threaded Variant

When logging occurs exclusively from one thread, use `android_logger_st` to eliminate mutex overhead.

```cpp
#if defined(__ANDROID__)
#include "spdlog/sinks/android_sink.h"

auto logger = spdlog::android_logger_st("android_logger_st", "single-thread");
logger->debug("Debug message without mutex overhead");
#endif

```

## Custom Tags and Raw Message Mode

For advanced use cases, instantiate `android_sink` directly to control the tag and formatting behavior. Setting `use_raw_msg` to `true` bypasses spdlog's formatter and sends the original payload directly to Android.

```cpp
#if defined(__ANDROID__)
#include "spdlog/sinks/android_sink.h"

using raw_android_sink = spdlog::sinks::android_sink<std::mutex>;
auto raw_sink = std::make_shared<raw_android_sink>("RAW_TAG", true);
auto logger = std::make_shared<spdlog::logger>("raw_logger", raw_sink);

// Sends unformatted message directly to logcat
logger->info("Raw message – no formatting");
#endif

```

## Writing to Alternative Log Buffers

By default, `android_sink` writes to `LOG_ID_MAIN`. You can specify alternative buffers such as `LOG_ID_RADIO` or `LOG_ID_EVENTS` by providing a custom `BufferID` template parameter. This causes the sink to call `__android_log_buf_write` instead of `__android_log_write`.

```cpp
#if defined(__ANDROID__)
#include "spdlog/sinks/android_sink.h"

using radio_sink = spdlog::sinks::android_sink<std::mutex, log_id::LOG_ID_RADIO>;
auto logger = std::make_shared<spdlog::logger>(
    "radio_logger", std::make_shared<radio_sink>("RADIO_TAG"));

logger->info("Message written to the RADIO log buffer");
#endif

```

## Summary

- **`android_sink`** in [`include/spdlog/sinks/android_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/android_sink.h) integrates spdlog with Android's logcat by calling `__android_log_write` or `__android_log_buf_write`.
- **Factory helpers** `android_logger_mt` and `android_logger_st` provide convenient thread-safe and single-threaded logger creation.
- **Log level mapping** automatically converts spdlog levels to Android priorities via `convert_to_android_`.
- **Retry logic** handles `EAGAIN` errors up to `SPDLOG_ANDROID_RETRIES` times before failing.
- **Template parameters** allow customization of mutex type, log buffer ID, and raw message mode.

## Frequently Asked Questions

### How do I configure `android_sink` to use a custom log buffer like `LOG_ID_RADIO`?

Instantiate the sink template with a non-default `BufferID` parameter. Change `android_sink<std::mutex>` to `android_sink<std::mutex, log_id::LOG_ID_RADIO>`. This instructs the sink to call `__android_log_buf_write` targeting the radio buffer instead of the main log.

### What is the difference between `android_logger_mt` and `android_logger_st`?

`android_logger_mt` creates a thread-safe logger backed by `std::mutex`, suitable when multiple threads log concurrently. `android_logger_st` uses a null-mutex and avoids synchronization overhead, making it faster for single-threaded scenarios but unsafe for concurrent access.

### How does spdlog handle Android log level conversion?

The `convert_to_android_` method in [`android_sink.h`](https://github.com/gabime/spdlog/blob/main/android_sink.h) (lines 88–105) maps internal spdlog levels to Android priorities: `trace` becomes `ANDROID_LOG_VERBOSE`, `debug` becomes `ANDROID_LOG_DEBUG`, `info` becomes `ANDROID_LOG_INFO`, `warn` becomes `ANDROID_LOG_WARN`, and `error`/`critical` become `ANDROID_LOG_ERROR`/`ANDROID_LOG_FATAL`.

### Why am I missing log messages in logcat?

Messages may drop if the Android log buffer is full. The sink implements retry logic for `EAGAIN` errors up to `SPDLOG_ANDROID_RETRIES`, but persistent buffer overflow or incorrect tag filtering in logcat commands can hide messages. Verify your logcat filter includes the tag specified in the sink constructor.