在android中 spdlog库的log如何在控制台上输出

在 Android 中使用 spdlog 并将日志输出到控制台(Logcat),需要结合 Android 的日志系统(android/log.h)进行适配,因为 spdlog 本身默认的控制台输出在 Android 环境中无法直接映射到 Logcat。以下是具体实现步骤:

1. 确保 spdlog 已集成到 Android 项目

首先需要将 spdlog 源码引入 Android 项目(可通过 CMake 或 ndk-build 配置),确保 C++ 代码能正常包含 <spdlog/spdlog.h>

2. 自定义 spdlog sink 适配 Android Logcat

spdlog 通过 sink (日志输出目标)控制日志流向,Android 中需要自定义一个 sink,将日志转发到 android/log.h 提供的 __android_log_write 函数(该函数会将日志输出到 Logcat)。

示例代码(自定义 Logcat sink):

cpp 复制代码
// 自定义 sink 类(不变)
template<typename Mutex>
class android_sink : public spdlog::sinks::base_sink<Mutex> {
protected:
    void sink_it_(const spdlog::details::log_msg& msg) override {
        spdlog::memory_buf_t formatted;
        this->formatter_->format(msg, formatted); // 注意:用 this-> 访问父类成员
        std::string str = fmt::to_string(formatted);

        android_LogPriority priority;
        switch (msg.level) {
            case spdlog::level::trace: priority = ANDROID_LOG_VERBOSE; break;
            case spdlog::level::debug: priority = ANDROID_LOG_DEBUG; break;
            case spdlog::level::info:  priority = ANDROID_LOG_INFO; break;
            case spdlog::level::warn:  priority = ANDROID_LOG_WARN; break;
            case spdlog::level::err:   priority = ANDROID_LOG_ERROR; break;
            case spdlog::level::critical: priority = ANDROID_LOG_FATAL; break;
            default: priority = ANDROID_LOG_DEFAULT;
        }

        __android_log_write(priority, LOG_TAG, str.c_str());
    }

    void flush_() override {}
};

using android_sink_mt = android_sink<std::mutex>;
using android_sink_st = android_sink<spdlog::details::null_mutex>;

3. 配置 spdlog 使用自定义 sink

在初始化 spdlog 时,将自定义的 android_sink 添加为日志输出目标,示例:

cpp 复制代码
#include <spdlog/spdlog.h>

// 初始化函数(修正后)
void init_spdlog_for_android() {
    auto android_sink = std::make_shared<android_sink_mt>();
    
    // 修正 1:用 unique_ptr 创建 formatter,并通过 std::move 传递
    auto formatter = std::make_unique<spdlog::pattern_formatter>("[%H:%M:%S] [%l] %v");
    android_sink->set_formatter(std::move(formatter)); // 关键:转移 unique_ptr 所有权
    
    // 修正 2:正确创建 logger(用 initializer_list 包装 sink)
    auto logger = std::make_shared<spdlog::logger>(
        "android_logger", 
        std::initializer_list<spdlog::sink_ptr>{android_sink}
    );
    
    logger->set_level(spdlog::level::debug);
    
    // 修正 3:设置默认日志器(确保版本支持)
    spdlog::set_default_logger(logger);
}

4. 使用 spdlog 输出日志

初始化后,直接使用 spdlog 的日志函数,日志会通过自定义 sink 输出到 Logcat:

cpp 复制代码
// 在合适的地方(如 JNI_OnLoad 中)初始化
init_spdlog_for_android();

// 输出日志
spdlog::debug("Debug message from spdlog");
spdlog::info("Info message, value: {}", 123);
spdlog::warn("Warning message");
spdlog::error("Error message");

5. 在 Logcat 中查看日志

通过 Android Studio 的 Logcat 面板,过滤标签 SPDLOG_ANDROID(或自定义的 LOG_TAG),即可看到 spdlog 输出的日志:

cpp 复制代码
[10:30:45] [debug] Debug message from spdlog
[10:30:45] [info] Info message, value: 123
[10:30:45] [warn] Warning message
[10:30:45] [error] Error message

