How to Use `android_sink` for Android Logging with spdlog
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 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 (lines 123–132):
spdlog::android_logger_mt– Creates a multi-threaded logger usingstd::mutexfor thread safety.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.
#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.
#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.
#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.
#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_sinkininclude/spdlog/sinks/android_sink.hintegrates spdlog with Android's logcat by calling__android_log_writeor__android_log_buf_write.- Factory helpers
android_logger_mtandandroid_logger_stprovide 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
EAGAINerrors up toSPDLOG_ANDROID_RETRIEStimes 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 (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.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →