Add logger class
authorJunghyun Yeon <jungh.yeon@samsung.com>
Mon, 22 Feb 2021 10:50:58 +0000 (19:50 +0900)
committerJunghyun Yeon <jungh.yeon@samsung.com>
Mon, 22 Feb 2021 10:50:58 +0000 (19:50 +0900)
Signed-off-by: Junghyun Yeon <jungh.yeon@samsung.com>
src/logging.cc [new file with mode: 0644]
src/logging.hh [new file with mode: 0644]
src/manager/pkginfo_manager.cc

diff --git a/src/logging.cc b/src/logging.cc
new file mode 100644 (file)
index 0000000..cf641e5
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by a apache 2.0 license that can be
+// found in the LICENSE file.
+
+#include "logging.hh"
+
+namespace utils {
+
+log_priority LogLevelToPriority(LogLevel level) {
+  switch (level) {
+    case LogLevel::LOG_ERROR:
+      return log_priority::DLOG_ERROR;
+    case LogLevel::LOG_WARNING:
+      return log_priority::DLOG_WARN;
+    case LogLevel::LOG_INFO:
+      return log_priority::DLOG_INFO;
+    case LogLevel::LOG_DEBUG:
+      return log_priority::DLOG_DEBUG;
+    default:
+      return log_priority::DLOG_UNKNOWN;
+  }
+}
+
+}  // namespace utils
diff --git a/src/logging.hh b/src/logging.hh
new file mode 100644 (file)
index 0000000..45d6e90
--- /dev/null
@@ -0,0 +1,183 @@
+// Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by a apache 2.0 license that can be
+// found in the LICENSE file.
+
+#ifndef LOGGING_H_
+#define LOGGING_H_
+
+#include <dlog.h>
+
+#ifndef PROJECT_TAG
+#define PROJECT_TAG ""
+#endif
+
+#ifdef LOG
+#undef LOG
+#endif
+
+#include <cassert>
+#include <climits>
+#include <cstdio>
+#include <cstring>
+#include <iomanip>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#ifndef __FILENAME__
+#define __FILENAME__                                                           \
+    (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
+#endif
+
+namespace utils {
+
+enum class LogLevel {
+  LOG_ERROR,
+  LOG_WARNING,
+  LOG_INFO,
+  LOG_DEBUG,
+};
+
+log_priority LogLevelToPriority(LogLevel level);
+
+template<LogLevel> struct LogTag;
+template<> struct LogTag<LogLevel::LOG_ERROR> {
+  static constexpr const char* value = "\033[1;31m| ERROR   |\033[0m";
+};
+template<> struct LogTag<LogLevel::LOG_WARNING> {
+  static constexpr const char* value = "\033[1;33m| WARNING |\033[0m";
+};
+template<> struct LogTag<LogLevel::LOG_INFO>  {
+  static constexpr const char* value = "\033[1;32m| INFO    |\033[0m";
+};
+template<> struct LogTag<LogLevel::LOG_DEBUG> {
+  static constexpr const char* value = "\033[0m| DEBUG   |\033[0m";
+};
+
+template <class charT, class traits = std::char_traits<charT>>
+class StringStream : private std::basic_ostringstream<charT, traits> {
+ public:
+  using std::basic_ostringstream<charT, traits>::str;
+
+  template <class T>
+  StringStream&  operator<<(const T& value) {
+    static_cast<std::basic_ostringstream<charT, traits> &>(*this) << value;
+    return *this;
+  }
+};
+
+// Interface class for logging backends. The custom LogBackend which wants
+// log using LOG() macro should be implement following interface.
+class ILogBackend {
+ public:
+  virtual void WriteLog(LogLevel level, const std::string& tag,
+      const std::string& logstr) = 0;
+};
+
+class DLogBackend : public ILogBackend {
+ public:
+  void WriteLog(LogLevel level, const std::string& tag,
+      const std::string& logstr) override {
+    dlog_print(LogLevelToPriority(level), tag.c_str(), "%s",
+        Escape(logstr).c_str());
+
+    if (level == LogLevel::LOG_ERROR)
+      std::cerr << logstr << std::endl;
+  }
+
+ private:
+  // Since LogCatcher passes input to dlog_print(), the input which contains
+  // format string(such as %d, %n) can cause unexpected result.
+  // This is simple function to escape '%'.
+  // NOTE: Is there any gorgeous way instead of this?
+  std::string Escape(const std::string& str) const {
+    std::string escaped = std::string(str);
+    size_t start_pos = 0;
+    std::string from = "%";
+    std::string to = "%%";
+    while ((start_pos = escaped.find(from, start_pos)) != std::string::npos) {
+      escaped.replace(start_pos, from.length(), to);
+      start_pos += to.length();
+    }
+    return escaped;
+  }
+};
+
+class LogCore {
+ public:
+  // Do not call this function at destructor of global object
+  static LogCore& GetCore() {
+    static LogCore core;
+    return core;
+  }
+
+  void AddLogBackend(std::shared_ptr<ILogBackend> backend) {
+    backend_list_.emplace_back(backend);
+  }
+
+  void Log(LogLevel level, const std::string& tag, const std::string& log) {
+    for (auto backend : backend_list_)
+      backend->WriteLog(level, tag, log);
+  }
+
+ private:
+  LogCore() {
+    // add default dlog backend
+    AddLogBackend(std::shared_ptr<ILogBackend>(new DLogBackend()));
+  }
+  ~LogCore() = default;
+  LogCore(const LogCore&) = delete;
+  LogCore& operator=(const LogCore&) = delete;
+
+  std::vector<std::shared_ptr<ILogBackend>> backend_list_;
+};
+
+class LogCatcher {
+ public:
+  LogCatcher(LogLevel level, const char* tag)
+    : level_(level), tag_(tag) { }
+
+  void operator&(const StringStream<char>& str) const {
+    LogCore::GetCore().Log(level_, tag_, str.str());
+  }
+
+ private:
+  LogLevel level_;
+  std::string tag_;
+};
+
+}  // namespace utils
+
+
+inline static const constexpr char* __tag_for_logging() {
+  return "";
+}
+
+inline static const constexpr char* __tag_for_project() {
+  return PROJECT_TAG;
+}
+
+// To be defined in class namespace if user want different log tag for given
+// scope
+#define SCOPE_LOG_TAG(TAG)                                                     \
+  inline static const constexpr char* __tag_for_logging() {                    \
+    return #TAG;                                                               \
+  }                                                                            \
+
+// Simple logging macro of following usage:
+//   LOG(LEVEL) << object_1 << object_2 << object_n;
+//     where:
+//       LEVEL = ERROR | WARNING | INFO | DEBUG
+#define LOG(LEVEL)                                                             \
+    ::utils::LogCatcher(                                                       \
+      ::utils::LogLevel::LOG_ ## LEVEL, __tag_for_project())                   \
+      & ::utils::StringStream<char>()                                          \
+      << std::string(::utils::LogTag<::utils::LogLevel::LOG_ ## LEVEL>::value) \
+      << " " << std::setw(25) << std::left << __tag_for_logging()              \
+      << " : " << std::setw(36)                                                \
+      << (std::string(__FILENAME__) + ":" + std::to_string(__LINE__)).c_str()  \
+      << std::setw(0) << " : "                                                 \
+
+#endif  // MANIFEST_PARSER_UTILS_LOGGING_H_
index 730a68e..c031023 100644 (file)
 
 #include "pkgmgrinfo_private.h"
 
+#include "logging.hh"
+#include "filter_parcelable.hh"
+#include "pkginfo_parcelable.hh"
+
+#include "client/pkginfo_client.hh"
+
+#include <parcel.hh>
+
 #ifdef LOG_TAG
 #undef LOG_TAG
 #endif