syslog_logging.cc 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // Copyright 2016 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/syslog_logging.h"
  5. #include "build/build_config.h"
  6. #if BUILDFLAG(IS_WIN)
  7. #include <windows.h>
  8. #include <sddl.h>
  9. #include "base/debug/stack_trace.h"
  10. #include "base/strings/string_util.h"
  11. #include "base/win/scoped_handle.h"
  12. #include "base/win/win_util.h"
  13. #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  14. // <syslog.h> defines LOG_INFO, LOG_WARNING macros that could conflict with
  15. // base::LOG_INFO, base::LOG_WARNING.
  16. #include <syslog.h>
  17. #undef LOG_INFO
  18. #undef LOG_WARNING
  19. #endif
  20. #include <ostream>
  21. #include <string>
  22. namespace logging {
  23. namespace {
  24. // The syslog logging is on by default, but tests or fuzzers can disable it.
  25. bool g_logging_enabled = true;
  26. } // namespace
  27. #if BUILDFLAG(IS_WIN)
  28. namespace {
  29. std::string* g_event_source_name = nullptr;
  30. uint16_t g_category = 0;
  31. uint32_t g_event_id = 0;
  32. std::wstring* g_user_sid = nullptr;
  33. class EventLogHandleTraits {
  34. public:
  35. using Handle = HANDLE;
  36. EventLogHandleTraits() = delete;
  37. EventLogHandleTraits(const EventLogHandleTraits&) = delete;
  38. EventLogHandleTraits& operator=(const EventLogHandleTraits&) = delete;
  39. // Closes the handle.
  40. static bool CloseHandle(HANDLE handle) {
  41. return ::DeregisterEventSource(handle) != FALSE;
  42. }
  43. // Returns true if the handle value is valid.
  44. static bool IsHandleValid(HANDLE handle) { return handle != nullptr; }
  45. // Returns null handle value.
  46. static HANDLE NullHandle() { return nullptr; }
  47. };
  48. using ScopedEventLogHandle =
  49. base::win::GenericScopedHandle<EventLogHandleTraits,
  50. base::win::DummyVerifierTraits>;
  51. } // namespace
  52. void SetEventSource(const std::string& name,
  53. uint16_t category,
  54. uint32_t event_id) {
  55. DCHECK_EQ(nullptr, g_event_source_name);
  56. g_event_source_name = new std::string(name);
  57. g_category = category;
  58. g_event_id = event_id;
  59. DCHECK_EQ(nullptr, g_user_sid);
  60. g_user_sid = new std::wstring();
  61. base::win::GetUserSidString(g_user_sid);
  62. }
  63. void ResetEventSourceForTesting() {
  64. delete g_event_source_name;
  65. g_event_source_name = nullptr;
  66. delete g_user_sid;
  67. g_user_sid = nullptr;
  68. }
  69. #endif // BUILDFLAG(IS_WIN)
  70. EventLogMessage::EventLogMessage(const char* file,
  71. int line,
  72. LogSeverity severity)
  73. : log_message_(file, line, severity) {
  74. }
  75. EventLogMessage::~EventLogMessage() {
  76. if (!g_logging_enabled)
  77. return;
  78. #if BUILDFLAG(IS_WIN)
  79. // If g_event_source_name is nullptr (which it is per default) SYSLOG will
  80. // degrade gracefully to regular LOG. If you see this happening most probably
  81. // you are using SYSLOG before you called SetEventSourceName.
  82. if (g_event_source_name == nullptr)
  83. return;
  84. ScopedEventLogHandle event_log_handle(
  85. RegisterEventSourceA(nullptr, g_event_source_name->c_str()));
  86. if (!event_log_handle.is_valid()) {
  87. stream() << " !!NOT ADDED TO EVENTLOG!!";
  88. return;
  89. }
  90. std::string message(log_message_.str());
  91. WORD log_type = EVENTLOG_ERROR_TYPE;
  92. switch (log_message_.severity()) {
  93. case LOGGING_INFO:
  94. log_type = EVENTLOG_INFORMATION_TYPE;
  95. break;
  96. case LOGGING_WARNING:
  97. log_type = EVENTLOG_WARNING_TYPE;
  98. break;
  99. case LOGGING_ERROR:
  100. case LOGGING_FATAL:
  101. // The price of getting the stack trace is not worth the hassle for
  102. // non-error conditions.
  103. base::debug::StackTrace trace;
  104. message.append(trace.ToString());
  105. log_type = EVENTLOG_ERROR_TYPE;
  106. break;
  107. }
  108. LPCSTR strings[1] = {message.data()};
  109. PSID user_sid = nullptr;
  110. if (!::ConvertStringSidToSid(g_user_sid->c_str(), &user_sid)) {
  111. stream() << " !!ERROR GETTING USER SID!!";
  112. }
  113. if (!ReportEventA(event_log_handle.get(), log_type, g_category, g_event_id,
  114. user_sid, 1, 0, strings, nullptr)) {
  115. stream() << " !!NOT ADDED TO EVENTLOG!!";
  116. }
  117. if (user_sid != nullptr)
  118. ::LocalFree(user_sid);
  119. #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  120. const char kEventSource[] = "chrome";
  121. openlog(kEventSource, LOG_NOWAIT | LOG_PID, LOG_USER);
  122. // We can't use the defined names for the logging severity from syslog.h
  123. // because they collide with the names of our own severity levels. Therefore
  124. // we use the actual values which of course do not match ours.
  125. // See sys/syslog.h for reference.
  126. int priority = 3;
  127. switch (log_message_.severity()) {
  128. case LOGGING_INFO:
  129. priority = 6;
  130. break;
  131. case LOGGING_WARNING:
  132. priority = 4;
  133. break;
  134. case LOGGING_ERROR:
  135. priority = 3;
  136. break;
  137. case LOGGING_FATAL:
  138. priority = 2;
  139. break;
  140. }
  141. syslog(priority, "%s", log_message_.str().c_str());
  142. closelog();
  143. #endif // BUILDFLAG(IS_WIN)
  144. }
  145. void SetSyslogLoggingForTesting(bool logging_enabled) {
  146. g_logging_enabled = logging_enabled;
  147. }
  148. } // namespace logging