1 //
2 // Copyright(c) 2015 Gabi Melman.
3 // Distributed under the MIT License (http://opensource.org/licenses/MIT)
4 //
5 
6 #pragma once
7 
8 #include "spdlog/details/fmt_helper.h"
9 #include "spdlog/details/null_mutex.h"
10 #include "spdlog/details/os.h"
11 #include "spdlog/sinks/base_sink.h"
12 
13 #include <android/log.h>
14 #include <chrono>
15 #include <mutex>
16 #include <string>
17 #include <thread>
18 
19 #if !defined(SPDLOG_ANDROID_RETRIES)
20 #define SPDLOG_ANDROID_RETRIES 2
21 #endif
22 
23 namespace spdlog {
24 namespace sinks {
25 
26 /*
27  * Android sink (logging using __android_log_write)
28  */
29 template<typename Mutex>
30 class android_sink SPDLOG_FINAL : public base_sink<Mutex>
31 {
32 public:
android_sink(std::string tag = �, bool use_raw_msg = false)33     explicit android_sink(std::string tag = "spdlog", bool use_raw_msg = false)
34         : tag_(std::move(tag))
35         , use_raw_msg_(use_raw_msg)
36     {
37     }
38 
39 protected:
40     void sink_it_(const details::log_msg &msg) override
41     {
42         const android_LogPriority priority = convert_to_android_(msg.level);
43         fmt::memory_buffer formatted;
44         if (use_raw_msg_)
45         {
46             details::fmt_helper::append_buf(msg.raw, formatted);
47         }
48         else
49         {
50             sink::formatter_->format(msg, formatted);
51         }
52         formatted.push_back('\0');
53         const char *msg_output = formatted.data();
54 
55         // See system/core/liblog/logger_write.c for explanation of return value
56         int ret = __android_log_write(priority, tag_.c_str(), msg_output);
57         int retry_count = 0;
58         while ((ret == -11 /*EAGAIN*/) && (retry_count < SPDLOG_ANDROID_RETRIES))
59         {
60             details::os::sleep_for_millis(5);
61             ret = __android_log_write(priority, tag_.c_str(), msg_output);
62             retry_count++;
63         }
64 
65         if (ret < 0)
66         {
67             throw spdlog_ex("__android_log_write() failed", ret);
68         }
69     }
70 
71     void flush_() override {}
72 
73 private:
convert_to_android_(spdlog::level::level_enum level)74     static android_LogPriority convert_to_android_(spdlog::level::level_enum level)
75     {
76         switch (level)
77         {
78         case spdlog::level::trace:
79             return ANDROID_LOG_VERBOSE;
80         case spdlog::level::debug:
81             return ANDROID_LOG_DEBUG;
82         case spdlog::level::info:
83             return ANDROID_LOG_INFO;
84         case spdlog::level::warn:
85             return ANDROID_LOG_WARN;
86         case spdlog::level::err:
87             return ANDROID_LOG_ERROR;
88         case spdlog::level::critical:
89             return ANDROID_LOG_FATAL;
90         default:
91             return ANDROID_LOG_DEFAULT;
92         }
93     }
94 
95     std::string tag_;
96     bool use_raw_msg_;
97 };
98 
99 using android_sink_mt = android_sink<std::mutex>;
100 using android_sink_st = android_sink<details::null_mutex>;
101 } // namespace sinks
102 
103 // Create and register android syslog logger
104 
105 template<typename Factory = default_factory>
android_logger_mt(const std::string &logger_name, const std::string &tag = �)106 inline std::shared_ptr<logger> android_logger_mt(const std::string &logger_name, const std::string &tag = "spdlog")
107 {
108     return Factory::template create<sinks::android_sink_mt>(logger_name, tag);
109 }
110 
111 template<typename Factory = default_factory>
android_logger_st(const std::string &logger_name, const std::string &tag = �)112 inline std::shared_ptr<logger> android_logger_st(const std::string &logger_name, const std::string &tag = "spdlog")
113 {
114     return Factory::template create<sinks::android_sink_st>(logger_name, tag);
115 }
116 
117 } // namespace spdlog
118