Add basic logging infrastructure for bugreports
Test: as follows
- built, flashed, booted
- "adb shell dumpsys netd" shows logs
- tests/runtests.sh passes
Change-Id: I0e44da7f9a9cc53074ffc396b958e9e2dbcd2603
diff --git a/libnetdutils/include/netdutils/Log.h b/libnetdutils/include/netdutils/Log.h
new file mode 100644
index 0000000..7a68a8f
--- /dev/null
+++ b/libnetdutils/include/netdutils/Log.h
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NETUTILS_LOG_H
+#define NETUTILS_LOG_H
+
+#include <chrono>
+#include <deque>
+#include <shared_mutex>
+#include <string>
+
+#include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
+
+#include <netdutils/Status.h>
+
+namespace android {
+namespace netdutils {
+
+class LogEntry {
+ public:
+ LogEntry() = default;
+ LogEntry(const LogEntry&) = default;
+ LogEntry(LogEntry&&) = default;
+ ~LogEntry() = default;
+ LogEntry& operator=(const LogEntry&) = default;
+ LogEntry& operator=(LogEntry&&) = default;
+
+ std::string toString() const;
+
+ ///
+ // Helper methods that make it easy to build up a LogEntry message.
+ // If performance becomes a factor the implementations could be inlined.
+ ///
+ LogEntry& message(const std::string& message);
+
+ // For calling with __FUNCTION__.
+ LogEntry& function(const std::string& function_name);
+ // For calling with __PRETTY_FUNCTION__.
+ LogEntry& prettyFunction(const std::string& pretty_function);
+
+ // Convenience methods for each of the common types of function arguments.
+ LogEntry& arg(const std::string& val);
+ LogEntry& arg(const std::vector<int32_t>& val);
+ LogEntry& arg(const std::vector<uint8_t>& val);
+ LogEntry& arg(const std::vector<std::string>& val);
+ LogEntry& arg(bool val);
+ template <class T>
+ LogEntry& arg(T val) {
+ mArgs.push_back(std::to_string(val));
+ return *this;
+ }
+
+ // Some things can return more than one value, or have multiple output
+ // parameters, so each of these adds to the mReturns vector.
+ LogEntry& returns(const std::string& rval);
+ LogEntry& returns(const Status& status);
+ LogEntry& returns(bool rval);
+ template <class T>
+ LogEntry& returns(T val) {
+ mReturns.push_back(std::to_string(val));
+ return *this;
+ }
+
+ LogEntry& withUid(uid_t uid);
+
+ // Append the duration computed since the creation of this instance.
+ LogEntry& withAutomaticDuration();
+ // Append the string-ified duration computed by some other means.
+ LogEntry& withDuration(const std::string& duration);
+
+ private:
+ std::chrono::steady_clock::time_point mStart = std::chrono::steady_clock::now();
+ std::string mMsg{};
+ std::string mFunc{};
+ std::vector<std::string> mArgs{};
+ std::vector<std::string> mReturns{};
+ std::string mUid{};
+ std::string mDuration{};
+};
+
+class Log {
+ public:
+ Log() = delete;
+ Log(const std::string& tag) : Log(tag, MAX_ENTRIES) {}
+ Log(const std::string& tag, size_t maxEntries) : mTag(tag), mMaxEntries(maxEntries) {}
+ Log(const Log&) = delete;
+ Log(Log&&) = delete;
+ ~Log();
+ Log& operator=(const Log&) = delete;
+ Log& operator=(Log&&) = delete;
+
+ LogEntry newEntry() const { return LogEntry(); }
+
+ // Record a log entry in internal storage only.
+ void log(const std::string& entry) { record(Level::LOG, entry); }
+ template <size_t n>
+ void log(const char entry[n]) { log(std::string(entry)); }
+ void log(const LogEntry& entry) { log(entry.toString()); }
+ void log(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
+ using ::android::base::StringAppendV;
+ std::string result;
+ va_list ap;
+ va_start(ap, fmt);
+ StringAppendV(&result, fmt, ap);
+ va_end(ap);
+ log(result);
+ }
+
+ // Record a log entry in internal storage and to ALOGI as well.
+ void info(const std::string& entry) { record(Level::INFO, entry); }
+ template <size_t n>
+ void info(const char entry[n]) { info(std::string(entry)); }
+ void info(const LogEntry& entry) { info(entry.toString()); }
+ void info(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
+ using ::android::base::StringAppendV;
+ std::string result;
+ va_list ap;
+ va_start(ap, fmt);
+ StringAppendV(&result, fmt, ap);
+ va_end(ap);
+ info(result);
+ }
+
+ // Record a log entry in internal storage and to ALOGW as well.
+ void warn(const std::string& entry) { record(Level::WARN, entry); }
+ template <size_t n>
+ void warn(const char entry[n]) { warn(std::string(entry)); }
+ void warn(const LogEntry& entry) { warn(entry.toString()); }
+ void warn(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
+ using ::android::base::StringAppendV;
+ std::string result;
+ va_list ap;
+ va_start(ap, fmt);
+ StringAppendV(&result, fmt, ap);
+ va_end(ap);
+ warn(result);
+ }
+
+ // Record a log entry in internal storage and to ALOGE as well.
+ void error(const std::string& entry) { record(Level::ERROR, entry); }
+ template <size_t n>
+ void error(const char entry[n]) { error(std::string(entry)); }
+ void error(const LogEntry& entry) { error(entry.toString()); }
+ void error(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
+ using ::android::base::StringAppendV;
+ std::string result;
+ va_list ap;
+ va_start(ap, fmt);
+ StringAppendV(&result, fmt, ap);
+ va_end(ap);
+ error(result);
+ }
+
+ // Iterates over every entry in the log in chronological order. Operates
+ // on a copy of the log entries, and so perEntryFn may itself call one of
+ // the logging functions if needed.
+ void forEachEntry(const std::function<void(const std::string&)>& perEntryFn) const;
+
+ private:
+ static constexpr const size_t MAX_ENTRIES = 750U;
+ const std::string mTag;
+ const size_t mMaxEntries;
+
+ // The LOG level adds an entry to mEntries but does not output the message
+ // to the system log. All other levels append to mEntries and output to the
+ // the system log.
+ enum class Level {
+ LOG,
+ INFO,
+ WARN,
+ ERROR,
+ };
+
+ void record(Level lvl, const std::string& entry);
+
+ mutable std::shared_mutex mLock;
+ std::deque<const std::string> mEntries; // GUARDED_BY(mLock), when supported
+};
+
+} // namespace netdutils
+} // namespace android
+
+#endif /* NETUTILS_LOG_H */