Просмотр исходного кода

Windows Events Log improvements 4 (#18567)

* instruct the UI to render pretty XML

* show number of entries per source; add more aggregated sources

* XML visualization in transformation

* merge the options of the keys

* fix reording

* fix broken code

* update unicode management

* code reorganization and cleanup
Costa Tsaousis 5 месяцев назад
Родитель
Сommit
0693b018b8

+ 4 - 0
CMakeLists.txt

@@ -794,6 +794,8 @@ set(LIBNETDATA_FILES
         src/libnetdata/facets/logs_query_status.h
         src/libnetdata/os/timestamps.c
         src/libnetdata/os/timestamps.h
+        src/libnetdata/parsers/entries.c
+        src/libnetdata/parsers/entries.h
 )
 
 if(ENABLE_PLUGIN_EBPF)
@@ -1415,6 +1417,8 @@ set(WINDOWS_EVENTS_PLUGIN_FILES
         src/collectors/windows-events.plugin/windows-events-publishers.h
         src/collectors/windows-events.plugin/windows-events-fields-cache.c
         src/collectors/windows-events.plugin/windows-events-fields-cache.h
+        src/collectors/windows-events.plugin/windows-events-query-builder.c
+        src/collectors/windows-events.plugin/windows-events-query-builder.h
 )
 
 set(WINDOWS_PLUGIN_FILES

+ 1 - 1
src/collectors/systemd-journal.plugin/systemd-main.c

@@ -46,7 +46,7 @@ int main(int argc __maybe_unused, char **argv __maybe_unused) {
 
         bool cancelled = false;
         usec_t stop_monotonic_ut = now_monotonic_usec() + 600 * USEC_PER_SEC;
-        // char buf[] = "systemd-journal after:-8640000 before:0 direction:backward last:200 data_only:false slice:true source:all";
+        // char buf[] = "systemd-journal after:1726573205 before:1726574105 last:200 facets:F9q1S4.MEeL,DHKucpqUoe1,MewN7JHJ.3X,LKWfxQdCIoc,IjWzTvQ9.4t,O6O.cgYOhns,KmQ1KSeTSfO,IIsT7Ytfxy6,EQD6.NflJQq,I6rMJzShJIE,DxoIlg6RTuM,AU4H2NMVPXJ,H4mcdIPho07,EDYhj5U8330,DloDtGMQHje,JHSbsQ2fXqr,AIRrOu._40Z,NFZXv8AEpS_,Iiic3t4NuxV,F2YCtRNSfDv,GOUMAmZiRrq,O0VYoHcyq49,FDQoaBH15Bp,ClBB5dSGmCc,GTwmQptJYkk,BWH4O3GPNSL,APv6JsKkF9X,IAURKhjtcRF,Jw1dz4fJmFr slice:true source:all";
         char buf[] = "systemd-journal after:-8640000 before:0 direction:backward last:200 data_only:false slice:true facets: source:all";
         // char buf[] = "systemd-journal after:1695332964 before:1695937764 direction:backward last:100 slice:true source:all DHKucpqUoe1:PtVoyIuX.MU";
         // char buf[] = "systemd-journal after:1694511062 before:1694514662 anchor:1694514122024403";

+ 5 - 6
src/collectors/windows-events.plugin/windows-events-publishers.c

@@ -68,7 +68,7 @@ static struct {
         .spinlock = NETDATA_SPINLOCK_INITIALIZER,
 };
 
-static void publisher_load_list(PROVIDER_META_HANDLE *h, WEVT_VARIANT *content, WEVT_VARIANT *property, TXT_UNICODE *unicode, struct provider_list *l, EVT_PUBLISHER_METADATA_PROPERTY_ID property_id);
+static void publisher_load_list(PROVIDER_META_HANDLE *h, WEVT_VARIANT *content, WEVT_VARIANT *property, TXT_UNICODE *dst, struct provider_list *l, EVT_PUBLISHER_METADATA_PROPERTY_ID property_id);
 
 static inline ND_UUID *publisher_value_to_key(PUBLISHER *p) {
     return &p->uuid;
@@ -253,7 +253,7 @@ static int compare_ascending(const void *a, const void *b) {
 //    return 0;
 //}
 
-static void publisher_load_list(PROVIDER_META_HANDLE *h, WEVT_VARIANT *content, WEVT_VARIANT *property, TXT_UNICODE *unicode, struct provider_list *l, EVT_PUBLISHER_METADATA_PROPERTY_ID property_id) {
+static void publisher_load_list(PROVIDER_META_HANDLE *h, WEVT_VARIANT *content, WEVT_VARIANT *property, TXT_UNICODE *dst, struct provider_list *l, EVT_PUBLISHER_METADATA_PROPERTY_ID property_id) {
     if(!h || !h->hMetadata) return;
 
     EVT_PUBLISHER_METADATA_PROPERTY_ID name_id, message_id, value_id;
@@ -375,9 +375,9 @@ static void publisher_load_list(PROVIDER_META_HANDLE *h, WEVT_VARIANT *content,
             uint32_t messageID = wevt_field_get_uint32(property->data);
 
             if (messageID != (uint32_t)-1) {
-                if (wevt_get_message_unicode(unicode, hMetadata, NULL, messageID, EvtFormatMessageId)) {
+                if (wevt_get_message_unicode(dst, hMetadata, NULL, messageID, EvtFormatMessageId)) {
                     size_t len;
-                    d->name = unicode2utf8_strdupz(unicode->data, &len);
+                    d->name = unicode2utf8_strdupz(dst->data, &len);
                     d->len = len;
                 }
             }
@@ -450,7 +450,7 @@ static bool publisher_bitmap_metadata(TXT_UTF8 *dst, struct provider_list *l, ui
         }
     }
 
-    if(dst->used) {
+    if(dst->used > 1) {
         txt_utf8_resize(dst, dst->used + 1, true);
         dst->data[dst->used++] = 0;
     }
@@ -533,7 +533,6 @@ static bool publisher_value_metadata(TXT_UTF8 *dst, struct provider_list *l, uin
     }
 
     fatal_assert(dst->used <= dst->size);
-
     return (dst->used > 0);
 }
 

+ 107 - 0
src/collectors/windows-events.plugin/windows-events-query-builder.c

@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "windows-events-query-builder.h"
+
+// --------------------------------------------------------------------------------------------------------------------
+// query without XPath
+
+typedef struct static_utf8_8k {
+    char buffer[8192];
+    size_t size;
+    size_t len;
+} STATIC_BUF_8K;
+
+typedef struct static_unicode_16k {
+    wchar_t buffer[16384];
+    size_t size;
+    size_t len;
+} STATIC_UNI_16K;
+
+static bool wevt_foreach_selected_value_cb(FACETS *facets __maybe_unused, size_t id, const char *key, const char *value, void *data) {
+    STATIC_BUF_8K *b = data;
+
+    b->len += snprintfz(&b->buffer[b->len], b->size - b->len,
+                        "%s%s=%s",
+                        id ? " or " : "", key, value);
+
+    return b->len < b->size;
+}
+
+wchar_t *wevt_generate_query_no_xpath(LOGS_QUERY_STATUS *lqs, BUFFER *wb) {
+    static __thread STATIC_UNI_16K q = {
+            .size = sizeof(q.buffer) / sizeof(wchar_t),
+            .len = 0,
+    };
+    static __thread STATIC_BUF_8K b = {
+            .size = sizeof(b.buffer) / sizeof(char),
+            .len = 0,
+    };
+
+    lqs_query_timeframe(lqs, ANCHOR_DELTA_UT);
+
+    usec_t seek_to = lqs->query.start_ut;
+    if(lqs->rq.direction == FACETS_ANCHOR_DIRECTION_BACKWARD)
+        // windows events queries are limited to millisecond resolution
+        // so, in order not to lose data, we have to add
+        // a millisecond when the direction is backward
+        seek_to += USEC_PER_MS;
+
+    // Convert the microseconds since Unix epoch to FILETIME (used in Windows APIs)
+    FILETIME fileTime = os_unix_epoch_ut_to_filetime(seek_to);
+
+    // Convert FILETIME to SYSTEMTIME for use in XPath
+    SYSTEMTIME systemTime;
+    if (!FileTimeToSystemTime(&fileTime, &systemTime)) {
+        nd_log(NDLS_COLLECTORS, NDLP_ERR, "FileTimeToSystemTime() failed");
+        return NULL;
+    }
+
+    // Format SYSTEMTIME into ISO 8601 format (YYYY-MM-DDTHH:MM:SS.sssZ)
+    q.len = swprintf(q.buffer, q.size,
+                     L"Event/System[TimeCreated[@SystemTime%ls\"%04d-%02d-%02dT%02d:%02d:%02d.%03dZ\"]",
+                     lqs->rq.direction == FACETS_ANCHOR_DIRECTION_BACKWARD ? L"<=" : L">=",
+                     systemTime.wYear, systemTime.wMonth, systemTime.wDay,
+                     systemTime.wHour, systemTime.wMinute, systemTime.wSecond, systemTime.wMilliseconds);
+
+    if(lqs->rq.slice) {
+        b.len = snprintf(b.buffer, b.size, " and (");
+        if (facets_foreach_selected_value_in_key(
+                lqs->facets,
+                WEVT_FIELD_LEVEL,
+                sizeof(WEVT_FIELD_LEVEL) - 1,
+                used_hashes_registry,
+                wevt_foreach_selected_value_cb,
+                &b)) {
+            b.len += snprintf(&b.buffer[b.len], b.size - b.len, ")");
+            if (b.len < b.size) {
+                utf82unicode(&q.buffer[q.len], q.size - q.len, b.buffer);
+                q.len = wcslen(q.buffer);
+            }
+        }
+
+        b.len = snprintf(b.buffer, b.size, " and (");
+        if (facets_foreach_selected_value_in_key(
+                lqs->facets,
+                WEVT_FIELD_EVENTID,
+                sizeof(WEVT_FIELD_EVENTID) - 1,
+                used_hashes_registry,
+                wevt_foreach_selected_value_cb,
+                &b)) {
+            b.len += snprintf(&b.buffer[b.len], b.size - b.len, ")");
+            if (b.len < b.size) {
+                utf82unicode(&q.buffer[q.len], q.size - q.len, b.buffer);
+                q.len = wcslen(q.buffer);
+            }
+        }
+    }
+
+    q.len += swprintf(&q.buffer[q.len], q.size - q.len, L"]");
+
+    buffer_json_member_add_string(wb, "_query", channel2utf8(q.buffer));
+
+    return q.buffer;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// query with XPath
+

+ 10 - 0
src/collectors/windows-events.plugin/windows-events-query-builder.h

@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef NETDATA_WINDOWS_EVENTS_QUERY_BUILDER_H
+#define NETDATA_WINDOWS_EVENTS_QUERY_BUILDER_H
+
+#include "windows-events.h"
+
+wchar_t *wevt_generate_query_no_xpath(LOGS_QUERY_STATUS *lqs, BUFFER *wb);
+
+#endif //NETDATA_WINDOWS_EVENTS_QUERY_BUILDER_H

+ 90 - 91
src/collectors/windows-events.plugin/windows-events-query.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-3.0-or-later
 
-#include "windows-events-query.h"
+#include "windows-events.h"
 
 static uint64_t wevt_log_file_size(const wchar_t *channel);
 
@@ -62,69 +62,70 @@ static const char *wevt_extended_status(void) {
     return buf;
 }
 
-bool wevt_get_message_unicode(TXT_UNICODE *unicode, EVT_HANDLE hMetadata, EVT_HANDLE bookmark, DWORD dwMessageId, EVT_FORMAT_MESSAGE_FLAGS flags) {
-    unicode->used = 0;
+bool wevt_get_message_unicode(TXT_UNICODE *dst, EVT_HANDLE hMetadata, EVT_HANDLE hEvent, DWORD dwMessageId, EVT_FORMAT_MESSAGE_FLAGS flags) {
+    dst->used = 0;
 
     DWORD size = 0;
-    if(!unicode->data) {
-        EvtFormatMessage(hMetadata, bookmark, dwMessageId, 0, NULL, flags, 0, NULL, &size);
+    if(!dst->data) {
+        EvtFormatMessage(hMetadata, hEvent, dwMessageId, 0, NULL, flags, 0, NULL, &size);
         if(!size) {
             // nd_log(NDLS_COLLECTORS, NDLP_ERR, "EvtFormatMessage() to get message size failed.");
             goto cleanup;
         }
-        txt_unicode_resize(unicode, size);
+        txt_unicode_resize(dst, size, false);
     }
 
     // First, try to get the message using the existing buffer
-    if (!EvtFormatMessage(hMetadata, bookmark, dwMessageId, 0, NULL, flags, unicode->size, unicode->data, &size) || !unicode->data) {
-        if (unicode->data && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+    if (!EvtFormatMessage(hMetadata, hEvent, dwMessageId, 0, NULL, flags, dst->size, dst->data, &size) || !dst->data) {
+        if (dst->data && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
             // nd_log(NDLS_COLLECTORS, NDLP_ERR, "EvtFormatMessage() failed.");
             goto cleanup;
         }
 
         // Try again with the resized buffer
-        txt_unicode_resize(unicode, size);
-        if (!EvtFormatMessage(hMetadata, bookmark, dwMessageId, 0, NULL, flags, unicode->size, unicode->data, &size)) {
+        txt_unicode_resize(dst, size, false);
+        if (!EvtFormatMessage(hMetadata, hEvent, dwMessageId, 0, NULL, flags, dst->size, dst->data, &size)) {
             // nd_log(NDLS_COLLECTORS, NDLP_ERR, "EvtFormatMessage() failed after resizing buffer.");
             goto cleanup;
         }
     }
 
     // make sure it is null terminated
-    if(size <= unicode->size)
-        unicode->data[size - 1] = 0;
+    if(size <= dst->size)
+        dst->data[size - 1] = 0;
     else
-        unicode->data[unicode->size - 1] = 0;
+        dst->data[dst->size - 1] = 0;
 
     // unfortunately we have to calculate the length every time
-    // the size returned may not be the length of the unicode string
-    unicode->used = wcslen(unicode->data) + 1;
+    // the size returned may not be the length of the dst string
+    dst->used = wcslen(dst->data) + 1;
+
     return true;
 
 cleanup:
-    unicode->used = 0;
+    dst->used = 0;
     return false;
 }
 
 static bool wevt_get_field_from_events_log(
-    WEVT_LOG *log, PROVIDER_META_HANDLE *p, EVT_HANDLE event_handle,
+    WEVT_LOG *log, PROVIDER_META_HANDLE *p, EVT_HANDLE hEvent,
     TXT_UTF8 *dst, EVT_FORMAT_MESSAGE_FLAGS flags) {
 
     dst->src = TXT_SOURCE_EVENT_LOG;
 
-    if(wevt_get_message_unicode(&log->ops.unicode, publisher_handle(p), event_handle, 0, flags))
+    if(wevt_get_message_unicode(&log->ops.unicode, publisher_handle(p), hEvent, 0, flags))
         return wevt_str_unicode_to_utf8(dst, &log->ops.unicode);
 
     wevt_utf8_empty(dst);
     return false;
 }
 
-bool wevt_get_event_utf8(WEVT_LOG *log, PROVIDER_META_HANDLE *p, EVT_HANDLE event_handle, TXT_UTF8 *dst) {
-    return wevt_get_field_from_events_log(log, p, event_handle, dst, EvtFormatMessageEvent);
+bool wevt_get_event_utf8(WEVT_LOG *log, PROVIDER_META_HANDLE *p, EVT_HANDLE hEvent, TXT_UTF8 *dst) {
+    return wevt_get_field_from_events_log(log, p, hEvent, dst, EvtFormatMessageEvent);
 }
 
-bool wevt_get_xml_utf8(WEVT_LOG *log, PROVIDER_META_HANDLE *p, EVT_HANDLE event_handle, TXT_UTF8 *dst) {
-    return wevt_get_field_from_events_log(log, p, event_handle, dst, EvtFormatMessageXml);
+bool wevt_get_xml_utf8(WEVT_LOG *log, PROVIDER_META_HANDLE *p, EVT_HANDLE hEvent, TXT_UTF8 *dst) {
+    return wevt_get_field_from_events_log(log, p, hEvent, dst, EvtFormatMessageXml);
 }
 
 static inline void wevt_event_done(WEVT_LOG *log) {
@@ -133,9 +134,9 @@ static inline void wevt_event_done(WEVT_LOG *log) {
         log->publisher = NULL;
     }
 
-    if (log->bookmark) {
-        EvtClose(log->bookmark);
-        log->bookmark = NULL;
+    if (log->hEvent) {
+        EvtClose(log->hEvent);
+        log->hEvent = NULL;
     }
 
     log->ops.level.src = TXT_SOURCE_UNKNOWN;
@@ -152,7 +153,7 @@ static void wevt_get_field_from_cache(
     if (field_cache_get(cache_type, provider, value, dst))
         return;
 
-    wevt_get_field_from_events_log(log, h, log->bookmark, dst, flags);
+    wevt_get_field_from_events_log(log, h, log->hEvent, dst, flags);
     field_cache_set(cache_type, provider, value, dst);
 }
 
@@ -160,12 +161,12 @@ static void wevt_get_field_from_cache(
 
 static inline const char *wevt_level_hardcoded(uint64_t level, size_t *len) {
     switch(level) {
-        case WINEVENT_LEVEL_NONE:        SET_LEN_AND_RETURN(WINEVENT_NAME_NONE);
-        case WINEVENT_LEVEL_CRITICAL:    SET_LEN_AND_RETURN(WINEVENT_NAME_CRITICAL);
-        case WINEVENT_LEVEL_ERROR:       SET_LEN_AND_RETURN(WINEVENT_NAME_ERROR);
-        case WINEVENT_LEVEL_WARNING:     SET_LEN_AND_RETURN(WINEVENT_NAME_WARNING);
-        case WINEVENT_LEVEL_INFORMATION: SET_LEN_AND_RETURN(WINEVENT_NAME_INFORMATION);
-        case WINEVENT_LEVEL_VERBOSE:     SET_LEN_AND_RETURN(WINEVENT_NAME_VERBOSE);
+        case WEVT_LEVEL_NONE:        SET_LEN_AND_RETURN(WEVT_LEVEL_NAME_NONE);
+        case WEVT_LEVEL_CRITICAL:    SET_LEN_AND_RETURN(WEVT_LEVEL_NAME_CRITICAL);
+        case WEVT_LEVEL_ERROR:       SET_LEN_AND_RETURN(WEVT_LEVEL_NAME_ERROR);
+        case WEVT_LEVEL_WARNING:     SET_LEN_AND_RETURN(WEVT_LEVEL_NAME_WARNING);
+        case WEVT_LEVEL_INFORMATION: SET_LEN_AND_RETURN(WEVT_LEVEL_NAME_INFORMATION);
+        case WEVT_LEVEL_VERBOSE:     SET_LEN_AND_RETURN(WEVT_LEVEL_NAME_VERBOSE);
         default: *len = 0; return NULL;
     }
 }
@@ -199,22 +200,22 @@ static void wevt_get_level(WEVT_LOG *log, WEVT_EVENT *ev, PROVIDER_META_HANDLE *
     }
 
     txt_utf8_set_numeric_if_empty(
-        dst, WINEVENT_NAME_LEVEL_PREFIX, sizeof(WINEVENT_NAME_LEVEL_PREFIX) - 1, ev->level);
+            dst, WEVT_PREFIX_LEVEL, sizeof(WEVT_PREFIX_LEVEL) - 1, ev->level);
 }
 
 static inline const char *wevt_opcode_hardcoded(uint64_t opcode, size_t *len) {
     switch(opcode) {
-        case WINEVENT_OPCODE_INFO:      SET_LEN_AND_RETURN(WINEVENT_NAME_INFO);
-        case WINEVENT_OPCODE_START:     SET_LEN_AND_RETURN(WINEVENT_NAME_START);
-        case WINEVENT_OPCODE_STOP:      SET_LEN_AND_RETURN(WINEVENT_NAME_STOP);
-        case WINEVENT_OPCODE_DC_START:  SET_LEN_AND_RETURN(WINEVENT_NAME_DC_START);
-        case WINEVENT_OPCODE_DC_STOP:   SET_LEN_AND_RETURN(WINEVENT_NAME_DC_STOP);
-        case WINEVENT_OPCODE_EXTENSION: SET_LEN_AND_RETURN(WINEVENT_NAME_EXTENSION);
-        case WINEVENT_OPCODE_REPLY:     SET_LEN_AND_RETURN(WINEVENT_NAME_REPLY);
-        case WINEVENT_OPCODE_RESUME:    SET_LEN_AND_RETURN(WINEVENT_NAME_RESUME);
-        case WINEVENT_OPCODE_SUSPEND:   SET_LEN_AND_RETURN(WINEVENT_NAME_SUSPEND);
-        case WINEVENT_OPCODE_SEND:      SET_LEN_AND_RETURN(WINEVENT_NAME_SEND);
-        case WINEVENT_OPCODE_RECEIVE:   SET_LEN_AND_RETURN(WINEVENT_NAME_RECEIVE);
+        case WEVT_OPCODE_INFO:      SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_INFO);
+        case WEVT_OPCODE_START:     SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_START);
+        case WEVT_OPCODE_STOP:      SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_STOP);
+        case WEVT_OPCODE_DC_START:  SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_DC_START);
+        case WEVT_OPCODE_DC_STOP:   SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_DC_STOP);
+        case WEVT_OPCODE_EXTENSION: SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_EXTENSION);
+        case WEVT_OPCODE_REPLY:     SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_REPLY);
+        case WEVT_OPCODE_RESUME:    SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_RESUME);
+        case WEVT_OPCODE_SUSPEND:   SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_SUSPEND);
+        case WEVT_OPCODE_SEND:      SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_SEND);
+        case WEVT_OPCODE_RECEIVE:   SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_RECEIVE);
         default: *len = 0; return NULL;
     }
 }
@@ -248,12 +249,12 @@ static void wevt_get_opcode(WEVT_LOG *log, WEVT_EVENT *ev, PROVIDER_META_HANDLE
     }
 
     txt_utf8_set_numeric_if_empty(
-        dst, WINEVENT_NAME_OPCODE_PREFIX, sizeof(WINEVENT_NAME_OPCODE_PREFIX) - 1, ev->opcode);
+            dst, WEVT_PREFIX_OPCODE, sizeof(WEVT_PREFIX_OPCODE) - 1, ev->opcode);
 }
 
 static const char *wevt_task_hardcoded(uint64_t task, size_t *len) {
     switch(task) {
-        case WINEVENT_TASK_NONE: SET_LEN_AND_RETURN(WINEVENT_NAME_NONE);
+        case WEVT_TASK_NONE: SET_LEN_AND_RETURN(WEVT_TASK_NAME_NONE);
         default: *len = 0; return NULL;
     }
 }
@@ -287,7 +288,7 @@ static void wevt_get_task(WEVT_LOG *log, WEVT_EVENT *ev, PROVIDER_META_HANDLE *h
     }
 
     txt_utf8_set_numeric_if_empty(
-        dst, WINEVENT_NAME_TASK_PREFIX, sizeof(WINEVENT_NAME_TASK_PREFIX) - 1, ev->task);
+            dst, WEVT_PREFIX_TASK, sizeof(WEVT_PREFIX_TASK) - 1, ev->task);
 }
 
 #define SET_BITS(msk, txt) { .mask = msk, .name = txt, .len = sizeof(txt) - 1, }
@@ -298,14 +299,14 @@ static uint64_t wevt_keywords_handle_reserved(uint64_t value, TXT_UTF8 *dst) {
         const char *name;
         size_t len;
     } bits[] = {
-        SET_BITS(WINEVENT_KEYWORD_EVENTLOG_CLASSIC, WINEVENT_NAME_EVENTLOG_CLASSIC),
-        SET_BITS(WINEVENT_KEYWORD_CORRELATION_HINT, WINEVENT_NAME_CORRELATION_HINT),
-        SET_BITS(WINEVENT_KEYWORD_AUDIT_SUCCESS,    WINEVENT_NAME_AUDIT_SUCCESS),
-        SET_BITS(WINEVENT_KEYWORD_AUDIT_FAILURE,    WINEVENT_NAME_AUDIT_FAILURE),
-        SET_BITS(WINEVENT_KEYWORD_SQM,              WINEVENT_NAME_SQM),
-        SET_BITS(WINEVENT_KEYWORD_WDI_DIAG,         WINEVENT_NAME_WDI_DIAG),
-        SET_BITS(WINEVENT_KEYWORD_WDI_CONTEXT,      WINEVENT_NAME_WDI_CONTEXT),
-        SET_BITS(WINEVENT_KEYWORD_RESPONSE_TIME,    WINEVENT_NAME_RESPONSE_TIME),
+        SET_BITS(WEVT_KEYWORD_EVENTLOG_CLASSIC, WEVT_KEYWORD_NAME_EVENTLOG_CLASSIC),
+        SET_BITS(WEVT_KEYWORD_CORRELATION_HINT, WEVT_KEYWORD_NAME_CORRELATION_HINT),
+        SET_BITS(WEVT_KEYWORD_AUDIT_SUCCESS, WEVT_KEYWORD_NAME_AUDIT_SUCCESS),
+        SET_BITS(WEVT_KEYWORD_AUDIT_FAILURE, WEVT_KEYWORD_NAME_AUDIT_FAILURE),
+        SET_BITS(WEVT_KEYWORD_SQM, WEVT_KEYWORD_NAME_SQM),
+        SET_BITS(WEVT_KEYWORD_WDI_DIAG, WEVT_KEYWORD_NAME_WDI_DIAG),
+        SET_BITS(WEVT_KEYWORD_WDI_CONTEXT, WEVT_KEYWORD_NAME_WDI_CONTEXT),
+        SET_BITS(WEVT_KEYWORD_RESPONSE_TIME, WEVT_KEYWORD_NAME_RESPONSE_TIME),
     };
 
     wevt_utf8_empty(dst);
@@ -326,10 +327,8 @@ static uint64_t wevt_keywords_handle_reserved(uint64_t value, TXT_UTF8 *dst) {
 static void wevt_get_keywords(WEVT_LOG *log, WEVT_EVENT *ev, PROVIDER_META_HANDLE *h) {
     TXT_UTF8 *dst = &log->ops.keywords;
 
-    if(ev->keywords == WINEVT_KEYWORD_NONE) {
-        txt_utf8_resize(dst, sizeof(WINEVENT_NAME_NONE),  false);
-        memcpy(dst->data, WINEVENT_NAME_NONE, sizeof(WINEVENT_NAME_NONE));
-        dst->used = sizeof(WINEVENT_NAME_NONE);
+    if(ev->keywords == WEVT_KEYWORD_NONE) {
+        txt_utf8_set(dst, WEVT_KEYWORD_NAME_NONE, sizeof(WEVT_KEYWORD_NAME_NONE) - 1);
         dst->src = TXT_SOURCE_HARDCODED;
     }
 
@@ -340,7 +339,7 @@ static void wevt_get_keywords(WEVT_LOG *log, WEVT_EVENT *ev, PROVIDER_META_HANDL
 
     if(!value && dst->used <= 1) {
         // no hardcoded info in the buffer, make it None
-        txt_utf8_set(dst, WINEVENT_NAME_NONE,  sizeof(WINEVENT_NAME_NONE) - 1);
+        txt_utf8_set(dst, WEVT_KEYWORD_NAME_NONE, sizeof(WEVT_KEYWORD_NAME_NONE) - 1);
         dst->src = TXT_SOURCE_HARDCODED;
     }
     else if (value && !publisher_get_keywords(dst, h, value) && dst->used <= 1) {
@@ -351,7 +350,7 @@ static void wevt_get_keywords(WEVT_LOG *log, WEVT_EVENT *ev, PROVIDER_META_HANDL
     }
 
     txt_utf8_set_hex_if_empty(
-        dst, WINEVENT_NAME_KEYWORDS_PREFIX, sizeof(WINEVENT_NAME_KEYWORDS_PREFIX) - 1, ev->keywords);
+            dst, WEVT_PREFIX_KEYWORDS, sizeof(WEVT_PREFIX_KEYWORDS) - 1, ev->keywords);
 }
 
 bool wevt_get_next_event_one(WEVT_LOG *log, WEVT_EVENT *ev, bool full) {
@@ -359,16 +358,16 @@ bool wevt_get_next_event_one(WEVT_LOG *log, WEVT_EVENT *ev, bool full) {
 
     // obtain the information from selected events
     DWORD bytes_used = 0, property_count = 0;
-    if (!EvtRender(log->render_context, log->bookmark, EvtRenderEventValues, log->ops.content.size, log->ops.content.data, &bytes_used, &property_count)) {
+    if (!EvtRender(log->hRenderContext, log->hEvent, EvtRenderEventValues, log->ops.content.size, log->ops.content.data, &bytes_used, &property_count)) {
         // information exceeds the allocated space
         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
-            nd_log(NDLS_COLLECTORS, NDLP_ERR, "EvtRender() failed, render_context: 0x%lx, bookmark: 0x%lx, content: 0x%lx, size: %zu, extended info: %s",
-                   (uintptr_t)log->render_context, (uintptr_t)log->bookmark, (uintptr_t)log->ops.content.data, log->ops.content.size, wevt_extended_status());
+            nd_log(NDLS_COLLECTORS, NDLP_ERR, "EvtRender() failed, hRenderContext: 0x%lx, hEvent: 0x%lx, content: 0x%lx, size: %zu, extended info: %s",
+                   (uintptr_t)log->hRenderContext, (uintptr_t)log->hEvent, (uintptr_t)log->ops.content.data, log->ops.content.size, wevt_extended_status());
             goto cleanup;
         }
 
         wevt_variant_resize(&log->ops.content, bytes_used);
-        if (!EvtRender(log->render_context, log->bookmark, EvtRenderEventValues, log->ops.content.size, log->ops.content.data, &bytes_used, &property_count)) {
+        if (!EvtRender(log->hRenderContext, log->hEvent, EvtRenderEventValues, log->ops.content.size, log->ops.content.data, &bytes_used, &property_count)) {
             nd_log(NDLS_COLLECTORS, NDLP_ERR, "EvtRender() failed, after bytes_used increase, extended info: %s",
                    wevt_extended_status());
             goto cleanup;
@@ -417,14 +416,14 @@ bool wevt_get_next_event(WEVT_LOG *log, WEVT_EVENT *ev, bool full) {
     DWORD size = full ? BATCH_NEXT_EVENT : 1;
     DWORD max_failures = 10;
 
-    fatal_assert(log && log->event_query && log->render_context);
+    fatal_assert(log && log->hQuery && log->hRenderContext);
 
     while(max_failures > 0) {
         if (log->batch.used >= log->batch.size) {
             log->batch.size = 0;
             log->batch.used = 0;
             DWORD err;
-            if(!EvtNext(log->event_query, size, log->batch.bk, INFINITE, 0, &log->batch.size)) {
+            if(!EvtNext(log->hQuery, size, log->batch.hEvents, INFINITE, 0, &log->batch.size)) {
                 err = GetLastError();
                 if(err == ERROR_NO_MORE_ITEMS)
                     return false; // no data available, return failure
@@ -433,8 +432,8 @@ bool wevt_get_next_event(WEVT_LOG *log, WEVT_EVENT *ev, bool full) {
             if(!log->batch.size) {
                 if(size == 1) {
                     nd_log(NDLS_COLLECTORS, NDLP_ERR,
-                           "EvtNext() failed, event_query: 0x%lx, size: %zu, extended info: %s",
-                           (uintptr_t)log->event_query, (size_t)size, wevt_extended_status());
+                           "EvtNext() failed, hQuery: 0x%lx, size: %zu, extended info: %s",
+                           (uintptr_t)log->hQuery, (size_t)size, wevt_extended_status());
                     return false;
                 }
 
@@ -452,8 +451,8 @@ bool wevt_get_next_event(WEVT_LOG *log, WEVT_EVENT *ev, bool full) {
         // cleanup any previous event data
         wevt_event_done(log);
 
-        log->bookmark = log->batch.bk[log->batch.used];
-        log->batch.bk[log->batch.used] = NULL;
+        log->hEvent = log->batch.hEvents[log->batch.used];
+        log->batch.hEvents[log->batch.used] = NULL;
         log->batch.used++;
 
         if(wevt_get_next_event_one(log, ev, full))
@@ -469,22 +468,22 @@ bool wevt_get_next_event(WEVT_LOG *log, WEVT_EVENT *ev, bool full) {
 }
 
 void wevt_query_done(WEVT_LOG *log) {
-    // close the last working bookmark
+    // close the last working hEvent
     wevt_event_done(log);
 
-    // close all batched bookmarks
+    // close all batched hEvents
     for(DWORD i = log->batch.used; i < log->batch.size ;i++) {
-        if(log->batch.bk[i])
-            EvtClose(log->batch.bk[i]);
+        if(log->batch.hEvents[i])
+            EvtClose(log->batch.hEvents[i]);
 
-        log->batch.bk[i] = NULL;
+        log->batch.hEvents[i] = NULL;
     }
     log->batch.used = 0;
     log->batch.size = 0;
 
-    if (log->event_query) {
-        EvtClose(log->event_query);
-        log->event_query = NULL;
+    if (log->hQuery) {
+        EvtClose(log->hQuery);
+        log->hQuery = NULL;
     }
 
     log->query_stats.event_count = 0;
@@ -494,8 +493,8 @@ void wevt_query_done(WEVT_LOG *log) {
 void wevt_closelog6(WEVT_LOG *log) {
     wevt_query_done(log);
 
-    if (log->render_context)
-        EvtClose(log->render_context);
+    if (log->hRenderContext)
+        EvtClose(log->hRenderContext);
 
     wevt_variant_cleanup(&log->ops.content);
     txt_unicode_cleanup(&log->ops.unicode);
@@ -514,7 +513,7 @@ void wevt_closelog6(WEVT_LOG *log) {
     freez(log);
 }
 
-bool wevt_channel_retention(WEVT_LOG *log, const wchar_t *channel, EVT_RETENTION *retention) {
+bool wevt_channel_retention(WEVT_LOG *log, const wchar_t *channel, const wchar_t *query, EVT_RETENTION *retention) {
     bool ret = false;
 
     // get the number of the oldest record in the log
@@ -522,8 +521,8 @@ bool wevt_channel_retention(WEVT_LOG *log, const wchar_t *channel, EVT_RETENTION
     // we have to get it from the first EventRecordID
 
     // query the eventlog
-    log->event_query = EvtQuery(NULL, channel, NULL, EvtQueryChannelPath | EvtQueryForwardDirection);
-    if (!log->event_query) {
+    log->hQuery = EvtQuery(NULL, channel, query, EvtQueryChannelPath | EvtQueryForwardDirection | EvtQueryTolerateQueryErrors);
+    if (!log->hQuery) {
         if (GetLastError() == ERROR_EVT_CHANNEL_NOT_FOUND)
             nd_log(NDLS_COLLECTORS, NDLP_ERR, "EvtQuery() for retention failed, channel '%s' not found, cannot get retention, extended info: %s",
                    channel2utf8(channel), wevt_extended_status());
@@ -543,10 +542,10 @@ bool wevt_channel_retention(WEVT_LOG *log, const wchar_t *channel, EVT_RETENTION
         ret = true;
         goto cleanup;
     }
-    EvtClose(log->event_query);
+    EvtClose(log->hQuery);
 
-    log->event_query = EvtQuery(NULL, channel, NULL, EvtQueryChannelPath | EvtQueryReverseDirection);
-    if (!log->event_query) {
+    log->hQuery = EvtQuery(NULL, channel, query, EvtQueryChannelPath | EvtQueryReverseDirection | EvtQueryTolerateQueryErrors);
+    if (!log->hQuery) {
         if (GetLastError() == ERROR_EVT_CHANNEL_NOT_FOUND)
             nd_log(NDLS_COLLECTORS, NDLP_ERR, "EvtQuery() for retention failed, channel '%s' not found, extended info: %s",
                    channel2utf8(channel), wevt_extended_status());
@@ -568,7 +567,7 @@ cleanup:
     wevt_query_done(log);
 
     if(ret) {
-        retention->entries = retention->last_event.id - retention->first_event.id;
+        retention->entries = (channel && !query) ? retention->last_event.id - retention->first_event.id : 0;
 
         if(retention->last_event.created_ns >= retention->first_event.created_ns)
             retention->duration_ns = retention->last_event.created_ns - retention->first_event.created_ns;
@@ -589,8 +588,8 @@ WEVT_LOG *wevt_openlog6(void) {
     WEVT_LOG *log = callocz(1, sizeof(*log));
 
     // create the system render
-    log->render_context = EvtCreateRenderContext(RENDER_ITEMS_count, RENDER_ITEMS, EvtRenderContextValues);
-    if (!log->render_context) {
+    log->hRenderContext = EvtCreateRenderContext(RENDER_ITEMS_count, RENDER_ITEMS, EvtRenderContextValues);
+    if (!log->hRenderContext) {
         nd_log(NDLS_COLLECTORS, NDLP_ERR, "EvtCreateRenderContext failed, extended info: %s", wevt_extended_status());
         freez(log);
         log = NULL;
@@ -645,6 +644,6 @@ bool wevt_query(WEVT_LOG *log, LPCWSTR channel, LPCWSTR query, EVT_QUERY_FLAGS d
         return false;
     }
 
-    log->event_query = hQuery;
+    log->hQuery = hQuery;
     return true;
 }

+ 9 - 10
src/collectors/windows-events.plugin/windows-events-query.h

@@ -3,7 +3,7 @@
 #ifndef NETDATA_WINDOWS_EVENTS_QUERY_H
 #define NETDATA_WINDOWS_EVENTS_QUERY_H
 
-#include "windows-events.h"
+#include "libnetdata/libnetdata.h"
 
 #define BATCH_NEXT_EVENT 500
 
@@ -45,12 +45,12 @@ typedef struct wevt_log {
     struct {
         DWORD size;
         DWORD used;
-        EVT_HANDLE bk[BATCH_NEXT_EVENT];
+        EVT_HANDLE hEvents[BATCH_NEXT_EVENT];
     } batch;
 
-    EVT_HANDLE bookmark;
-    EVT_HANDLE event_query;
-    EVT_HANDLE render_context;
+    EVT_HANDLE hEvent;
+    EVT_HANDLE hQuery;
+    EVT_HANDLE hRenderContext;
     struct provider_meta_handle *publisher;
 
     struct {
@@ -105,18 +105,17 @@ typedef struct wevt_log {
 WEVT_LOG *wevt_openlog6(void);
 void wevt_closelog6(WEVT_LOG *log);
 
-bool wevt_channel_retention(WEVT_LOG *log, const wchar_t *channel, EVT_RETENTION *retention);
+bool wevt_channel_retention(WEVT_LOG *log, const wchar_t *channel, const wchar_t *query, EVT_RETENTION *retention);
 
 bool wevt_query(WEVT_LOG *log, LPCWSTR channel, LPCWSTR query, EVT_QUERY_FLAGS direction);
 void wevt_query_done(WEVT_LOG *log);
 
 bool wevt_get_next_event(WEVT_LOG *log, WEVT_EVENT *ev, bool full);
 
-bool wevt_get_message_unicode(TXT_UNICODE *unicode, EVT_HANDLE hMetadata, EVT_HANDLE bookmark, DWORD dwMessageId, EVT_FORMAT_MESSAGE_FLAGS flags);
+bool wevt_get_message_unicode(TXT_UNICODE *dst, EVT_HANDLE hMetadata, EVT_HANDLE hEvent, DWORD dwMessageId, EVT_FORMAT_MESSAGE_FLAGS flags);
 
-struct provider_meta_handle;
-bool wevt_get_event_utf8(WEVT_LOG *log, struct provider_meta_handle *p, EVT_HANDLE event_handle, TXT_UTF8 *dst);
-bool wevt_get_xml_utf8(WEVT_LOG *log, struct provider_meta_handle *p, EVT_HANDLE event_handle, TXT_UTF8 *dst);
+bool wevt_get_event_utf8(WEVT_LOG *log, struct provider_meta_handle *p, EVT_HANDLE hEvent, TXT_UTF8 *dst);
+bool wevt_get_xml_utf8(WEVT_LOG *log, struct provider_meta_handle *p, EVT_HANDLE hEvent, TXT_UTF8 *dst);
 
 static inline void wevt_variant_cleanup(WEVT_VARIANT *v) {
     freez(v->data);

+ 233 - 16
src/collectors/windows-events.plugin/windows-events-sources.c

@@ -1,6 +1,141 @@
 // SPDX-License-Identifier: GPL-3.0-or-later
 
-#include "windows-events-sources.h"
+#include "windows-events.h"
+
+//struct {
+//    const char *name;
+//    const wchar_t *query;
+//} custom_queries[] = {
+//    {
+//        .name = "All-Administrative-Events",
+//        .query = L"<QueryList>\n"
+//                 "  <Query Id=\"0\" Path=\"Application\">\n"
+//                 "    <Select Path=\"Application\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Security\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"System\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"HardwareEvents\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Internet Explorer\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Key Management Service\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-AppV-Client/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-AppV-Client/Virtual Applications\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-All-User-Install-Agent/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-AppHost/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-Application Server-Applications/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-AppModel-Runtime/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-AppReadiness/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-AssignedAccess/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-AssignedAccessBroker/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-Storage-ATAPort/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-BitLocker-DrivePreparationTool/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Client-Licensing-Platform/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-DataIntegrityScan/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-DataIntegrityScan/CrashRecovery\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-DSC/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-DeviceManagement-Enterprise-Diagnostics-Provider/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-DeviceManagement-Enterprise-Diagnostics-Provider/Autopilot\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-DeviceSetupManager/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-Dhcp-Client/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-Dhcpv6-Client/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-Diagnosis-Scripted/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-Storage-Disk/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-DxgKrnl-Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-EDP-Application-Learning/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-EDP-Audit-Regular/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-EDP-Audit-TCB/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Client-License-Flexible-Platform/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-GenericRoaming/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-Hyper-V-Guest-Drivers/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-Hyper-V-Hypervisor-Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-Hyper-V-VID-Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-Kernel-EventTracing/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-KeyboardFilter/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-ModernDeployment-Diagnostics-Provider/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-ModernDeployment-Diagnostics-Provider/Autopilot\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-ModernDeployment-Diagnostics-Provider/Diagnostics\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-ModernDeployment-Diagnostics-Provider/ManagementService\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-MUI/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-PowerShell/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-PrintBRM/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-PrintService/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-Provisioning-Diagnostics-Provider/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-Provisioning-Diagnostics-Provider/AutoPilot\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-Provisioning-Diagnostics-Provider/ManagementService\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-PushNotification-Platform/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-RemoteApp and Desktop Connections/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-RemoteAssistance/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-RetailDemo/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-SecurityMitigationsBroker/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-SmartCard-TPM-VCard-Module/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-SMBDirect/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-SMBWitnessClient/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-Storage-Tiering/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-Storage-ClassPnP/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-Storage-Storport/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-ClientUSBDevices/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-LocalSessionManager/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-PnPDevices/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-Printers/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-RemoteConnectionManager/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-ServerUSBDevices/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-Troubleshooting-Recommended/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-User Device Registration/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-VerifyHardwareSecurity/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-WindowsBackup/ActionCenter\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-Workplace Join/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"OAlerts\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"OneApp_IGCC\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"OpenSSH/Admin\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"USER_ESRV_SVC_QUEENCREEK\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Visual Studio\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "    <Select Path=\"Windows PowerShell\">*[System[(Level=1  or Level=2 or Level=3)]]</Select>\n"
+//                 "  </Query>\n"
+//                 "</QueryList>",
+//    },
+//    {
+//        .name = "All-Remote-Desktop-Services",
+//        .query = L"<QueryList>\n"
+//                 "  <Query Id=\"0\" Path=\"Microsoft-Rdms-UI/Admin\">\n"
+//                 "    <Select Path=\"Microsoft-Rdms-UI/Admin\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Rdms-UI/Operational\">*</Select>\n"
+//                 "    <Select Path=\"Remote-Desktop-Management-Service/Admin\">*</Select>\n"
+//                 "    <Select Path=\"Remote-Desktop-Management-Service/Operational\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-SessionBroker-Client/Admin\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-SessionBroker-Client/Operational\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-RemoteConnectionManager/Admin\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-PnPDevices/Admin\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-PnPDevices/Operational\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-RemoteApp and Desktop Connections/Admin\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-RemoteApp and Desktop Connection Management/Admin\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-RemoteApp and Desktop Connection Management/Operational\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-SessionBroker/Admin\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-SessionBroker/Operational\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-TSV-VmHostAgent/Operational\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-TSV-VmHostAgent/Admin\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-ServerUSBDevices/Operational\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-ServerUSBDevices/Admin\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-LocalSessionManager/Operational\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-LocalSessionManager/Admin\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-ClientUSBDevices/Operational\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-ClientUSBDevices/Admin\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-RDPClient/Operational\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-Licensing/Admin\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-Licensing/Operational\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-Gateway/Admin\">*</Select>\n"
+//                 "    <Select Path=\"Microsoft-Windows-TerminalServices-Gateway/Operational\">*</Select>\n"
+//                 "  </Query>\n"
+//                 "</QueryList>",
+//    },
+//    {
+//        .name = "All-Security-SPP",
+//        .query = L"<QueryList>\n"
+//                 "  <Query Id=\"0\" Path=\"Microsoft-Windows-HelloForBusiness/Operational\">\n"
+//                 "    <Select Path=\"Microsoft-Windows-HelloForBusiness/Operational\">*[System[(Level&gt;5 )]]</Select>\n"
+//                 "  </Query>\n"
+//                 "</QueryList>",
+//    }
+//};
 
 DICTIONARY *wevt_sources = NULL;
 DICTIONARY *used_hashes_registry = NULL;
@@ -22,6 +157,15 @@ WEVT_SOURCE_TYPE wevt_internal_source_type(const char *value) {
     if(strcmp(value, WEVT_SOURCE_ALL_DEBUG_NAME) == 0)
         return WEVTS_DEBUG;
 
+    if(strcmp(value, WEVT_SOURCE_ALL_DIAGNOSTIC_NAME) == 0)
+        return WEVTS_DIAGNOSTIC;
+
+    if(strcmp(value, WEVT_SOURCE_ALL_TRACING_NAME) == 0)
+        return WEVTS_TRACING;
+
+    if(strcmp(value, WEVT_SOURCE_ALL_PERFORMANCE_NAME) == 0)
+        return WEVTS_PERFORMANCE;
+
     if(strcmp(value, WEVT_SOURCE_ALL_WINDOWS_NAME) == 0)
         return WEVTS_WINDOWS;
 
@@ -125,6 +269,7 @@ struct wevt_source {
     usec_t first_ut;
     usec_t last_ut;
     size_t count;
+    size_t entries;
     uint64_t size;
 };
 
@@ -143,9 +288,13 @@ static int wevt_source_to_json_array_cb(const DICTIONARY_ITEM *item, void *entry
         duration_snprintf(duration_for_humans, sizeof(duration_for_humans),
                           (time_t)((s->last_ut - s->first_ut) / USEC_PER_SEC), "s", true);
 
+        char entries_for_humans[128];
+        entries_snprintf(entries_for_humans, sizeof(entries_for_humans), s->entries, "", false);
+
         char info[1024];
-        snprintfz(info, sizeof(info), "%zu channel%s, with a total size of %s, covering %s",
-                s->count, s->count > 1 ? "s":"", size_for_humans, duration_for_humans);
+        snprintfz(info, sizeof(info), "%zu channel%s, with a total size of %s, covering %s%s%s%s",
+                s->count, s->count > 1 ? "s":"", size_for_humans, duration_for_humans,
+                s->entries ? ", having " : "", s->entries ? entries_for_humans : "", s->entries ? " entries" : "");
 
         buffer_json_member_add_string(wb, "id", name);
         buffer_json_member_add_string(wb, "name", name);
@@ -163,6 +312,7 @@ static bool wevt_source_merge_sizes(const DICTIONARY_ITEM *item __maybe_unused,
 
     old_v->count += new_v->count;
     old_v->size += new_v->size;
+    old_v->entries += new_v->entries;
 
     if(new_v->first_ut && new_v->first_ut < old_v->first_ut)
         old_v->first_ut = new_v->first_ut;
@@ -185,6 +335,7 @@ void wevt_sources_to_json_array(BUFFER *wb) {
         t.last_ut = src->msg_last_ut;
         t.count = 1;
         t.size = src->size;
+        t.entries = src->entries;
 
         dictionary_set(dict, WEVT_SOURCE_ALL_NAME, &t, sizeof(t));
 
@@ -200,6 +351,15 @@ void wevt_sources_to_json_array(BUFFER *wb) {
         if(src->source_type & WEVTS_DEBUG)
             dictionary_set(dict, WEVT_SOURCE_ALL_DEBUG_NAME, &t, sizeof(t));
 
+        if(src->source_type & WEVTS_DIAGNOSTIC)
+            dictionary_set(dict, WEVT_SOURCE_ALL_DIAGNOSTIC_NAME, &t, sizeof(t));
+
+        if(src->source_type & WEVTS_TRACING)
+            dictionary_set(dict, WEVT_SOURCE_ALL_TRACING_NAME, &t, sizeof(t));
+
+        if(src->source_type & WEVTS_PERFORMANCE)
+            dictionary_set(dict, WEVT_SOURCE_ALL_PERFORMANCE_NAME, &t, sizeof(t));
+
         if(src->source_type & WEVTS_WINDOWS)
             dictionary_set(dict, WEVT_SOURCE_ALL_WINDOWS_NAME, &t, sizeof(t));
 
@@ -211,6 +371,29 @@ void wevt_sources_to_json_array(BUFFER *wb) {
     dictionary_sorted_walkthrough_read(dict, wevt_source_to_json_array_cb, wb);
 }
 
+static bool check_and_remove_suffix(char *name, size_t len, const char *suffix) {
+    char s[strlen(suffix) + 2];
+    s[0] = '/';
+    memcpy(&s[1], suffix, sizeof(s) - 1);
+    size_t slen = sizeof(s) - 1;
+
+    if(slen + 1 >= len) return false;
+
+    char *match = &name[len - slen];
+    if(strcasecmp(match, s) == 0) {
+        *match = '\0';
+        return true;
+    }
+
+    s[0] = '-';
+    if(strcasecmp(match, s) == 0) {
+        *match = '\0';
+        return true;
+    }
+
+    return false;
+}
+
 void wevt_sources_scan(void) {
     static SPINLOCK spinlock = NETDATA_SPINLOCK_INITIALIZER;
     LPWSTR channel = NULL;
@@ -252,24 +435,35 @@ void wevt_sources_scan(void) {
             }
 
             EVT_RETENTION retention;
-            if(!wevt_channel_retention(log, channel, &retention))
+            if(!wevt_channel_retention(log, channel, NULL, &retention))
                 continue;
 
             const char *name = channel2utf8(channel);
             const char *fullname = strdupz(name);
-            char *slash = strchr(name, '/');
+
             WEVT_SOURCE_TYPE sources = WEVTS_ALL;
-            if(slash) {
-                *slash++ = '\0';
-                if(strcasecmp(slash, "Admin") == 0)
-                    sources |= WEVTS_ADMIN;
-                if(strcasecmp(slash, "Operational") == 0)
-                    sources |= WEVTS_OPERATIONAL;
-                if(strcasecmp(slash, "Analytic") == 0)
-                    sources |= WEVTS_ANALYTIC;
-                if(strcasecmp(slash, "Debug") == 0)
-                    sources |= WEVTS_DEBUG;
-            }
+            size_t len = strlen(fullname);
+            if(check_and_remove_suffix((char *)name, len, "Admin"))
+                sources |= WEVTS_ADMIN;
+            else if(check_and_remove_suffix((char *)name, len, "Operational"))
+                sources |= WEVTS_OPERATIONAL;
+            else if(check_and_remove_suffix((char *)name, len, "Analytic"))
+                sources |= WEVTS_ANALYTIC;
+            else if(check_and_remove_suffix((char *)name, len, "Debug") ||
+                    check_and_remove_suffix((char *)name, len, "Verbose"))
+                sources |= WEVTS_DEBUG;
+            else if(check_and_remove_suffix((char *)name, len, "Diagnostic"))
+                sources |= WEVTS_DIAGNOSTIC;
+            else if(check_and_remove_suffix((char *)name, len, "Trace") ||
+                    check_and_remove_suffix((char *)name, len, "Tracing"))
+                sources |= WEVTS_TRACING;
+            else if(check_and_remove_suffix((char *)name, len, "Performance") ||
+                    check_and_remove_suffix((char *)name, len, "Perf"))
+                sources |= WEVTS_PERFORMANCE;
+
+            char *slash = strchr(name, '/');
+            if(slash)
+                *slash = '\0';
 
             if(strcasecmp(name, "Application") == 0)
                 sources |= WEVTS_WINDOWS;
@@ -297,6 +491,29 @@ void wevt_sources_scan(void) {
             dictionary_set(wevt_sources, src.fullname, &src, sizeof(src));
         }
 
+//        // add custom queries
+//        for(size_t i = 0; i < sizeof(custom_queries) / sizeof(custom_queries[0]) ;i++) {
+//            EVT_RETENTION retention;
+//            if(!wevt_channel_retention(log, NULL, custom_queries[i].query, &retention))
+//                continue;
+//
+//            LOGS_QUERY_SOURCE src = {
+//                    .entries = 0,
+//                    .fullname = strdupz(custom_queries[i].name),
+//                    .fullname_len = strlen(custom_queries[i].name),
+//                    .last_scan_monotonic_ut = now_monotonic_usec(),
+//                    .msg_first_id = retention.first_event.id,
+//                    .msg_last_id = retention.last_event.id,
+//                    .msg_first_ut = retention.first_event.created_ns / NSEC_PER_USEC,
+//                    .msg_last_ut = retention.last_event.created_ns / NSEC_PER_USEC,
+//                    .size = retention.size_bytes,
+//                    .source_type = WEVTS_ALL,
+//                    .source = string_strdupz(custom_queries[i].name),
+//            };
+//
+//            dictionary_set(wevt_sources, src.fullname, &src, sizeof(src));
+//        }
+//
         wevt_closelog6(log);
 
         LOGS_QUERY_SOURCE *src;

+ 10 - 2
src/collectors/windows-events.plugin/windows-events-sources.h

@@ -3,7 +3,7 @@
 #ifndef NETDATA_WINDOWS_EVENTS_SOURCES_H
 #define NETDATA_WINDOWS_EVENTS_SOURCES_H
 
-#include "windows-events.h"
+#include "libnetdata/libnetdata.h"
 
 typedef enum {
     WEVTS_NONE               = 0,
@@ -12,13 +12,18 @@ typedef enum {
     WEVTS_OPERATIONAL        = (1 << 2),
     WEVTS_ANALYTIC           = (1 << 3),
     WEVTS_DEBUG              = (1 << 4),
-    WEVTS_WINDOWS            = (1 << 5),
+    WEVTS_DIAGNOSTIC         = (1 << 5),
+    WEVTS_TRACING            = (1 << 6),
+    WEVTS_PERFORMANCE        = (1 << 7),
+    WEVTS_WINDOWS            = (1 << 8),
 } WEVT_SOURCE_TYPE;
 
 typedef struct {
     const char *fullname;
     size_t fullname_len;
 
+    const wchar_t *custom_query;
+
     STRING *source;
     WEVT_SOURCE_TYPE source_type;
     usec_t msg_first_ut;
@@ -40,6 +45,9 @@ extern DICTIONARY *used_hashes_registry;
 #define WEVT_SOURCE_ALL_OPERATIONAL_NAME    "All-Operational"
 #define WEVT_SOURCE_ALL_ANALYTIC_NAME       "All-Analytic"
 #define WEVT_SOURCE_ALL_DEBUG_NAME          "All-Debug"
+#define WEVT_SOURCE_ALL_DIAGNOSTIC_NAME     "All-Diagnostic"
+#define WEVT_SOURCE_ALL_TRACING_NAME        "All-Tracing"
+#define WEVT_SOURCE_ALL_PERFORMANCE_NAME    "All-Performance"
 #define WEVT_SOURCE_ALL_WINDOWS_NAME        "All-Windows"
 
 void wevt_sources_init(void);

+ 17 - 18
src/collectors/windows-events.plugin/windows-events-unicode.c

@@ -41,7 +41,7 @@ char *unicode2utf8_strdupz(const wchar_t *src, size_t *utf8_len) {
 
 wchar_t *channel2unicode(const char *utf8str) {
     static __thread wchar_t buffer[1024];
-    utf82unicode(buffer, sizeof(buffer) / sizeof(buffer[0]), utf8str);
+    utf82unicode(buffer, sizeof(buffer) / sizeof(wchar_t), utf8str);
     return buffer;
 }
 
@@ -69,7 +69,7 @@ char *query2utf8(const wchar_t *query) {
     return buffer;
 }
 
-bool wevt_str_wchar_to_utf8(TXT_UTF8 *utf8, const wchar_t *src, int src_len_with_null) {
+bool wevt_str_wchar_to_utf8(TXT_UTF8 *dst, const wchar_t *src, int src_len_with_null) {
     if(!src || !src_len_with_null)
         goto cleanup;
 
@@ -78,11 +78,11 @@ bool wevt_str_wchar_to_utf8(TXT_UTF8 *utf8, const wchar_t *src, int src_len_with
     fatal_assert(src_len_with_null == -1 || (src_len_with_null >= 1 && src[src_len_with_null - 1] == 0));
 
     // Try to convert using the existing buffer (if it exists, otherwise get the required buffer size)
-    int size = WideCharToMultiByte(CP_UTF8, 0, src, src_len_with_null, utf8->data, (int)utf8->size, NULL, NULL);
-    if(size <= 0 || !utf8->data) {
+    int size = WideCharToMultiByte(CP_UTF8, 0, src, src_len_with_null, dst->data, (int)dst->size, NULL, NULL);
+    if(size <= 0 || !dst->data) {
         // we have to set a buffer, or increase it
 
-        if(utf8->data) {
+        if(dst->data) {
             // we need to increase it the buffer size
 
             if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
@@ -97,8 +97,8 @@ bool wevt_str_wchar_to_utf8(TXT_UTF8 *utf8, const wchar_t *src, int src_len_with
         }
 
         // Retry conversion with the new buffer
-        txt_utf8_resize(utf8, size, false);
-        size = WideCharToMultiByte(CP_UTF8, 0, src, src_len_with_null, utf8->data, (int)utf8->size, NULL, NULL);
+        txt_utf8_resize(dst, size, false);
+        size = WideCharToMultiByte(CP_UTF8, 0, src, src_len_with_null, dst->data, (int)dst->size, NULL, NULL);
         if (size <= 0) {
             nd_log(NDLS_COLLECTORS, NDLP_ERR, "WideCharToMultiByte() failed after resizing.");
             goto cleanup;
@@ -106,34 +106,33 @@ bool wevt_str_wchar_to_utf8(TXT_UTF8 *utf8, const wchar_t *src, int src_len_with
     }
 
     // Make sure it is not zero padded at the end
-    while(size >= 2 && utf8->data[size - 2] == 0)
+    while(size >= 2 && dst->data[size - 2] == 0)
         size--;
 
-    utf8->used = (size_t)size;
+    dst->used = (size_t)size;
 
-    internal_fatal(strlen(utf8->data) + 1 != utf8->used,
+    internal_fatal(strlen(dst->data) + 1 != dst->used,
                    "Wrong UTF8 string length");
 
     return true;
 
 cleanup:
-    txt_utf8_resize(utf8, 128, false);
+    txt_utf8_resize(dst, 128, false);
     if(src)
-        utf8->used = snprintfz(utf8->data, utf8->size, "[failed conv.]") + 1;
+        dst->used = snprintfz(dst->data, dst->size, "[failed conv.]") + 1;
     else {
-        utf8->data[0] = '\0';
-        utf8->used = 1;
+        dst->data[0] = '\0';
+        dst->used = 1;
     }
 
     return false;
 }
 
-bool wevt_str_unicode_to_utf8(TXT_UTF8 *utf8, TXT_UNICODE *unicode) {
-    fatal_assert(utf8 && ((utf8->data && utf8->size) || (!utf8->data && !utf8->size)));
+bool wevt_str_unicode_to_utf8(TXT_UTF8 *dst, TXT_UNICODE *unicode) {
+    fatal_assert(dst && ((dst->data && dst->size) || (!dst->data && !dst->size)));
     fatal_assert(unicode && ((unicode->data && unicode->size) || (!unicode->data && !unicode->size)));
 
     // pass the entire unicode size, including the null terminator
     // so that the resulting utf8 message will be null terminated too.
-    return wevt_str_wchar_to_utf8(utf8, unicode->data, (int)unicode->used);
+    return wevt_str_wchar_to_utf8(dst, unicode->data, (int)unicode->used);
 }
-

Некоторые файлы не были показаны из-за большого количества измененных файлов