Commit | Line | Data |
---|---|---|
b47b01d8 JR |
1 | /* |
2 | * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com> | |
3 | * | |
4 | * SPDX-License-Identifier: LGPL-2.1-only | |
5 | * | |
6 | */ | |
7 | ||
b47b01d8 JR |
8 | #include <common/credentials.h> |
9 | #include <common/error.h> | |
6a751b95 JR |
10 | #include <common/hashtable/hashtable.h> |
11 | #include <common/hashtable/utils.h> | |
b47b01d8 | 12 | #include <common/macros.h> |
6a751b95 | 13 | #include <common/mi-lttng.h> |
b47b01d8 | 14 | #include <common/optional.h> |
b47b01d8 | 15 | #include <common/payload-view.h> |
6a751b95 | 16 | #include <common/payload.h> |
b47b01d8 | 17 | #include <common/runas.h> |
b47b01d8 JR |
18 | #include <common/string-utils/string-utils.h> |
19 | #include <lttng/event-rule/event-rule-internal.h> | |
20 | #include <lttng/event-rule/jul-logging-internal.h> | |
b47b01d8 | 21 | #include <lttng/event.h> |
6a751b95 | 22 | #include <lttng/log-level-rule.h> |
b47b01d8 JR |
23 | |
24 | #define IS_JUL_LOGGING_EVENT_RULE(rule) \ | |
25 | (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_JUL_LOGGING) | |
26 | ||
27 | static void lttng_event_rule_jul_logging_destroy(struct lttng_event_rule *rule) | |
28 | { | |
29 | struct lttng_event_rule_jul_logging *jul_logging; | |
30 | ||
31 | if (rule == NULL) { | |
32 | return; | |
33 | } | |
34 | ||
35 | jul_logging = container_of( | |
36 | rule, struct lttng_event_rule_jul_logging, parent); | |
37 | ||
38 | lttng_log_level_rule_destroy(jul_logging->log_level_rule); | |
39 | free(jul_logging->pattern); | |
40 | free(jul_logging->filter_expression); | |
41 | free(jul_logging->internal_filter.filter); | |
42 | free(jul_logging->internal_filter.bytecode); | |
43 | free(jul_logging); | |
44 | } | |
45 | ||
46 | static bool lttng_event_rule_jul_logging_validate( | |
47 | const struct lttng_event_rule *rule) | |
48 | { | |
49 | bool valid = false; | |
50 | struct lttng_event_rule_jul_logging *jul_logging; | |
51 | ||
52 | if (!rule) { | |
53 | goto end; | |
54 | } | |
55 | ||
56 | jul_logging = container_of( | |
57 | rule, struct lttng_event_rule_jul_logging, parent); | |
58 | ||
59 | /* Required field. */ | |
60 | if (!jul_logging->pattern) { | |
61 | ERR("Invalid jul_logging event rule: a pattern must be set."); | |
62 | goto end; | |
63 | } | |
64 | ||
65 | valid = true; | |
66 | end: | |
67 | return valid; | |
68 | } | |
69 | ||
70 | static int lttng_event_rule_jul_logging_serialize( | |
71 | const struct lttng_event_rule *rule, | |
72 | struct lttng_payload *payload) | |
73 | { | |
74 | int ret; | |
75 | size_t pattern_len, filter_expression_len, header_offset; | |
76 | size_t size_before_log_level_rule; | |
77 | struct lttng_event_rule_jul_logging *jul_logging; | |
78 | struct lttng_event_rule_jul_logging_comm jul_logging_comm; | |
79 | struct lttng_event_rule_jul_logging_comm *header; | |
80 | ||
81 | if (!rule || !IS_JUL_LOGGING_EVENT_RULE(rule)) { | |
82 | ret = -1; | |
83 | goto end; | |
84 | } | |
85 | ||
86 | header_offset = payload->buffer.size; | |
87 | ||
88 | DBG("Serializing jul_logging event rule."); | |
89 | jul_logging = container_of( | |
90 | rule, struct lttng_event_rule_jul_logging, parent); | |
91 | ||
92 | pattern_len = strlen(jul_logging->pattern) + 1; | |
93 | ||
94 | if (jul_logging->filter_expression != NULL) { | |
95 | filter_expression_len = | |
96 | strlen(jul_logging->filter_expression) + 1; | |
97 | } else { | |
98 | filter_expression_len = 0; | |
99 | } | |
100 | ||
101 | jul_logging_comm.pattern_len = pattern_len; | |
102 | jul_logging_comm.filter_expression_len = filter_expression_len; | |
103 | ||
104 | ret = lttng_dynamic_buffer_append(&payload->buffer, &jul_logging_comm, | |
105 | sizeof(jul_logging_comm)); | |
106 | if (ret) { | |
107 | goto end; | |
108 | } | |
109 | ||
110 | ret = lttng_dynamic_buffer_append( | |
111 | &payload->buffer, jul_logging->pattern, pattern_len); | |
112 | if (ret) { | |
113 | goto end; | |
114 | } | |
115 | ||
116 | ret = lttng_dynamic_buffer_append(&payload->buffer, jul_logging->filter_expression, | |
117 | filter_expression_len); | |
118 | if (ret) { | |
119 | goto end; | |
120 | } | |
121 | ||
122 | size_before_log_level_rule = payload->buffer.size; | |
123 | ||
124 | ret = lttng_log_level_rule_serialize(jul_logging->log_level_rule, payload); | |
125 | if (ret < 0) { | |
126 | goto end; | |
127 | } | |
128 | ||
129 | header = (typeof(header)) ((char *) payload->buffer.data + header_offset); | |
130 | header->log_level_rule_len = | |
131 | payload->buffer.size - size_before_log_level_rule; | |
132 | ||
133 | end: | |
134 | return ret; | |
135 | } | |
136 | ||
137 | static bool lttng_event_rule_jul_logging_is_equal( | |
138 | const struct lttng_event_rule *_a, | |
139 | const struct lttng_event_rule *_b) | |
140 | { | |
141 | bool is_equal = false; | |
142 | struct lttng_event_rule_jul_logging *a, *b; | |
143 | ||
144 | a = container_of(_a, struct lttng_event_rule_jul_logging, parent); | |
145 | b = container_of(_b, struct lttng_event_rule_jul_logging, parent); | |
146 | ||
147 | /* Quick checks. */ | |
148 | ||
149 | if (!!a->filter_expression != !!b->filter_expression) { | |
150 | goto end; | |
151 | } | |
152 | ||
153 | /* Long check. */ | |
a0377dfe FD |
154 | LTTNG_ASSERT(a->pattern); |
155 | LTTNG_ASSERT(b->pattern); | |
b47b01d8 JR |
156 | if (strcmp(a->pattern, b->pattern)) { |
157 | goto end; | |
158 | } | |
159 | ||
160 | if (a->filter_expression && b->filter_expression) { | |
161 | if (strcmp(a->filter_expression, b->filter_expression)) { | |
162 | goto end; | |
163 | } | |
164 | } else if (!!a->filter_expression != !!b->filter_expression) { | |
165 | /* One is set; not the other. */ | |
166 | goto end; | |
167 | } | |
168 | ||
169 | if (!lttng_log_level_rule_is_equal( | |
170 | a->log_level_rule, b->log_level_rule)) { | |
171 | goto end; | |
172 | } | |
173 | ||
174 | is_equal = true; | |
175 | end: | |
176 | return is_equal; | |
177 | } | |
178 | ||
179 | /* | |
180 | * On success ret is 0; | |
181 | * | |
182 | * On error ret is negative. | |
183 | * | |
184 | * An event with NO loglevel and the name is * will return NULL. | |
185 | */ | |
186 | static int generate_agent_filter( | |
187 | const struct lttng_event_rule *rule, char **_agent_filter) | |
188 | { | |
189 | int err; | |
190 | int ret = 0; | |
191 | char *agent_filter = NULL; | |
192 | const char *pattern; | |
193 | const char *filter; | |
194 | const struct lttng_log_level_rule *log_level_rule = NULL; | |
195 | enum lttng_event_rule_status status; | |
196 | ||
a0377dfe FD |
197 | LTTNG_ASSERT(rule); |
198 | LTTNG_ASSERT(_agent_filter); | |
b47b01d8 JR |
199 | |
200 | status = lttng_event_rule_jul_logging_get_name_pattern(rule, &pattern); | |
201 | if (status != LTTNG_EVENT_RULE_STATUS_OK) { | |
202 | ret = -1; | |
203 | goto end; | |
204 | } | |
205 | ||
206 | status = lttng_event_rule_jul_logging_get_filter(rule, &filter); | |
207 | if (status == LTTNG_EVENT_RULE_STATUS_UNSET) { | |
208 | filter = NULL; | |
209 | } else if (status != LTTNG_EVENT_RULE_STATUS_OK) { | |
210 | ret = -1; | |
211 | goto end; | |
212 | } | |
213 | ||
214 | ||
215 | /* Don't add filter for the '*' event. */ | |
216 | if (strcmp(pattern, "*") != 0) { | |
217 | if (filter) { | |
218 | err = asprintf(&agent_filter, | |
219 | "(%s) && (logger_name == \"%s\")", | |
220 | filter, pattern); | |
221 | } else { | |
222 | err = asprintf(&agent_filter, "logger_name == \"%s\"", | |
223 | pattern); | |
224 | } | |
225 | ||
226 | if (err < 0) { | |
227 | PERROR("Failed to format agent filter string"); | |
228 | ret = -1; | |
229 | goto end; | |
230 | } | |
231 | } | |
232 | ||
233 | status = lttng_event_rule_jul_logging_get_log_level_rule( | |
234 | rule, &log_level_rule); | |
235 | if (status == LTTNG_EVENT_RULE_STATUS_OK) { | |
236 | enum lttng_log_level_rule_status llr_status; | |
237 | const char *op; | |
238 | int level; | |
239 | ||
240 | switch (lttng_log_level_rule_get_type(log_level_rule)) | |
241 | { | |
242 | case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY: | |
243 | llr_status = lttng_log_level_rule_exactly_get_level( | |
244 | log_level_rule, &level); | |
245 | op = "=="; | |
246 | break; | |
247 | case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS: | |
248 | llr_status = lttng_log_level_rule_at_least_as_severe_as_get_level( | |
249 | log_level_rule, &level); | |
250 | op = ">="; | |
251 | break; | |
252 | default: | |
253 | abort(); | |
254 | } | |
255 | ||
256 | if (llr_status != LTTNG_LOG_LEVEL_RULE_STATUS_OK) { | |
257 | ret = -1; | |
258 | goto end; | |
259 | } | |
260 | ||
261 | if (filter || agent_filter) { | |
262 | char *new_filter; | |
263 | ||
264 | err = asprintf(&new_filter, | |
265 | "(%s) && (int_loglevel %s %d)", | |
266 | agent_filter ? agent_filter : filter, | |
267 | op, level); | |
268 | if (agent_filter) { | |
269 | free(agent_filter); | |
270 | } | |
271 | agent_filter = new_filter; | |
272 | } else { | |
273 | err = asprintf(&agent_filter, "int_loglevel %s %d", op, | |
274 | level); | |
275 | } | |
276 | ||
277 | if (err < 0) { | |
278 | PERROR("Failed to format agent filter string"); | |
279 | ret = -1; | |
280 | goto end; | |
281 | } | |
282 | } | |
283 | ||
284 | *_agent_filter = agent_filter; | |
285 | agent_filter = NULL; | |
286 | ||
287 | end: | |
288 | free(agent_filter); | |
289 | return ret; | |
290 | } | |
291 | ||
292 | static enum lttng_error_code | |
293 | lttng_event_rule_jul_logging_generate_filter_bytecode( | |
294 | struct lttng_event_rule *rule, | |
295 | const struct lttng_credentials *creds) | |
296 | { | |
297 | int ret; | |
298 | enum lttng_error_code ret_code; | |
299 | struct lttng_event_rule_jul_logging *jul_logging; | |
300 | enum lttng_event_rule_status status; | |
301 | const char *filter; | |
302 | struct lttng_bytecode *bytecode = NULL; | |
303 | char *agent_filter; | |
304 | ||
a0377dfe | 305 | LTTNG_ASSERT(rule); |
b47b01d8 JR |
306 | |
307 | jul_logging = container_of( | |
308 | rule, struct lttng_event_rule_jul_logging, parent); | |
309 | ||
310 | status = lttng_event_rule_jul_logging_get_filter(rule, &filter); | |
311 | if (status == LTTNG_EVENT_RULE_STATUS_UNSET) { | |
312 | filter = NULL; | |
313 | } else if (status != LTTNG_EVENT_RULE_STATUS_OK) { | |
314 | ret_code = LTTNG_ERR_FILTER_INVAL; | |
315 | goto end; | |
316 | } | |
317 | ||
318 | if (filter && filter[0] == '\0') { | |
319 | ret_code = LTTNG_ERR_FILTER_INVAL; | |
320 | goto error; | |
321 | } | |
322 | ||
323 | ret = generate_agent_filter(rule, &agent_filter); | |
324 | if (ret) { | |
325 | ret_code = LTTNG_ERR_FILTER_INVAL; | |
326 | goto error; | |
327 | } | |
328 | ||
329 | jul_logging->internal_filter.filter = agent_filter; | |
330 | ||
331 | if (jul_logging->internal_filter.filter == NULL) { | |
332 | ret_code = LTTNG_OK; | |
333 | goto end; | |
334 | } | |
335 | ||
336 | ret = run_as_generate_filter_bytecode( | |
337 | jul_logging->internal_filter.filter, creds, | |
338 | &bytecode); | |
339 | if (ret) { | |
340 | ret_code = LTTNG_ERR_FILTER_INVAL; | |
341 | goto end; | |
342 | } | |
343 | ||
344 | jul_logging->internal_filter.bytecode = bytecode; | |
345 | bytecode = NULL; | |
346 | ret_code = LTTNG_OK; | |
347 | ||
348 | error: | |
349 | end: | |
350 | free(bytecode); | |
351 | return ret_code; | |
352 | } | |
353 | ||
354 | static const char *lttng_event_rule_jul_logging_get_internal_filter( | |
355 | const struct lttng_event_rule *rule) | |
356 | { | |
357 | struct lttng_event_rule_jul_logging *jul_logging; | |
358 | ||
a0377dfe | 359 | LTTNG_ASSERT(rule); |
b47b01d8 JR |
360 | jul_logging = container_of( |
361 | rule, struct lttng_event_rule_jul_logging, parent); | |
362 | return jul_logging->internal_filter.filter; | |
363 | } | |
364 | ||
365 | static const struct lttng_bytecode * | |
366 | lttng_event_rule_jul_logging_get_internal_filter_bytecode( | |
367 | const struct lttng_event_rule *rule) | |
368 | { | |
369 | struct lttng_event_rule_jul_logging *jul_logging; | |
370 | ||
a0377dfe | 371 | LTTNG_ASSERT(rule); |
b47b01d8 JR |
372 | jul_logging = container_of( |
373 | rule, struct lttng_event_rule_jul_logging, parent); | |
374 | return jul_logging->internal_filter.bytecode; | |
375 | } | |
376 | ||
377 | static enum lttng_event_rule_generate_exclusions_status | |
378 | lttng_event_rule_jul_logging_generate_exclusions( | |
f46376a1 | 379 | const struct lttng_event_rule *rule __attribute__((unused)), |
b47b01d8 JR |
380 | struct lttng_event_exclusion **_exclusions) |
381 | { | |
382 | /* Unsupported. */ | |
383 | *_exclusions = NULL; | |
384 | return LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE; | |
385 | } | |
386 | ||
387 | static unsigned long lttng_event_rule_jul_logging_hash( | |
388 | const struct lttng_event_rule *rule) | |
389 | { | |
390 | unsigned long hash; | |
391 | struct lttng_event_rule_jul_logging *tp_rule = | |
392 | container_of(rule, typeof(*tp_rule), parent); | |
393 | ||
394 | hash = hash_key_ulong((void *) LTTNG_EVENT_RULE_TYPE_JUL_LOGGING, | |
395 | lttng_ht_seed); | |
396 | hash ^= hash_key_str(tp_rule->pattern, lttng_ht_seed); | |
397 | ||
398 | if (tp_rule->filter_expression) { | |
399 | hash ^= hash_key_str(tp_rule->filter_expression, lttng_ht_seed); | |
400 | } | |
401 | ||
402 | if (tp_rule->log_level_rule) { | |
403 | hash ^= lttng_log_level_rule_hash(tp_rule->log_level_rule); | |
404 | } | |
405 | ||
406 | return hash; | |
407 | } | |
408 | ||
409 | static struct lttng_event *lttng_event_rule_jul_logging_generate_lttng_event( | |
410 | const struct lttng_event_rule *rule) | |
411 | { | |
412 | int ret; | |
413 | const struct lttng_event_rule_jul_logging *jul_logging; | |
414 | struct lttng_event *local_event = NULL; | |
415 | struct lttng_event *event = NULL; | |
416 | enum lttng_loglevel_type loglevel_type; | |
417 | int loglevel_value = 0; | |
418 | enum lttng_event_rule_status status; | |
419 | const struct lttng_log_level_rule *log_level_rule; | |
420 | ||
421 | jul_logging = container_of( | |
422 | rule, const struct lttng_event_rule_jul_logging, parent); | |
423 | ||
a6bc4ca9 | 424 | local_event = (lttng_event *) zmalloc(sizeof(*local_event)); |
b47b01d8 JR |
425 | if (!local_event) { |
426 | goto error; | |
427 | } | |
428 | ||
429 | local_event->type = LTTNG_EVENT_TRACEPOINT; | |
430 | ret = lttng_strncpy(local_event->name, jul_logging->pattern, | |
431 | sizeof(local_event->name)); | |
432 | if (ret) { | |
433 | ERR("Truncation occurred when copying event rule pattern to `lttng_event` structure: pattern = '%s'", | |
434 | jul_logging->pattern); | |
435 | goto error; | |
436 | } | |
437 | ||
438 | ||
439 | /* Map the log level rule to an equivalent lttng_loglevel. */ | |
440 | status = lttng_event_rule_jul_logging_get_log_level_rule( | |
441 | rule, &log_level_rule); | |
442 | if (status == LTTNG_EVENT_RULE_STATUS_UNSET) { | |
443 | loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL; | |
444 | loglevel_value = 0; | |
445 | } else if (status == LTTNG_EVENT_RULE_STATUS_OK) { | |
446 | enum lttng_log_level_rule_status llr_status; | |
447 | ||
448 | switch (lttng_log_level_rule_get_type(log_level_rule)) { | |
449 | case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY: | |
450 | llr_status = lttng_log_level_rule_exactly_get_level( | |
451 | log_level_rule, &loglevel_value); | |
452 | loglevel_type = LTTNG_EVENT_LOGLEVEL_SINGLE; | |
453 | break; | |
454 | case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS: | |
455 | llr_status = lttng_log_level_rule_at_least_as_severe_as_get_level( | |
456 | log_level_rule, &loglevel_value); | |
457 | loglevel_type = LTTNG_EVENT_LOGLEVEL_RANGE; | |
458 | break; | |
459 | default: | |
460 | abort(); | |
461 | break; | |
462 | } | |
463 | ||
464 | if (llr_status != LTTNG_LOG_LEVEL_RULE_STATUS_OK) { | |
465 | goto error; | |
466 | } | |
467 | } else { | |
468 | goto error; | |
469 | } | |
470 | ||
471 | local_event->loglevel_type = loglevel_type; | |
472 | local_event->loglevel = loglevel_value; | |
473 | ||
474 | event = local_event; | |
475 | local_event = NULL; | |
476 | error: | |
477 | free(local_event); | |
478 | return event; | |
479 | } | |
480 | ||
6a751b95 JR |
481 | static enum lttng_error_code lttng_event_rule_jul_logging_mi_serialize( |
482 | const struct lttng_event_rule *rule, struct mi_writer *writer) | |
483 | { | |
484 | int ret; | |
485 | enum lttng_error_code ret_code; | |
486 | enum lttng_event_rule_status status; | |
487 | ||
488 | const char *filter = NULL; | |
489 | const char *name_pattern = NULL; | |
490 | const struct lttng_log_level_rule *log_level_rule = NULL; | |
491 | ||
a0377dfe FD |
492 | LTTNG_ASSERT(rule); |
493 | LTTNG_ASSERT(writer); | |
494 | LTTNG_ASSERT(IS_JUL_LOGGING_EVENT_RULE(rule)); | |
6a751b95 JR |
495 | |
496 | status = lttng_event_rule_jul_logging_get_name_pattern( | |
497 | rule, &name_pattern); | |
a0377dfe FD |
498 | LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK); |
499 | LTTNG_ASSERT(name_pattern); | |
6a751b95 JR |
500 | |
501 | status = lttng_event_rule_jul_logging_get_filter(rule, &filter); | |
a0377dfe | 502 | LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK || |
6a751b95 JR |
503 | status == LTTNG_EVENT_RULE_STATUS_UNSET); |
504 | ||
505 | status = lttng_event_rule_jul_logging_get_log_level_rule( | |
506 | rule, &log_level_rule); | |
a0377dfe | 507 | LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK || |
6a751b95 JR |
508 | status == LTTNG_EVENT_RULE_STATUS_UNSET); |
509 | ||
510 | /* Open event rule jul logging element. */ | |
511 | ret = mi_lttng_writer_open_element( | |
512 | writer, mi_lttng_element_event_rule_jul_logging); | |
513 | if (ret) { | |
514 | goto mi_error; | |
515 | } | |
516 | ||
517 | /* Name pattern. */ | |
518 | ret = mi_lttng_writer_write_element_string(writer, | |
519 | mi_lttng_element_event_rule_name_pattern, name_pattern); | |
520 | if (ret) { | |
521 | goto mi_error; | |
522 | } | |
523 | ||
524 | /* Filter expression. */ | |
525 | if (filter != NULL) { | |
526 | ret = mi_lttng_writer_write_element_string(writer, | |
527 | mi_lttng_element_event_rule_filter_expression, | |
528 | filter); | |
529 | if (ret) { | |
530 | goto mi_error; | |
531 | } | |
532 | } | |
533 | ||
534 | /* Log level rule. */ | |
535 | if (log_level_rule) { | |
536 | ret_code = lttng_log_level_rule_mi_serialize( | |
537 | log_level_rule, writer); | |
538 | if (ret_code != LTTNG_OK) { | |
539 | goto end; | |
540 | } | |
541 | } | |
542 | ||
543 | /* Close event rule jul logging element. */ | |
544 | ret = mi_lttng_writer_close_element(writer); | |
545 | if (ret) { | |
546 | goto mi_error; | |
547 | } | |
548 | ||
549 | ret_code = LTTNG_OK; | |
550 | goto end; | |
551 | ||
552 | mi_error: | |
553 | ret_code = LTTNG_ERR_MI_IO_FAIL; | |
554 | end: | |
555 | return ret_code; | |
556 | } | |
557 | ||
b47b01d8 JR |
558 | struct lttng_event_rule *lttng_event_rule_jul_logging_create(void) |
559 | { | |
560 | struct lttng_event_rule *rule = NULL; | |
561 | struct lttng_event_rule_jul_logging *tp_rule; | |
562 | enum lttng_event_rule_status status; | |
563 | ||
a6bc4ca9 | 564 | tp_rule = (lttng_event_rule_jul_logging *) zmalloc(sizeof(struct lttng_event_rule_jul_logging)); |
b47b01d8 JR |
565 | if (!tp_rule) { |
566 | goto end; | |
567 | } | |
568 | ||
569 | rule = &tp_rule->parent; | |
570 | lttng_event_rule_init(&tp_rule->parent, LTTNG_EVENT_RULE_TYPE_JUL_LOGGING); | |
571 | tp_rule->parent.validate = lttng_event_rule_jul_logging_validate; | |
572 | tp_rule->parent.serialize = lttng_event_rule_jul_logging_serialize; | |
573 | tp_rule->parent.equal = lttng_event_rule_jul_logging_is_equal; | |
574 | tp_rule->parent.destroy = lttng_event_rule_jul_logging_destroy; | |
575 | tp_rule->parent.generate_filter_bytecode = | |
576 | lttng_event_rule_jul_logging_generate_filter_bytecode; | |
577 | tp_rule->parent.get_filter = | |
578 | lttng_event_rule_jul_logging_get_internal_filter; | |
579 | tp_rule->parent.get_filter_bytecode = | |
580 | lttng_event_rule_jul_logging_get_internal_filter_bytecode; | |
581 | tp_rule->parent.generate_exclusions = | |
582 | lttng_event_rule_jul_logging_generate_exclusions; | |
583 | tp_rule->parent.hash = lttng_event_rule_jul_logging_hash; | |
584 | tp_rule->parent.generate_lttng_event = | |
585 | lttng_event_rule_jul_logging_generate_lttng_event; | |
6a751b95 | 586 | tp_rule->parent.mi_serialize = lttng_event_rule_jul_logging_mi_serialize; |
b47b01d8 JR |
587 | |
588 | tp_rule->log_level_rule = NULL; | |
589 | ||
590 | /* Default pattern is '*'. */ | |
591 | status = lttng_event_rule_jul_logging_set_name_pattern(rule, "*"); | |
592 | if (status != LTTNG_EVENT_RULE_STATUS_OK) { | |
593 | lttng_event_rule_destroy(rule); | |
594 | rule = NULL; | |
595 | } | |
596 | ||
597 | end: | |
598 | return rule; | |
599 | } | |
600 | ||
b47b01d8 JR |
601 | ssize_t lttng_event_rule_jul_logging_create_from_payload( |
602 | struct lttng_payload_view *view, | |
603 | struct lttng_event_rule **_event_rule) | |
604 | { | |
605 | ssize_t ret, offset = 0; | |
606 | enum lttng_event_rule_status status; | |
607 | const struct lttng_event_rule_jul_logging_comm *jul_logging_comm; | |
608 | const char *pattern; | |
609 | const char *filter_expression = NULL; | |
610 | struct lttng_buffer_view current_buffer_view; | |
611 | struct lttng_event_rule *rule = NULL; | |
612 | struct lttng_log_level_rule *log_level_rule = NULL; | |
613 | ||
614 | if (!_event_rule) { | |
615 | ret = -1; | |
616 | goto end; | |
617 | } | |
618 | ||
619 | current_buffer_view = lttng_buffer_view_from_view( | |
620 | &view->buffer, offset, sizeof(*jul_logging_comm)); | |
621 | if (!lttng_buffer_view_is_valid(¤t_buffer_view)) { | |
622 | ERR("Failed to initialize from malformed event rule jul_logging: buffer too short to contain header."); | |
623 | ret = -1; | |
624 | goto end; | |
625 | } | |
626 | ||
627 | jul_logging_comm = (typeof(jul_logging_comm)) current_buffer_view.data; | |
628 | ||
629 | rule = lttng_event_rule_jul_logging_create(); | |
630 | if (!rule) { | |
631 | ERR("Failed to create event rule jul_logging."); | |
632 | ret = -1; | |
633 | goto end; | |
634 | } | |
635 | ||
636 | /* Skip to payload. */ | |
637 | offset += current_buffer_view.size; | |
638 | ||
639 | /* Map the pattern. */ | |
640 | current_buffer_view = lttng_buffer_view_from_view( | |
641 | &view->buffer, offset, jul_logging_comm->pattern_len); | |
642 | ||
643 | if (!lttng_buffer_view_is_valid(¤t_buffer_view)) { | |
644 | ret = -1; | |
645 | goto end; | |
646 | } | |
647 | ||
648 | pattern = current_buffer_view.data; | |
649 | if (!lttng_buffer_view_contains_string(¤t_buffer_view, pattern, | |
650 | jul_logging_comm->pattern_len)) { | |
651 | ret = -1; | |
652 | goto end; | |
653 | } | |
654 | ||
655 | /* Skip after the pattern. */ | |
656 | offset += jul_logging_comm->pattern_len; | |
657 | ||
658 | if (!jul_logging_comm->filter_expression_len) { | |
659 | goto skip_filter_expression; | |
660 | } | |
661 | ||
662 | /* Map the filter_expression. */ | |
663 | current_buffer_view = lttng_buffer_view_from_view(&view->buffer, offset, | |
664 | jul_logging_comm->filter_expression_len); | |
665 | if (!lttng_buffer_view_is_valid(¤t_buffer_view)) { | |
666 | ret = -1; | |
667 | goto end; | |
668 | } | |
669 | ||
670 | filter_expression = current_buffer_view.data; | |
671 | if (!lttng_buffer_view_contains_string(¤t_buffer_view, | |
672 | filter_expression, | |
673 | jul_logging_comm->filter_expression_len)) { | |
674 | ret = -1; | |
675 | goto end; | |
676 | } | |
677 | ||
678 | /* Skip after the pattern. */ | |
679 | offset += jul_logging_comm->filter_expression_len; | |
680 | ||
681 | skip_filter_expression: | |
682 | if (!jul_logging_comm->log_level_rule_len) { | |
683 | goto skip_log_level_rule; | |
684 | } | |
685 | ||
686 | { | |
687 | /* Map the log level rule. */ | |
688 | struct lttng_payload_view current_payload_view = | |
689 | lttng_payload_view_from_view(view, offset, | |
690 | jul_logging_comm->log_level_rule_len); | |
691 | ||
692 | ret = lttng_log_level_rule_create_from_payload( | |
693 | ¤t_payload_view, &log_level_rule); | |
694 | if (ret < 0) { | |
695 | ret = -1; | |
696 | goto end; | |
697 | } | |
698 | ||
a0377dfe | 699 | LTTNG_ASSERT(ret == jul_logging_comm->log_level_rule_len); |
b47b01d8 JR |
700 | } |
701 | ||
702 | /* Skip after the log level rule. */ | |
703 | offset += jul_logging_comm->log_level_rule_len; | |
704 | ||
705 | skip_log_level_rule: | |
706 | ||
707 | status = lttng_event_rule_jul_logging_set_name_pattern(rule, pattern); | |
708 | if (status != LTTNG_EVENT_RULE_STATUS_OK) { | |
709 | ERR("Failed to set event rule jul_logging pattern."); | |
710 | ret = -1; | |
711 | goto end; | |
712 | } | |
713 | ||
714 | if (filter_expression) { | |
715 | status = lttng_event_rule_jul_logging_set_filter( | |
716 | rule, filter_expression); | |
717 | if (status != LTTNG_EVENT_RULE_STATUS_OK) { | |
718 | ERR("Failed to set event rule jul_logging pattern."); | |
719 | ret = -1; | |
720 | goto end; | |
721 | } | |
722 | } | |
723 | ||
724 | if (log_level_rule) { | |
725 | status = lttng_event_rule_jul_logging_set_log_level_rule( | |
726 | rule, log_level_rule); | |
727 | if (status != LTTNG_EVENT_RULE_STATUS_OK) { | |
728 | ERR("Failed to set event rule jul_logging log level rule."); | |
729 | ret = -1; | |
730 | goto end; | |
731 | } | |
732 | } | |
733 | ||
734 | *_event_rule = rule; | |
735 | rule = NULL; | |
736 | ret = offset; | |
737 | end: | |
738 | lttng_log_level_rule_destroy(log_level_rule); | |
739 | lttng_event_rule_destroy(rule); | |
740 | return ret; | |
741 | } | |
742 | ||
743 | enum lttng_event_rule_status lttng_event_rule_jul_logging_set_name_pattern( | |
744 | struct lttng_event_rule *rule, const char *pattern) | |
745 | { | |
746 | char *pattern_copy = NULL; | |
747 | struct lttng_event_rule_jul_logging *jul_logging; | |
748 | enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; | |
749 | ||
750 | if (!rule || !IS_JUL_LOGGING_EVENT_RULE(rule) || !pattern || | |
751 | strlen(pattern) == 0) { | |
752 | status = LTTNG_EVENT_RULE_STATUS_INVALID; | |
753 | goto end; | |
754 | } | |
755 | ||
756 | jul_logging = container_of( | |
757 | rule, struct lttng_event_rule_jul_logging, parent); | |
758 | pattern_copy = strdup(pattern); | |
759 | if (!pattern_copy) { | |
760 | status = LTTNG_EVENT_RULE_STATUS_ERROR; | |
761 | goto end; | |
762 | } | |
763 | ||
764 | /* Normalize the pattern. */ | |
765 | strutils_normalize_star_glob_pattern(pattern_copy); | |
766 | ||
767 | free(jul_logging->pattern); | |
768 | ||
769 | jul_logging->pattern = pattern_copy; | |
770 | pattern_copy = NULL; | |
771 | end: | |
772 | return status; | |
773 | } | |
774 | ||
775 | enum lttng_event_rule_status lttng_event_rule_jul_logging_get_name_pattern( | |
776 | const struct lttng_event_rule *rule, const char **pattern) | |
777 | { | |
778 | struct lttng_event_rule_jul_logging *jul_logging; | |
779 | enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; | |
780 | ||
781 | if (!rule || !IS_JUL_LOGGING_EVENT_RULE(rule) || !pattern) { | |
782 | status = LTTNG_EVENT_RULE_STATUS_INVALID; | |
783 | goto end; | |
784 | } | |
785 | ||
786 | jul_logging = container_of( | |
787 | rule, struct lttng_event_rule_jul_logging, parent); | |
788 | if (!jul_logging->pattern) { | |
789 | status = LTTNG_EVENT_RULE_STATUS_UNSET; | |
790 | goto end; | |
791 | } | |
792 | ||
793 | *pattern = jul_logging->pattern; | |
794 | end: | |
795 | return status; | |
796 | } | |
797 | ||
798 | enum lttng_event_rule_status lttng_event_rule_jul_logging_set_filter( | |
799 | struct lttng_event_rule *rule, const char *expression) | |
800 | { | |
801 | char *expression_copy = NULL; | |
802 | struct lttng_event_rule_jul_logging *jul_logging; | |
803 | enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; | |
804 | ||
805 | if (!rule || !IS_JUL_LOGGING_EVENT_RULE(rule) || !expression || | |
806 | strlen(expression) == 0) { | |
807 | status = LTTNG_EVENT_RULE_STATUS_INVALID; | |
808 | goto end; | |
809 | } | |
810 | ||
811 | jul_logging = container_of( | |
812 | rule, struct lttng_event_rule_jul_logging, parent); | |
813 | expression_copy = strdup(expression); | |
814 | if (!expression_copy) { | |
815 | PERROR("Failed to copy filter expression"); | |
816 | status = LTTNG_EVENT_RULE_STATUS_ERROR; | |
817 | goto end; | |
818 | } | |
819 | ||
820 | if (jul_logging->filter_expression) { | |
821 | free(jul_logging->filter_expression); | |
822 | } | |
823 | ||
824 | jul_logging->filter_expression = expression_copy; | |
825 | expression_copy = NULL; | |
826 | end: | |
827 | return status; | |
828 | } | |
829 | ||
830 | enum lttng_event_rule_status lttng_event_rule_jul_logging_get_filter( | |
831 | const struct lttng_event_rule *rule, const char **expression) | |
832 | { | |
833 | struct lttng_event_rule_jul_logging *jul_logging; | |
834 | enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; | |
835 | ||
836 | if (!rule || !IS_JUL_LOGGING_EVENT_RULE(rule) || !expression) { | |
837 | status = LTTNG_EVENT_RULE_STATUS_INVALID; | |
838 | goto end; | |
839 | } | |
840 | ||
841 | jul_logging = container_of( | |
842 | rule, struct lttng_event_rule_jul_logging, parent); | |
843 | if (!jul_logging->filter_expression) { | |
844 | status = LTTNG_EVENT_RULE_STATUS_UNSET; | |
845 | goto end; | |
846 | } | |
847 | ||
848 | *expression = jul_logging->filter_expression; | |
849 | end: | |
850 | return status; | |
851 | } | |
852 | ||
f46376a1 MJ |
853 | static bool log_level_rule_valid( |
854 | const struct lttng_log_level_rule *rule __attribute__((unused))) | |
b47b01d8 JR |
855 | { |
856 | /* | |
857 | * For both JUL and LOG4J custom log level are possible and can | |
858 | * span the entire int32 range. | |
859 | */ | |
860 | return true; | |
861 | } | |
862 | ||
863 | enum lttng_event_rule_status lttng_event_rule_jul_logging_set_log_level_rule( | |
864 | struct lttng_event_rule *rule, | |
865 | const struct lttng_log_level_rule *log_level_rule) | |
866 | { | |
867 | struct lttng_event_rule_jul_logging *jul_logging; | |
868 | enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; | |
869 | struct lttng_log_level_rule *copy = NULL; | |
870 | ||
871 | if (!rule || !IS_JUL_LOGGING_EVENT_RULE(rule)) { | |
872 | status = LTTNG_EVENT_RULE_STATUS_INVALID; | |
873 | goto end; | |
874 | } | |
875 | ||
876 | jul_logging = container_of( | |
877 | rule, struct lttng_event_rule_jul_logging, parent); | |
878 | ||
879 | if (!log_level_rule_valid(log_level_rule)) { | |
880 | status = LTTNG_EVENT_RULE_STATUS_INVALID; | |
881 | goto end; | |
882 | } | |
883 | ||
884 | copy = lttng_log_level_rule_copy(log_level_rule); | |
885 | if (copy == NULL) { | |
886 | status = LTTNG_EVENT_RULE_STATUS_ERROR; | |
887 | goto end; | |
888 | } | |
889 | ||
890 | if (jul_logging->log_level_rule) { | |
891 | lttng_log_level_rule_destroy(jul_logging->log_level_rule); | |
892 | } | |
893 | ||
894 | jul_logging->log_level_rule = copy; | |
895 | ||
896 | end: | |
897 | return status; | |
898 | } | |
899 | ||
900 | enum lttng_event_rule_status lttng_event_rule_jul_logging_get_log_level_rule( | |
901 | const struct lttng_event_rule *rule, | |
902 | const struct lttng_log_level_rule **log_level_rule | |
903 | ) | |
904 | { | |
905 | struct lttng_event_rule_jul_logging *jul_logging; | |
906 | enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; | |
907 | ||
908 | if (!rule || !IS_JUL_LOGGING_EVENT_RULE(rule) || !log_level_rule) { | |
909 | status = LTTNG_EVENT_RULE_STATUS_INVALID; | |
910 | goto end; | |
911 | } | |
912 | ||
913 | jul_logging = container_of( | |
914 | rule, struct lttng_event_rule_jul_logging, parent); | |
915 | if (jul_logging->log_level_rule == NULL) { | |
916 | status = LTTNG_EVENT_RULE_STATUS_UNSET; | |
917 | goto end; | |
918 | } | |
919 | ||
920 | *log_level_rule = jul_logging->log_level_rule; | |
921 | end: | |
922 | return status; | |
923 | } |