diff --git a/doc/09-object-types.md b/doc/09-object-types.md index 85b397ece..950a843a7 100644 --- a/doc/09-object-types.md +++ b/doc/09-object-types.md @@ -1864,4 +1864,21 @@ Facility Constants: FacilityUucp | LOG\_UUCP | The UUCP system. +### WindowsEventLogLogger +Specifies Icinga 2 logging to the Windows Event Log. +This configuration object is available as `windowseventlog` [logging feature](14-features.md#logging). + +Example: + +``` +object WindowsEventLogLogger "windowseventlog" { + severity = "warning" +} +``` + +Configuration Attributes: + + Name | Type | Description + --------------------------|-----------------------|---------------------------------- + severity | String | **Optional.** The minimum severity for this log. Can be "debug", "notice", "information", "warning" or "critical". Defaults to "warning". diff --git a/doc/14-features.md b/doc/14-features.md index 823d4149a..2b5a30c62 100644 --- a/doc/14-features.md +++ b/doc/14-features.md @@ -11,11 +11,12 @@ Icinga 2 supports three different types of logging: You can enable additional loggers using the `icinga2 feature enable` and `icinga2 feature disable` commands to configure loggers: -Feature | Description ----------|------------ -debuglog | Debug log (path: `/var/log/icinga2/debug.log`, severity: `debug` or higher) -mainlog | Main log (path: `/var/log/icinga2/icinga2.log`, severity: `information` or higher) -syslog | Syslog (severity: `warning` or higher) +Feature | Description +----------------|------------ +debuglog | Debug log (path: `/var/log/icinga2/debug.log`, severity: `debug` or higher) +mainlog | Main log (path: `/var/log/icinga2/icinga2.log`, severity: `information` or higher) +syslog | Syslog (severity: `warning` or higher) +windowseventlog | Windows Event Log (severity: `warning` or higher) By default file the `mainlog` feature is enabled. When running Icinga 2 on a terminal log messages with severity `information` or higher are diff --git a/etc/CMakeLists.txt b/etc/CMakeLists.txt index f693bbcd4..47c8a40e2 100644 --- a/etc/CMakeLists.txt +++ b/etc/CMakeLists.txt @@ -39,6 +39,8 @@ install_if_not_exists(icinga2/features-available/debuglog.conf ${ICINGA2_CONFIGD install_if_not_exists(icinga2/features-available/mainlog.conf ${ICINGA2_CONFIGDIR}/features-available) if(NOT WIN32) install_if_not_exists(icinga2/features-available/syslog.conf ${ICINGA2_CONFIGDIR}/features-available) +else() + install_if_not_exists(icinga2/features-available/windowseventlog.conf ${ICINGA2_CONFIGDIR}/features-available) endif() install_if_not_exists(icinga2/scripts/mail-host-notification.sh ${ICINGA2_CONFIGDIR}/scripts) install_if_not_exists(icinga2/scripts/mail-service-notification.sh ${ICINGA2_CONFIGDIR}/scripts) diff --git a/etc/icinga2/features-available/windowseventlog.conf b/etc/icinga2/features-available/windowseventlog.conf new file mode 100644 index 000000000..ddd5716ee --- /dev/null +++ b/etc/icinga2/features-available/windowseventlog.conf @@ -0,0 +1,8 @@ +/** + * The WindowsEventLogLogger type writes log information to the Windows Event Log. + */ + +object WindowsEventLogLogger "windowseventlog" { + severity = "warning" +} + diff --git a/icinga-installer/icinga2.wixpatch.cmake b/icinga-installer/icinga2.wixpatch.cmake index 5ee6361ae..eee4027ca 100644 --- a/icinga-installer/icinga2.wixpatch.cmake +++ b/icinga-installer/icinga2.wixpatch.cmake @@ -20,6 +20,20 @@ $CM_CP_sbin.icinga2_installer.exe=2 AND NOT SUPPRESS_XTRA + + + + + + + + + diff --git a/lib/base/CMakeLists.txt b/lib/base/CMakeLists.txt index 2a5391818..9707d2935 100644 --- a/lib/base/CMakeLists.txt +++ b/lib/base/CMakeLists.txt @@ -85,6 +85,33 @@ set(base_SOURCES workqueue.cpp workqueue.hpp ) +if(WIN32) + mkclass_target(windowseventloglogger.ti windowseventloglogger-ti.cpp windowseventloglogger-ti.hpp) + list(APPEND base_SOURCES windowseventloglogger.cpp windowseventloglogger.hpp windowseventloglogger-ti.hpp) + + # Generate a DLL containing message definitions for the Windows Event Viewer. + # See also: https://docs.microsoft.com/en-us/windows/win32/eventlog/reporting-an-event + add_custom_command( + OUTPUT windowseventloglogger-provider.rc windowseventloglogger-provider.h + COMMAND mc ARGS -U ${CMAKE_CURRENT_SOURCE_DIR}/windowseventloglogger-provider.mc + DEPENDS windowseventloglogger-provider.mc + ) + + list(APPEND base_SOURCES windowseventloglogger-provider.h) + + add_custom_command( + OUTPUT windowseventloglogger-provider.res + COMMAND rc ARGS windowseventloglogger-provider.rc + DEPENDS windowseventloglogger-provider.rc + ) + + add_library(eventprovider MODULE windowseventloglogger-provider.res windowseventloglogger-provider.rc) + set_target_properties(eventprovider PROPERTIES LINKER_LANGUAGE CXX) + target_link_libraries(eventprovider PRIVATE -noentry) + + install(TARGETS eventprovider LIBRARY DESTINATION ${CMAKE_INSTALL_SBINDIR}) +endif() + set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/application-version.cpp PROPERTY EXCLUDE_UNITY_BUILD TRUE) if(ICINGA2_UNITY_BUILD) diff --git a/lib/base/windowseventloglogger-provider.mc b/lib/base/windowseventloglogger-provider.mc new file mode 100644 index 000000000..09e65ba57 --- /dev/null +++ b/lib/base/windowseventloglogger-provider.mc @@ -0,0 +1,5 @@ +MessageId=0x1 +SymbolicName=MSG_PLAIN_LOG_ENTRY +Language=English +%1 +. diff --git a/lib/base/windowseventloglogger.cpp b/lib/base/windowseventloglogger.cpp new file mode 100644 index 000000000..8c9582351 --- /dev/null +++ b/lib/base/windowseventloglogger.cpp @@ -0,0 +1,71 @@ +/* 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 + +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"); +} + +void WindowsEventLogLogger::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&) +{ + DictionaryData nodes; + + for (const WindowsEventLogLogger::Ptr& logger : ConfigType::GetObjectsByType()) { + 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. + * + * @param entry The log entry. + */ +void WindowsEventLogLogger::ProcessLogEntry(const LogEntry& entry) +{ + if (l_EventLog != nullptr) { + std::string message = Logger::SeverityToString(entry.Severity) + "/" + entry.Facility + ": " + entry.Message; + std::array 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 */ diff --git a/lib/base/windowseventloglogger.hpp b/lib/base/windowseventloglogger.hpp new file mode 100644 index 000000000..7b8b03e91 --- /dev/null +++ b/lib/base/windowseventloglogger.hpp @@ -0,0 +1,35 @@ +/* Icinga 2 | (c) 2021 Icinga GmbH | GPLv2+ */ + +#ifndef WINDOWSEVENTLOGLOGGER_H +#define WINDOWSEVENTLOGLOGGER_H + +#ifdef _WIN32 +#include "base/i2-base.hpp" +#include "base/windowseventloglogger-ti.hpp" + +namespace icinga +{ + +/** + * A logger that logs to the Windows Event Log. + * + * @ingroup base + */ +class WindowsEventLogLogger final : public ObjectImpl +{ +public: + DECLARE_OBJECT(WindowsEventLogLogger); + DECLARE_OBJECTNAME(WindowsEventLogLogger); + + static void StaticInitialize(); + static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); + +protected: + void ProcessLogEntry(const LogEntry& entry) override; + void Flush() override; +}; + +} +#endif /* _WIN32 */ + +#endif /* WINDOWSEVENTLOGLOGGER_H */ diff --git a/lib/base/windowseventloglogger.ti b/lib/base/windowseventloglogger.ti new file mode 100644 index 000000000..edf65fc06 --- /dev/null +++ b/lib/base/windowseventloglogger.ti @@ -0,0 +1,15 @@ +/* Icinga 2 | (c) 2021 Icinga GmbH | GPLv2+ */ + +#include "base/logger.hpp" + +library base; + +namespace icinga +{ + +class WindowsEventLogLogger : Logger +{ + activation_priority -100; +}; + +} diff --git a/tools/syntax/vim/syntax/icinga2.vim b/tools/syntax/vim/syntax/icinga2.vim index 0374c7b5a..59ff202f1 100644 --- a/tools/syntax/vim/syntax/icinga2.vim +++ b/tools/syntax/vim/syntax/icinga2.vim @@ -60,7 +60,7 @@ syn keyword icinga2ObjType IcingaApplication IdoMysqlConnection IdoPgsqlConnec syn keyword icinga2ObjType InfluxdbWriter LivestatusListener Notification NotificationCommand syn keyword icinga2ObjType NotificationComponent OpenTsdbWriter PerfdataWriter syn keyword icinga2ObjType ScheduledDowntime Service ServiceGroup SyslogLogger -syn keyword icinga2ObjType TimePeriod User UserGroup Zone +syn keyword icinga2ObjType TimePeriod User UserGroup WindowsEventLogLogger Zone " Object/Template marker (simplified) syn match icinga2ObjDef "\(object\|template\)[ \t]\+.*"