aboutsummaryrefslogtreecommitdiff
path: root/src/common/log/Logger.cpp
blob: e13cb1228e55e899f470182c1f1c77b6e7445eba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include "cru/common/log/Logger.h"
#include "cru/common/log/StdioLogTarget.h"

#include <array>
#include <cstdlib>
#include <ctime>

#ifdef CRU_PLATFORM_WINDOWS
#include "cru/common/platform/win/DebugLogTarget.h"
#endif

namespace cru::log {
Logger *Logger::GetInstance() {
  static Logger logger;

  logger.AddLogTarget(std::make_unique<StdioLogTarget>());

#ifdef CRU_PLATFORM_WINDOWS
  logger.AddLogTarget(std::make_unique<platform::win::WinDebugLogTarget>());
#endif

  return &logger;
}

void Logger::AddLogTarget(std::unique_ptr<ILogTarget> target) {
  std::lock_guard<std::mutex> lock(target_list_mutex_);
  target_list_.push_back(std::move(target));
}

void Logger::RemoveLogTarget(ILogTarget *target) {
  std::lock_guard<std::mutex> lock(target_list_mutex_);
  target_list_.erase(
      std::remove_if(target_list_.begin(), target_list_.end(),
                     [target](const auto &t) { return t.get() == target; }),
      target_list_.end());
}

namespace {
String LogLevelToString(LogLevel level) {
  switch (level) {
    case LogLevel::Debug:
      return u"DEBUG";
    case LogLevel::Info:
      return u"INFO";
    case LogLevel::Warn:
      return u"WARN";
    case LogLevel::Error:
      return u"ERROR";
    default:
      std::terminate();
  }
}

String GetLogTime() {
  auto time = std::time(nullptr);
  auto calendar = std::localtime(&time);
  return Format(u"{}:{}:{}", calendar->tm_hour, calendar->tm_min,
                calendar->tm_sec);
}

String MakeLogFinalMessage(const LogInfo &log_info) {
  if (log_info.tag.empty()) {
    return Format(u"[{}] {}: {}", GetLogTime(),
                  LogLevelToString(log_info.level), log_info.message);
  } else {
    return Format(u"[{}] {} {}: {}", GetLogTime(),
                  LogLevelToString(log_info.level), log_info.tag,
                  log_info.message);
  }
}
}  // namespace

Logger::Logger()
    : log_thread_([this] {
        while (true) {
          auto log_info = log_queue_.Pull();
          std::lock_guard<std::mutex> lock_guard{target_list_mutex_};
          for (const auto &target : target_list_) {
            target->Write(log_info.level, MakeLogFinalMessage(log_info));
          }
        }
      }) {}

Logger::~Logger() {}

void Logger::Log(LogInfo log_info) {
#ifndef CRU_DEBUG
  if (log_info.level == LogLevel::Debug) {
    return;
  }
#endif
  log_queue_.Push(std::move(log_info));
}
}  // namespace cru::log