blob: 77ae6494244d46f5f0938de5fe64792aed0d7d54 [file] [log] [blame]
Erik Klineb31fd692018-06-06 20:50:11 +09001/*
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>
Bernie Innocentic7994ae2018-09-06 16:36:38 +090024#include <type_traits>
Bernie Innocenti97f388f2018-10-16 19:17:08 +090025#include <vector>
Erik Klineb31fd692018-06-06 20:50:11 +090026
27#include <android-base/stringprintf.h>
28#include <android-base/thread_annotations.h>
29
30#include <netdutils/Status.h>
31
32namespace android {
33namespace netdutils {
34
35class 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);
Bernie Innocentie2cda072018-09-06 21:39:49 +090059 // Intended for binary buffers, formats as hex
60 LogEntry& arg(const std::vector<uint8_t>& val);
Erik Klineb31fd692018-06-06 20:50:11 +090061 LogEntry& arg(const std::vector<int32_t>& val);
Erik Klineb31fd692018-06-06 20:50:11 +090062 LogEntry& arg(const std::vector<std::string>& val);
Bernie Innocentic7994ae2018-09-06 16:36:38 +090063 template <typename IntT, typename = std::enable_if_t<std::is_arithmetic_v<IntT>>>
64 LogEntry& arg(IntT val) {
Erik Klineb31fd692018-06-06 20:50:11 +090065 mArgs.push_back(std::to_string(val));
66 return *this;
67 }
Bernie Innocentic7994ae2018-09-06 16:36:38 +090068 // 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
Bernie Innocentie2cda072018-09-06 21:39:49 +090073 template <typename... Args>
74 LogEntry& args(const Args&... a) {
Bernie Innocentic7994ae2018-09-06 16:36:38 +090075 // Cleverness ahead: we throw away the initializer_list filled with
76 // zeroes, all we care about is calling arg() for each argument.
Bernie Innocentie2cda072018-09-06 21:39:49 +090077 (void) std::initializer_list<int>{(arg(a), 0)...};
Bernie Innocentic7994ae2018-09-06 16:36:38 +090078 return *this;
79 }
Erik Klineb31fd692018-06-06 20:50:11 +090080
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>
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
109class Log {
110 public:
111 Log() = delete;
112 Log(const std::string& tag) : Log(tag, MAX_ENTRIES) {}
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
120 LogEntry newEntry() const { return LogEntry(); }
121
122 // Record a log entry in internal storage only.
123 void log(const std::string& entry) { record(Level::LOG, entry); }
124 template <size_t n>
125 void log(const char entry[n]) { log(std::string(entry)); }
126 void log(const LogEntry& entry) { log(entry.toString()); }
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.
138 void info(const std::string& entry) { record(Level::INFO, entry); }
139 template <size_t n>
140 void info(const char entry[n]) { info(std::string(entry)); }
141 void info(const LogEntry& entry) { info(entry.toString()); }
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.
153 void warn(const std::string& entry) { record(Level::WARN, entry); }
154 template <size_t n>
155 void warn(const char entry[n]) { warn(std::string(entry)); }
156 void warn(const LogEntry& entry) { warn(entry.toString()); }
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.
168 void error(const std::string& entry) { record(Level::ERROR, entry); }
169 template <size_t n>
170 void error(const char entry[n]) { error(std::string(entry)); }
171 void error(const LogEntry& entry) { error(entry.toString()); }
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 */