最近工作需要,原有的 native 模块需要编译支持 OHOS(BTW, OHOS 真的很容易拼错)。因此,我为 OHOS 增加了一个 console 的 sink,与 Android 基本一致。废话不多说,直接上代码吧。直接复制 android_sink.h
即可,里面的 level 转换和 output 接口改一下就能完美运行。当然,其中的 domain 和失败返回重试还有待商榷。
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/details/fmt_helper.h>
#include <spdlog/details/null_mutex.h>
#include <spdlog/details/os.h>
#include <spdlog/details/synchronous_factory.h>
#include <spdlog/sinks/base_sink.h>
#include <chrono>
// $OHOS_HOME/sdk/default/openharmony/native/sysroot/usr/include/hilog/log.h
#include <hilog/log.h>
#include <mutex>
#include <string>
#include <thread>
#if !defined(SPDLOG_OHOS_RETRIES)
#define SPDLOG_OHOS_RETRIES 2
#endif
namespace spdlog {
namespace sinks {
/*
* OHOS sink (logging using OH_LOG_Print)
*/
template<typename Mutex>
class ohos_sink final : public base_sink<Mutex> {
public:
explicit ohos_sink(std::string tag = "spdlog", bool use_raw_msg = false)
: tag_(std::move(tag)), use_raw_msg_(use_raw_msg) {}
protected:
void sink_it_(const details::log_msg &msg) override {
const LogLevel log_level = convert_to_ohos_(msg.level);
memory_buf_t formatted;
if (use_raw_msg_) {
details::fmt_helper::append_string_view(msg.payload, formatted);
} else {
base_sink<Mutex>::formatter_->format(msg, formatted);
}
formatted.push_back('\0');
const char *msg_output = formatted.data();
constexpr unsigned int _DOMAIN = 0X0;
// See $OHOS_HOME/sdk/default/openharmony/native/sysroot/usr/include/hilog/log.h
int ret = OH_LOG_Print(LogType::LOG_APP, log_level, _DOMAIN, tag_.c_str(),
"%{public}s", msg_output);
int retry_count = 0;
while ((ret < 0 /*FAILED*/) && (retry_count < SPDLOG_OHOS_RETRIES)) {
details::os::sleep_for_millis(5);
ret = OH_LOG_Print(LogType::LOG_APP, log_level, _DOMAIN, tag_.c_str(),
"%{public}s", msg_output);
retry_count++;
}
if (ret < 0) { throw_spdlog_ex("OH_LOG_Print() failed", ret); }
}
void flush_() override {}
private:
static LogLevel convert_to_ohos_(spdlog::level::level_enum level) {
switch (level) {
case spdlog::level::trace:
return LogLevel::LOG_DEBUG; // NO TRACE LEVEL IN OHOS
case spdlog::level::debug: return LogLevel::LOG_DEBUG;
case spdlog::level::info: return LogLevel::LOG_INFO;
case spdlog::level::warn: return LogLevel::LOG_WARN;
case spdlog::level::err: return LogLevel::LOG_ERROR;
case spdlog::level::critical: return LogLevel::LOG_FATAL;
default: return LogLevel::LOG_INFO;
}
}
std::string tag_;
bool use_raw_msg_;
};
using ohos_sink_mt = ohos_sink<std::mutex>;
using ohos_sink_st = ohos_sink<details::null_mutex>;
} // namespace sinks
// Create and register ohos syslog logger
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger>
ohos_logger_mt(const std::string &logger_name,
const std::string &tag = "spdlog") {
return Factory::template create<sinks::ohos_sink_mt>(logger_name, tag);
}
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger>
ohos_logger_st(const std::string &logger_name,
const std::string &tag = "spdlog") {
return Factory::template create<sinks::ohos_sink_st>(logger_name, tag);
}
} // namespace spdlog
代码说明
- 包含必要的头文件:包括
spdlog
和hilog
的头文件。 - 定义
ohos_sink
类:继承自base_sink
,实现sink_it_
和flush_
方法。 - 日志级别转换:将
spdlog
的日志级别转换为 OHOS 的日志级别。 - 日志输出:使用
OH_LOG_Print
输出日志,并在失败时重试。 - 创建和注册 logger:提供
ohos_logger_mt
和ohos_logger_st
两个工厂方法,分别用于多线程和单线程环境。
这样,我们就为 OHOS 增加了一个 console 的 sink,可以方便地在 OHOS 平台上使用 spdlog
进行日志记录。