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>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