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