关键说明

  • 日志级别映射spdlog 的级别(trace/debug/info 等)需手动映射到 Android 的 Logcat 级别(VERBOSE/DEBUG/INFO 等),确保日志在 Logcat 中正确分类。
  • 线程安全 :多线程环境下使用 android_sink_mt(带互斥锁),单线程可使用 android_sink_st 提升性能。
  • 格式化 :通过 pattern_formatter 自定义日志格式(如时间、文件名、行号等),具体格式语法参考 spdlog 格式化文档

通过以上步骤,spdlog 的日志即可正常输出到 Android 控制台(Logcat)。

6.完整修代码

cpp 复制代码
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/null_mutex.h>
#include <spdlog/logger.h>       // 新增:包含 logger 头文件
#include <spdlog/spdlog.h>
#include <android/log.h>
#include <mutex>
#include <memory>                // 确保包含智能指针头文件

#define LOG_TAG "SPDLOG_ANDROID"

// 自定义 sink 类(不变)
template<typename Mutex>
class android_sink : public spdlog::sinks::base_sink<Mutex> {
protected:
    void sink_it_(const spdlog::details::log_msg& msg) override {
        spdlog::memory_buf_t formatted;
        this->formatter_->format(msg, formatted); // 注意:用 this-> 访问父类成员
        std::string str = fmt::to_string(formatted);

        android_LogPriority priority;
        switch (msg.level) {
            case spdlog::level::trace: priority = ANDROID_LOG_VERBOSE; break;
            case spdlog::level::debug: priority = ANDROID_LOG_DEBUG; break;
            case spdlog::level::info:  priority = ANDROID_LOG_INFO; break;
            case spdlog::level::warn:  priority = ANDROID_LOG_WARN; break;
            case spdlog::level::err:   priority = ANDROID_LOG_ERROR; break;
            case spdlog::level::critical: priority = ANDROID_LOG_FATAL; break;
            default: priority = ANDROID_LOG_DEFAULT;
        }

        __android_log_write(priority, LOG_TAG, str.c_str());
    }

    void flush_() override {}
};

using android_sink_mt = android_sink<std::mutex>;
using android_sink_st = android_sink<spdlog::details::null_mutex>;

// 初始化函数(修正后)
void init_spdlog_for_android() {
    auto android_sink = std::make_shared<android_sink_mt>();
    
    // 修正 1:用 unique_ptr 创建 formatter,并通过 std::move 传递
    auto formatter = std::make_unique<spdlog::pattern_formatter>("[%H:%M:%S] [%l] %v");
    android_sink->set_formatter(std::move(formatter)); // 关键:转移 unique_ptr 所有权
    
    // 修正 2:正确创建 logger(用 initializer_list 包装 sink)
    auto logger = std::make_shared<spdlog::logger>(
        "android_logger", 
        std::initializer_list<spdlog::sink_ptr>{android_sink}
    );
    
    logger->set_level(spdlog::level::debug);
    
    // 修正 3:设置默认日志器(确保版本支持)
    spdlog::set_default_logger(logger);
}
相关推荐
雨白34 分钟前
重识 Java IO、NIO 与 OkIO
android·java
啦啦9117141 小时前
Niagara Launcher 全新Android桌面启动器!给手机换个门面!
android·智能手机
游戏开发爱好者81 小时前
iOS 上架要求全解析,App Store 审核标准、开发者准备事项与开心上架(Appuploader)跨平台免 Mac 实战指南
android·macos·ios·小程序·uni-app·iphone·webview
xrkhy1 小时前
canal1.1.8+mysql8.0+jdk17+redis的使用
android·redis·adb
_dindong1 小时前
笔试强训:Week-4
数据结构·c++·笔记·学习·算法·哈希算法·散列表
00后程序员张2 小时前
混淆 iOS 类名与变量名的实战指南,多工具组合把混淆做成工程能力(混淆 iOS 类名变量名/IPA 成品混淆Ipa/Guard CLI 实操)
android·ios·小程序·https·uni-app·iphone·webview
liu****2 小时前
12.线程(二)
linux·开发语言·c++·1024程序员节
小冯的编程学习之路3 小时前
【C++】:C++基于微服务的即时通讯系统(2)
开发语言·c++·微服务
许长安3 小时前
C/C++中的extern关键字详解
c语言·开发语言·c++·经验分享·笔记
介一安全3 小时前
【Frida Android】实战篇1:环境准备
android·网络安全·逆向·frida