Commit | Line | Data |
---|---|---|
6530ec7d 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 | ||
6530ec7d 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> | |
6530ec7d | 12 | #include <common/macros.h> |
6a751b95 | 13 | #include <common/mi-lttng.h> |
6530ec7d | 14 | #include <common/optional.h> |
6530ec7d | 15 | #include <common/payload-view.h> |
6a751b95 | 16 | #include <common/payload.h> |
6530ec7d | 17 | #include <common/runas.h> |
6530ec7d JR |
18 | #include <common/string-utils/string-utils.h> |
19 | #include <lttng/event-rule/event-rule-internal.h> | |
20 | #include <lttng/event-rule/python-logging-internal.h> | |
6530ec7d | 21 | #include <lttng/event.h> |
6a751b95 | 22 | #include <lttng/log-level-rule.h> |
6530ec7d JR |
23 | |
24 | #define IS_PYTHON_LOGGING_EVENT_RULE(rule) \ | |
25 | (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING) | |
26 | ||
27 | static void lttng_event_rule_python_logging_destroy(struct lttng_event_rule *rule) | |
28 | { | |
29 | struct lttng_event_rule_python_logging *python_logging; | |
30 | ||
31 | if (rule == NULL) { | |
32 | return; | |
33 | } | |
34 | ||
35 | python_logging = container_of( | |
36 | rule, struct lttng_event_rule_python_logging, parent); | |
37 | ||
38 | lttng_log_level_rule_destroy(python_logging->log_level_rule); | |
39 | free(python_logging->pattern); | |
40 | free(python_logging->filter_expression); | |
41 | free(python_logging->internal_filter.filter); | |
42 | free(python_logging->internal_filter.bytecode); | |
43 | free(python_logging); | |
44 | } | |
45 | ||
46 | static bool lttng_event_rule_python_logging_validate( | |
47 | const struct lttng_event_rule *rule) | |
48 | { | |
49 | bool valid = false; | |
50 | struct lttng_event_rule_python_logging *python_logging; | |
51 | ||
52 | if (!rule) { | |
53 | goto end; | |
54 | } | |
55 | ||
56 | python_logging = container_of( | |
57 | rule, struct lttng_event_rule_python_logging, parent); | |
58 | ||
59 | /* Required field. */ | |
60 | if (!python_logging->pattern) { | |
61 | ERR("Invalid python_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_python_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_python_logging *python_logging; | |
78 | struct lttng_event_rule_python_logging_comm python_logging_comm; | |
79 | struct lttng_event_rule_python_logging_comm *header; | |
80 | ||
81 | if (!rule || !IS_PYTHON_LOGGING_EVENT_RULE(rule)) { | |
82 | ret = -1; | |
83 | goto end; | |
84 | } | |
85 | ||
86 | header_offset = payload->buffer.size; | |
87 | ||
88 | DBG("Serializing python_logging event rule."); | |
89 | python_logging = container_of( | |
90 | rule, struct lttng_event_rule_python_logging, parent); | |
91 | ||
92 | pattern_len = strlen(python_logging->pattern) + 1; | |
93 | ||
94 | if (python_logging->filter_expression != NULL) { | |
95 | filter_expression_len = | |
96 | strlen(python_logging->filter_expression) + 1; | |
97 | } else { | |
98 | filter_expression_len = 0; | |
99 | } | |
100 | ||
101 | python_logging_comm.pattern_len = pattern_len; | |
102 | python_logging_comm.filter_expression_len = filter_expression_len; | |
103 | ||
104 | ret = lttng_dynamic_buffer_append(&payload->buffer, &python_logging_comm, | |
105 | sizeof(python_logging_comm)); | |
106 | if (ret) { | |
107 | goto end; | |
108 | } | |
109 | ||
110 | ret = lttng_dynamic_buffer_append( | |
111 | &payload->buffer, python_logging->pattern, pattern_len); | |
112 | if (ret) { | |
113 | goto end; | |
114 | } | |
115 | ||
116 | ret = lttng_dynamic_buffer_append(&payload->buffer, python_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(python_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_python_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_python_logging *a, *b; | |
143 | ||
144 | a = container_of(_a, struct lttng_event_rule_python_logging, parent); | |
145 | b = container_of(_b, struct lttng_event_rule_python_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); | |
6530ec7d 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); | |
6530ec7d JR |
199 | |
200 | status = lttng_event_rule_python_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_python_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_python_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_python_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_python_logging *python_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); |
6530ec7d JR |
306 | |
307 | python_logging = container_of( | |
308 | rule, struct lttng_event_rule_python_logging, parent); | |
309 | ||
310 | status = lttng_event_rule_python_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 | python_logging->internal_filter.filter = agent_filter; | |
330 | ||
331 | if (python_logging->internal_filter.filter == NULL) { | |
332 | ret_code = LTTNG_OK; | |
333 | goto end; | |
334 | } | |
335 | ||
336 | ret = run_as_generate_filter_bytecode( | |
337 | python_logging->internal_filter.filter, creds, | |
338 | &bytecode); | |
339 | if (ret) { | |
340 | ret_code = LTTNG_ERR_FILTER_INVAL; | |
341 | goto end; | |
342 | } | |
343 | ||
344 | python_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_python_logging_get_internal_filter( | |
355 | const struct lttng_event_rule *rule) | |
356 | { | |
357 | struct lttng_event_rule_python_logging *python_logging; | |
358 | ||
a0377dfe | 359 | LTTNG_ASSERT(rule); |
6530ec7d JR |
360 | python_logging = container_of( |
361 | rule, struct lttng_event_rule_python_logging, parent); | |
362 | return python_logging->internal_filter.filter; | |
363 | } | |
364 | ||
365 | static const struct lttng_bytecode * | |
366 | lttng_event_rule_python_logging_get_internal_filter_bytecode( | |
367 | const struct lttng_event_rule *rule) | |
368 | { | |
369 | struct lttng_event_rule_python_logging *python_logging; | |
370 | ||
a0377dfe | 371 | LTTNG_ASSERT(rule); |
6530ec7d JR |
372 | python_logging = container_of( |
373 | rule, struct lttng_event_rule_python_logging, parent); | |
374 | return python_logging->internal_filter.bytecode; | |
375 | } | |
376 | ||
377 | static enum lttng_event_rule_generate_exclusions_status | |
378 | lttng_event_rule_python_logging_generate_exclusions( | |
379 | const struct lttng_event_rule *rule, | |
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_python_logging_hash( | |
388 | const struct lttng_event_rule *rule) | |
389 | { | |
390 | unsigned long hash; | |
391 | struct lttng_event_rule_python_logging *tp_rule = | |
392 | container_of(rule, typeof(*tp_rule), parent); | |
393 | ||
394 | hash = hash_key_ulong((void *) LTTNG_EVENT_RULE_TYPE_PYTHON_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_python_logging_generate_lttng_event( | |
410 | const struct lttng_event_rule *rule) | |
411 | { | |
412 | int ret; | |
413 | const struct lttng_event_rule_python_logging *python_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 | python_logging = container_of( | |
422 | rule, const struct lttng_event_rule_python_logging, parent); | |
423 | ||
424 | local_event = zmalloc(sizeof(*local_event)); | |
425 | if (!local_event) { | |
426 | goto error; | |
427 | } | |
428 | ||
429 | local_event->type = LTTNG_EVENT_TRACEPOINT; | |
430 | ret = lttng_strncpy(local_event->name, python_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 | python_logging->pattern); | |
435 | goto error; | |
436 | } | |
437 | ||
438 | ||
439 | /* Map the log level rule to an equivalent lttng_loglevel. */ | |
440 | status = lttng_event_rule_python_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_python_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 | const char *filter = NULL; | |
488 | const char *name_pattern = NULL; | |
489 | const struct lttng_log_level_rule *log_level_rule = NULL; | |
490 | ||
a0377dfe FD |
491 | LTTNG_ASSERT(rule); |
492 | LTTNG_ASSERT(writer); | |
493 | LTTNG_ASSERT(IS_PYTHON_LOGGING_EVENT_RULE(rule)); | |
6a751b95 JR |
494 | |
495 | status = lttng_event_rule_python_logging_get_name_pattern( | |
496 | rule, &name_pattern); | |
a0377dfe FD |
497 | LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK); |
498 | LTTNG_ASSERT(name_pattern); | |
6a751b95 JR |
499 | |
500 | status = lttng_event_rule_python_logging_get_filter(rule, &filter); | |
a0377dfe | 501 | LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK || |
6a751b95 JR |
502 | status == LTTNG_EVENT_RULE_STATUS_UNSET); |
503 | ||
504 | status = lttng_event_rule_python_logging_get_log_level_rule( | |
505 | rule, &log_level_rule); | |
a0377dfe | 506 | LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK || |
6a751b95 JR |
507 | status == LTTNG_EVENT_RULE_STATUS_UNSET); |
508 | ||
509 | /* Open event rule python logging element. */ | |
510 | ret = mi_lttng_writer_open_element( | |
511 | writer, mi_lttng_element_event_rule_python_logging); | |
512 | if (ret) { | |
513 | goto mi_error; | |
514 | } | |
515 | ||
516 | /* Name pattern. */ | |
517 | ret = mi_lttng_writer_write_element_string(writer, | |
518 | mi_lttng_element_event_rule_name_pattern, name_pattern); | |
519 | if (ret) { | |
520 | goto mi_error; | |
521 | } | |
522 | ||
523 | /* Filter expression. */ | |
524 | if (filter != NULL) { | |
525 | ret = mi_lttng_writer_write_element_string(writer, | |
526 | mi_lttng_element_event_rule_filter_expression, | |
527 | filter); | |
528 | if (ret) { | |
529 | goto mi_error; | |
530 | } | |
531 | } | |
532 | ||
533 | /* Log level rule. */ | |
534 | if (log_level_rule) { | |
535 | ret_code = lttng_log_level_rule_mi_serialize( | |
536 | log_level_rule, writer); | |
537 | if (ret_code != LTTNG_OK) { | |
538 | goto end; | |
539 | } | |
540 | } | |
541 | ||
542 | /* Close event rule python logging element. */ | |
543 | ret = mi_lttng_writer_close_element(writer); | |
544 | if (ret) { | |
545 | goto mi_error; | |
546 | } | |
547 | ||
548 | ret_code = LTTNG_OK; | |
549 | goto end; | |
550 | ||
551 | mi_error: | |
552 | ret_code = LTTNG_ERR_MI_IO_FAIL; | |
553 | end: | |
554 | return ret_code; | |
555 | } | |
556 | ||
6530ec7d JR |
557 | struct lttng_event_rule *lttng_event_rule_python_logging_create(void) |
558 | { | |
559 | struct lttng_event_rule *rule = NULL; | |
560 | struct lttng_event_rule_python_logging *tp_rule; | |
561 | enum lttng_event_rule_status status; | |
562 | ||
563 | tp_rule = zmalloc(sizeof(struct lttng_event_rule_python_logging)); | |
564 | if (!tp_rule) { | |
565 | goto end; | |
566 | } | |
567 | ||
568 | rule = &tp_rule->parent; | |
569 | lttng_event_rule_init(&tp_rule->parent, LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING); | |
570 | tp_rule->parent.validate = lttng_event_rule_python_logging_validate; | |
571 | tp_rule->parent.serialize = lttng_event_rule_python_logging_serialize; | |
572 | tp_rule->parent.equal = lttng_event_rule_python_logging_is_equal; | |
573 | tp_rule->parent.destroy = lttng_event_rule_python_logging_destroy; | |
574 | tp_rule->parent.generate_filter_bytecode = | |
575 | lttng_event_rule_python_logging_generate_filter_bytecode; | |
576 | tp_rule->parent.get_filter = | |
577 | lttng_event_rule_python_logging_get_internal_filter; | |
578 | tp_rule->parent.get_filter_bytecode = | |
579 | lttng_event_rule_python_logging_get_internal_filter_bytecode; | |
580 | tp_rule->parent.generate_exclusions = | |
581 | lttng_event_rule_python_logging_generate_exclusions; | |
582 | tp_rule->parent.hash = lttng_event_rule_python_logging_hash; | |
583 | tp_rule->parent.generate_lttng_event = | |
584 | lttng_event_rule_python_logging_generate_lttng_event; | |
6a751b95 | 585 | tp_rule->parent.mi_serialize = lttng_event_rule_python_logging_mi_serialize; |
6530ec7d JR |
586 | |
587 | tp_rule->log_level_rule = NULL; | |
588 | ||
589 | /* Default pattern is '*'. */ | |
590 | status = lttng_event_rule_python_logging_set_name_pattern(rule, "*"); | |
591 | if (status != LTTNG_EVENT_RULE_STATUS_OK) { | |
592 | lttng_event_rule_destroy(rule); | |
593 | rule = NULL; | |
594 | } | |
595 | ||
596 | end: | |
597 | return rule; | |
598 | } | |
599 | ||
6530ec7d JR |
600 | ssize_t lttng_event_rule_python_logging_create_from_payload( |
601 | struct lttng_payload_view *view, | |
602 | struct lttng_event_rule **_event_rule) | |
603 | { | |
604 | ssize_t ret, offset = 0; | |
605 | enum lttng_event_rule_status status; | |
606 | const struct lttng_event_rule_python_logging_comm *python_logging_comm; | |
607 | const char *pattern; | |
608 | const char *filter_expression = NULL; | |
609 | struct lttng_buffer_view current_buffer_view; | |
610 | struct lttng_event_rule *rule = NULL; | |
611 | struct lttng_log_level_rule *log_level_rule = NULL; | |
612 | ||
613 | if (!_event_rule) { | |
614 | ret = -1; | |
615 | goto end; | |
616 | } | |
617 | ||
618 | current_buffer_view = lttng_buffer_view_from_view( | |
619 | &view->buffer, offset, sizeof(*python_logging_comm)); | |
620 | if (!lttng_buffer_view_is_valid(¤t_buffer_view)) { | |
621 | ERR("Failed to initialize from malformed event rule python_logging: buffer too short to contain header."); | |
622 | ret = -1; | |
623 | goto end; | |
624 | } | |
625 | ||
626 | python_logging_comm = (typeof(python_logging_comm)) current_buffer_view.data; | |
627 | ||
628 | rule = lttng_event_rule_python_logging_create(); | |
629 | if (!rule) { | |
630 | ERR("Failed to create event rule python_logging."); | |
631 | ret = -1; | |
632 | goto end; | |
633 | } | |
634 | ||
635 | /* Skip to payload. */ | |
636 | offset += current_buffer_view.size; | |
637 | ||
638 | /* Map the pattern. */ | |
639 | current_buffer_view = lttng_buffer_view_from_view( | |
640 | &view->buffer, offset, python_logging_comm->pattern_len); | |
641 | ||
642 | if (!lttng_buffer_view_is_valid(¤t_buffer_view)) { | |
643 | ret = -1; | |
644 | goto end; | |
645 | } | |
646 | ||
647 | pattern = current_buffer_view.data; | |
648 | if (!lttng_buffer_view_contains_string(¤t_buffer_view, pattern, | |
649 | python_logging_comm->pattern_len)) { | |
650 | ret = -1; | |
651 | goto end; | |
652 | } | |
653 | ||
654 | /* Skip after the pattern. */ | |
655 | offset += python_logging_comm->pattern_len; | |
656 | ||
657 | if (!python_logging_comm->filter_expression_len) { | |
658 | goto skip_filter_expression; | |
659 | } | |
660 | ||
661 | /* Map the filter_expression. */ | |
662 | current_buffer_view = lttng_buffer_view_from_view(&view->buffer, offset, | |
663 | python_logging_comm->filter_expression_len); | |
664 | if (!lttng_buffer_view_is_valid(¤t_buffer_view)) { | |
665 | ret = -1; | |
666 | goto end; | |
667 | } | |
668 | ||
669 | filter_expression = current_buffer_view.data; | |
670 | if (!lttng_buffer_view_contains_string(¤t_buffer_view, | |
671 | filter_expression, | |
672 | python_logging_comm->filter_expression_len)) { | |
673 | ret = -1; | |
674 | goto end; | |
675 | } | |
676 | ||
677 | /* Skip after the pattern. */ | |
678 | offset += python_logging_comm->filter_expression_len; | |
679 | ||
680 | skip_filter_expression: | |
681 | if (!python_logging_comm->log_level_rule_len) { | |
682 | goto skip_log_level_rule; | |
683 | } | |
684 | ||
685 | { | |
686 | /* Map the log level rule. */ | |
687 | struct lttng_payload_view current_payload_view = | |
688 | lttng_payload_view_from_view(view, offset, | |
689 | python_logging_comm->log_level_rule_len); | |
690 | ||
691 | ret = lttng_log_level_rule_create_from_payload( | |
692 | ¤t_payload_view, &log_level_rule); | |
693 | if (ret < 0) { | |
694 | ret = -1; | |
695 | goto end; | |
696 | } | |
697 | ||
a0377dfe | 698 | LTTNG_ASSERT(ret == python_logging_comm->log_level_rule_len); |
6530ec7d JR |
699 | } |
700 | ||
701 | /* Skip after the log level rule. */ | |
702 | offset += python_logging_comm->log_level_rule_len; | |
703 | ||
704 | skip_log_level_rule: | |
705 | ||
706 | status = lttng_event_rule_python_logging_set_name_pattern(rule, pattern); | |
707 | if (status != LTTNG_EVENT_RULE_STATUS_OK) { | |
708 | ERR("Failed to set event rule python_logging pattern."); | |
709 | ret = -1; | |
710 | goto end; | |
711 | } | |
712 | ||
713 | if (filter_expression) { | |
714 | status = lttng_event_rule_python_logging_set_filter( | |
715 | rule, filter_expression); | |
716 | if (status != LTTNG_EVENT_RULE_STATUS_OK) { | |
717 | ERR("Failed to set event rule python_logging pattern."); | |
718 | ret = -1; | |
719 | goto end; | |
720 | } | |
721 | } | |
722 | ||
723 | if (log_level_rule) { | |
724 | status = lttng_event_rule_python_logging_set_log_level_rule( | |
725 | rule, log_level_rule); | |
726 | if (status != LTTNG_EVENT_RULE_STATUS_OK) { | |
727 | ERR("Failed to set event rule python_logging log level rule."); | |
728 | ret = -1; | |
729 | goto end; | |
730 | } | |
731 | } | |
732 | ||
733 | *_event_rule = rule; | |
734 | rule = NULL; | |
735 | ret = offset; | |
736 | end: | |
737 | lttng_log_level_rule_destroy(log_level_rule); | |
738 | lttng_event_rule_destroy(rule); | |
739 | return ret; | |
740 | } | |
741 | ||
742 | enum lttng_event_rule_status lttng_event_rule_python_logging_set_name_pattern( | |
743 | struct lttng_event_rule *rule, const char *pattern) | |
744 | { | |
745 | char *pattern_copy = NULL; | |
746 | struct lttng_event_rule_python_logging *python_logging; | |
747 | enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; | |
748 | ||
749 | if (!rule || !IS_PYTHON_LOGGING_EVENT_RULE(rule) || !pattern || | |
750 | strlen(pattern) == 0) { | |
751 | status = LTTNG_EVENT_RULE_STATUS_INVALID; | |
752 | goto end; | |
753 | } | |
754 | ||
755 | python_logging = container_of( | |
756 | rule, struct lttng_event_rule_python_logging, parent); | |
757 | pattern_copy = strdup(pattern); | |
758 | if (!pattern_copy) { | |
759 | status = LTTNG_EVENT_RULE_STATUS_ERROR; | |
760 | goto end; | |
761 | } | |
762 | ||
763 | /* Normalize the pattern. */ | |
764 | strutils_normalize_star_glob_pattern(pattern_copy); | |
765 | ||
766 | free(python_logging->pattern); | |
767 | ||
768 | python_logging->pattern = pattern_copy; | |
769 | pattern_copy = NULL; | |
770 | end: | |
771 | return status; | |
772 | } | |
773 | ||
774 | enum lttng_event_rule_status lttng_event_rule_python_logging_get_name_pattern( | |
775 | const struct lttng_event_rule *rule, const char **pattern) | |
776 | { | |
777 | struct lttng_event_rule_python_logging *python_logging; | |
778 | enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; | |
779 | ||
780 | if (!rule || !IS_PYTHON_LOGGING_EVENT_RULE(rule) || !pattern) { | |
781 | status = LTTNG_EVENT_RULE_STATUS_INVALID; | |
782 | goto end; | |
783 | } | |
784 | ||
785 | python_logging = container_of( | |
786 | rule, struct lttng_event_rule_python_logging, parent); | |
787 | if (!python_logging->pattern) { | |
788 | status = LTTNG_EVENT_RULE_STATUS_UNSET; | |
789 | goto end; | |
790 | } | |
791 | ||
792 | *pattern = python_logging->pattern; | |
793 | end: | |
794 | return status; | |
795 | } | |
796 | ||
797 | enum lttng_event_rule_status lttng_event_rule_python_logging_set_filter( | |
798 | struct lttng_event_rule *rule, const char *expression) | |
799 | { | |
800 | char *expression_copy = NULL; | |
801 | struct lttng_event_rule_python_logging *python_logging; | |
802 | enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; | |
803 | ||
804 | if (!rule || !IS_PYTHON_LOGGING_EVENT_RULE(rule) || !expression || | |
805 | strlen(expression) == 0) { | |
806 | status = LTTNG_EVENT_RULE_STATUS_INVALID; | |
807 | goto end; | |
808 | } | |
809 | ||
810 | python_logging = container_of( | |
811 | rule, struct lttng_event_rule_python_logging, parent); | |
812 | expression_copy = strdup(expression); | |
813 | if (!expression_copy) { | |
814 | PERROR("Failed to copy filter expression"); | |
815 | status = LTTNG_EVENT_RULE_STATUS_ERROR; | |
816 | goto end; | |
817 | } | |
818 | ||
819 | if (python_logging->filter_expression) { | |
820 | free(python_logging->filter_expression); | |
821 | } | |
822 | ||
823 | python_logging->filter_expression = expression_copy; | |
824 | expression_copy = NULL; | |
825 | end: | |
826 | return status; | |
827 | } | |
828 | ||
829 | enum lttng_event_rule_status lttng_event_rule_python_logging_get_filter( | |
830 | const struct lttng_event_rule *rule, const char **expression) | |
831 | { | |
832 | struct lttng_event_rule_python_logging *python_logging; | |
833 | enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; | |
834 | ||
835 | if (!rule || !IS_PYTHON_LOGGING_EVENT_RULE(rule) || !expression) { | |
836 | status = LTTNG_EVENT_RULE_STATUS_INVALID; | |
837 | goto end; | |
838 | } | |
839 | ||
840 | python_logging = container_of( | |
841 | rule, struct lttng_event_rule_python_logging, parent); | |
842 | if (!python_logging->filter_expression) { | |
843 | status = LTTNG_EVENT_RULE_STATUS_UNSET; | |
844 | goto end; | |
845 | } | |
846 | ||
847 | *expression = python_logging->filter_expression; | |
848 | end: | |
849 | return status; | |
850 | } | |
851 | ||
852 | static bool log_level_rule_valid(const struct lttng_log_level_rule *rule) | |
853 | { | |
854 | /* | |
855 | * For python, custom log level are possible, it is not clear if | |
856 | * negative value are accepted (NOTSET == 0) but the source code | |
857 | * validates against the int type implying that negative values | |
858 | * are accepted. | |
859 | */ | |
860 | return true; | |
861 | } | |
862 | ||
863 | enum lttng_event_rule_status lttng_event_rule_python_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_python_logging *python_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_PYTHON_LOGGING_EVENT_RULE(rule)) { | |
872 | status = LTTNG_EVENT_RULE_STATUS_INVALID; | |
873 | goto end; | |
874 | } | |
875 | ||
876 | python_logging = container_of( | |
877 | rule, struct lttng_event_rule_python_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 (python_logging->log_level_rule) { | |
891 | lttng_log_level_rule_destroy(python_logging->log_level_rule); | |
892 | } | |
893 | ||
894 | python_logging->log_level_rule = copy; | |
895 | ||
896 | end: | |
897 | return status; | |
898 | } | |
899 | ||
900 | enum lttng_event_rule_status lttng_event_rule_python_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_python_logging *python_logging; | |
906 | enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; | |
907 | ||
908 | if (!rule || !IS_PYTHON_LOGGING_EVENT_RULE(rule) || !log_level_rule) { | |
909 | status = LTTNG_EVENT_RULE_STATUS_INVALID; | |
910 | goto end; | |
911 | } | |
912 | ||
913 | python_logging = container_of( | |
914 | rule, struct lttng_event_rule_python_logging, parent); | |
915 | if (python_logging->log_level_rule == NULL) { | |
916 | status = LTTNG_EVENT_RULE_STATUS_UNSET; | |
917 | goto end; | |
918 | } | |
919 | ||
920 | *log_level_rule = python_logging->log_level_rule; | |
921 | end: | |
922 | return status; | |
923 | } |