• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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