@cryptotaxi247 / netdata-1 / commits / 0693b018b

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 committed Sep 18, 2024 at 00:04 UTC 0693b018b8489d9cad528821d18a185066b6ca03
19 files changed +1022 -528
CMakeLists.txt
+4
@@ -794,6 +794,8 @@ set(LIBNETDATA_FILES
794 src/libnetdata/facets/logs_query_status.h
795 src/libnetdata/os/timestamps.c
796 src/libnetdata/os/timestamps.h
797 + src/libnetdata/parsers/entries.c
798 + src/libnetdata/parsers/entries.h
799 )
800
801 if(ENABLE_PLUGIN_EBPF)
@@ -1415,6 +1417,8 @@ set(WINDOWS_EVENTS_PLUGIN_FILES
1417 src/collectors/windows-events.plugin/windows-events-publishers.h
1418 src/collectors/windows-events.plugin/windows-events-fields-cache.c
1419 src/collectors/windows-events.plugin/windows-events-fields-cache.h
1420 + src/collectors/windows-events.plugin/windows-events-query-builder.c
1421 + src/collectors/windows-events.plugin/windows-events-query-builder.h
1422 )
1423
1424 set(WINDOWS_PLUGIN_FILES
src/collectors/systemd-journal.plugin/systemd-main.c
+1 -1
@@ -46,7 +46,7 @@ int main(int argc __maybe_unused, char **argv __maybe_unused) {
46
47 bool cancelled = false;
48 usec_t stop_monotonic_ut = now_monotonic_usec() + 600 * USEC_PER_SEC;
49 - // char buf[] = "systemd-journal after:-8640000 before:0 direction:backward last:200 data_only:false slice:true source:all";
49 + // 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";
50 char buf[] = "systemd-journal after:-8640000 before:0 direction:backward last:200 data_only:false slice:true facets: source:all";
51 // char buf[] = "systemd-journal after:1695332964 before:1695937764 direction:backward last:100 slice:true source:all DHKucpqUoe1:PtVoyIuX.MU";
52 // char buf[] = "systemd-journal after:1694511062 before:1694514662 anchor:1694514122024403";
src/collectors/windows-events.plugin/windows-events-publishers.c
+5 -6
@@ -68,7 +68,7 @@ static struct {
68 .spinlock = NETDATA_SPINLOCK_INITIALIZER,
69 };
70
71 -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);
71 +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);
72
73 static inline ND_UUID *publisher_value_to_key(PUBLISHER *p) {
74 return &p->uuid;
@@ -253,7 +253,7 @@ static int compare_ascending(const void *a, const void *b) {
253 // return 0;
254 //}
255
256 -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) {
256 +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) {
257 if(!h || !h->hMetadata) return;
258
259 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,
375 uint32_t messageID = wevt_field_get_uint32(property->data);
376
377 if (messageID != (uint32_t)-1) {
378 - if (wevt_get_message_unicode(unicode, hMetadata, NULL, messageID, EvtFormatMessageId)) {
378 + if (wevt_get_message_unicode(dst, hMetadata, NULL, messageID, EvtFormatMessageId)) {
379 size_t len;
380 - d->name = unicode2utf8_strdupz(unicode->data, &len);
380 + d->name = unicode2utf8_strdupz(dst->data, &len);
381 d->len = len;
382 }
383 }
@@ -450,7 +450,7 @@ static bool publisher_bitmap_metadata(TXT_UTF8 *dst, struct provider_list *l, ui
450 }
451 }
452
453 - if(dst->used) {
453 + if(dst->used > 1) {
454 txt_utf8_resize(dst, dst->used + 1, true);
455 dst->data[dst->used++] = 0;
456 }
@@ -533,7 +533,6 @@ static bool publisher_value_metadata(TXT_UTF8 *dst, struct provider_list *l, uin
533 }
534
535 fatal_assert(dst->used <= dst->size);
536 -
536 return (dst->used > 0);
537 }
538
src/collectors/windows-events.plugin/windows-events-query-builder.c new
+107
@@ -0,0 +1,107 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "windows-events-query-builder.h"
4 +
5 +// --------------------------------------------------------------------------------------------------------------------
6 +// query without XPath
7 +
8 +typedef struct static_utf8_8k {
9 + char buffer[8192];
10 + size_t size;
11 + size_t len;
12 +} STATIC_BUF_8K;
13 +
14 +typedef struct static_unicode_16k {
15 + wchar_t buffer[16384];
16 + size_t size;
17 + size_t len;
18 +} STATIC_UNI_16K;
19 +
20 +static bool wevt_foreach_selected_value_cb(FACETS *facets __maybe_unused, size_t id, const char *key, const char *value, void *data) {
21 + STATIC_BUF_8K *b = data;
22 +
23 + b->len += snprintfz(&b->buffer[b->len], b->size - b->len,
24 + "%s%s=%s",
25 + id ? " or " : "", key, value);
26 +
27 + return b->len < b->size;
28 +}
29 +
30 +wchar_t *wevt_generate_query_no_xpath(LOGS_QUERY_STATUS *lqs, BUFFER *wb) {
31 + static __thread STATIC_UNI_16K q = {
32 + .size = sizeof(q.buffer) / sizeof(wchar_t),
33 + .len = 0,
34 + };
35 + static __thread STATIC_BUF_8K b = {
36 + .size = sizeof(b.buffer) / sizeof(char),
37 + .len = 0,
38 + };
39 +
40 + lqs_query_timeframe(lqs, ANCHOR_DELTA_UT);
41 +
42 + usec_t seek_to = lqs->query.start_ut;
43 + if(lqs->rq.direction == FACETS_ANCHOR_DIRECTION_BACKWARD)
44 + // windows events queries are limited to millisecond resolution
45 + // so, in order not to lose data, we have to add
46 + // a millisecond when the direction is backward
47 + seek_to += USEC_PER_MS;
48 +
49 + // Convert the microseconds since Unix epoch to FILETIME (used in Windows APIs)
50 + FILETIME fileTime = os_unix_epoch_ut_to_filetime(seek_to);
51 +
52 + // Convert FILETIME to SYSTEMTIME for use in XPath
53 + SYSTEMTIME systemTime;
54 + if (!FileTimeToSystemTime(&fileTime, &systemTime)) {
55 + nd_log(NDLS_COLLECTORS, NDLP_ERR, "FileTimeToSystemTime() failed");
56 + return NULL;
57 + }
58 +
59 + // Format SYSTEMTIME into ISO 8601 format (YYYY-MM-DDTHH:MM:SS.sssZ)
60 + q.len = swprintf(q.buffer, q.size,
61 + L"Event/System[TimeCreated[@SystemTime%ls\"%04d-%02d-%02dT%02d:%02d:%02d.%03dZ\"]",
62 + lqs->rq.direction == FACETS_ANCHOR_DIRECTION_BACKWARD ? L"<=" : L">=",
63 + systemTime.wYear, systemTime.wMonth, systemTime.wDay,
64 + systemTime.wHour, systemTime.wMinute, systemTime.wSecond, systemTime.wMilliseconds);
65 +
66 + if(lqs->rq.slice) {
67 + b.len = snprintf(b.buffer, b.size, " and (");
68 + if (facets_foreach_selected_value_in_key(
69 + lqs->facets,
70 + WEVT_FIELD_LEVEL,
71 + sizeof(WEVT_FIELD_LEVEL) - 1,
72 + used_hashes_registry,
73 + wevt_foreach_selected_value_cb,
74 + &b)) {
75 + b.len += snprintf(&b.buffer[b.len], b.size - b.len, ")");
76 + if (b.len < b.size) {
77 + utf82unicode(&q.buffer[q.len], q.size - q.len, b.buffer);
78 + q.len = wcslen(q.buffer);
79 + }
80 + }
81 +
82 + b.len = snprintf(b.buffer, b.size, " and (");
83 + if (facets_foreach_selected_value_in_key(
84 + lqs->facets,
85 + WEVT_FIELD_EVENTID,
86 + sizeof(WEVT_FIELD_EVENTID) - 1,
87 + used_hashes_registry,
88 + wevt_foreach_selected_value_cb,
89 + &b)) {
90 + b.len += snprintf(&b.buffer[b.len], b.size - b.len, ")");
91 + if (b.len < b.size) {
92 + utf82unicode(&q.buffer[q.len], q.size - q.len, b.buffer);
93 + q.len = wcslen(q.buffer);
94 + }
95 + }
96 + }
97 +
98 + q.len += swprintf(&q.buffer[q.len], q.size - q.len, L"]");
99 +
100 + buffer_json_member_add_string(wb, "_query", channel2utf8(q.buffer));
101 +
102 + return q.buffer;
103 +}
104 +
105 +// --------------------------------------------------------------------------------------------------------------------
106 +// query with XPath
107 +
src/collectors/windows-events.plugin/windows-events-query-builder.h new
+10
@@ -0,0 +1,10 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_WINDOWS_EVENTS_QUERY_BUILDER_H
4 +#define NETDATA_WINDOWS_EVENTS_QUERY_BUILDER_H
5 +
6 +#include "windows-events.h"
7 +
8 +wchar_t *wevt_generate_query_no_xpath(LOGS_QUERY_STATUS *lqs, BUFFER *wb);
9 +
10 +#endif //NETDATA_WINDOWS_EVENTS_QUERY_BUILDER_H
src/collectors/windows-events.plugin/windows-events-query.c
+90 -91
@@ -1,6 +1,6 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 -#include "windows-events-query.h"
3 +#include "windows-events.h"
4
5 static uint64_t wevt_log_file_size(const wchar_t *channel);
6
@@ -62,69 +62,70 @@ static const char *wevt_extended_status(void) {
62 return buf;
63 }
64
65 -bool wevt_get_message_unicode(TXT_UNICODE *unicode, EVT_HANDLE hMetadata, EVT_HANDLE bookmark, DWORD dwMessageId, EVT_FORMAT_MESSAGE_FLAGS flags) {
66 - unicode->used = 0;
65 +bool wevt_get_message_unicode(TXT_UNICODE *dst, EVT_HANDLE hMetadata, EVT_HANDLE hEvent, DWORD dwMessageId, EVT_FORMAT_MESSAGE_FLAGS flags) {
66 + dst->used = 0;
67
68 DWORD size = 0;
69 - if(!unicode->data) {
70 - EvtFormatMessage(hMetadata, bookmark, dwMessageId, 0, NULL, flags, 0, NULL, &size);
69 + if(!dst->data) {
70 + EvtFormatMessage(hMetadata, hEvent, dwMessageId, 0, NULL, flags, 0, NULL, &size);
71 if(!size) {
72 // nd_log(NDLS_COLLECTORS, NDLP_ERR, "EvtFormatMessage() to get message size failed.");
73 goto cleanup;
74 }
75 - txt_unicode_resize(unicode, size);
75 + txt_unicode_resize(dst, size, false);
76 }
77
78 // First, try to get the message using the existing buffer
79 - if (!EvtFormatMessage(hMetadata, bookmark, dwMessageId, 0, NULL, flags, unicode->size, unicode->data, &size) || !unicode->data) {
80 - if (unicode->data && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
79 + if (!EvtFormatMessage(hMetadata, hEvent, dwMessageId, 0, NULL, flags, dst->size, dst->data, &size) || !dst->data) {
80 + if (dst->data && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
81 // nd_log(NDLS_COLLECTORS, NDLP_ERR, "EvtFormatMessage() failed.");
82 goto cleanup;
83 }
84
85 // Try again with the resized buffer
86 - txt_unicode_resize(unicode, size);
87 - if (!EvtFormatMessage(hMetadata, bookmark, dwMessageId, 0, NULL, flags, unicode->size, unicode->data, &size)) {
86 + txt_unicode_resize(dst, size, false);
87 + if (!EvtFormatMessage(hMetadata, hEvent, dwMessageId, 0, NULL, flags, dst->size, dst->data, &size)) {
88 // nd_log(NDLS_COLLECTORS, NDLP_ERR, "EvtFormatMessage() failed after resizing buffer.");
89 goto cleanup;
90 }
91 }
92
93 // make sure it is null terminated
94 - if(size <= unicode->size)
95 - unicode->data[size - 1] = 0;
94 + if(size <= dst->size)
95 + dst->data[size - 1] = 0;
96 else
97 - unicode->data[unicode->size - 1] = 0;
97 + dst->data[dst->size - 1] = 0;
98
99 // unfortunately we have to calculate the length every time
100 - // the size returned may not be the length of the unicode string
101 - unicode->used = wcslen(unicode->data) + 1;
100 + // the size returned may not be the length of the dst string
101 + dst->used = wcslen(dst->data) + 1;
102 +
103 return true;
104
105 cleanup:
105 - unicode->used = 0;
106 + dst->used = 0;
107 return false;
108 }
109
110 static bool wevt_get_field_from_events_log(
110 - WEVT_LOG *log, PROVIDER_META_HANDLE *p, EVT_HANDLE event_handle,
111 + WEVT_LOG *log, PROVIDER_META_HANDLE *p, EVT_HANDLE hEvent,
112 TXT_UTF8 *dst, EVT_FORMAT_MESSAGE_FLAGS flags) {
113
114 dst->src = TXT_SOURCE_EVENT_LOG;
115
115 - if(wevt_get_message_unicode(&log->ops.unicode, publisher_handle(p), event_handle, 0, flags))
116 + if(wevt_get_message_unicode(&log->ops.unicode, publisher_handle(p), hEvent, 0, flags))
117 return wevt_str_unicode_to_utf8(dst, &log->ops.unicode);
118
119 wevt_utf8_empty(dst);
120 return false;
121 }
122
122 -bool wevt_get_event_utf8(WEVT_LOG *log, PROVIDER_META_HANDLE *p, EVT_HANDLE event_handle, TXT_UTF8 *dst) {
123 - return wevt_get_field_from_events_log(log, p, event_handle, dst, EvtFormatMessageEvent);
123 +bool wevt_get_event_utf8(WEVT_LOG *log, PROVIDER_META_HANDLE *p, EVT_HANDLE hEvent, TXT_UTF8 *dst) {
124 + return wevt_get_field_from_events_log(log, p, hEvent, dst, EvtFormatMessageEvent);
125 }
126
126 -bool wevt_get_xml_utf8(WEVT_LOG *log, PROVIDER_META_HANDLE *p, EVT_HANDLE event_handle, TXT_UTF8 *dst) {
127 - return wevt_get_field_from_events_log(log, p, event_handle, dst, EvtFormatMessageXml);
127 +bool wevt_get_xml_utf8(WEVT_LOG *log, PROVIDER_META_HANDLE *p, EVT_HANDLE hEvent, TXT_UTF8 *dst) {
128 + return wevt_get_field_from_events_log(log, p, hEvent, dst, EvtFormatMessageXml);
129 }
130
131 static inline void wevt_event_done(WEVT_LOG *log) {
@@ -133,9 +134,9 @@ static inline void wevt_event_done(WEVT_LOG *log) {
134 log->publisher = NULL;
135 }
136
136 - if (log->bookmark) {
137 - EvtClose(log->bookmark);
138 - log->bookmark = NULL;
137 + if (log->hEvent) {
138 + EvtClose(log->hEvent);
139 + log->hEvent = NULL;
140 }
141
142 log->ops.level.src = TXT_SOURCE_UNKNOWN;
@@ -152,7 +153,7 @@ static void wevt_get_field_from_cache(
153 if (field_cache_get(cache_type, provider, value, dst))
154 return;
155
155 - wevt_get_field_from_events_log(log, h, log->bookmark, dst, flags);
156 + wevt_get_field_from_events_log(log, h, log->hEvent, dst, flags);
157 field_cache_set(cache_type, provider, value, dst);
158 }
159
@@ -160,12 +161,12 @@ static void wevt_get_field_from_cache(
161
162 static inline const char *wevt_level_hardcoded(uint64_t level, size_t *len) {
163 switch(level) {
163 - case WINEVENT_LEVEL_NONE: SET_LEN_AND_RETURN(WINEVENT_NAME_NONE);
164 - case WINEVENT_LEVEL_CRITICAL: SET_LEN_AND_RETURN(WINEVENT_NAME_CRITICAL);
165 - case WINEVENT_LEVEL_ERROR: SET_LEN_AND_RETURN(WINEVENT_NAME_ERROR);
166 - case WINEVENT_LEVEL_WARNING: SET_LEN_AND_RETURN(WINEVENT_NAME_WARNING);
167 - case WINEVENT_LEVEL_INFORMATION: SET_LEN_AND_RETURN(WINEVENT_NAME_INFORMATION);
168 - case WINEVENT_LEVEL_VERBOSE: SET_LEN_AND_RETURN(WINEVENT_NAME_VERBOSE);
164 + case WEVT_LEVEL_NONE: SET_LEN_AND_RETURN(WEVT_LEVEL_NAME_NONE);
165 + case WEVT_LEVEL_CRITICAL: SET_LEN_AND_RETURN(WEVT_LEVEL_NAME_CRITICAL);
166 + case WEVT_LEVEL_ERROR: SET_LEN_AND_RETURN(WEVT_LEVEL_NAME_ERROR);
167 + case WEVT_LEVEL_WARNING: SET_LEN_AND_RETURN(WEVT_LEVEL_NAME_WARNING);
168 + case WEVT_LEVEL_INFORMATION: SET_LEN_AND_RETURN(WEVT_LEVEL_NAME_INFORMATION);
169 + case WEVT_LEVEL_VERBOSE: SET_LEN_AND_RETURN(WEVT_LEVEL_NAME_VERBOSE);
170 default: *len = 0; return NULL;
171 }
172 }
@@ -199,22 +200,22 @@ static void wevt_get_level(WEVT_LOG *log, WEVT_EVENT *ev, PROVIDER_META_HANDLE *
200 }
201
202 txt_utf8_set_numeric_if_empty(
202 - dst, WINEVENT_NAME_LEVEL_PREFIX, sizeof(WINEVENT_NAME_LEVEL_PREFIX) - 1, ev->level);
203 + dst, WEVT_PREFIX_LEVEL, sizeof(WEVT_PREFIX_LEVEL) - 1, ev->level);
204 }
205
206 static inline const char *wevt_opcode_hardcoded(uint64_t opcode, size_t *len) {
207 switch(opcode) {
207 - case WINEVENT_OPCODE_INFO: SET_LEN_AND_RETURN(WINEVENT_NAME_INFO);
208 - case WINEVENT_OPCODE_START: SET_LEN_AND_RETURN(WINEVENT_NAME_START);
209 - case WINEVENT_OPCODE_STOP: SET_LEN_AND_RETURN(WINEVENT_NAME_STOP);
210 - case WINEVENT_OPCODE_DC_START: SET_LEN_AND_RETURN(WINEVENT_NAME_DC_START);
211 - case WINEVENT_OPCODE_DC_STOP: SET_LEN_AND_RETURN(WINEVENT_NAME_DC_STOP);
212 - case WINEVENT_OPCODE_EXTENSION: SET_LEN_AND_RETURN(WINEVENT_NAME_EXTENSION);
213 - case WINEVENT_OPCODE_REPLY: SET_LEN_AND_RETURN(WINEVENT_NAME_REPLY);
214 - case WINEVENT_OPCODE_RESUME: SET_LEN_AND_RETURN(WINEVENT_NAME_RESUME);
215 - case WINEVENT_OPCODE_SUSPEND: SET_LEN_AND_RETURN(WINEVENT_NAME_SUSPEND);
216 - case WINEVENT_OPCODE_SEND: SET_LEN_AND_RETURN(WINEVENT_NAME_SEND);
217 - case WINEVENT_OPCODE_RECEIVE: SET_LEN_AND_RETURN(WINEVENT_NAME_RECEIVE);
208 + case WEVT_OPCODE_INFO: SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_INFO);
209 + case WEVT_OPCODE_START: SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_START);
210 + case WEVT_OPCODE_STOP: SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_STOP);
211 + case WEVT_OPCODE_DC_START: SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_DC_START);
212 + case WEVT_OPCODE_DC_STOP: SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_DC_STOP);
213 + case WEVT_OPCODE_EXTENSION: SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_EXTENSION);
214 + case WEVT_OPCODE_REPLY: SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_REPLY);
215 + case WEVT_OPCODE_RESUME: SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_RESUME);
216 + case WEVT_OPCODE_SUSPEND: SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_SUSPEND);
217 + case WEVT_OPCODE_SEND: SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_SEND);
218 + case WEVT_OPCODE_RECEIVE: SET_LEN_AND_RETURN(WEVT_OPCODE_NAME_RECEIVE);
219 default: *len = 0; return NULL;
220 }
221 }
@@ -248,12 +249,12 @@ static void wevt_get_opcode(WEVT_LOG *log, WEVT_EVENT *ev, PROVIDER_META_HANDLE
249 }
250
251 txt_utf8_set_numeric_if_empty(
251 - dst, WINEVENT_NAME_OPCODE_PREFIX, sizeof(WINEVENT_NAME_OPCODE_PREFIX) - 1, ev->opcode);
252 + dst, WEVT_PREFIX_OPCODE, sizeof(WEVT_PREFIX_OPCODE) - 1, ev->opcode);
253 }
254
255 static const char *wevt_task_hardcoded(uint64_t task, size_t *len) {
256 switch(task) {
256 - case WINEVENT_TASK_NONE: SET_LEN_AND_RETURN(WINEVENT_NAME_NONE);
257 + case WEVT_TASK_NONE: SET_LEN_AND_RETURN(WEVT_TASK_NAME_NONE);
258 default: *len = 0; return NULL;
259 }
260 }
@@ -287,7 +288,7 @@ static void wevt_get_task(WEVT_LOG *log, WEVT_EVENT *ev, PROVIDER_META_HANDLE *h
288 }
289
290 txt_utf8_set_numeric_if_empty(
290 - dst, WINEVENT_NAME_TASK_PREFIX, sizeof(WINEVENT_NAME_TASK_PREFIX) - 1, ev->task);
291 + dst, WEVT_PREFIX_TASK, sizeof(WEVT_PREFIX_TASK) - 1, ev->task);
292 }
293
294 #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) {
299 const char *name;
300 size_t len;
301 } bits[] = {
301 - SET_BITS(WINEVENT_KEYWORD_EVENTLOG_CLASSIC, WINEVENT_NAME_EVENTLOG_CLASSIC),
302 - SET_BITS(WINEVENT_KEYWORD_CORRELATION_HINT, WINEVENT_NAME_CORRELATION_HINT),
303 - SET_BITS(WINEVENT_KEYWORD_AUDIT_SUCCESS, WINEVENT_NAME_AUDIT_SUCCESS),
304 - SET_BITS(WINEVENT_KEYWORD_AUDIT_FAILURE, WINEVENT_NAME_AUDIT_FAILURE),
305 - SET_BITS(WINEVENT_KEYWORD_SQM, WINEVENT_NAME_SQM),
306 - SET_BITS(WINEVENT_KEYWORD_WDI_DIAG, WINEVENT_NAME_WDI_DIAG),
307 - SET_BITS(WINEVENT_KEYWORD_WDI_CONTEXT, WINEVENT_NAME_WDI_CONTEXT),
308 - SET_BITS(WINEVENT_KEYWORD_RESPONSE_TIME, WINEVENT_NAME_RESPONSE_TIME),
302 + SET_BITS(WEVT_KEYWORD_EVENTLOG_CLASSIC, WEVT_KEYWORD_NAME_EVENTLOG_CLASSIC),
303 + SET_BITS(WEVT_KEYWORD_CORRELATION_HINT, WEVT_KEYWORD_NAME_CORRELATION_HINT),
304 + SET_BITS(WEVT_KEYWORD_AUDIT_SUCCESS, WEVT_KEYWORD_NAME_AUDIT_SUCCESS),
305 + SET_BITS(WEVT_KEYWORD_AUDIT_FAILURE, WEVT_KEYWORD_NAME_AUDIT_FAILURE),
306 + SET_BITS(WEVT_KEYWORD_SQM, WEVT_KEYWORD_NAME_SQM),
307 + SET_BITS(WEVT_KEYWORD_WDI_DIAG, WEVT_KEYWORD_NAME_WDI_DIAG),
308 + SET_BITS(WEVT_KEYWORD_WDI_CONTEXT, WEVT_KEYWORD_NAME_WDI_CONTEXT),
309 + SET_BITS(WEVT_KEYWORD_RESPONSE_TIME, WEVT_KEYWORD_NAME_RESPONSE_TIME),
310 };
311
312 wevt_utf8_empty(dst);
@@ -326,10 +327,8 @@ static uint64_t wevt_keywords_handle_reserved(uint64_t value, TXT_UTF8 *dst) {
327 static void wevt_get_keywords(WEVT_LOG *log, WEVT_EVENT *ev, PROVIDER_META_HANDLE *h) {
328 TXT_UTF8 *dst = &log->ops.keywords;
329
329 - if(ev->keywords == WINEVT_KEYWORD_NONE) {
330 - txt_utf8_resize(dst, sizeof(WINEVENT_NAME_NONE), false);
331 - memcpy(dst->data, WINEVENT_NAME_NONE, sizeof(WINEVENT_NAME_NONE));
332 - dst->used = sizeof(WINEVENT_NAME_NONE);
330 + if(ev->keywords == WEVT_KEYWORD_NONE) {
331 + txt_utf8_set(dst, WEVT_KEYWORD_NAME_NONE, sizeof(WEVT_KEYWORD_NAME_NONE) - 1);
332 dst->src = TXT_SOURCE_HARDCODED;
333 }
334
@@ -340,7 +339,7 @@ static void wevt_get_keywords(WEVT_LOG *log, WEVT_EVENT *ev, PROVIDER_META_HANDL
339
340 if(!value && dst->used <= 1) {
341 // no hardcoded info in the buffer, make it None
343 - txt_utf8_set(dst, WINEVENT_NAME_NONE, sizeof(WINEVENT_NAME_NONE) - 1);
342 + txt_utf8_set(dst, WEVT_KEYWORD_NAME_NONE, sizeof(WEVT_KEYWORD_NAME_NONE) - 1);
343 dst->src = TXT_SOURCE_HARDCODED;
344 }
345 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
350 }
351
352 txt_utf8_set_hex_if_empty(
354 - dst, WINEVENT_NAME_KEYWORDS_PREFIX, sizeof(WINEVENT_NAME_KEYWORDS_PREFIX) - 1, ev->keywords);
353 + dst, WEVT_PREFIX_KEYWORDS, sizeof(WEVT_PREFIX_KEYWORDS) - 1, ev->keywords);
354 }
355
356 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) {
358
359 // obtain the information from selected events
360 DWORD bytes_used = 0, property_count = 0;
362 - if (!EvtRender(log->render_context, log->bookmark, EvtRenderEventValues, log->ops.content.size, log->ops.content.data, &bytes_used, &property_count)) {
361 + if (!EvtRender(log->hRenderContext, log->hEvent, EvtRenderEventValues, log->ops.content.size, log->ops.content.data, &bytes_used, &property_count)) {
362 // information exceeds the allocated space
363 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
365 - nd_log(NDLS_COLLECTORS, NDLP_ERR, "EvtRender() failed, render_context: 0x%lx, bookmark: 0x%lx, content: 0x%lx, size: %zu, extended info: %s",
366 - (uintptr_t)log->render_context, (uintptr_t)log->bookmark, (uintptr_t)log->ops.content.data, log->ops.content.size, wevt_extended_status());
364 + nd_log(NDLS_COLLECTORS, NDLP_ERR, "EvtRender() failed, hRenderContext: 0x%lx, hEvent: 0x%lx, content: 0x%lx, size: %zu, extended info: %s",
365 + (uintptr_t)log->hRenderContext, (uintptr_t)log->hEvent, (uintptr_t)log->ops.content.data, log->ops.content.size, wevt_extended_status());
366 goto cleanup;
367 }
368
369 wevt_variant_resize(&log->ops.content, bytes_used);
371 - if (!EvtRender(log->render_context, log->bookmark, EvtRenderEventValues, log->ops.content.size, log->ops.content.data, &bytes_used, &property_count)) {
370 + if (!EvtRender(log->hRenderContext, log->hEvent, EvtRenderEventValues, log->ops.content.size, log->ops.content.data, &bytes_used, &property_count)) {
371 nd_log(NDLS_COLLECTORS, NDLP_ERR, "EvtRender() failed, after bytes_used increase, extended info: %s",
372 wevt_extended_status());
373 goto cleanup;
@@ -417,14 +416,14 @@ bool wevt_get_next_event(WEVT_LOG *log, WEVT_EVENT *ev, bool full) {
416 DWORD size = full ? BATCH_NEXT_EVENT : 1;
417 DWORD max_failures = 10;
418
420 - fatal_assert(log && log->event_query && log->render_context);
419 + fatal_assert(log && log->hQuery && log->hRenderContext);
420
421 while(max_failures > 0) {
422 if (log->batch.used >= log->batch.size) {
423 log->batch.size = 0;
424 log->batch.used = 0;
425 DWORD err;
427 - if(!EvtNext(log->event_query, size, log->batch.bk, INFINITE, 0, &log->batch.size)) {
426 + if(!EvtNext(log->hQuery, size, log->batch.hEvents, INFINITE, 0, &log->batch.size)) {
427 err = GetLastError();
428 if(err == ERROR_NO_MORE_ITEMS)
429 return false; // no data available, return failure
@@ -433,8 +432,8 @@ bool wevt_get_next_event(WEVT_LOG *log, WEVT_EVENT *ev, bool full) {
432 if(!log->batch.size) {
433 if(size == 1) {
434 nd_log(NDLS_COLLECTORS, NDLP_ERR,
436 - "EvtNext() failed, event_query: 0x%lx, size: %zu, extended info: %s",
437 - (uintptr_t)log->event_query, (size_t)size, wevt_extended_status());
435 + "EvtNext() failed, hQuery: 0x%lx, size: %zu, extended info: %s",
436 + (uintptr_t)log->hQuery, (size_t)size, wevt_extended_status());
437 return false;
438 }
439
@@ -452,8 +451,8 @@ bool wevt_get_next_event(WEVT_LOG *log, WEVT_EVENT *ev, bool full) {
451 // cleanup any previous event data
452 wevt_event_done(log);
453
455 - log->bookmark = log->batch.bk[log->batch.used];
456 - log->batch.bk[log->batch.used] = NULL;
454 + log->hEvent = log->batch.hEvents[log->batch.used];
455 + log->batch.hEvents[log->batch.used] = NULL;
456 log->batch.used++;
457
458 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) {
468 }
469
470 void wevt_query_done(WEVT_LOG *log) {
472 - // close the last working bookmark
471 + // close the last working hEvent
472 wevt_event_done(log);
473
475 - // close all batched bookmarks
474 + // close all batched hEvents
475 for(DWORD i = log->batch.used; i < log->batch.size ;i++) {
477 - if(log->batch.bk[i])
478 - EvtClose(log->batch.bk[i]);
476 + if(log->batch.hEvents[i])
477 + EvtClose(log->batch.hEvents[i]);
478
480 - log->batch.bk[i] = NULL;
479 + log->batch.hEvents[i] = NULL;
480 }
481 log->batch.used = 0;
482 log->batch.size = 0;
483
485 - if (log->event_query) {
486 - EvtClose(log->event_query);
487 - log->event_query = NULL;
484 + if (log->hQuery) {
485 + EvtClose(log->hQuery);
486 + log->hQuery = NULL;
487 }
488
489 log->query_stats.event_count = 0;
@@ -494,8 +493,8 @@ void wevt_query_done(WEVT_LOG *log) {
493 void wevt_closelog6(WEVT_LOG *log) {
494 wevt_query_done(log);
495
497 - if (log->render_context)
498 - EvtClose(log->render_context);
496 + if (log->hRenderContext)
497 + EvtClose(log->hRenderContext);
498
499 wevt_variant_cleanup(&log->ops.content);
500 txt_unicode_cleanup(&log->ops.unicode);
@@ -514,7 +513,7 @@ void wevt_closelog6(WEVT_LOG *log) {
513 freez(log);
514 }
515
517 -bool wevt_channel_retention(WEVT_LOG *log, const wchar_t *channel, EVT_RETENTION *retention) {
516 +bool wevt_channel_retention(WEVT_LOG *log, const wchar_t *channel, const wchar_t *query, EVT_RETENTION *retention) {
517 bool ret = false;
518
519 // 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
521 // we have to get it from the first EventRecordID
522
523 // query the eventlog
525 - log->event_query = EvtQuery(NULL, channel, NULL, EvtQueryChannelPath | EvtQueryForwardDirection);
526 - if (!log->event_query) {
524 + log->hQuery = EvtQuery(NULL, channel, query, EvtQueryChannelPath | EvtQueryForwardDirection | EvtQueryTolerateQueryErrors);
525 + if (!log->hQuery) {
526 if (GetLastError() == ERROR_EVT_CHANNEL_NOT_FOUND)
527 nd_log(NDLS_COLLECTORS, NDLP_ERR, "EvtQuery() for retention failed, channel '%s' not found, cannot get retention, extended info: %s",
528 channel2utf8(channel), wevt_extended_status());
@@ -543,10 +542,10 @@ bool wevt_channel_retention(WEVT_LOG *log, const wchar_t *channel, EVT_RETENTION
542 ret = true;
543 goto cleanup;
544 }
546 - EvtClose(log->event_query);
545 + EvtClose(log->hQuery);
546
548 - log->event_query = EvtQuery(NULL, channel, NULL, EvtQueryChannelPath | EvtQueryReverseDirection);
549 - if (!log->event_query) {
547 + log->hQuery = EvtQuery(NULL, channel, query, EvtQueryChannelPath | EvtQueryReverseDirection | EvtQueryTolerateQueryErrors);
548 + if (!log->hQuery) {
549 if (GetLastError() == ERROR_EVT_CHANNEL_NOT_FOUND)
550 nd_log(NDLS_COLLECTORS, NDLP_ERR, "EvtQuery() for retention failed, channel '%s' not found, extended info: %s",
551 channel2utf8(channel), wevt_extended_status());
@@ -568,7 +567,7 @@ cleanup:
567 wevt_query_done(log);
568
569 if(ret) {
571 - retention->entries = retention->last_event.id - retention->first_event.id;
570 + retention->entries = (channel && !query) ? retention->last_event.id - retention->first_event.id : 0;
571
572 if(retention->last_event.created_ns >= retention->first_event.created_ns)
573 retention->duration_ns = retention->last_event.created_ns - retention->first_event.created_ns;
@@ -589,8 +588,8 @@ WEVT_LOG *wevt_openlog6(void) {
588 WEVT_LOG *log = callocz(1, sizeof(*log));
589
590 // create the system render
592 - log->render_context = EvtCreateRenderContext(RENDER_ITEMS_count, RENDER_ITEMS, EvtRenderContextValues);
593 - if (!log->render_context) {
591 + log->hRenderContext = EvtCreateRenderContext(RENDER_ITEMS_count, RENDER_ITEMS, EvtRenderContextValues);
592 + if (!log->hRenderContext) {
593 nd_log(NDLS_COLLECTORS, NDLP_ERR, "EvtCreateRenderContext failed, extended info: %s", wevt_extended_status());
594 freez(log);
595 log = NULL;
@@ -645,6 +644,6 @@ bool wevt_query(WEVT_LOG *log, LPCWSTR channel, LPCWSTR query, EVT_QUERY_FLAGS d
644 return false;
645 }
646
648 - log->event_query = hQuery;
647 + log->hQuery = hQuery;
648 return true;
649 }
src/collectors/windows-events.plugin/windows-events-query.h
+9 -10
@@ -3,7 +3,7 @@
3 #ifndef NETDATA_WINDOWS_EVENTS_QUERY_H
4 #define NETDATA_WINDOWS_EVENTS_QUERY_H
5
6 -#include "windows-events.h"
6 +#include "libnetdata/libnetdata.h"
7
8 #define BATCH_NEXT_EVENT 500
9
@@ -45,12 +45,12 @@ typedef struct wevt_log {
45 struct {
46 DWORD size;
47 DWORD used;
48 - EVT_HANDLE bk[BATCH_NEXT_EVENT];
48 + EVT_HANDLE hEvents[BATCH_NEXT_EVENT];
49 } batch;
50
51 - EVT_HANDLE bookmark;
52 - EVT_HANDLE event_query;
53 - EVT_HANDLE render_context;
51 + EVT_HANDLE hEvent;
52 + EVT_HANDLE hQuery;
53 + EVT_HANDLE hRenderContext;
54 struct provider_meta_handle *publisher;
55
56 struct {
@@ -105,18 +105,17 @@ typedef struct wevt_log {
105 WEVT_LOG *wevt_openlog6(void);
106 void wevt_closelog6(WEVT_LOG *log);
107
108 -bool wevt_channel_retention(WEVT_LOG *log, const wchar_t *channel, EVT_RETENTION *retention);
108 +bool wevt_channel_retention(WEVT_LOG *log, const wchar_t *channel, const wchar_t *query, EVT_RETENTION *retention);
109
110 bool wevt_query(WEVT_LOG *log, LPCWSTR channel, LPCWSTR query, EVT_QUERY_FLAGS direction);
111 void wevt_query_done(WEVT_LOG *log);
112
113 bool wevt_get_next_event(WEVT_LOG *log, WEVT_EVENT *ev, bool full);
114
115 -bool wevt_get_message_unicode(TXT_UNICODE *unicode, EVT_HANDLE hMetadata, EVT_HANDLE bookmark, DWORD dwMessageId, EVT_FORMAT_MESSAGE_FLAGS flags);
115 +bool wevt_get_message_unicode(TXT_UNICODE *dst, EVT_HANDLE hMetadata, EVT_HANDLE hEvent, DWORD dwMessageId, EVT_FORMAT_MESSAGE_FLAGS flags);
116
117 -struct provider_meta_handle;
118 -bool wevt_get_event_utf8(WEVT_LOG *log, struct provider_meta_handle *p, EVT_HANDLE event_handle, TXT_UTF8 *dst);
119 -bool wevt_get_xml_utf8(WEVT_LOG *log, struct provider_meta_handle *p, EVT_HANDLE event_handle, TXT_UTF8 *dst);
117 +bool wevt_get_event_utf8(WEVT_LOG *log, struct provider_meta_handle *p, EVT_HANDLE hEvent, TXT_UTF8 *dst);
118 +bool wevt_get_xml_utf8(WEVT_LOG *log, struct provider_meta_handle *p, EVT_HANDLE hEvent, TXT_UTF8 *dst);
119
120 static inline void wevt_variant_cleanup(WEVT_VARIANT *v) {
121 freez(v->data);
src/collectors/windows-events.plugin/windows-events-sources.c
+233 -16
@@ -1,6 +1,141 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 -#include "windows-events-sources.h"
3 +#include "windows-events.h"
4 +
5 +//struct {
6 +// const char *name;
7 +// const wchar_t *query;
8 +//} custom_queries[] = {
9 +// {
10 +// .name = "All-Administrative-Events",
11 +// .query = L"<QueryList>\n"
12 +// " <Query Id=\"0\" Path=\"Application\">\n"
13 +// " <Select Path=\"Application\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
14 +// " <Select Path=\"Security\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
15 +// " <Select Path=\"System\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
16 +// " <Select Path=\"HardwareEvents\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
17 +// " <Select Path=\"Internet Explorer\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
18 +// " <Select Path=\"Key Management Service\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
19 +// " <Select Path=\"Microsoft-AppV-Client/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
20 +// " <Select Path=\"Microsoft-AppV-Client/Virtual Applications\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
21 +// " <Select Path=\"Microsoft-Windows-All-User-Install-Agent/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
22 +// " <Select Path=\"Microsoft-Windows-AppHost/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
23 +// " <Select Path=\"Microsoft-Windows-Application Server-Applications/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
24 +// " <Select Path=\"Microsoft-Windows-AppModel-Runtime/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
25 +// " <Select Path=\"Microsoft-Windows-AppReadiness/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
26 +// " <Select Path=\"Microsoft-Windows-AssignedAccess/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
27 +// " <Select Path=\"Microsoft-Windows-AssignedAccessBroker/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
28 +// " <Select Path=\"Microsoft-Windows-Storage-ATAPort/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
29 +// " <Select Path=\"Microsoft-Windows-BitLocker-DrivePreparationTool/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
30 +// " <Select Path=\"Microsoft-Client-Licensing-Platform/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
31 +// " <Select Path=\"Microsoft-Windows-DataIntegrityScan/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
32 +// " <Select Path=\"Microsoft-Windows-DataIntegrityScan/CrashRecovery\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
33 +// " <Select Path=\"Microsoft-Windows-DSC/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
34 +// " <Select Path=\"Microsoft-Windows-DeviceManagement-Enterprise-Diagnostics-Provider/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
35 +// " <Select Path=\"Microsoft-Windows-DeviceManagement-Enterprise-Diagnostics-Provider/Autopilot\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
36 +// " <Select Path=\"Microsoft-Windows-DeviceSetupManager/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
37 +// " <Select Path=\"Microsoft-Windows-Dhcp-Client/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
38 +// " <Select Path=\"Microsoft-Windows-Dhcpv6-Client/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
39 +// " <Select Path=\"Microsoft-Windows-Diagnosis-Scripted/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
40 +// " <Select Path=\"Microsoft-Windows-Storage-Disk/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
41 +// " <Select Path=\"Microsoft-Windows-DxgKrnl-Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
42 +// " <Select Path=\"Microsoft-Windows-EDP-Application-Learning/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
43 +// " <Select Path=\"Microsoft-Windows-EDP-Audit-Regular/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
44 +// " <Select Path=\"Microsoft-Windows-EDP-Audit-TCB/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
45 +// " <Select Path=\"Microsoft-Client-License-Flexible-Platform/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
46 +// " <Select Path=\"Microsoft-Windows-GenericRoaming/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
47 +// " <Select Path=\"Microsoft-Windows-Hyper-V-Guest-Drivers/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
48 +// " <Select Path=\"Microsoft-Windows-Hyper-V-Hypervisor-Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
49 +// " <Select Path=\"Microsoft-Windows-Hyper-V-VID-Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
50 +// " <Select Path=\"Microsoft-Windows-Kernel-EventTracing/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
51 +// " <Select Path=\"Microsoft-Windows-KeyboardFilter/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
52 +// " <Select Path=\"Microsoft-Windows-ModernDeployment-Diagnostics-Provider/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
53 +// " <Select Path=\"Microsoft-Windows-ModernDeployment-Diagnostics-Provider/Autopilot\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
54 +// " <Select Path=\"Microsoft-Windows-ModernDeployment-Diagnostics-Provider/Diagnostics\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
55 +// " <Select Path=\"Microsoft-Windows-ModernDeployment-Diagnostics-Provider/ManagementService\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
56 +// " <Select Path=\"Microsoft-Windows-MUI/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
57 +// " <Select Path=\"Microsoft-Windows-PowerShell/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
58 +// " <Select Path=\"Microsoft-Windows-PrintBRM/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
59 +// " <Select Path=\"Microsoft-Windows-PrintService/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
60 +// " <Select Path=\"Microsoft-Windows-Provisioning-Diagnostics-Provider/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
61 +// " <Select Path=\"Microsoft-Windows-Provisioning-Diagnostics-Provider/AutoPilot\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
62 +// " <Select Path=\"Microsoft-Windows-Provisioning-Diagnostics-Provider/ManagementService\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
63 +// " <Select Path=\"Microsoft-Windows-PushNotification-Platform/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
64 +// " <Select Path=\"Microsoft-Windows-RemoteApp and Desktop Connections/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
65 +// " <Select Path=\"Microsoft-Windows-RemoteAssistance/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
66 +// " <Select Path=\"Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
67 +// " <Select Path=\"Microsoft-Windows-RetailDemo/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
68 +// " <Select Path=\"Microsoft-Windows-SecurityMitigationsBroker/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
69 +// " <Select Path=\"Microsoft-Windows-SmartCard-TPM-VCard-Module/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
70 +// " <Select Path=\"Microsoft-Windows-SMBDirect/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
71 +// " <Select Path=\"Microsoft-Windows-SMBWitnessClient/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
72 +// " <Select Path=\"Microsoft-Windows-Storage-Tiering/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
73 +// " <Select Path=\"Microsoft-Windows-Storage-ClassPnP/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
74 +// " <Select Path=\"Microsoft-Windows-Storage-Storport/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
75 +// " <Select Path=\"Microsoft-Windows-TerminalServices-ClientUSBDevices/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
76 +// " <Select Path=\"Microsoft-Windows-TerminalServices-LocalSessionManager/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
77 +// " <Select Path=\"Microsoft-Windows-TerminalServices-PnPDevices/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
78 +// " <Select Path=\"Microsoft-Windows-TerminalServices-Printers/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
79 +// " <Select Path=\"Microsoft-Windows-TerminalServices-RemoteConnectionManager/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
80 +// " <Select Path=\"Microsoft-Windows-TerminalServices-ServerUSBDevices/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
81 +// " <Select Path=\"Microsoft-Windows-Troubleshooting-Recommended/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
82 +// " <Select Path=\"Microsoft-Windows-User Device Registration/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
83 +// " <Select Path=\"Microsoft-Windows-VerifyHardwareSecurity/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
84 +// " <Select Path=\"Microsoft-Windows-WindowsBackup/ActionCenter\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
85 +// " <Select Path=\"Microsoft-Windows-Workplace Join/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
86 +// " <Select Path=\"OAlerts\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
87 +// " <Select Path=\"OneApp_IGCC\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
88 +// " <Select Path=\"OpenSSH/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
89 +// " <Select Path=\"USER_ESRV_SVC_QUEENCREEK\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
90 +// " <Select Path=\"Visual Studio\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
91 +// " <Select Path=\"Windows PowerShell\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
92 +// " </Query>\n"
93 +// "</QueryList>",
94 +// },
95 +// {
96 +// .name = "All-Remote-Desktop-Services",
97 +// .query = L"<QueryList>\n"
98 +// " <Query Id=\"0\" Path=\"Microsoft-Rdms-UI/Admin\">\n"
99 +// " <Select Path=\"Microsoft-Rdms-UI/Admin\">*</Select>\n"
100 +// " <Select Path=\"Microsoft-Rdms-UI/Operational\">*</Select>\n"
101 +// " <Select Path=\"Remote-Desktop-Management-Service/Admin\">*</Select>\n"
102 +// " <Select Path=\"Remote-Desktop-Management-Service/Operational\">*</Select>\n"
103 +// " <Select Path=\"Microsoft-Windows-TerminalServices-SessionBroker-Client/Admin\">*</Select>\n"
104 +// " <Select Path=\"Microsoft-Windows-TerminalServices-SessionBroker-Client/Operational\">*</Select>\n"
105 +// " <Select Path=\"Microsoft-Windows-TerminalServices-RemoteConnectionManager/Admin\">*</Select>\n"
106 +// " <Select Path=\"Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational\">*</Select>\n"
107 +// " <Select Path=\"Microsoft-Windows-TerminalServices-PnPDevices/Admin\">*</Select>\n"
108 +// " <Select Path=\"Microsoft-Windows-TerminalServices-PnPDevices/Operational\">*</Select>\n"
109 +// " <Select Path=\"Microsoft-Windows-RemoteApp and Desktop Connections/Admin\">*</Select>\n"
110 +// " <Select Path=\"Microsoft-Windows-RemoteApp and Desktop Connection Management/Admin\">*</Select>\n"
111 +// " <Select Path=\"Microsoft-Windows-RemoteApp and Desktop Connection Management/Operational\">*</Select>\n"
112 +// " <Select Path=\"Microsoft-Windows-TerminalServices-SessionBroker/Admin\">*</Select>\n"
113 +// " <Select Path=\"Microsoft-Windows-TerminalServices-SessionBroker/Operational\">*</Select>\n"
114 +// " <Select Path=\"Microsoft-Windows-TerminalServices-TSV-VmHostAgent/Operational\">*</Select>\n"
115 +// " <Select Path=\"Microsoft-Windows-TerminalServices-TSV-VmHostAgent/Admin\">*</Select>\n"
116 +// " <Select Path=\"Microsoft-Windows-TerminalServices-ServerUSBDevices/Operational\">*</Select>\n"
117 +// " <Select Path=\"Microsoft-Windows-TerminalServices-ServerUSBDevices/Admin\">*</Select>\n"
118 +// " <Select Path=\"Microsoft-Windows-TerminalServices-LocalSessionManager/Operational\">*</Select>\n"
119 +// " <Select Path=\"Microsoft-Windows-TerminalServices-LocalSessionManager/Admin\">*</Select>\n"
120 +// " <Select Path=\"Microsoft-Windows-TerminalServices-ClientUSBDevices/Operational\">*</Select>\n"
121 +// " <Select Path=\"Microsoft-Windows-TerminalServices-ClientUSBDevices/Admin\">*</Select>\n"
122 +// " <Select Path=\"Microsoft-Windows-TerminalServices-RDPClient/Operational\">*</Select>\n"
123 +// " <Select Path=\"Microsoft-Windows-TerminalServices-Licensing/Admin\">*</Select>\n"
124 +// " <Select Path=\"Microsoft-Windows-TerminalServices-Licensing/Operational\">*</Select>\n"
125 +// " <Select Path=\"Microsoft-Windows-TerminalServices-Gateway/Admin\">*</Select>\n"
126 +// " <Select Path=\"Microsoft-Windows-TerminalServices-Gateway/Operational\">*</Select>\n"
127 +// " </Query>\n"
128 +// "</QueryList>",
129 +// },
130 +// {
131 +// .name = "All-Security-SPP",
132 +// .query = L"<QueryList>\n"
133 +// " <Query Id=\"0\" Path=\"Microsoft-Windows-HelloForBusiness/Operational\">\n"
134 +// " <Select Path=\"Microsoft-Windows-HelloForBusiness/Operational\">*[System[(Level&gt;5 )]]</Select>\n"
135 +// " </Query>\n"
136 +// "</QueryList>",
137 +// }
138 +//};
139
140 DICTIONARY *wevt_sources = NULL;
141 DICTIONARY *used_hashes_registry = NULL;
@@ -22,6 +157,15 @@ WEVT_SOURCE_TYPE wevt_internal_source_type(const char *value) {
157 if(strcmp(value, WEVT_SOURCE_ALL_DEBUG_NAME) == 0)
158 return WEVTS_DEBUG;
159
160 + if(strcmp(value, WEVT_SOURCE_ALL_DIAGNOSTIC_NAME) == 0)
161 + return WEVTS_DIAGNOSTIC;
162 +
163 + if(strcmp(value, WEVT_SOURCE_ALL_TRACING_NAME) == 0)
164 + return WEVTS_TRACING;
165 +
166 + if(strcmp(value, WEVT_SOURCE_ALL_PERFORMANCE_NAME) == 0)
167 + return WEVTS_PERFORMANCE;
168 +
169 if(strcmp(value, WEVT_SOURCE_ALL_WINDOWS_NAME) == 0)
170 return WEVTS_WINDOWS;
171
@@ -125,6 +269,7 @@ struct wevt_source {
269 usec_t first_ut;
270 usec_t last_ut;
271 size_t count;
272 + size_t entries;
273 uint64_t size;
274 };
275
@@ -143,9 +288,13 @@ static int wevt_source_to_json_array_cb(const DICTIONARY_ITEM *item, void *entry
288 duration_snprintf(duration_for_humans, sizeof(duration_for_humans),
289 (time_t)((s->last_ut - s->first_ut) / USEC_PER_SEC), "s", true);
290
291 + char entries_for_humans[128];
292 + entries_snprintf(entries_for_humans, sizeof(entries_for_humans), s->entries, "", false);
293 +
294 char info[1024];
147 - snprintfz(info, sizeof(info), "%zu channel%s, with a total size of %s, covering %s",
148 - s->count, s->count > 1 ? "s":"", size_for_humans, duration_for_humans);
295 + snprintfz(info, sizeof(info), "%zu channel%s, with a total size of %s, covering %s%s%s%s",
296 + s->count, s->count > 1 ? "s":"", size_for_humans, duration_for_humans,
297 + s->entries ? ", having " : "", s->entries ? entries_for_humans : "", s->entries ? " entries" : "");
298
299 buffer_json_member_add_string(wb, "id", name);
300 buffer_json_member_add_string(wb, "name", name);
@@ -163,6 +312,7 @@ static bool wevt_source_merge_sizes(const DICTIONARY_ITEM *item __maybe_unused,
312
313 old_v->count += new_v->count;
314 old_v->size += new_v->size;
315 + old_v->entries += new_v->entries;
316
317 if(new_v->first_ut && new_v->first_ut < old_v->first_ut)
318 old_v->first_ut = new_v->first_ut;
@@ -185,6 +335,7 @@ void wevt_sources_to_json_array(BUFFER *wb) {
335 t.last_ut = src->msg_last_ut;
336 t.count = 1;
337 t.size = src->size;
338 + t.entries = src->entries;
339
340 dictionary_set(dict, WEVT_SOURCE_ALL_NAME, &t, sizeof(t));
341
@@ -200,6 +351,15 @@ void wevt_sources_to_json_array(BUFFER *wb) {
351 if(src->source_type & WEVTS_DEBUG)
352 dictionary_set(dict, WEVT_SOURCE_ALL_DEBUG_NAME, &t, sizeof(t));
353
354 + if(src->source_type & WEVTS_DIAGNOSTIC)
355 + dictionary_set(dict, WEVT_SOURCE_ALL_DIAGNOSTIC_NAME, &t, sizeof(t));
356 +
357 + if(src->source_type & WEVTS_TRACING)
358 + dictionary_set(dict, WEVT_SOURCE_ALL_TRACING_NAME, &t, sizeof(t));
359 +
360 + if(src->source_type & WEVTS_PERFORMANCE)
361 + dictionary_set(dict, WEVT_SOURCE_ALL_PERFORMANCE_NAME, &t, sizeof(t));
362 +
363 if(src->source_type & WEVTS_WINDOWS)
364 dictionary_set(dict, WEVT_SOURCE_ALL_WINDOWS_NAME, &t, sizeof(t));
365
@@ -211,6 +371,29 @@ void wevt_sources_to_json_array(BUFFER *wb) {
371 dictionary_sorted_walkthrough_read(dict, wevt_source_to_json_array_cb, wb);
372 }
373
374 +static bool check_and_remove_suffix(char *name, size_t len, const char *suffix) {
375 + char s[strlen(suffix) + 2];
376 + s[0] = '/';
377 + memcpy(&s[1], suffix, sizeof(s) - 1);
378 + size_t slen = sizeof(s) - 1;
379 +
380 + if(slen + 1 >= len) return false;
381 +
382 + char *match = &name[len - slen];
383 + if(strcasecmp(match, s) == 0) {
384 + *match = '\0';
385 + return true;
386 + }
387 +
388 + s[0] = '-';
389 + if(strcasecmp(match, s) == 0) {
390 + *match = '\0';
391 + return true;
392 + }
393 +
394 + return false;
395 +}
396 +
397 void wevt_sources_scan(void) {
398 static SPINLOCK spinlock = NETDATA_SPINLOCK_INITIALIZER;
399 LPWSTR channel = NULL;
@@ -252,24 +435,35 @@ void wevt_sources_scan(void) {
435 }
436
437 EVT_RETENTION retention;
255 - if(!wevt_channel_retention(log, channel, &retention))
438 + if(!wevt_channel_retention(log, channel, NULL, &retention))
439 continue;
440
441 const char *name = channel2utf8(channel);
442 const char *fullname = strdupz(name);
260 - char *slash = strchr(name, '/');
443 +
444 WEVT_SOURCE_TYPE sources = WEVTS_ALL;
262 - if(slash) {
263 - *slash++ = '\0';
264 - if(strcasecmp(slash, "Admin") == 0)
265 - sources |= WEVTS_ADMIN;
266 - if(strcasecmp(slash, "Operational") == 0)
267 - sources |= WEVTS_OPERATIONAL;
268 - if(strcasecmp(slash, "Analytic") == 0)
269 - sources |= WEVTS_ANALYTIC;
270 - if(strcasecmp(slash, "Debug") == 0)
271 - sources |= WEVTS_DEBUG;
272 - }
445 + size_t len = strlen(fullname);
446 + if(check_and_remove_suffix((char *)name, len, "Admin"))
447 + sources |= WEVTS_ADMIN;
448 + else if(check_and_remove_suffix((char *)name, len, "Operational"))
449 + sources |= WEVTS_OPERATIONAL;
450 + else if(check_and_remove_suffix((char *)name, len, "Analytic"))
451 + sources |= WEVTS_ANALYTIC;
452 + else if(check_and_remove_suffix((char *)name, len, "Debug") ||
453 + check_and_remove_suffix((char *)name, len, "Verbose"))
454 + sources |= WEVTS_DEBUG;
455 + else if(check_and_remove_suffix((char *)name, len, "Diagnostic"))
456 + sources |= WEVTS_DIAGNOSTIC;
457 + else if(check_and_remove_suffix((char *)name, len, "Trace") ||
458 + check_and_remove_suffix((char *)name, len, "Tracing"))
459 + sources |= WEVTS_TRACING;
460 + else if(check_and_remove_suffix((char *)name, len, "Performance") ||
461 + check_and_remove_suffix((char *)name, len, "Perf"))
462 + sources |= WEVTS_PERFORMANCE;
463 +
464 + char *slash = strchr(name, '/');
465 + if(slash)
466 + *slash = '\0';
467
468 if(strcasecmp(name, "Application") == 0)
469 sources |= WEVTS_WINDOWS;
@@ -297,6 +491,29 @@ void wevt_sources_scan(void) {
491 dictionary_set(wevt_sources, src.fullname, &src, sizeof(src));
492 }
493
494 +// // add custom queries
495 +// for(size_t i = 0; i < sizeof(custom_queries) / sizeof(custom_queries[0]) ;i++) {
496 +// EVT_RETENTION retention;
497 +// if(!wevt_channel_retention(log, NULL, custom_queries[i].query, &retention))
498 +// continue;
499 +//
500 +// LOGS_QUERY_SOURCE src = {
501 +// .entries = 0,
502 +// .fullname = strdupz(custom_queries[i].name),
503 +// .fullname_len = strlen(custom_queries[i].name),
504 +// .last_scan_monotonic_ut = now_monotonic_usec(),
505 +// .msg_first_id = retention.first_event.id,
506 +// .msg_last_id = retention.last_event.id,
507 +// .msg_first_ut = retention.first_event.created_ns / NSEC_PER_USEC,
508 +// .msg_last_ut = retention.last_event.created_ns / NSEC_PER_USEC,
509 +// .size = retention.size_bytes,
510 +// .source_type = WEVTS_ALL,
511 +// .source = string_strdupz(custom_queries[i].name),
512 +// };
513 +//
514 +// dictionary_set(wevt_sources, src.fullname, &src, sizeof(src));
515 +// }
516 +//
517 wevt_closelog6(log);
518
519 LOGS_QUERY_SOURCE *src;
src/collectors/windows-events.plugin/windows-events-sources.h
+10 -2
@@ -3,7 +3,7 @@
3 #ifndef NETDATA_WINDOWS_EVENTS_SOURCES_H
4 #define NETDATA_WINDOWS_EVENTS_SOURCES_H
5
6 -#include "windows-events.h"
6 +#include "libnetdata/libnetdata.h"
7
8 typedef enum {
9 WEVTS_NONE = 0,
@@ -12,13 +12,18 @@ typedef enum {
12 WEVTS_OPERATIONAL = (1 << 2),
13 WEVTS_ANALYTIC = (1 << 3),
14 WEVTS_DEBUG = (1 << 4),
15 - WEVTS_WINDOWS = (1 << 5),
15 + WEVTS_DIAGNOSTIC = (1 << 5),
16 + WEVTS_TRACING = (1 << 6),
17 + WEVTS_PERFORMANCE = (1 << 7),
18 + WEVTS_WINDOWS = (1 << 8),
19 } WEVT_SOURCE_TYPE;
20
21 typedef struct {
22 const char *fullname;
23 size_t fullname_len;
24
25 + const wchar_t *custom_query;
26 +
27 STRING *source;
28 WEVT_SOURCE_TYPE source_type;
29 usec_t msg_first_ut;
@@ -40,6 +45,9 @@ extern DICTIONARY *used_hashes_registry;
45 #define WEVT_SOURCE_ALL_OPERATIONAL_NAME "All-Operational"
46 #define WEVT_SOURCE_ALL_ANALYTIC_NAME "All-Analytic"
47 #define WEVT_SOURCE_ALL_DEBUG_NAME "All-Debug"
48 +#define WEVT_SOURCE_ALL_DIAGNOSTIC_NAME "All-Diagnostic"
49 +#define WEVT_SOURCE_ALL_TRACING_NAME "All-Tracing"
50 +#define WEVT_SOURCE_ALL_PERFORMANCE_NAME "All-Performance"
51 #define WEVT_SOURCE_ALL_WINDOWS_NAME "All-Windows"
52
53 void wevt_sources_init(void);
src/collectors/windows-events.plugin/windows-events-unicode.c
+17 -18
@@ -41,7 +41,7 @@ char *unicode2utf8_strdupz(const wchar_t *src, size_t *utf8_len) {
41
42 wchar_t *channel2unicode(const char *utf8str) {
43 static __thread wchar_t buffer[1024];
44 - utf82unicode(buffer, sizeof(buffer) / sizeof(buffer[0]), utf8str);
44 + utf82unicode(buffer, sizeof(buffer) / sizeof(wchar_t), utf8str);
45 return buffer;
46 }
47
@@ -69,7 +69,7 @@ char *query2utf8(const wchar_t *query) {
69 return buffer;
70 }
71
72 -bool wevt_str_wchar_to_utf8(TXT_UTF8 *utf8, const wchar_t *src, int src_len_with_null) {
72 +bool wevt_str_wchar_to_utf8(TXT_UTF8 *dst, const wchar_t *src, int src_len_with_null) {
73 if(!src || !src_len_with_null)
74 goto cleanup;
75
@@ -78,11 +78,11 @@ bool wevt_str_wchar_to_utf8(TXT_UTF8 *utf8, const wchar_t *src, int src_len_with
78 fatal_assert(src_len_with_null == -1 || (src_len_with_null >= 1 && src[src_len_with_null - 1] == 0));
79
80 // Try to convert using the existing buffer (if it exists, otherwise get the required buffer size)
81 - int size = WideCharToMultiByte(CP_UTF8, 0, src, src_len_with_null, utf8->data, (int)utf8->size, NULL, NULL);
82 - if(size <= 0 || !utf8->data) {
81 + int size = WideCharToMultiByte(CP_UTF8, 0, src, src_len_with_null, dst->data, (int)dst->size, NULL, NULL);
82 + if(size <= 0 || !dst->data) {
83 // we have to set a buffer, or increase it
84
85 - if(utf8->data) {
85 + if(dst->data) {
86 // we need to increase it the buffer size
87
88 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
97 }
98
99 // Retry conversion with the new buffer
100 - txt_utf8_resize(utf8, size, false);
101 - size = WideCharToMultiByte(CP_UTF8, 0, src, src_len_with_null, utf8->data, (int)utf8->size, NULL, NULL);
100 + txt_utf8_resize(dst, size, false);
101 + size = WideCharToMultiByte(CP_UTF8, 0, src, src_len_with_null, dst->data, (int)dst->size, NULL, NULL);
102 if (size <= 0) {
103 nd_log(NDLS_COLLECTORS, NDLP_ERR, "WideCharToMultiByte() failed after resizing.");
104 goto cleanup;
@@ -106,34 +106,33 @@ bool wevt_str_wchar_to_utf8(TXT_UTF8 *utf8, const wchar_t *src, int src_len_with
106 }
107
108 // Make sure it is not zero padded at the end
109 - while(size >= 2 && utf8->data[size - 2] == 0)
109 + while(size >= 2 && dst->data[size - 2] == 0)
110 size--;
111
112 - utf8->used = (size_t)size;
112 + dst->used = (size_t)size;
113
114 - internal_fatal(strlen(utf8->data) + 1 != utf8->used,
114 + internal_fatal(strlen(dst->data) + 1 != dst->used,
115 "Wrong UTF8 string length");
116
117 return true;
118
119 cleanup:
120 - txt_utf8_resize(utf8, 128, false);
120 + txt_utf8_resize(dst, 128, false);
121 if(src)
122 - utf8->used = snprintfz(utf8->data, utf8->size, "[failed conv.]") + 1;
122 + dst->used = snprintfz(dst->data, dst->size, "[failed conv.]") + 1;
123 else {
124 - utf8->data[0] = '\0';
125 - utf8->used = 1;
124 + dst->data[0] = '\0';
125 + dst->used = 1;
126 }
127
128 return false;
129 }
130
131 -bool wevt_str_unicode_to_utf8(TXT_UTF8 *utf8, TXT_UNICODE *unicode) {
132 - fatal_assert(utf8 && ((utf8->data && utf8->size) || (!utf8->data && !utf8->size)));
131 +bool wevt_str_unicode_to_utf8(TXT_UTF8 *dst, TXT_UNICODE *unicode) {
132 + fatal_assert(dst && ((dst->data && dst->size) || (!dst->data && !dst->size)));
133 fatal_assert(unicode && ((unicode->data && unicode->size) || (!unicode->data && !unicode->size)));
134
135 // pass the entire unicode size, including the null terminator
136 // so that the resulting utf8 message will be null terminated too.
137 - return wevt_str_wchar_to_utf8(utf8, unicode->data, (int)unicode->used);
137 + return wevt_str_wchar_to_utf8(dst, unicode->data, (int)unicode->used);
138 }
139 -
src/collectors/windows-events.plugin/windows-events-unicode.h
+80 -42
@@ -18,19 +18,6 @@ typedef enum __attribute__((packed)) {
18 TXT_SOURCE_MAX,
19 } TXT_SOURCE;
20
21 -typedef struct {
22 - char *data;
23 - size_t size; // the allocated size of data buffer
24 - size_t used; // the used size of the data buffer (including null terminators, if any)
25 - TXT_SOURCE src;
26 -} TXT_UTF8;
27 -
28 -typedef struct {
29 - wchar_t *data;
30 - size_t size; // the allocated size of data buffer
31 - size_t used; // the used size of the data buffer (including null terminators, if any)
32 -} TXT_UNICODE;
33 -
21 static inline size_t compute_new_size(size_t old_size, size_t required_size) {
22 size_t size = (required_size % 2048 == 0) ? required_size : required_size + 2048;
23 size = (size / 2048) * 2048;
@@ -41,27 +28,43 @@ static inline size_t compute_new_size(size_t old_size, size_t required_size) {
28 return size;
29 }
30
44 -static inline void txt_utf8_cleanup(TXT_UTF8 *utf8) {
45 - freez(utf8->data);
46 - utf8->data = NULL;
47 - utf8->used = 0;
31 +// --------------------------------------------------------------------------------------------------------------------
32 +// TXT_UTF8
33 +
34 +typedef struct {
35 + char *data;
36 + size_t size; // the allocated size of data buffer
37 + size_t used; // the used size of the data buffer (including null terminators, if any)
38 + TXT_SOURCE src;
39 +} TXT_UTF8;
40 +
41 +static inline void txt_utf8_cleanup(TXT_UTF8 *dst) {
42 + freez(dst->data);
43 + dst->data = NULL;
44 + dst->used = 0;
45 }
46
50 -static inline void txt_utf8_resize(TXT_UTF8 *utf8, size_t required_size, bool keep) {
51 - if(required_size < utf8->size)
47 +static inline void txt_utf8_resize(TXT_UTF8 *dst, size_t required_size, bool keep) {
48 + if(required_size <= dst->size)
49 return;
50
54 - if(keep) {
55 - size_t new_size = compute_new_size(utf8->size, required_size);
56 - utf8->data = reallocz(utf8->data, new_size);
57 - utf8->size = new_size;
58 - }
51 + size_t new_size = compute_new_size(dst->size, required_size);
52 +
53 + if(keep && dst->data)
54 + dst->data = reallocz(dst->data, new_size);
55 else {
60 - txt_utf8_cleanup(utf8);
61 - utf8->size = compute_new_size(utf8->size, required_size);
62 - utf8->data = mallocz(utf8->size);
63 - utf8->used = 0;
56 + txt_utf8_cleanup(dst);
57 + dst->data = mallocz(new_size);
58 + dst->used = 0;
59 }
60 +
61 + dst->size = new_size;
62 +}
63 +
64 +static inline void wevt_utf8_empty(TXT_UTF8 *dst) {
65 + txt_utf8_resize(dst, 1, false);
66 + dst->data[0] = '\0';
67 + dst->used = 1;
68 }
69
70 static inline void txt_utf8_set(TXT_UTF8 *dst, const char *txt, size_t txt_len) {
@@ -107,20 +110,61 @@ static inline void txt_utf8_set_hex_if_empty(TXT_UTF8 *dst, const char *prefix,
110 }
111 }
112
110 -static inline void txt_unicode_cleanup(TXT_UNICODE *unicode) {
111 - freez(unicode->data);
113 +// --------------------------------------------------------------------------------------------------------------------
114 +// TXT_UNICODE
115 +
116 +typedef struct {
117 + wchar_t *data;
118 + size_t size; // the allocated size of data buffer
119 + size_t used; // the used size of the data buffer (including null terminators, if any)
120 +} TXT_UNICODE;
121 +
122 +static inline void txt_unicode_cleanup(TXT_UNICODE *dst) {
123 + freez(dst->data);
124 }
125
114 -static inline void txt_unicode_resize(TXT_UNICODE *unicode, size_t required_size) {
115 - if(required_size < unicode->size)
126 +static inline void txt_unicode_resize(TXT_UNICODE *dst, size_t required_size, bool keep) {
127 + if(required_size <= dst->size)
128 return;
129
118 - txt_unicode_cleanup(unicode);
119 - unicode->size = compute_new_size(unicode->size, required_size);
120 - unicode->data = mallocz(unicode->size * sizeof(wchar_t));
130 + size_t new_size = compute_new_size(dst->size, required_size);
131 +
132 + if (keep && dst->data) {
133 + dst->data = reallocz(dst->data, new_size * sizeof(wchar_t));
134 + } else {
135 + txt_unicode_cleanup(dst);
136 + dst->data = mallocz(new_size * sizeof(wchar_t));
137 + dst->used = 0;
138 + }
139 +
140 + dst->size = new_size;
141 +}
142 +
143 +static inline void txt_unicode_set(TXT_UNICODE *dst, const wchar_t *txt, size_t txt_len) {
144 + txt_unicode_resize(dst, dst->used + txt_len + 1, true);
145 + memcpy(dst->data, txt, txt_len * sizeof(wchar_t));
146 + dst->used = txt_len + 1;
147 + dst->data[dst->used - 1] = '\0';
148 +}
149 +
150 +static inline void txt_unicode_append(TXT_UNICODE *dst, const wchar_t *txt, size_t txt_len) {
151 + if(dst->used <= 1) {
152 + // the destination is empty
153 + txt_unicode_set(dst, txt, txt_len);
154 + }
155 + else {
156 + // there is something already in the buffer
157 + txt_unicode_resize(dst, dst->used + txt_len, true);
158 + memcpy(&dst->data[dst->used - 1], txt, txt_len * sizeof(wchar_t));
159 + dst->used += txt_len; // the null was already counted
160 + dst->data[dst->used - 1] = '\0';
161 + }
162 }
163
123 -bool wevt_str_unicode_to_utf8(TXT_UTF8 *utf8, TXT_UNICODE *unicode);
164 +// --------------------------------------------------------------------------------------------------------------------
165 +// conversions
166 +
167 +bool wevt_str_unicode_to_utf8(TXT_UTF8 *dst, TXT_UNICODE *unicode);
168 bool wevt_str_wchar_to_utf8(TXT_UTF8 *dst, const wchar_t *src, int src_len_with_null);
169
170 void unicode2utf8(char *dst, size_t dst_size, const wchar_t *src);
@@ -136,10 +180,4 @@ char *query2utf8(const wchar_t *query);
180
181 char *unicode2utf8_strdupz(const wchar_t *src, size_t *utf8_len);
182
139 -static inline void wevt_utf8_empty(TXT_UTF8 *dst) {
140 - txt_utf8_resize(dst, 1, false);
141 - dst->data[0] = '\0';
142 - dst->used = 1;
143 -}
144 -
183 #endif //NETDATA_WINDOWS_EVENTS_UNICODE_H
src/collectors/windows-events.plugin/windows-events.c
+15 -222
@@ -5,118 +5,9 @@
5
6 #include "windows-events.h"
7
8 -#define WINDOWS_EVENTS_WORKER_THREADS 5
9 -#define WINDOWS_EVENTS_DEFAULT_TIMEOUT 600
10 -#define WINDOWS_EVENTS_SCAN_EVERY_USEC (5 * 60 * USEC_PER_SEC)
11 -#define WINDOWS_EVENTS_PROGRESS_EVERY_UT (250 * USEC_PER_MS)
12 -
13 -#define FUNCTION_PROGRESS_EVERY_ROWS (2000)
14 -#define FUNCTION_DATA_ONLY_CHECK_EVERY_ROWS (1000)
15 -#define ANCHOR_DELTA_UT (10 * USEC_PER_SEC)
16 -
8 netdata_mutex_t stdout_mutex = NETDATA_MUTEX_INITIALIZER;
9 static bool plugin_should_exit = false;
10
20 -#define WEVT_FUNCTION_DESCRIPTION "View, search and analyze the Microsoft Windows Events log."
21 -#define WEVT_FUNCTION_NAME "windows-events"
22 -
23 -// functions needed by LQS
24 -
25 -// structures needed by LQS
26 -struct lqs_extension {
27 - wchar_t *query;
28 -
29 - struct {
30 - struct {
31 - size_t completed;
32 - size_t total;
33 - } queries;
34 -
35 - struct {
36 - size_t current_query_total;
37 - size_t completed;
38 - size_t total;
39 - } entries;
40 -
41 - usec_t last_ut;
42 - } progress;
43 -
44 - // struct {
45 - // usec_t start_ut;
46 - // usec_t stop_ut;
47 - // usec_t first_msg_ut;
48 - //
49 - // uint64_t first_msg_seqnum;
50 - // } query_file;
51 -
52 - // struct {
53 - // uint32_t enable_after_samples;
54 - // uint32_t slots;
55 - // uint32_t sampled;
56 - // uint32_t unsampled;
57 - // uint32_t estimated;
58 - // } samples;
59 -
60 - // struct {
61 - // uint32_t enable_after_samples;
62 - // uint32_t every;
63 - // uint32_t skipped;
64 - // uint32_t recalibrate;
65 - // uint32_t sampled;
66 - // uint32_t unsampled;
67 - // uint32_t estimated;
68 - // } samples_per_file;
69 -
70 - // struct {
71 - // usec_t start_ut;
72 - // usec_t end_ut;
73 - // usec_t step_ut;
74 - // uint32_t enable_after_samples;
75 - // uint32_t sampled[SYSTEMD_JOURNAL_SAMPLING_SLOTS];
76 - // uint32_t unsampled[SYSTEMD_JOURNAL_SAMPLING_SLOTS];
77 - // } samples_per_time_slot;
78 -
79 - // per file progress info
80 - // size_t cached_count;
81 -
82 - // progress statistics
83 - usec_t matches_setup_ut;
84 - size_t rows_useful;
85 - size_t rows_read;
86 - size_t bytes_read;
87 - size_t files_matched;
88 - size_t file_working;
89 -};
90 -
91 -// prepare LQS
92 -#define LQS_DEFAULT_SLICE_MODE 0
93 -#define LQS_FUNCTION_NAME WEVT_FUNCTION_NAME
94 -#define LQS_FUNCTION_DESCRIPTION WEVT_FUNCTION_DESCRIPTION
95 -#define LQS_DEFAULT_ITEMS_PER_QUERY 200
96 -#define LQS_DEFAULT_ITEMS_SAMPLING 1000000
97 -#define LQS_SOURCE_TYPE WEVT_SOURCE_TYPE
98 -#define LQS_SOURCE_TYPE_ALL WEVTS_ALL
99 -#define LQS_SOURCE_TYPE_NONE WEVTS_NONE
100 -#define LQS_FUNCTION_GET_INTERNAL_SOURCE_TYPE(value) wevt_internal_source_type(value)
101 -#define LQS_FUNCTION_SOURCE_TO_JSON_ARRAY(wb) wevt_sources_to_json_array(wb)
102 -#include "libnetdata/facets/logs_query_status.h"
103 -
104 -#define WEVT_FIELD_COMPUTER "Computer"
105 -#define WEVT_FIELD_CHANNEL "Channel"
106 -#define WEVT_FIELD_PROVIDER "Provider"
107 -#define WEVT_FIELD_SOURCE "Source"
108 -#define WEVT_FIELD_EVENTRECORDID "EventRecordID"
109 -#define WEVT_FIELD_EVENTID "EventID"
110 -#define WEVT_FIELD_LEVEL "Level"
111 -#define WEVT_FIELD_KEYWORDS "Keywords"
112 -#define WEVT_FIELD_OPCODE "Opcode"
113 -#define WEVT_FIELD_USER "User"
114 -#define WEVT_FIELD_TASK "Task"
115 -#define WEVT_FIELD_PROCESSID "ProcessID"
116 -#define WEVT_FIELD_THREADID "ThreadID"
117 -#define WEVT_FIELD_XML "XML"
118 -#define WEVT_FIELD_MESSAGE "Message"
119 -
11 #define WEVT_ALWAYS_VISIBLE_KEYS NULL
12
13 #define WEVT_KEYS_EXCLUDED_FROM_FACETS \
@@ -157,18 +48,18 @@ FACET_ROW_SEVERITY wevt_levelid_to_facet_severity(FACETS *facets __maybe_unused,
48 int windows_event_level = str2i(buffer_tostring(levelid_rkv->wb));
49
50 switch (windows_event_level) {
160 - case WINEVENT_LEVEL_VERBOSE:
51 + case WEVT_LEVEL_VERBOSE:
52 return FACET_ROW_SEVERITY_DEBUG;
53
54 default:
164 - case WINEVENT_LEVEL_INFORMATION:
55 + case WEVT_LEVEL_INFORMATION:
56 return FACET_ROW_SEVERITY_NORMAL;
57
167 - case WINEVENT_LEVEL_WARNING:
58 + case WEVT_LEVEL_WARNING:
59 return FACET_ROW_SEVERITY_WARNING;
60
170 - case WINEVENT_LEVEL_ERROR:
171 - case WINEVENT_LEVEL_CRITICAL:
61 + case WEVT_LEVEL_ERROR:
62 + case WEVT_LEVEL_CRITICAL:
63 return FACET_ROW_SEVERITY_CRITICAL;
64 }
65 }
@@ -176,15 +67,15 @@ FACET_ROW_SEVERITY wevt_levelid_to_facet_severity(FACETS *facets __maybe_unused,
67 struct wevt_bin_data {
68 bool rendered;
69 WEVT_LOG *log;
179 - EVT_HANDLE bookmark;
70 + EVT_HANDLE hEvent;
71 PROVIDER_META_HANDLE *publisher;
72 };
73
74 static void wevt_cleanup_bin_data(void *data) {
75 struct wevt_bin_data *d = data;
76
186 - if(d->bookmark)
187 - EvtClose(d->bookmark);
77 + if(d->hEvent)
78 + EvtClose(d->hEvent);
79
80 publisher_release(d->publisher);
81 freez(d);
@@ -197,7 +88,7 @@ static inline void wevt_facets_register_bin_data(WEVT_LOG *log, FACETS *facets,
88 d->rendered = false;
89
90 // take the bookmark
200 - d->bookmark = log->bookmark; log->bookmark = NULL;
91 + d->hEvent = log->hEvent; log->hEvent = NULL;
92
93 // dup the publisher
94 d->publisher = publisher_dup(log->publisher);
@@ -208,8 +99,8 @@ static inline void wevt_facets_register_bin_data(WEVT_LOG *log, FACETS *facets,
99 static void wevt_lazy_loading_event_and_xml(struct wevt_bin_data *d, FACET_ROW *row __maybe_unused) {
100 if(d->rendered) return;
101
211 - wevt_get_xml_utf8(d->log, d->publisher, d->bookmark, &d->log->ops.xml);
212 - wevt_get_event_utf8(d->log, d->publisher, d->bookmark, &d->log->ops.event);
102 + wevt_get_xml_utf8(d->log, d->publisher, d->hEvent, &d->log->ops.xml);
103 + wevt_get_event_utf8(d->log, d->publisher, d->hEvent, &d->log->ops.event);
104 d->rendered = true;
105 }
106
@@ -392,7 +283,7 @@ static void wevt_register_fields(LOGS_QUERY_STATUS *lqs) {
283
284 facets_register_dynamic_key_name(
285 facets, WEVT_FIELD_XML,
395 - FACET_KEY_OPTION_NEVER_FACET,
286 + FACET_KEY_OPTION_NEVER_FACET | FACET_KEY_OPTION_PRETTY_XML,
287 wevt_render_xml, NULL);
288
289 #ifdef NETDATA_INTERNAL_CHECKS
@@ -882,111 +773,13 @@ static bool source_is_mine(LOGS_QUERY_SOURCE *src, LOGS_QUERY_STATUS *lqs) {
773 return false;
774 }
775
885 -typedef struct static_utf8_8k {
886 - char buffer[8192];
887 - size_t size;
888 - size_t len;
889 -} STATIC_BUF_8K;
890 -
891 -typedef struct static_unicode_16k {
892 - wchar_t buffer[16384];
893 - size_t size;
894 - size_t len;
895 -} STATIC_UNI_16K;
896 -
897 -static bool wevt_foreach_selected_value_cb(FACETS *facets __maybe_unused, size_t id, const char *key, const char *value, void *data) {
898 - STATIC_BUF_8K *b = data;
899 -
900 - b->len += snprintfz(&b->buffer[b->len], b->size - b->len,
901 - "%s%s=%s",
902 - id ? " or " : "", key, value);
903 -
904 - return b->len < b->size;
905 -}
906 -
907 -static wchar_t *wevt_generate_query(LOGS_QUERY_STATUS *lqs, BUFFER *wb) {
908 - static __thread STATIC_UNI_16K q = {
909 - .size = sizeof(q.buffer) / sizeof(wchar_t),
910 - .len = 0,
911 - };
912 - static __thread STATIC_BUF_8K b = {
913 - .size = sizeof(b.buffer) / sizeof(char),
914 - .len = 0,
915 - };
916 -
917 - lqs_query_timeframe(lqs, ANCHOR_DELTA_UT);
918 -
919 - usec_t seek_to = lqs->query.start_ut;
920 - if(lqs->rq.direction == FACETS_ANCHOR_DIRECTION_BACKWARD)
921 - // windows events queries are limited to millisecond resolution
922 - // so, in order not to lose data, we have to add
923 - // a millisecond when the direction is backward
924 - seek_to += USEC_PER_MS;
925 -
926 - // Convert the microseconds since Unix epoch to FILETIME (used in Windows APIs)
927 - FILETIME fileTime = os_unix_epoch_ut_to_filetime(seek_to);
928 -
929 - // Convert FILETIME to SYSTEMTIME for use in XPath
930 - SYSTEMTIME systemTime;
931 - if (!FileTimeToSystemTime(&fileTime, &systemTime)) {
932 - nd_log(NDLS_COLLECTORS, NDLP_ERR, "FileTimeToSystemTime() failed");
933 - return NULL;
934 - }
935 -
936 - // Format SYSTEMTIME into ISO 8601 format (YYYY-MM-DDTHH:MM:SS.sssZ)
937 - q.len = swprintf(q.buffer, q.size,
938 - L"Event/System[TimeCreated[@SystemTime%ls\"%04d-%02d-%02dT%02d:%02d:%02d.%03dZ\"]",
939 - lqs->rq.direction == FACETS_ANCHOR_DIRECTION_BACKWARD ? L"<=" : L">=",
940 - systemTime.wYear, systemTime.wMonth, systemTime.wDay,
941 - systemTime.wHour, systemTime.wMinute, systemTime.wSecond, systemTime.wMilliseconds);
942 -
943 -
944 - if(lqs->rq.slice) {
945 - b.len = snprintf(b.buffer, b.size, " and (");
946 - if (facets_foreach_selected_value_in_key(
947 - lqs->facets,
948 - WEVT_FIELD_LEVEL,
949 - sizeof(WEVT_FIELD_LEVEL) - 1,
950 - used_hashes_registry,
951 - wevt_foreach_selected_value_cb,
952 - &b)) {
953 - b.len += snprintf(&b.buffer[b.len], b.size - b.len, ")");
954 - if (b.len < b.size) {
955 - utf82unicode(&q.buffer[q.len], q.size - q.len, b.buffer);
956 - q.len = wcslen(q.buffer);
957 - }
958 - }
959 -
960 - b.len = snprintf(b.buffer, b.size, " and (");
961 - if (facets_foreach_selected_value_in_key(
962 - lqs->facets,
963 - WEVT_FIELD_EVENTID,
964 - sizeof(WEVT_FIELD_EVENTID) - 1,
965 - used_hashes_registry,
966 - wevt_foreach_selected_value_cb,
967 - &b)) {
968 - b.len += snprintf(&b.buffer[b.len], b.size - b.len, ")");
969 - if (b.len < b.size) {
970 - utf82unicode(&q.buffer[q.len], q.size - q.len, b.buffer);
971 - q.len = wcslen(q.buffer);
972 - }
973 - }
974 - }
975 -
976 - q.len += swprintf(&q.buffer[q.len], q.size - q.len, L"]");
977 -
978 - buffer_json_member_add_string(wb, "_query", channel2utf8(q.buffer));
979 -
980 - return q.buffer;
981 -}
982 -
776 static int wevt_master_query(BUFFER *wb __maybe_unused, LOGS_QUERY_STATUS *lqs __maybe_unused) {
777 // make sure the sources list is updated
778 wevt_sources_scan();
779
987 - lqs->c.query = wevt_generate_query(lqs, wb);
780 + lqs->c.query = wevt_generate_query_no_xpath(lqs, wb);
781 if(!lqs->c.query)
989 - return rrd_call_function_error(wb, "failed to generate XPath query", HTTP_RESP_INTERNAL_SERVER_ERROR);
782 + return rrd_call_function_error(wb, "failed to generate query", HTTP_RESP_INTERNAL_SERVER_ERROR);
783
784 FACETS *facets = lqs->facets;
785
@@ -1355,9 +1148,9 @@ int main(int argc __maybe_unused, char **argv __maybe_unused) {
1148 struct {
1149 const char *func;
1150 } array[] = {
1151 + { "windows-events after:-8640000 before:0 last:200 source:All" },
1152 //{ "windows-events after:-86400 before:0 direction:backward last:200 facets:HdUoSYab5wV,Cq2r7mRUv4a,LAnVlsIQfeD,BnPLNbA5VWT,KeCITtVD5AD,HytMJ9kj82B,JM3OPW3kHn6,H106l8MXSSr,HREiMN.4Ahu,ClaDGnYSQE7,ApYltST_icg,PtkRm91M0En data_only:false slice:true source:All" },
1153 //{ "windows-events after:1726055370 before:1726056270 direction:backward last:200 facets:HdUoSYab5wV,Cq2r7mRUv4a,LAnVlsIQfeD,BnPLNbA5VWT,KeCITtVD5AD,HytMJ9kj82B,LT.Xp9I9tiP,No4kPTQbS.g,LQ2LQzfE8EG,PtkRm91M0En,JM3OPW3kHn6,ClaDGnYSQE7,H106l8MXSSr,HREiMN.4Ahu data_only:false source:All HytMJ9kj82B:BlC24d5JBBV,PtVoyIuX.MU,HMj1B38kHTv KeCITtVD5AD:PY1JtCeWwSe,O9kz5J37nNl,JZoJURadhDb" },
1360 - { "windows-events after:1725738894 before:0 last:200 facets:HdUoSYab5wV,Cq2r7mRUv4a,LAnVlsIQfeD,BnPLNbA5VWT,KeCITtVD5AD,HytMJ9kj82B,JM3OPW3kHn6,H106l8MXSSr,HREiMN.4Ahu,ClaDGnYSQE7,ApYltST_icg,PtkRm91M0En source:All" },
1154 // { "windows-events after:1725636012 before:1726240812 direction:backward last:200 facets:HdUoSYab5wV,Cq2r7mRUv4a,LAnVlsIQfeD,BnPLNbA5VWT,KeCITtVD5AD,HytMJ9kj82B,JM3OPW3kHn6,H106l8MXSSr,HREiMN.4Ahu,ClaDGnYSQE7,ApYltST_icg,PtkRm91M0En data_only:false source:All PtkRm91M0En:LDzHbP5libb" },
1155 //{ "windows-events after:1725650386 before:1725736786 anchor:1725652420809461 direction:forward last:200 facets:HWNGeY7tg6c,LAnVlsIQfeD,BnPLNbA5VWT,Cq2r7mRUv4a,KeCITtVD5AD,I_Amz_APBm3,HytMJ9kj82B,LT.Xp9I9tiP,No4kPTQbS.g,LQ2LQzfE8EG,PtkRm91M0En,JM3OPW3kHn6 if_modified_since:1725736649011085 data_only:true delta:true tail:true source:all Cq2r7mRUv4a:PPc9fUy.q6o No4kPTQbS.g:Dwo9PhK27v3 HytMJ9kj82B:KbbznGjt_9r LAnVlsIQfeD:OfU1t5cpjgG JM3OPW3kHn6:CS_0g5AEpy2" },
1156 //{ "windows-events info after:1725650420 before:1725736820" },
src/collectors/windows-events.plugin/windows-events.h
+217 -105
@@ -19,116 +19,228 @@ typedef enum {
19 WEVT_CANCELLED,
20 } WEVT_QUERY_STATUS;
21
22 -#define WINEVENT_CHANNEL_CLASSIC_TRACE 0x0
23 -#define WINEVENT_CHANNEL_GLOBAL_SYSTEM 0x8
24 -#define WINEVENT_CHANNEL_GLOBAL_APPLICATION 0x9
25 -#define WINEVENT_CHANNEL_GLOBAL_SECURITY 0xa
26 -
27 -#define WINEVENT_LEVEL_NONE 0x0
28 -#define WINEVENT_LEVEL_CRITICAL 0x1
29 -#define WINEVENT_LEVEL_ERROR 0x2
30 -#define WINEVENT_LEVEL_WARNING 0x3
31 -#define WINEVENT_LEVEL_INFORMATION 0x4
32 -#define WINEVENT_LEVEL_VERBOSE 0x5
33 -#define WINEVENT_LEVEL_RESERVED_6 0x6
34 -#define WINEVENT_LEVEL_RESERVED_7 0x7
35 -#define WINEVENT_LEVEL_RESERVED_8 0x8
36 -#define WINEVENT_LEVEL_RESERVED_9 0x9
37 -#define WINEVENT_LEVEL_RESERVED_10 0xa
38 -#define WINEVENT_LEVEL_RESERVED_11 0xb
39 -#define WINEVENT_LEVEL_RESERVED_12 0xc
40 -#define WINEVENT_LEVEL_RESERVED_13 0xd
41 -#define WINEVENT_LEVEL_RESERVED_14 0xe
42 -#define WINEVENT_LEVEL_RESERVED_15 0xf
43 -
44 -#define WINEVENT_OPCODE_INFO 0x0
45 -#define WINEVENT_OPCODE_START 0x1
46 -#define WINEVENT_OPCODE_STOP 0x2
47 -#define WINEVENT_OPCODE_DC_START 0x3
48 -#define WINEVENT_OPCODE_DC_STOP 0x4
49 -#define WINEVENT_OPCODE_EXTENSION 0x5
50 -#define WINEVENT_OPCODE_REPLY 0x6
51 -#define WINEVENT_OPCODE_RESUME 0x7
52 -#define WINEVENT_OPCODE_SUSPEND 0x8
53 -#define WINEVENT_OPCODE_SEND 0x9
54 -#define WINEVENT_OPCODE_RECEIVE 0xf0
55 -#define WINEVENT_OPCODE_RESERVED_241 0xf1
56 -#define WINEVENT_OPCODE_RESERVED_242 0xf2
57 -#define WINEVENT_OPCODE_RESERVED_243 0xf3
58 -#define WINEVENT_OPCODE_RESERVED_244 0xf4
59 -#define WINEVENT_OPCODE_RESERVED_245 0xf5
60 -#define WINEVENT_OPCODE_RESERVED_246 0xf6
61 -#define WINEVENT_OPCODE_RESERVED_247 0xf7
62 -#define WINEVENT_OPCODE_RESERVED_248 0xf8
63 -#define WINEVENT_OPCODE_RESERVED_249 0xf9
64 -#define WINEVENT_OPCODE_RESERVED_250 0xfa
65 -#define WINEVENT_OPCODE_RESERVED_251 0xfb
66 -#define WINEVENT_OPCODE_RESERVED_252 0xfc
67 -#define WINEVENT_OPCODE_RESERVED_253 0xfd
68 -#define WINEVENT_OPCODE_RESERVED_254 0xfe
69 -#define WINEVENT_OPCODE_RESERVED_255 0xff
70 -
71 -#define WINEVENT_TASK_NONE 0x0
72 -
73 -#define WINEVT_KEYWORD_NONE 0x0
74 -#define WINEVENT_KEYWORD_RESPONSE_TIME 0x0001000000000000
75 -#define WINEVENT_KEYWORD_WDI_CONTEXT 0x0002000000000000
76 -#define WINEVENT_KEYWORD_WDI_DIAG 0x0004000000000000
77 -#define WINEVENT_KEYWORD_SQM 0x0008000000000000
78 -#define WINEVENT_KEYWORD_AUDIT_FAILURE 0x0010000000000000
79 -#define WINEVENT_KEYWORD_AUDIT_SUCCESS 0x0020000000000000
80 -#define WINEVENT_KEYWORD_CORRELATION_HINT 0x0040000000000000
81 -#define WINEVENT_KEYWORD_EVENTLOG_CLASSIC 0x0080000000000000
82 -#define WINEVENT_KEYWORD_RESERVED_56 0x0100000000000000
83 -#define WINEVENT_KEYWORD_RESERVED_57 0x0200000000000000
84 -#define WINEVENT_KEYWORD_RESERVED_58 0x0400000000000000
85 -#define WINEVENT_KEYWORD_RESERVED_59 0x0800000000000000
86 -#define WINEVENT_KEYWORDE_RESERVED_60 0x1000000000000000
87 -#define WINEVENT_KEYWORD_RESERVED_61 0x2000000000000000
88 -#define WINEVENT_KEYWORD_RESERVED_62 0x4000000000000000
89 -#define WINEVENT_KEYWORD_RESERVED_63 0x8000000000000000
90 -
91 -#define WINEVENT_NAME_NONE "None"
92 -
93 -#define WINEVENT_NAME_CRITICAL "Critical"
94 -#define WINEVENT_NAME_ERROR "Error"
95 -#define WINEVENT_NAME_WARNING "Warning"
96 -#define WINEVENT_NAME_INFORMATION "Information"
97 -#define WINEVENT_NAME_VERBOSE "Verbose"
98 -
99 -#define WINEVENT_NAME_INFO "Info"
100 -#define WINEVENT_NAME_START "Start"
101 -#define WINEVENT_NAME_STOP "Stop"
102 -#define WINEVENT_NAME_DC_START "DC Start"
103 -#define WINEVENT_NAME_DC_STOP "DC Stop"
104 -#define WINEVENT_NAME_EXTENSION "Extension"
105 -#define WINEVENT_NAME_REPLY "Reply"
106 -#define WINEVENT_NAME_RESUME "Resume"
107 -#define WINEVENT_NAME_SUSPEND "Suspend"
108 -#define WINEVENT_NAME_SEND "Send"
109 -#define WINEVENT_NAME_RECEIVE "Receive"
110 -
111 -#define WINEVENT_NAME_RESPONSE_TIME "Response Time"
112 -#define WINEVENT_NAME_WDI_CONTEXT "WDI Context"
113 -#define WINEVENT_NAME_WDI_DIAG "WDI Diagnostics"
114 -#define WINEVENT_NAME_SQM "SQM (Software Quality Metrics)"
115 -#define WINEVENT_NAME_AUDIT_FAILURE "Audit Failure"
116 -#define WINEVENT_NAME_AUDIT_SUCCESS "Audit Success"
117 -#define WINEVENT_NAME_CORRELATION_HINT "Correlation Hint"
118 -#define WINEVENT_NAME_EVENTLOG_CLASSIC "Event Log Classic"
119 -
120 -#define WINEVENT_NAME_LEVEL_PREFIX "Level "
121 -#define WINEVENT_NAME_KEYWORDS_PREFIX "Keywords "
122 -#define WINEVENT_NAME_OPCODE_PREFIX "Opcode "
123 -#define WINEVENT_NAME_TASK_PREFIX "Task "
22 +#define WEVT_CHANNEL_CLASSIC_TRACE 0x0
23 +#define WEVT_CHANNEL_GLOBAL_SYSTEM 0x8
24 +#define WEVT_CHANNEL_GLOBAL_APPLICATION 0x9
25 +#define WEVT_CHANNEL_GLOBAL_SECURITY 0xa
26 +
27 +#define WEVT_LEVEL_NONE 0x0
28 +#define WEVT_LEVEL_CRITICAL 0x1
29 +#define WEVT_LEVEL_ERROR 0x2
30 +#define WEVT_LEVEL_WARNING 0x3
31 +#define WEVT_LEVEL_INFORMATION 0x4
32 +#define WEVT_LEVEL_VERBOSE 0x5
33 +#define WEVT_LEVEL_RESERVED_6 0x6
34 +#define WEVT_LEVEL_RESERVED_7 0x7
35 +#define WEVT_LEVEL_RESERVED_8 0x8
36 +#define WEVT_LEVEL_RESERVED_9 0x9
37 +#define WEVT_LEVEL_RESERVED_10 0xa
38 +#define WEVT_LEVEL_RESERVED_11 0xb
39 +#define WEVT_LEVEL_RESERVED_12 0xc
40 +#define WEVT_LEVEL_RESERVED_13 0xd
41 +#define WEVT_LEVEL_RESERVED_14 0xe
42 +#define WEVT_LEVEL_RESERVED_15 0xf
43 +
44 +#define WEVT_OPCODE_INFO 0x0
45 +#define WEVT_OPCODE_START 0x1
46 +#define WEVT_OPCODE_STOP 0x2
47 +#define WEVT_OPCODE_DC_START 0x3
48 +#define WEVT_OPCODE_DC_STOP 0x4
49 +#define WEVT_OPCODE_EXTENSION 0x5
50 +#define WEVT_OPCODE_REPLY 0x6
51 +#define WEVT_OPCODE_RESUME 0x7
52 +#define WEVT_OPCODE_SUSPEND 0x8
53 +#define WEVT_OPCODE_SEND 0x9
54 +#define WEVT_OPCODE_RECEIVE 0xf0
55 +#define WEVT_OPCODE_RESERVED_241 0xf1
56 +#define WEVT_OPCODE_RESERVED_242 0xf2
57 +#define WEVT_OPCODE_RESERVED_243 0xf3
58 +#define WEVT_OPCODE_RESERVED_244 0xf4
59 +#define WEVT_OPCODE_RESERVED_245 0xf5
60 +#define WEVT_OPCODE_RESERVED_246 0xf6
61 +#define WEVT_OPCODE_RESERVED_247 0xf7
62 +#define WEVT_OPCODE_RESERVED_248 0xf8
63 +#define WEVT_OPCODE_RESERVED_249 0xf9
64 +#define WEVT_OPCODE_RESERVED_250 0xfa
65 +#define WEVT_OPCODE_RESERVED_251 0xfb
66 +#define WEVT_OPCODE_RESERVED_252 0xfc
67 +#define WEVT_OPCODE_RESERVED_253 0xfd
68 +#define WEVT_OPCODE_RESERVED_254 0xfe
69 +#define WEVT_OPCODE_RESERVED_255 0xff
70 +
71 +#define WEVT_TASK_NONE 0x0
72 +
73 +#define WEVT_KEYWORD_NONE 0x0
74 +#define WEVT_KEYWORD_RESPONSE_TIME 0x0001000000000000
75 +#define WEVT_KEYWORD_WDI_CONTEXT 0x0002000000000000
76 +#define WEVT_KEYWORD_WDI_DIAG 0x0004000000000000
77 +#define WEVT_KEYWORD_SQM 0x0008000000000000
78 +#define WEVT_KEYWORD_AUDIT_FAILURE 0x0010000000000000
79 +#define WEVT_KEYWORD_AUDIT_SUCCESS 0x0020000000000000
80 +#define WEVT_KEYWORD_CORRELATION_HINT 0x0040000000000000
81 +#define WEVT_KEYWORD_EVENTLOG_CLASSIC 0x0080000000000000
82 +#define WEVT_KEYWORD_RESERVED_56 0x0100000000000000
83 +#define WEVT_KEYWORD_RESERVED_57 0x0200000000000000
84 +#define WEVT_KEYWORD_RESERVED_58 0x0400000000000000
85 +#define WEVT_KEYWORD_RESERVED_59 0x0800000000000000
86 +#define WEVT_KEYWORDE_RESERVED_60 0x1000000000000000
87 +#define WEVT_KEYWORD_RESERVED_61 0x2000000000000000
88 +#define WEVT_KEYWORD_RESERVED_62 0x4000000000000000
89 +#define WEVT_KEYWORD_RESERVED_63 0x8000000000000000
90 +
91 +#define WEVT_LEVEL_NAME_NONE "None"
92 +#define WEVT_LEVEL_NAME_CRITICAL "Critical"
93 +#define WEVT_LEVEL_NAME_ERROR "Error"
94 +#define WEVT_LEVEL_NAME_WARNING "Warning"
95 +#define WEVT_LEVEL_NAME_INFORMATION "Information"
96 +#define WEVT_LEVEL_NAME_VERBOSE "Verbose"
97 +
98 +#define WEVT_OPCODE_NAME_INFO "Info"
99 +#define WEVT_OPCODE_NAME_START "Start"
100 +#define WEVT_OPCODE_NAME_STOP "Stop"
101 +#define WEVT_OPCODE_NAME_DC_START "DC Start"
102 +#define WEVT_OPCODE_NAME_DC_STOP "DC Stop"
103 +#define WEVT_OPCODE_NAME_EXTENSION "Extension"
104 +#define WEVT_OPCODE_NAME_REPLY "Reply"
105 +#define WEVT_OPCODE_NAME_RESUME "Resume"
106 +#define WEVT_OPCODE_NAME_SUSPEND "Suspend"
107 +#define WEVT_OPCODE_NAME_SEND "Send"
108 +#define WEVT_OPCODE_NAME_RECEIVE "Receive"
109 +
110 +#define WEVT_TASK_NAME_NONE "None"
111 +
112 +#define WEVT_KEYWORD_NAME_NONE "None"
113 +#define WEVT_KEYWORD_NAME_RESPONSE_TIME "Response Time"
114 +#define WEVT_KEYWORD_NAME_WDI_CONTEXT "WDI Context"
115 +#define WEVT_KEYWORD_NAME_WDI_DIAG "WDI Diagnostics"
116 +#define WEVT_KEYWORD_NAME_SQM "SQM (Software Quality Metrics)"
117 +#define WEVT_KEYWORD_NAME_AUDIT_FAILURE "Audit Failure"
118 +#define WEVT_KEYWORD_NAME_AUDIT_SUCCESS "Audit Success"
119 +#define WEVT_KEYWORD_NAME_CORRELATION_HINT "Correlation Hint"
120 +#define WEVT_KEYWORD_NAME_EVENTLOG_CLASSIC "Event Log Classic"
121 +
122 +#define WEVT_PREFIX_LEVEL "Level " // the space at the end is needed
123 +#define WEVT_PREFIX_KEYWORDS "Keywords " // the space at the end is needed
124 +#define WEVT_PREFIX_OPCODE "Opcode " // the space at the end is needed
125 +#define WEVT_PREFIX_TASK "Task " // the space at the end is needed
126
125 -
126 -#include "windows-events-unicode.h"
127 -#include "windows-events-query.h"
127 #include "windows-events-sources.h"
128 +#include "windows-events-unicode.h"
129 #include "windows-events-sid.h"
130 #include "windows-events-xml.h"
131 #include "windows-events-publishers.h"
132 #include "windows-events-fields-cache.h"
133 +#include "windows-events-query.h"
134 +
135 +#define WEVT_FUNCTION_DESCRIPTION "View, search and analyze the Microsoft Windows Events log."
136 +#define WEVT_FUNCTION_NAME "windows-events"
137 +
138 +#define WINDOWS_EVENTS_WORKER_THREADS 5
139 +#define WINDOWS_EVENTS_DEFAULT_TIMEOUT 600
140 +#define WINDOWS_EVENTS_SCAN_EVERY_USEC (5 * 60 * USEC_PER_SEC)
141 +#define WINDOWS_EVENTS_PROGRESS_EVERY_UT (250 * USEC_PER_MS)
142 +
143 +#define FUNCTION_PROGRESS_EVERY_ROWS (2000)
144 +#define FUNCTION_DATA_ONLY_CHECK_EVERY_ROWS (1000)
145 +#define ANCHOR_DELTA_UT (10 * USEC_PER_SEC)
146 +
147 +#define WEVT_FIELD_COMPUTER "Computer"
148 +#define WEVT_FIELD_CHANNEL "Channel"
149 +#define WEVT_FIELD_PROVIDER "Provider"
150 +#define WEVT_FIELD_SOURCE "Source"
151 +#define WEVT_FIELD_EVENTRECORDID "EventRecordID"
152 +#define WEVT_FIELD_EVENTID "EventID"
153 +#define WEVT_FIELD_LEVEL "Level"
154 +#define WEVT_FIELD_KEYWORDS "Keywords"
155 +#define WEVT_FIELD_OPCODE "Opcode"
156 +#define WEVT_FIELD_USER "User"
157 +#define WEVT_FIELD_TASK "Task"
158 +#define WEVT_FIELD_PROCESSID "ProcessID"
159 +#define WEVT_FIELD_THREADID "ThreadID"
160 +#define WEVT_FIELD_XML "XML"
161 +#define WEVT_FIELD_MESSAGE "Message"
162 +
163 +// functions needed by LQS
164 +
165 +// structures needed by LQS
166 +struct lqs_extension {
167 + wchar_t *query;
168 +
169 + struct {
170 + struct {
171 + size_t completed;
172 + size_t total;
173 + } queries;
174 +
175 + struct {
176 + size_t current_query_total;
177 + size_t completed;
178 + size_t total;
179 + } entries;
180 +
181 + usec_t last_ut;
182 + } progress;
183 +
184 + // struct {
185 + // usec_t start_ut;
186 + // usec_t stop_ut;
187 + // usec_t first_msg_ut;
188 + //
189 + // uint64_t first_msg_seqnum;
190 + // } query_file;
191 +
192 + // struct {
193 + // uint32_t enable_after_samples;
194 + // uint32_t slots;
195 + // uint32_t sampled;
196 + // uint32_t unsampled;
197 + // uint32_t estimated;
198 + // } samples;
199 +
200 + // struct {
201 + // uint32_t enable_after_samples;
202 + // uint32_t every;
203 + // uint32_t skipped;
204 + // uint32_t recalibrate;
205 + // uint32_t sampled;
206 + // uint32_t unsampled;
207 + // uint32_t estimated;
208 + // } samples_per_file;
209 +
210 + // struct {
211 + // usec_t start_ut;
212 + // usec_t end_ut;
213 + // usec_t step_ut;
214 + // uint32_t enable_after_samples;
215 + // uint32_t sampled[SYSTEMD_JOURNAL_SAMPLING_SLOTS];
216 + // uint32_t unsampled[SYSTEMD_JOURNAL_SAMPLING_SLOTS];
217 + // } samples_per_time_slot;
218 +
219 + // per file progress info
220 + // size_t cached_count;
221 +
222 + // progress statistics
223 + usec_t matches_setup_ut;
224 + size_t rows_useful;
225 + size_t rows_read;
226 + size_t bytes_read;
227 + size_t files_matched;
228 + size_t file_working;
229 +};
230 +
231 +// prepare LQS
232 +#define LQS_DEFAULT_SLICE_MODE 0
233 +#define LQS_FUNCTION_NAME WEVT_FUNCTION_NAME
234 +#define LQS_FUNCTION_DESCRIPTION WEVT_FUNCTION_DESCRIPTION
235 +#define LQS_DEFAULT_ITEMS_PER_QUERY 200
236 +#define LQS_DEFAULT_ITEMS_SAMPLING 1000000
237 +#define LQS_SOURCE_TYPE WEVT_SOURCE_TYPE
238 +#define LQS_SOURCE_TYPE_ALL WEVTS_ALL
239 +#define LQS_SOURCE_TYPE_NONE WEVTS_NONE
240 +#define LQS_FUNCTION_GET_INTERNAL_SOURCE_TYPE(value) wevt_internal_source_type(value)
241 +#define LQS_FUNCTION_SOURCE_TO_JSON_ARRAY(wb) wevt_sources_to_json_array(wb)
242 +#include "libnetdata/facets/logs_query_status.h"
243 +
244 +#include "windows-events-query-builder.h" // needs the LQS definition, so it has to be last
245
246 #endif //NETDATA_WINDOWS_EVENTS_H
src/libnetdata/buffer/buffer.h
+4
@@ -1118,6 +1118,7 @@ typedef enum __attribute__((packed)) {
1118 RRDF_FIELD_TRANSFORM_DURATION_S, // transform as duration in second to a human-readable duration
1119 RRDF_FIELD_TRANSFORM_DATETIME_MS, // UNIX epoch timestamp in ms
1120 RRDF_FIELD_TRANSFORM_DATETIME_USEC, // UNIX epoch timestamp in usec
1121 + RRDF_FIELD_TRANSFORM_XML, // format the field with an XML prettifier
1122 } RRDF_FIELD_TRANSFORM;
1123
1124 static inline const char *rrdf_field_transform_to_string(RRDF_FIELD_TRANSFORM transform) {
@@ -1137,6 +1138,9 @@ static inline const char *rrdf_field_transform_to_string(RRDF_FIELD_TRANSFORM tr
1138
1139 case RRDF_FIELD_TRANSFORM_DATETIME_USEC:
1140 return "datetime_usec";
1141 +
1142 + case RRDF_FIELD_TRANSFORM_XML:
1143 + return "xml";
1144 }
1145 }
1146
src/libnetdata/facets/facets.c
+13 -13
@@ -726,7 +726,7 @@ static inline FACET_KEY *FACETS_KEY_CREATE(FACETS *facets, FACETS_HASH hash, con
726 k->current_value.b = buffer_create(sizeof(FACET_VALUE_UNSET), NULL);
727 k->default_selected_for_values = true;
728
729 - if(!(k->options & FACET_KEY_OPTION_REORDER))
729 + if(unlikely((k->options & (FACET_KEY_OPTION_REORDER | FACET_KEY_OPTION_REORDER_DONE)) == 0))
730 k->order = facets->order++;
731
732 if((k->options & FACET_KEY_OPTION_FTS) || (facets->options & FACETS_OPTION_ALL_KEYS_FTS))
@@ -759,10 +759,11 @@ static inline FACET_KEY *FACETS_KEY_ADD_TO_INDEX(FACETS *facets, FACETS_HASH has
759 FACET_KEY *k = SIMPLE_HASHTABLE_SLOT_DATA(slot);
760
761 facet_key_set_name(k, name, name_length);
762 + k->options |= options;
763
763 - if(unlikely(k->options & FACET_KEY_OPTION_REORDER)) {
764 + if(unlikely((k->options & (FACET_KEY_OPTION_REORDER | FACET_KEY_OPTION_REORDER_DONE)) == FACET_KEY_OPTION_REORDER)) {
765 k->order = facets->order++;
765 - k->options &= ~FACET_KEY_OPTION_REORDER;
766 + k->options |= FACET_KEY_OPTION_REORDER_DONE;
767 }
768
769 return k;
@@ -2655,15 +2656,12 @@ void facets_report(FACETS *facets, BUFFER *wb, DICTIONARY *used_hashes_registry)
2656 FACET_KEY *k;
2657 foreach_key_in_facets(facets, k) {
2658 RRDF_FIELD_OPTIONS options = RRDF_FIELD_OPTS_WRAP;
2658 - bool visible = k->options & (FACET_KEY_OPTION_VISIBLE | FACET_KEY_OPTION_STICKY);
2659 + RRDF_FIELD_VISUAL visual = (k->options & FACET_KEY_OPTION_RICH_TEXT) ? RRDF_FIELD_VISUAL_RICH : RRDF_FIELD_VISUAL_VALUE;
2660 + RRDF_FIELD_TRANSFORM transform = RRDF_FIELD_TRANSFORM_NONE;
2661
2660 - if ((facets->options & FACETS_OPTION_ALL_FACETS_VISIBLE && k->values.enabled))
2661 - visible = true;
2662 -
2663 - if (!visible)
2664 - visible = simple_pattern_matches(facets->visible_keys, k->name);
2665 -
2666 - if (visible)
2662 + if (k->options & (FACET_KEY_OPTION_VISIBLE | FACET_KEY_OPTION_STICKY) ||
2663 + ((facets->options & FACETS_OPTION_ALL_FACETS_VISIBLE) && k->values.enabled) ||
2664 + simple_pattern_matches(facets->visible_keys, k->name))
2665 options |= RRDF_FIELD_OPTS_VISIBLE;
2666
2667 if (k->options & FACET_KEY_OPTION_MAIN_TEXT)
@@ -2672,14 +2670,16 @@ void facets_report(FACETS *facets, BUFFER *wb, DICTIONARY *used_hashes_registry)
2670 if (k->options & FACET_KEY_OPTION_EXPANDED_FILTER)
2671 options |= RRDF_FIELD_OPTS_EXPANDED_FILTER;
2672
2673 + if (k->options & FACET_KEY_OPTION_PRETTY_XML)
2674 + transform = RRDF_FIELD_TRANSFORM_XML;
2675 +
2676 const char *hash_str = hash_to_static_string(k->hash);
2677
2678 buffer_rrdf_table_add_field(
2679 wb, field_id++,
2680 hash_str, k->name ? k->name : hash_str,
2681 RRDF_FIELD_TYPE_STRING,
2681 - (k->options & FACET_KEY_OPTION_RICH_TEXT) ? RRDF_FIELD_VISUAL_RICH : RRDF_FIELD_VISUAL_VALUE,
2682 - RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN,
2682 + visual, transform, 0, NULL, NAN,
2683 RRDF_FIELD_SORT_FIXED,
2684 NULL,
2685 RRDF_FIELD_SUMMARY_COUNT,
src/libnetdata/facets/facets.h
+4 -2
@@ -33,8 +33,10 @@ typedef enum __attribute__((packed)) {
33 FACET_KEY_OPTION_MAIN_TEXT = (1 << 6), // full width and wrap
34 FACET_KEY_OPTION_RICH_TEXT = (1 << 7),
35 FACET_KEY_OPTION_REORDER = (1 << 8), // give the key a new order id on first encounter
36 - FACET_KEY_OPTION_TRANSFORM_VIEW = (1 << 9), // when registering the transformation, do it only at the view, not on all data
37 - FACET_KEY_OPTION_EXPANDED_FILTER = (1 << 10), // the presentation should have this filter expanded by default
36 + FACET_KEY_OPTION_REORDER_DONE = (1 << 9), // done re-ordering for this field
37 + FACET_KEY_OPTION_TRANSFORM_VIEW = (1 << 10), // when registering the transformation, do it only at the view, not on all data
38 + FACET_KEY_OPTION_EXPANDED_FILTER = (1 << 11), // the presentation should have this filter expanded by default
39 + FACET_KEY_OPTION_PRETTY_XML = (1 << 12), // instruct the UI to parse this as an XML document
40 } FACET_KEY_OPTIONS;
41
42 typedef enum __attribute__((packed)) {
src/libnetdata/parsers/entries.c new
+183
@@ -0,0 +1,183 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "entries.h"
4 +
5 +// Define multipliers for base 10 (decimal) units
6 +#define ENTRIES_MULTIPLIER_BASE10 1000ULL
7 +#define ENTRIES_MULTIPLIER_K (ENTRIES_MULTIPLIER_BASE10)
8 +#define ENTRIES_MULTIPLIER_M (ENTRIES_MULTIPLIER_K * ENTRIES_MULTIPLIER_BASE10)
9 +#define ENTRIES_MULTIPLIER_G (ENTRIES_MULTIPLIER_M * ENTRIES_MULTIPLIER_BASE10)
10 +#define ENTRIES_MULTIPLIER_T (ENTRIES_MULTIPLIER_G * ENTRIES_MULTIPLIER_BASE10)
11 +#define ENTRIES_MULTIPLIER_P (ENTRIES_MULTIPLIER_T * ENTRIES_MULTIPLIER_BASE10)
12 +#define ENTRIES_MULTIPLIER_E (ENTRIES_MULTIPLIER_P * ENTRIES_MULTIPLIER_BASE10)
13 +#define ENTRIES_MULTIPLIER_Z (ENTRIES_MULTIPLIER_E * ENTRIES_MULTIPLIER_BASE10)
14 +#define ENTRIES_MULTIPLIER_Y (ENTRIES_MULTIPLIER_Z * ENTRIES_MULTIPLIER_BASE10)
15 +
16 +// Define a structure to map size units to their multipliers
17 +static const struct size_unit {
18 + const char *unit;
19 + const bool formatter; // true when this unit should be used when formatting to string
20 + const uint64_t multiplier;
21 +} entries_units[] = {
22 + // the order of this table is important: smaller to bigger units!
23 +
24 + { .unit = "", .formatter = true, .multiplier = 1ULL },
25 + { .unit = "k", .formatter = false, .multiplier = ENTRIES_MULTIPLIER_K },
26 + { .unit = "K", .formatter = true, .multiplier = ENTRIES_MULTIPLIER_K },
27 + { .unit = "M", .formatter = true, .multiplier = ENTRIES_MULTIPLIER_M },
28 + { .unit = "G", .formatter = true, .multiplier = ENTRIES_MULTIPLIER_G },
29 + { .unit = "T", .formatter = true, .multiplier = ENTRIES_MULTIPLIER_T },
30 + { .unit = "P", .formatter = true, .multiplier = ENTRIES_MULTIPLIER_P },
31 + { .unit = "E", .formatter = true, .multiplier = ENTRIES_MULTIPLIER_E },
32 + { .unit = "Z", .formatter = true, .multiplier = ENTRIES_MULTIPLIER_Z },
33 + { .unit = "Y", .formatter = true, .multiplier = ENTRIES_MULTIPLIER_Y },
34 +};
35 +
36 +static inline const struct size_unit *entries_find_unit(const char *unit) {
37 + if (!unit || !*unit) unit = "";
38 +
39 + for (size_t i = 0; i < sizeof(entries_units) / sizeof(entries_units[0]); i++) {
40 + const struct size_unit *su = &entries_units[i];
41 + if ((uint8_t)unit[0] == (uint8_t)su->unit[0] && strcmp(unit, su->unit) == 0)
42 + return su;
43 + }
44 +
45 + return NULL;
46 +}
47 +
48 +static inline double entries_round_to_resolution_dbl2(uint64_t value, uint64_t resolution) {
49 + double converted = (double)value / (double)resolution;
50 + return round(converted * 100.0) / 100.0;
51 +}
52 +
53 +static inline uint64_t entries_round_to_resolution_int(uint64_t value, uint64_t resolution) {
54 + return (value + (resolution / 2)) / resolution;
55 +}
56 +
57 +// -------------------------------------------------------------------------------------------------------------------
58 +// parse a size string
59 +
60 +bool entries_parse(const char *entries_str, uint64_t *result, const char *default_unit) {
61 + if (!entries_str || !*entries_str) {
62 + *result = 0;
63 + return false;
64 + }
65 +
66 + const struct size_unit *su_def = entries_find_unit(default_unit);
67 + if(!su_def) {
68 + *result = 0;
69 + return false;
70 + }
71 +
72 + const char *s = entries_str;
73 +
74 + // Skip leading spaces
75 + while (isspace((uint8_t)*s)) s++;
76 +
77 + if(strcmp(s, "off") == 0) {
78 + *result = 0;
79 + return true;
80 + }
81 +
82 + // Parse the number
83 + const char *number_start = s;
84 + NETDATA_DOUBLE value = strtondd(s, (char **)&s);
85 +
86 + // If no valid number found, return false
87 + if (s == number_start || value < 0) {
88 + *result = 0;
89 + return false;
90 + }
91 +
92 + // Skip spaces between number and unit
93 + while (isspace((uint8_t)*s)) s++;
94 +
95 + const char *unit_start = s;
96 + while (isalpha((uint8_t)*s)) s++;
97 +
98 + char unit[4];
99 + size_t unit_len = s - unit_start;
100 + const struct size_unit *su;
101 + if (unit_len == 0)
102 + su = su_def;
103 + else {
104 + if (unit_len >= sizeof(unit)) unit_len = sizeof(unit) - 1;
105 + strncpy(unit, unit_start, unit_len);
106 + unit[unit_len] = '\0';
107 + su = entries_find_unit(unit);
108 + if (!su) {
109 + *result = 0;
110 + return false;
111 + }
112 + }
113 +
114 + uint64_t bytes = (uint64_t)round(value * (NETDATA_DOUBLE)su->multiplier);
115 + *result = entries_round_to_resolution_int(bytes, su_def->multiplier);
116 +
117 + return true;
118 +}
119 +
120 +// --------------------------------------------------------------------------------------------------------------------
121 +// generate a string to represent a size
122 +
123 +ssize_t entries_snprintf(char *dst, size_t dst_size, uint64_t value, const char *unit, bool accurate) {
124 + if (!dst || dst_size == 0) return -1;
125 + if (dst_size == 1) {
126 + dst[0] = '\0';
127 + return -2;
128 + }
129 +
130 + if (value == 0)
131 + return snprintfz(dst, dst_size, "off");
132 +
133 + const struct size_unit *su_def = entries_find_unit(unit);
134 + if(!su_def) return -3;
135 +
136 + // use the units multiplier to find the units
137 + uint64_t bytes = value * su_def->multiplier;
138 +
139 + // Find the best unit to represent the size with up to 2 fractional digits
140 + const struct size_unit *su_best = su_def;
141 + for (size_t i = 0; i < sizeof(entries_units) / sizeof(entries_units[0]); i++) {
142 + const struct size_unit *su = &entries_units[i];
143 + if (su->multiplier < su_def->multiplier || // the multiplier is too small
144 + (!su->formatter && su != su_def) || // it is not to be used in formatting (except our unit)
145 + (bytes < su->multiplier && su != su_def) ) // the converted value will be <1.0
146 + continue;
147 +
148 + double converted = entries_round_to_resolution_dbl2(bytes, su->multiplier);
149 +
150 + uint64_t reversed_bytes = (uint64_t)(converted * (double)su->multiplier);
151 +
152 + if(accurate) {
153 + // no precision loss is required
154 + if (reversed_bytes == bytes)
155 + // no precision loss, this is good to use
156 + su_best = su;
157 + }
158 + else {
159 + if(converted > 1.0)
160 + su_best = su;
161 + }
162 + }
163 +
164 + double converted = entries_round_to_resolution_dbl2(bytes, su_best->multiplier);
165 +
166 + // print it either with 0, 1 or 2 fractional digits
167 + int written;
168 + if(converted == (double)((uint64_t)converted))
169 + written = snprintfz(dst, dst_size, "%.0f%s", converted, su_best->unit);
170 + else if(converted * 10.0 == (double)((uint64_t)(converted * 10.0)))
171 + written = snprintfz(dst, dst_size, "%.1f%s", converted, su_best->unit);
172 + else
173 + written = snprintfz(dst, dst_size, "%.2f%s", converted, su_best->unit);
174 +
175 + if (written < 0)
176 + return -4;
177 +
178 + if ((size_t)written >= dst_size)
179 + return (ssize_t)(dst_size - 1);
180 +
181 + return written;
182 +}
183 +
src/libnetdata/parsers/entries.h new
+19
@@ -0,0 +1,19 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef LIBNETDATA_PARSERS_ENTRIES_H
4 +#define LIBNETDATA_PARSERS_ENTRIES_H
5 +
6 +#include "parsers.h"
7 +
8 +bool entries_parse(const char *entries_str, uint64_t *result, const char *default_unit);
9 +#define entries_parse_k(size_str, kb) size_parse(size_str, kb, "K")
10 +#define entries_parse_m(size_str, mb) size_parse(size_str, mb, "M")
11 +#define entries_parse_g(size_str, gb) size_parse(size_str, gb, "G")
12 +
13 +ssize_t entries_snprintf(char *dst, size_t dst_size, uint64_t value, const char *unit, bool accurate);
14 +#define entries_snprintf_n(dst, dst_size, value) size_snprintf(dst, dst_size, value, "", true)
15 +#define entries_snprintf_k(dst, dst_size, value) size_snprintf(dst, dst_size, value, "K", true)
16 +#define entries_snprintf_m(dst, dst_size, value) size_snprintf(dst, dst_size, value, "M", true)
17 +#define entries_snprintf_g(dst, dst_size, value) size_snprintf(dst, dst_size, value, "G", true)
18 +
19 +#endif //LIBNETDATA_PARSERS_ENTRIES_H
src/libnetdata/parsers/parsers.h
+1
@@ -5,6 +5,7 @@
5
6 #include "../libnetdata.h"
7 #include "size.h"
8 +#include "entries.h"
9 #include "duration.h"
10 #include "timeframe.h"
11