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]\+.*"