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

Use spdlog's built-in android_sink in 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, 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, 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. 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:

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:

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:

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:

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:

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 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, 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. 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →