icinga2/lib/base/windowseventloglogger.cpp
Julian Brost 1e316b6663 Windows: log into separate "Icinga 2" log
Previously, Icinga 2 logged to the shared "Application" log provided by
default. Due to the comparatively high volume of log messages, this lead to
complaints and for the early logging (before the final logging configuration is
loaded and enabled), the behavior isn't configurable easily. By using our own
log file, this should be less annoying for users.

The log is named "Icinga 2" and the source "Icinga 2 General" because according
to the documentation, these names should not be the same: "You cannot use a
source name that has already been used as a log name." [1]

This naming allows for distributing messages across different sources in the
future (think "Icinga 2 ApiListener", "Icinga2 CheckerComponent", ...).
However, this requires registering all these names in the registry, so this is
just left as an option for now.

The existing "Icinga for Windows" log is not used on explicit request. [2]

[1] https://docs.microsoft.com/en-us/windows/win32/eventlog/event-sources
[2] https://github.com/Icinga/icinga2/issues/8996#issuecomment-1183013092
2022-07-14 14:04:00 +02:00

84 lines
2.2 KiB
C++

/* Icinga 2 | (c) 2021 Icinga GmbH | GPLv2+ */
#ifdef _WIN32
#include "base/windowseventloglogger.hpp"
#include "base/windowseventloglogger-ti.cpp"
#include "base/windowseventloglogger-provider.h"
#include "base/configtype.hpp"
#include "base/statsfunction.hpp"
#include <windows.h>
using namespace icinga;
REGISTER_TYPE(WindowsEventLogLogger);
REGISTER_STATSFUNCTION(WindowsEventLogLogger, &WindowsEventLogLogger::StatsFunc);
INITIALIZE_ONCE(&WindowsEventLogLogger::StaticInitialize);
static HANDLE l_EventLog = nullptr;
void WindowsEventLogLogger::StaticInitialize()
{
l_EventLog = RegisterEventSourceA(nullptr, "Icinga 2 General");
}
void WindowsEventLogLogger::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
{
DictionaryData nodes;
for (const WindowsEventLogLogger::Ptr& logger : ConfigType::GetObjectsByType<WindowsEventLogLogger>()) {
nodes.emplace_back(logger->GetName(), 1);
}
status->Set("windowseventloglogger", new Dictionary(std::move(nodes)));
}
/**
* Processes a log entry and outputs it to the Windows Event Log.
*
* This function implements the interface expected by the Logger base class and passes
* the log entry to WindowsEventLogLogger::WriteToWindowsEventLog().
*
* @param entry The log entry.
*/
void WindowsEventLogLogger::ProcessLogEntry(const LogEntry& entry) {
WindowsEventLogLogger::WriteToWindowsEventLog(entry);
}
/**
* Writes a LogEntry object to the Windows Event Log.
*
* @param entry The log entry.
*/
void WindowsEventLogLogger::WriteToWindowsEventLog(const LogEntry& entry)
{
if (l_EventLog != nullptr) {
std::string message = Logger::SeverityToString(entry.Severity) + "/" + entry.Facility + ": " + entry.Message;
std::array<const char *, 1> strings{
message.c_str()
};
WORD eventType;
switch (entry.Severity) {
case LogCritical:
eventType = EVENTLOG_ERROR_TYPE;
break;
case LogWarning:
eventType = EVENTLOG_WARNING_TYPE;
break;
default:
eventType = EVENTLOG_INFORMATION_TYPE;
}
ReportEventA(l_EventLog, eventType, 0, MSG_PLAIN_LOG_ENTRY, NULL, strings.size(), 0, strings.data(), NULL);
}
}
void WindowsEventLogLogger::Flush()
{
/* Nothing to do here. */
}
#endif /* _WIN32 */