1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef NETUTILS_LOG_H 18 #define NETUTILS_LOG_H 19 20 #include <chrono> 21 #include <deque> 22 #include <functional> 23 #include <shared_mutex> 24 #include <string> 25 #include <type_traits> 26 #include <vector> 27 28 #include <android-base/stringprintf.h> 29 #include <android-base/thread_annotations.h> 30 31 #include <netdutils/Status.h> 32 33 namespace android { 34 namespace netdutils { 35 36 class LogEntry { 37 public: 38 LogEntry() = default; 39 LogEntry(const LogEntry&) = default; 40 LogEntry(LogEntry&&) = default; 41 ~LogEntry() = default; 42 LogEntry& operator=(const LogEntry&) = default; 43 LogEntry& operator=(LogEntry&&) = default; 44 45 std::string toString() const; 46 47 /// 48 // Helper methods that make it easy to build up a LogEntry message. 49 // If performance becomes a factor the implementations could be inlined. 50 /// 51 LogEntry& message(const std::string& message); 52 53 // For calling with __FUNCTION__. 54 LogEntry& function(const std::string& function_name); 55 // For calling with __PRETTY_FUNCTION__. 56 LogEntry& prettyFunction(const std::string& pretty_function); 57 58 // Convenience methods for each of the common types of function arguments. 59 LogEntry& arg(const std::string& val); 60 // Intended for binary buffers, formats as hex 61 LogEntry& arg(const std::vector<uint8_t>& val); 62 LogEntry& arg(const std::vector<int32_t>& val); 63 LogEntry& arg(const std::vector<std::string>& val); 64 template <typename IntT, typename = std::enable_if_t<std::is_arithmetic_v<IntT>>> arg(IntT val)65 LogEntry& arg(IntT val) { 66 mArgs.push_back(std::to_string(val)); 67 return *this; 68 } 69 // Not using a plain overload here to avoid the implicit conversion from 70 // any pointer to bool, which causes string literals to print as 'true'. 71 template <> 72 LogEntry& arg<>(bool val); 73 74 template <typename... Args> args(const Args &...a)75 LogEntry& args(const Args&... a) { 76 // Cleverness ahead: we throw away the initializer_list filled with 77 // zeroes, all we care about is calling arg() for each argument. 78 (void) std::initializer_list<int>{(arg(a), 0)...}; 79 return *this; 80 } 81 82 // Some things can return more than one value, or have multiple output 83 // parameters, so each of these adds to the mReturns vector. 84 LogEntry& returns(const std::string& rval); 85 LogEntry& returns(const Status& status); 86 LogEntry& returns(bool rval); 87 template <class T> returns(T val)88 LogEntry& returns(T val) { 89 mReturns.push_back(std::to_string(val)); 90 return *this; 91 } 92 93 LogEntry& withUid(uid_t uid); 94 95 // Append the duration computed since the creation of this instance. 96 LogEntry& withAutomaticDuration(); 97 // Append the string-ified duration computed by some other means. 98 LogEntry& withDuration(const std::string& duration); 99 100 private: 101 std::chrono::steady_clock::time_point mStart = std::chrono::steady_clock::now(); 102 std::string mMsg{}; 103 std::string mFunc{}; 104 std::vector<std::string> mArgs{}; 105 std::vector<std::string> mReturns{}; 106 std::string mUid{}; 107 std::string mDuration{}; 108 }; 109 110 class Log { 111 public: 112 Log() = delete; Log(const std::string & tag)113 Log(const std::string& tag) : Log(tag, MAX_ENTRIES) {} Log(const std::string & tag,size_t maxEntries)114 Log(const std::string& tag, size_t maxEntries) : mTag(tag), mMaxEntries(maxEntries) {} 115 Log(const Log&) = delete; 116 Log(Log&&) = delete; 117 ~Log(); 118 Log& operator=(const Log&) = delete; 119 Log& operator=(Log&&) = delete; 120 newEntry()121 LogEntry newEntry() const { return LogEntry(); } 122 123 // Record a log entry in internal storage only. log(const std::string & entry)124 void log(const std::string& entry) { record(Level::LOG, entry); } 125 template <size_t n> log(const char entry[n])126 void log(const char entry[n]) { log(std::string(entry)); } log(const LogEntry & entry)127 void log(const LogEntry& entry) { log(entry.toString()); } log(const char * fmt,...)128 void log(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) { 129 using ::android::base::StringAppendV; 130 std::string result; 131 va_list ap; 132 va_start(ap, fmt); 133 StringAppendV(&result, fmt, ap); 134 va_end(ap); 135 log(result); 136 } 137 138 // Record a log entry in internal storage and to ALOGI as well. info(const std::string & entry)139 void info(const std::string& entry) { record(Level::INFO, entry); } 140 template <size_t n> info(const char entry[n])141 void info(const char entry[n]) { info(std::string(entry)); } info(const LogEntry & entry)142 void info(const LogEntry& entry) { info(entry.toString()); } info(const char * fmt,...)143 void info(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) { 144 using ::android::base::StringAppendV; 145 std::string result; 146 va_list ap; 147 va_start(ap, fmt); 148 StringAppendV(&result, fmt, ap); 149 va_end(ap); 150 info(result); 151 } 152 153 // Record a log entry in internal storage and to ALOGW as well. warn(const std::string & entry)154 void warn(const std::string& entry) { record(Level::WARN, entry); } 155 template <size_t n> warn(const char entry[n])156 void warn(const char entry[n]) { warn(std::string(entry)); } warn(const LogEntry & entry)157 void warn(const LogEntry& entry) { warn(entry.toString()); } warn(const char * fmt,...)158 void warn(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) { 159 using ::android::base::StringAppendV; 160 std::string result; 161 va_list ap; 162 va_start(ap, fmt); 163 StringAppendV(&result, fmt, ap); 164 va_end(ap); 165 warn(result); 166 } 167 168 // Record a log entry in internal storage and to ALOGE as well. error(const std::string & entry)169 void error(const std::string& entry) { record(Level::ERROR, entry); } 170 template <size_t n> error(const char entry[n])171 void error(const char entry[n]) { error(std::string(entry)); } error(const LogEntry & entry)172 void error(const LogEntry& entry) { error(entry.toString()); } error(const char * fmt,...)173 void error(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) { 174 using ::android::base::StringAppendV; 175 std::string result; 176 va_list ap; 177 va_start(ap, fmt); 178 StringAppendV(&result, fmt, ap); 179 va_end(ap); 180 error(result); 181 } 182 183 // Iterates over every entry in the log in chronological order. Operates 184 // on a copy of the log entries, and so perEntryFn may itself call one of 185 // the logging functions if needed. 186 void forEachEntry(const std::function<void(const std::string&)>& perEntryFn) const; 187 188 private: 189 static constexpr const size_t MAX_ENTRIES = 750U; 190 const std::string mTag; 191 const size_t mMaxEntries; 192 193 // The LOG level adds an entry to mEntries but does not output the message 194 // to the system log. All other levels append to mEntries and output to the 195 // the system log. 196 enum class Level { 197 LOG, 198 INFO, 199 WARN, 200 ERROR, 201 }; 202 203 void record(Level lvl, const std::string& entry); 204 205 mutable std::shared_mutex mLock; 206 std::deque<const std::string> mEntries; // GUARDED_BY(mLock), when supported 207 }; 208 209 } // namespace netdutils 210 } // namespace android 211 212 #endif /* NETUTILS_LOG_H */ 213