master
c 341 lines 19.7 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 /*
4 * TODO
5 * _UDEV_DEVLINK is frequently set more than once per field - support multi-value faces
6 *
7 */
8
9 #include "collectors/systemd-journal.plugin/provider/netdata_provider.h"
10 #include "systemd-internals.h"
11 #include "systemd-journal-function.h"
12
13 #define ND_SD_JOURNAL_FUNCTION_DESCRIPTION "View, search and analyze systemd journal entries."
14 #define ND_SD_JOURNAL_FUNCTION_NAME "systemd-journal"
15
16 #define JOURNAL_KEY_ND_JOURNAL_PROCESS "ND_JOURNAL_PROCESS"
17
18 // functions needed by LQS
19 static __always_inline SD_JOURNAL_FILE_SOURCE_TYPE get_internal_source_type(const char *value)
20 {
21 if (strcmp(value, ND_SD_JF_SOURCE_ALL_NAME) == 0)
22 return ND_SD_JF_ALL;
23 else if (strcmp(value, ND_SD_JF_SOURCE_LOCAL_NAME) == 0)
24 return ND_SD_JF_LOCAL_ALL;
25 else if (strcmp(value, ND_SD_JF_SOURCE_REMOTES_NAME) == 0)
26 return ND_SD_JF_REMOTE_ALL;
27 else if (strcmp(value, ND_SD_JF_SOURCE_NAMESPACES_NAME) == 0)
28 return ND_SD_JF_LOCAL_NAMESPACE;
29 else if (strcmp(value, ND_SD_JF_SOURCE_LOCAL_SYSTEM_NAME) == 0)
30 return ND_SD_JF_LOCAL_SYSTEM;
31 else if (strcmp(value, ND_SD_JF_SOURCE_LOCAL_USERS_NAME) == 0)
32 return ND_SD_JF_LOCAL_USER;
33 else if (strcmp(value, ND_SD_JF_SOURCE_LOCAL_OTHER_NAME) == 0)
34 return ND_SD_JF_LOCAL_OTHER;
35
36 return ND_SD_JF_NONE;
37 }
38
39 // prepare LQS
40 #define LQS_FUNCTION_NAME ND_SD_JOURNAL_FUNCTION_NAME
41 #define LQS_FUNCTION_DESCRIPTION ND_SD_JOURNAL_FUNCTION_DESCRIPTION
42 #define LQS_DEFAULT_ITEMS_PER_QUERY 200
43 #define LQS_DEFAULT_ITEMS_SAMPLING 1000000
44 #define LQS_SOURCE_TYPE SD_JOURNAL_FILE_SOURCE_TYPE
45 #define LQS_SOURCE_TYPE_ALL ND_SD_JF_ALL
46 #define LQS_SOURCE_TYPE_NONE ND_SD_JF_NONE
47 #define LQS_PARAMETER_SOURCE_NAME "Journal Sources" // this is how it is shown to users
48 #define LQS_FUNCTION_GET_INTERNAL_SOURCE_TYPE(value) get_internal_source_type(value)
49 #define LQS_FUNCTION_SOURCE_TO_JSON_ARRAY(wb) available_journal_file_sources_to_json_array(wb)
50
51 #ifdef HAVE_SD_JOURNAL_RESTART_FIELDS
52 #define LQS_DEFAULT_SLICE_MODE 1
53 #else
54 #define LQS_DEFAULT_SLICE_MODE 0
55 #endif
56
57 #include "libnetdata/facets/logs_query_status.h"
58
59 #define SYSTEMD_ALWAYS_VISIBLE_KEYS NULL
60
61 #define SYSTEMD_KEYS_EXCLUDED_FROM_FACETS \
62 "!MESSAGE_ID" \
63 "|*MESSAGE*" \
64 "|*TIMESTAMP*" \
65 "|__*" \
66 ""
67
68 #define SYSTEMD_KEYS_INCLUDED_IN_FACETS \
69 \
70 /* --- USER JOURNAL FIELDS --- */ \
71 \
72 /* "|MESSAGE" */ \
73 "|MESSAGE_ID" \
74 "|PRIORITY" \
75 "|CODE_FILE" /* "|CODE_LINE" */ \
76 "|CODE_FUNC" \
77 "|ERRNO" /* "|INVOCATION_ID" */ /* "|USER_INVOCATION_ID" */ \
78 "|SYSLOG_FACILITY" \
79 "|SYSLOG_IDENTIFIER" /* "|SYSLOG_PID" */ /* "|SYSLOG_TIMESTAMP" */ /* "|SYSLOG_RAW" */ /* "!DOCUMENTATION" */ /* "|TID" */ \
80 "|UNIT" \
81 "|USER_UNIT" \
82 "|UNIT_RESULT" /* undocumented */ \
83 \
84 /* --- TRUSTED JOURNAL FIELDS --- */ \
85 \
86 /* "|_PID" */ \
87 "|_UID" \
88 "|_GID" \
89 "|_COMM" \
90 "|_EXE" /* "|_CMDLINE" "|_CAP_EFFECTIVE" "|_AUDIT_SESSION" */ \
91 "|_AUDIT_LOGINUID" \
92 "|_SYSTEMD_CGROUP" \
93 "|_SYSTEMD_SLICE" \
94 "|_SYSTEMD_UNIT" \
95 "|_SYSTEMD_USER_UNIT" \
96 "|_SYSTEMD_USER_SLICE" \
97 "|_SYSTEMD_SESSION" \
98 "|_SYSTEMD_OWNER_UID" \
99 "|_SELINUX_CONTEXT" /* "|_SOURCE_REALTIME_TIMESTAMP" */ \
100 "|_BOOT_ID" \
101 "|_MACHINE_ID" /* "|_SYSTEMD_INVOCATION_ID" */ \
102 "|_HOSTNAME" \
103 "|_TRANSPORT" /* "|_STREAM_ID" "|LINE_BREAK" */ \
104 "|_NAMESPACE" \
105 "|_RUNTIME_SCOPE" \
106 \
107 /* --- KERNEL JOURNAL FIELDS --- */ \
108 \
109 /* "|_KERNEL_DEVICE" */ \
110 "|_KERNEL_SUBSYSTEM" /* "|_UDEV_SYSNAME" */ \
111 "|_UDEV_DEVNODE" /* "|_UDEV_DEVLINK" */ \
112 \
113 /* --- LOGGING ON BEHALF --- */ \
114 \
115 "|OBJECT_UID" \
116 "|OBJECT_GID" \
117 "|OBJECT_COMM" \
118 "|OBJECT_EXE" /* "|OBJECT_CMDLINE" */ /* "|OBJECT_AUDIT_SESSION" */ \
119 "|OBJECT_AUDIT_LOGINUID" \
120 "|OBJECT_SYSTEMD_CGROUP" \
121 "|OBJECT_SYSTEMD_SESSION" \
122 "|OBJECT_SYSTEMD_OWNER_UID" \
123 "|OBJECT_SYSTEMD_UNIT" \
124 "|OBJECT_SYSTEMD_USER_UNIT" \
125 \
126 /* --- CORE DUMPS --- */ \
127 \
128 "|COREDUMP_COMM" \
129 "|COREDUMP_UNIT" \
130 "|COREDUMP_USER_UNIT" \
131 "|COREDUMP_SIGNAL_NAME" \
132 "|COREDUMP_CGROUP" \
133 \
134 /* --- DOCKER --- */ \
135 \
136 "|CONTAINER_ID" /* "|CONTAINER_ID_FULL" */ \
137 "|CONTAINER_NAME" \
138 "|CONTAINER_TAG" \
139 "|IMAGE_NAME" /* undocumented */ /* "|CONTAINER_PARTIAL_MESSAGE" */ \
140 \
141 /* --- NETDATA --- */ \
142 \
143 "|ND_NIDL_NODE" \
144 "|ND_NIDL_CONTEXT" \
145 "|ND_LOG_SOURCE" /*"|ND_MODULE" */ \
146 "|ND_ALERT_NAME" \
147 "|ND_ALERT_CLASS" \
148 "|ND_ALERT_COMPONENT" \
149 "|ND_ALERT_TYPE" \
150 "|ND_ALERT_STATUS" \
151 \
152 ""
153
154 #include "systemd-journal-execute.h"
155
156 static void systemd_journal_register_transformations(LOGS_QUERY_STATUS *lqs)
157 {
158 FACETS *facets = lqs->facets;
159 LOGS_QUERY_REQUEST *rq = &lqs->rq;
160
161 // ----------------------------------------------------------------------------------------------------------------
162 // register the fields in the order you want them on the dashboard
163
164 facets_register_row_severity(facets, syslog_priority_to_facet_severity, NULL);
165
166 facets_register_key_name(facets, "_HOSTNAME", rq->default_facet | FACET_KEY_OPTION_VISIBLE);
167
168 facets_register_dynamic_key_name(
169 facets,
170 JOURNAL_KEY_ND_JOURNAL_PROCESS,
171 FACET_KEY_OPTION_NEVER_FACET | FACET_KEY_OPTION_VISIBLE,
172 nd_sd_journal_dynamic_row_id,
173 NULL);
174
175 facets_register_key_name(
176 facets,
177 "MESSAGE",
178 FACET_KEY_OPTION_NEVER_FACET | FACET_KEY_OPTION_MAIN_TEXT | FACET_KEY_OPTION_VISIBLE | FACET_KEY_OPTION_FTS);
179
180 facets_register_key_name_transformation(
181 facets,
182 "PRIORITY",
183 rq->default_facet | FACET_KEY_OPTION_TRANSFORM_VIEW | FACET_KEY_OPTION_EXPANDED_FILTER,
184 nd_sd_journal_transform_priority,
185 NULL);
186
187 facets_register_key_name_transformation(
188 facets,
189 "SYSLOG_FACILITY",
190 rq->default_facet | FACET_KEY_OPTION_TRANSFORM_VIEW | FACET_KEY_OPTION_EXPANDED_FILTER,
191 nd_sd_journal_transform_syslog_facility,
192 NULL);
193
194 facets_register_key_name_transformation(
195 facets, "ERRNO", rq->default_facet | FACET_KEY_OPTION_TRANSFORM_VIEW, nd_sd_journal_transform_errno, NULL);
196
197 facets_register_key_name(facets, JOURNAL_KEY_ND_JOURNAL_FILE, FACET_KEY_OPTION_NEVER_FACET);
198
199 facets_register_key_name(facets, "SYSLOG_IDENTIFIER", rq->default_facet);
200
201 facets_register_key_name(facets, "UNIT", rq->default_facet);
202
203 facets_register_key_name(facets, "USER_UNIT", rq->default_facet);
204
205 facets_register_key_name_transformation(
206 facets,
207 "MESSAGE_ID",
208 rq->default_facet | FACET_KEY_OPTION_TRANSFORM_VIEW | FACET_KEY_OPTION_EXPANDED_FILTER,
209 nd_sd_journal_transform_message_id,
210 NULL);
211
212 facets_register_key_name_transformation(
213 facets, "_BOOT_ID", rq->default_facet | FACET_KEY_OPTION_TRANSFORM_VIEW, nd_sd_journal_transform_boot_id, NULL);
214
215 facets_register_key_name_transformation(
216 facets,
217 "_SYSTEMD_OWNER_UID",
218 rq->default_facet | FACET_KEY_OPTION_TRANSFORM_VIEW,
219 nd_sd_journal_transform_uid,
220 NULL);
221
222 facets_register_key_name_transformation(
223 facets, "_UID", rq->default_facet | FACET_KEY_OPTION_TRANSFORM_VIEW, nd_sd_journal_transform_uid, NULL);
224
225 facets_register_key_name_transformation(
226 facets,
227 "OBJECT_SYSTEMD_OWNER_UID",
228 rq->default_facet | FACET_KEY_OPTION_TRANSFORM_VIEW,
229 nd_sd_journal_transform_uid,
230 NULL);
231
232 facets_register_key_name_transformation(
233 facets, "OBJECT_UID", rq->default_facet | FACET_KEY_OPTION_TRANSFORM_VIEW, nd_sd_journal_transform_uid, NULL);
234
235 facets_register_key_name_transformation(
236 facets, "_GID", rq->default_facet | FACET_KEY_OPTION_TRANSFORM_VIEW, nd_sd_journal_transform_gid, NULL);
237
238 facets_register_key_name_transformation(
239 facets, "OBJECT_GID", rq->default_facet | FACET_KEY_OPTION_TRANSFORM_VIEW, nd_sd_journal_transform_gid, NULL);
240
241 facets_register_key_name_transformation(
242 facets, "_CAP_EFFECTIVE", FACET_KEY_OPTION_TRANSFORM_VIEW, nd_sd_journal_transform_cap_effective, NULL);
243
244 facets_register_key_name_transformation(
245 facets, "_AUDIT_LOGINUID", FACET_KEY_OPTION_TRANSFORM_VIEW, nd_sd_journal_transform_uid, NULL);
246
247 facets_register_key_name_transformation(
248 facets, "OBJECT_AUDIT_LOGINUID", FACET_KEY_OPTION_TRANSFORM_VIEW, nd_sd_journal_transform_uid, NULL);
249
250 facets_register_key_name_transformation(
251 facets,
252 "_SOURCE_REALTIME_TIMESTAMP",
253 FACET_KEY_OPTION_TRANSFORM_VIEW,
254 nd_sd_journal_transform_timestamp_usec,
255 NULL);
256 }
257
258 BUFFER *function_systemd_journal_result(
259 const char *transaction,
260 char *function,
261 usec_t *stop_monotonic_ut,
262 bool *cancelled,
263 BUFFER *payload,
264 HTTP_ACCESS access __maybe_unused,
265 const char *source __maybe_unused,
266 void *data __maybe_unused)
267 {
268 fstat_thread_calls = 0;
269 fstat_thread_cached_responses = 0;
270
271 #ifdef HAVE_SD_JOURNAL_RESTART_FIELDS
272 bool have_slice = true;
273 #else
274 bool have_slice = false;
275 #endif // HAVE_SD_JOURNAL_RESTART_FIELDS
276
277 LOGS_QUERY_STATUS tmp_fqs = {
278 .facets = lqs_facets_create(
279 LQS_DEFAULT_ITEMS_PER_QUERY,
280 FACETS_OPTION_ALL_KEYS_FTS | FACETS_OPTION_HASH_IDS,
281 SYSTEMD_ALWAYS_VISIBLE_KEYS,
282 SYSTEMD_KEYS_INCLUDED_IN_FACETS,
283 SYSTEMD_KEYS_EXCLUDED_FROM_FACETS,
284 have_slice),
285
286 .rq = LOGS_QUERY_REQUEST_DEFAULTS(transaction, LQS_DEFAULT_SLICE_MODE, JOURNAL_DEFAULT_DIRECTION),
287
288 .cancelled = cancelled,
289 .stop_monotonic_ut = stop_monotonic_ut,
290 };
291 LOGS_QUERY_STATUS *lqs = &tmp_fqs;
292
293 BUFFER *wb = lqs_create_output_buffer();
294
295 // ------------------------------------------------------------------------
296 // parse the parameters
297
298 if (lqs_request_parse_and_validate(lqs, wb, function, payload, have_slice, "PRIORITY")) {
299 systemd_journal_register_transformations(lqs);
300
301 // ------------------------------------------------------------------------
302 // add versions to the response
303
304 buffer_json_journal_versions(wb);
305
306 // ------------------------------------------------------------------------
307 // run the request
308
309 if (lqs->rq.info)
310 lqs_info_response(wb, lqs->facets);
311 else {
312 nd_sd_journal_query(wb, lqs);
313 if (wb->response_code == HTTP_RESP_OK)
314 buffer_json_finalize(wb);
315 }
316 }
317
318 lqs_cleanup(lqs);
319
320 return wb;
321 }
322
323 void function_systemd_journal(
324 const char *transaction,
325 char *function,
326 usec_t *stop_monotonic_ut,
327 bool *cancelled,
328 BUFFER *payload,
329 HTTP_ACCESS access,
330 const char *source,
331 void *data)
332 {
333 BUFFER *wb = function_systemd_journal_result(
334 transaction, function, stop_monotonic_ut, cancelled, payload, access, source, data);
335
336 netdata_mutex_lock(&stdout_mutex);
337 pluginsd_function_result_to_stdout(transaction, wb);
338 netdata_mutex_unlock(&stdout_mutex);
339
340 buffer_free(wb);
341 }