From: Jonathan Rajotte Date: Fri, 6 Nov 2020 15:06:23 +0000 (-0500) Subject: lttng-ctl: Introduce lttng_log_level_rule X-Git-Tag: v2.13.0-rc1~209 X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=85b053182c4e300c717483ad231f5c04cbf5e4b7;p=lttng-tools.git lttng-ctl: Introduce lttng_log_level_rule This object corresponds to the criteria a event-rule tracepoint must respect for an event to be consired under the event-rule tracepoint criteria. The lttng tracepoint event rule object now have the following API function in regards to log level rule: lttng_event_rule_tracepoint_set_log_level_rule lttng_event_rule_tracepoint_get_log_level_rule Signed-off-by: Jonathan Rajotte Signed-off-by: Jérémie Galarneau Change-Id: Iefd361d1b7d85c6803e891166429a2830e2404a2 --- diff --git a/.gitignore b/.gitignore index 3c76b61f2..5e2b0a189 100644 --- a/.gitignore +++ b/.gitignore @@ -148,6 +148,7 @@ health_check /tests/unit/test_buffer_view /tests/unit/test_kernel_probe /tests/unit/test_event_expr_to_bytecode +/tests/unit/test_log_level_rule /tests/utils/testapp/gen-ust-nevents-str/gen-ust-nevents-str /tests/utils/testapp/userspace-probe-elf-binary/userspace-probe-elf-binary /tests/utils/testapp/userspace-probe-elf-cxx-binary/userspace-probe-elf-cxx-binary diff --git a/include/Makefile.am b/include/Makefile.am index 96e541332..994c51166 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -112,6 +112,7 @@ lttnginclude_HEADERS = \ lttng/kernel-probe.h \ lttng/load.h \ lttng/location.h \ + lttng/log-level-rule.h \ lttng/lttng-error.h \ lttng/lttng.h \ lttng/rotation.h \ @@ -182,6 +183,7 @@ noinst_HEADERS = \ lttng/kernel-probe-internal.h \ lttng/load-internal.h \ lttng/location-internal.h \ + lttng/log-level-rule-internal.h \ lttng/notification/channel-internal.h \ lttng/notification/notification-internal.h \ lttng/ref-internal.h \ diff --git a/include/lttng/event-rule/tracepoint-internal.h b/include/lttng/event-rule/tracepoint-internal.h index 227fe6de9..6c4d438d5 100644 --- a/include/lttng/event-rule/tracepoint-internal.h +++ b/include/lttng/event-rule/tracepoint-internal.h @@ -10,10 +10,12 @@ #include #include +#include #include #include #include #include +#include struct lttng_event_rule_tracepoint { struct lttng_event_rule parent; @@ -27,11 +29,8 @@ struct lttng_event_rule_tracepoint { /* Filter. */ char *filter_expression; - /* Loglevel. */ - struct { - enum lttng_loglevel_type type; - int value; - } loglevel; + /* Log level. */ + struct lttng_log_level_rule *log_level_rule; /* Exclusions. */ struct lttng_dynamic_pointer_array exclusions; @@ -46,19 +45,19 @@ struct lttng_event_rule_tracepoint { struct lttng_event_rule_tracepoint_comm { /* enum lttng_domain_type. */ int8_t domain_type; - /* enum lttng_event_logleven_type. */ - int8_t loglevel_type; - int32_t loglevel_value; /* Includes terminator `\0`. */ uint32_t pattern_len; /* Includes terminator `\0`. */ uint32_t filter_expression_len; + /* enum lttng_log_level_rule_comm + payload if any */ + uint32_t log_level_rule_len; uint32_t exclusions_count; uint32_t exclusions_len; /* * Payload is composed of, in that order: * - pattern (null terminated), * - filter expression (null terminated), + * - log level rule serialized object, * - exclusions (32 bit length + null terminated string). */ char payload[]; diff --git a/include/lttng/event-rule/tracepoint.h b/include/lttng/event-rule/tracepoint.h index 5e83076d5..d86b53fed 100644 --- a/include/lttng/event-rule/tracepoint.h +++ b/include/lttng/event-rule/tracepoint.h @@ -10,6 +10,7 @@ #include #include +#include #include #ifdef __cplusplus @@ -92,58 +93,33 @@ extern enum lttng_event_rule_status lttng_event_rule_tracepoint_get_filter( const struct lttng_event_rule *rule, const char **expression); /* - * Set the single log level of a tracepoint event rule. + * Set the log level rule of a tracepoint event rule. * - * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID - * if invalid parameters are passed. - */ -extern enum lttng_event_rule_status lttng_event_rule_tracepoint_set_log_level( - struct lttng_event_rule *rule, int level); - -/* - * Set the log level range lower bound of a tracepoint event rule. + * The log level rule is copied internally. * * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID * if invalid parameters are passed. */ extern enum lttng_event_rule_status -lttng_event_rule_tracepoint_set_log_level_range_lower_bound( - struct lttng_event_rule *rule, int level); +lttng_event_rule_tracepoint_set_log_level_rule(struct lttng_event_rule *rule, + const struct lttng_log_level_rule *log_level_rule); /* - * Set the log level to all of a tracepoint event rule. + * Get the log level rule of a tracepoint event rule. * - * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID - * if invalid parameters are passed. - */ -extern enum lttng_event_rule_status -lttng_event_rule_tracepoint_set_log_level_all(struct lttng_event_rule *rule); - -/* - * Get the log level type of a tracepoint event rule. + * The caller does not assume the ownership of the returned log level rule. The + * log level rule shall only only be used for the duration of the event rule's + * lifetime, or before a different log level rule is set. * - * Returns LTTNG_EVENT_RULE_STATUS_OK and sets the log level type output + * Returns LTTNG_EVENT_RULE_STATUS_OK and sets the log level rule output * parameter on success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter - * is passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a log level was not set prior + * is passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a log level rule was not set prior * to this call. */ extern enum lttng_event_rule_status -lttng_event_rule_tracepoint_get_log_level_type( +lttng_event_rule_tracepoint_get_log_level_rule( const struct lttng_event_rule *rule, - enum lttng_loglevel_type *type); - -/* - * Get the log level of a tracepoint event rule. - * - * For range log level , the lower bound log level is returned. - * - * Returns LTTNG_EVENT_RULE_STATUS_OK and sets the log level output parameter - * on success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter is - * passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a log level was not set prior to - * this call. - */ -extern enum lttng_event_rule_status lttng_event_rule_tracepoint_get_log_level( - const struct lttng_event_rule *rule, int *level); + const struct lttng_log_level_rule **log_level_rule); /* * Add an exclusion to the set of exclusion of an event rule. diff --git a/include/lttng/log-level-rule-internal.h b/include/lttng/log-level-rule-internal.h new file mode 100644 index 000000000..f0ca63222 --- /dev/null +++ b/include/lttng/log-level-rule-internal.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2020 Jonathan Rajotte + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#ifndef LTTNG_LOG_LEVEL_RULE_INTERNAL_H +#define LTTNG_LOG_LEVEL_RULE_INTERNAL_H + +#include + +#include +#include +#include +#include +#include +#include +#include + +/* + * For now only a single backing struct is used for both type of log level + * rule (exactly, as_severe) since both only have require "level" as property. + */ +struct lttng_log_level_rule { + enum lttng_log_level_rule_type type; + int level; +}; + +struct lttng_log_level_rule_comm { + /* enum lttng_log_level_rule_type */ + int8_t type; + int32_t level; +}; + +LTTNG_HIDDEN +ssize_t lttng_log_level_rule_create_from_payload( + struct lttng_payload_view *view, + struct lttng_log_level_rule **rule); + +LTTNG_HIDDEN +int lttng_log_level_rule_serialize(const struct lttng_log_level_rule *rule, + struct lttng_payload *payload); + +LTTNG_HIDDEN +bool lttng_log_level_rule_is_equal(const struct lttng_log_level_rule *a, + const struct lttng_log_level_rule *b); + +LTTNG_HIDDEN +struct lttng_log_level_rule *lttng_log_level_rule_copy( + const struct lttng_log_level_rule *source); + +LTTNG_HIDDEN +void lttng_log_level_rule_to_loglevel( + const struct lttng_log_level_rule *log_level_rule, + enum lttng_loglevel_type *loglevel_type, + int *loglevel_value); + +LTTNG_HIDDEN +unsigned long lttng_log_level_rule_hash( + const struct lttng_log_level_rule *log_level_rule); + +#endif /* LTTNG_LOG_LEVEL_RULE_INTERNAL_H */ diff --git a/include/lttng/log-level-rule.h b/include/lttng/log-level-rule.h new file mode 100644 index 000000000..ea9045d56 --- /dev/null +++ b/include/lttng/log-level-rule.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2020 Jonathan Rajotte + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#ifndef LTTNG_LOG_LEVEL_RULE_H +#define LTTNG_LOG_LEVEL_RULE_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct lttng_log_level_rule; + +enum lttng_log_level_rule_type { + LTTNG_LOG_LEVEL_RULE_TYPE_UNKNOWN = -1, + LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY = 0, + LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS = 1, +}; + +enum lttng_log_level_rule_status { + LTTNG_LOG_LEVEL_RULE_STATUS_OK = 0, + LTTNG_LOG_LEVEL_RULE_STATUS_ERROR = -1, + LTTNG_LOG_LEVEL_RULE_STATUS_INVALID = -3, +}; + +/* + * Returns the type of the log level rule `rule`, or: + * + * `LTTNG_LOG_LEVEL_RULE_TYPE_UNKNOWN`: + * `rule` is `NULL`. + */ +extern enum lttng_log_level_rule_type lttng_log_level_rule_get_type( + const struct lttng_log_level_rule *rule); + +/* + * Creates a log level rule for which a log level must match exactly `level` to + * be considered. + * + * Returns `NULL` if: + * + * * There's a memory error. + * + * The returned log level rule must be destroyed using + * lttng_log_level_rule_destroy(). + */ +extern struct lttng_log_level_rule *lttng_log_level_rule_exactly_create( + int level); + +/* + * Sets `level` to the level of the "exactly" log level rule `rule`. + * + * Returns: + * + * `LTTNG_LOG_LEVEL_RULE_STATUS_OK`: + * Success. + * + * `LTTNG_LOG_LEVEL_RULE_STATUS_INVALID`: + * * `rule` is NULL. + * * `level` is NULL. + * * The type of `rule` is not `LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY`. + */ +extern enum lttng_log_level_rule_status lttng_log_level_rule_exactly_get_level( + const struct lttng_log_level_rule *rule, int *level); + +/* + * Creates a log level rule for which a log level must be at least as severe as + * `level` to be considered. + * + * Returns `NULL` if: + * + * * There's a memory error. + * + * The returned log level rule must be destroyed using + * lttng_log_level_rule_destroy(). + */ +extern struct lttng_log_level_rule * +lttng_log_level_rule_at_least_as_severe_as_create(int level); + +/* + * Sets `level` to the level of the "at least as severe as" log level rule + * `rule`. + * + * Returns: + * + * `LTTNG_LOG_LEVEL_RULE_STATUS_OK`: + * Success. + * + * `LTTNG_LOG_LEVEL_RULE_STATUS_INVALID`: + * * `rule` is NULL. + * * `level` is NULL. + * * The type of `rule` is not + * `LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS`. + */ +extern enum lttng_log_level_rule_status +lttng_log_level_rule_at_least_as_severe_as_get_level( + const struct lttng_log_level_rule *rule, int *level); + +/* + * Destroy the log level rule `log_level_rule` if not `NULL`. + */ +extern void lttng_log_level_rule_destroy( + struct lttng_log_level_rule *log_level_rule); + +#ifdef __cplusplus +} +#endif + +#endif /* LTTNG_LOG_LEVEL_RULE_H */ diff --git a/include/lttng/lttng.h b/include/lttng/lttng.h index 790943edf..5cdf1aa83 100644 --- a/include/lttng/lttng.h +++ b/include/lttng/lttng.h @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include diff --git a/src/bin/lttng-sessiond/agent.c b/src/bin/lttng-sessiond/agent.c index 9832e5ef9..b726e0184 100644 --- a/src/bin/lttng-sessiond/agent.c +++ b/src/bin/lttng-sessiond/agent.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -1243,6 +1244,7 @@ struct agent_event *agent_find_event_by_trigger( const struct lttng_event_rule *rule; const char *name; const char *filter_expression; + const struct lttng_log_level_rule *log_level_rule; /* Unused when loglevel_type is 'ALL'. */ int loglevel_value = 0; enum lttng_loglevel_type loglevel_type; @@ -1272,14 +1274,16 @@ struct agent_event *agent_find_event_by_trigger( /* Get the internal filter expression. */ filter_expression = lttng_event_rule_get_filter(rule); - er_status = lttng_event_rule_tracepoint_get_log_level_type( - rule, &loglevel_type); - assert(er_status == LTTNG_EVENT_RULE_STATUS_OK); - - if (loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) { - er_status = lttng_event_rule_tracepoint_get_log_level( - rule, &loglevel_value); - assert(er_status == LTTNG_EVENT_RULE_STATUS_OK); + /* Map log_level_rule to loglevel value. */ + er_status = lttng_event_rule_tracepoint_get_log_level_rule( + rule, &log_level_rule); + if (er_status == LTTNG_EVENT_RULE_STATUS_UNSET) { + loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL; + loglevel_value = 0; + } else if (er_status == LTTNG_EVENT_RULE_STATUS_OK) { + lttng_log_level_rule_to_loglevel(log_level_rule, &loglevel_type, &loglevel_value); + } else { + abort(); } return agent_find_event(name, loglevel_type, loglevel_value, diff --git a/src/bin/lttng-sessiond/ust-app.c b/src/bin/lttng-sessiond/ust-app.c index 81e3bd848..6d71df5c0 100644 --- a/src/bin/lttng-sessiond/ust-app.c +++ b/src/bin/lttng-sessiond/ust-app.c @@ -2000,7 +2000,6 @@ static int init_ust_event_notifier_from_event_rule( struct lttng_ust_abi_event_notifier *event_notifier) { enum lttng_event_rule_status status; - enum lttng_loglevel_type loglevel_type; enum lttng_ust_abi_loglevel_type ust_loglevel_type = LTTNG_UST_ABI_LOGLEVEL_ALL; int loglevel = -1, ret = 0; const char *pattern; @@ -2023,39 +2022,40 @@ static int init_ust_event_notifier_from_event_rule( loglevel = 0; ust_loglevel_type = LTTNG_UST_ABI_LOGLEVEL_ALL; } else { - status = lttng_event_rule_tracepoint_get_pattern( - rule, &pattern); - if (status != LTTNG_EVENT_RULE_STATUS_OK) { - /* At this point, this is a fatal error. */ - abort(); - } + const struct lttng_log_level_rule *log_level_rule; - status = lttng_event_rule_tracepoint_get_log_level_type( - rule, &loglevel_type); + status = lttng_event_rule_tracepoint_get_pattern(rule, &pattern); if (status != LTTNG_EVENT_RULE_STATUS_OK) { /* At this point, this is a fatal error. */ abort(); } - switch (loglevel_type) { - case LTTNG_EVENT_LOGLEVEL_ALL: + status = lttng_event_rule_tracepoint_get_log_level_rule( + rule, &log_level_rule); + if (status == LTTNG_EVENT_RULE_STATUS_UNSET) { ust_loglevel_type = LTTNG_UST_ABI_LOGLEVEL_ALL; - break; - case LTTNG_EVENT_LOGLEVEL_RANGE: - ust_loglevel_type = LTTNG_UST_ABI_LOGLEVEL_RANGE; - break; - case LTTNG_EVENT_LOGLEVEL_SINGLE: - ust_loglevel_type = LTTNG_UST_ABI_LOGLEVEL_SINGLE; - break; - default: - /* Unknown log level specification type. */ - abort(); - } + } else if (status == LTTNG_EVENT_RULE_STATUS_OK) { + enum lttng_log_level_rule_status llr_status; + + switch (lttng_log_level_rule_get_type(log_level_rule)) { + case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY: + ust_loglevel_type = LTTNG_UST_ABI_LOGLEVEL_SINGLE; + llr_status = lttng_log_level_rule_exactly_get_level( + log_level_rule, &loglevel); + break; + case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS: + ust_loglevel_type = LTTNG_UST_ABI_LOGLEVEL_RANGE; + llr_status = lttng_log_level_rule_at_least_as_severe_as_get_level( + log_level_rule, &loglevel); + break; + default: + abort(); + } - if (loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) { - status = lttng_event_rule_tracepoint_get_log_level( - rule, &loglevel); - assert(status == LTTNG_EVENT_RULE_STATUS_OK); + assert(llr_status == LTTNG_LOG_LEVEL_RULE_STATUS_OK); + } else { + /* At this point this is a fatal error. */ + abort(); } } diff --git a/src/bin/lttng/commands/add_trigger.c b/src/bin/lttng/commands/add_trigger.c index 776e24470..f1b505f25 100644 --- a/src/bin/lttng/commands/add_trigger.c +++ b/src/bin/lttng/commands/add_trigger.c @@ -541,6 +541,7 @@ struct parse_event_rule_res parse_event_rule(int *argc, const char ***argv) struct parse_event_rule_res res = { 0 }; struct lttng_event_expr *event_expr = NULL; struct filter_parser_ctx *parser_ctx = NULL; + struct lttng_log_level_rule *log_level_rule = NULL; /* Was the -a/--all flag provided? */ bool all_events = false; @@ -938,15 +939,20 @@ struct parse_event_rule_res parse_event_rule(int *argc, const char ***argv) } if (loglevel_only) { - event_rule_status = lttng_event_rule_tracepoint_set_log_level( - res.er, - loglevel); + log_level_rule = lttng_log_level_rule_exactly_create(loglevel); } else { - event_rule_status = lttng_event_rule_tracepoint_set_log_level_range_lower_bound( - res.er, - loglevel); + log_level_rule = lttng_log_level_rule_at_least_as_severe_as_create(loglevel); + } + + if (log_level_rule == NULL) { + ERR("Failed to create log level rule object."); + goto error; } + event_rule_status = + lttng_event_rule_tracepoint_set_log_level_rule( + res.er, log_level_rule); + if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) { ERR("Failed to set log level on event fule."); goto error; @@ -1068,6 +1074,7 @@ end: strutils_free_null_terminated_array_of_strings(exclusion_list); lttng_kernel_probe_location_destroy(kernel_probe_location); lttng_userspace_probe_location_destroy(userspace_probe_location); + lttng_log_level_rule_destroy(log_level_rule); return res; } diff --git a/src/bin/lttng/commands/list_triggers.c b/src/bin/lttng/commands/list_triggers.c index 054b3fb72..b8fb64a0a 100644 --- a/src/bin/lttng/commands/list_triggers.c +++ b/src/bin/lttng/commands/list_triggers.c @@ -16,6 +16,7 @@ #include "lttng/condition/condition-internal.h" /* For lttng_domain_type_str(). */ #include "lttng/domain-internal.h" +#include "../loglevel.h" #ifdef LTTNG_EMBED_HELP static const char help_msg[] = @@ -35,6 +36,37 @@ struct argpar_opt_descr list_trigger_options[] = { ARGPAR_OPT_DESCR_SENTINEL, }; +/* + * Returns the human-readable log level name associated with a numerical value + * if there is one. The Log4j and JUL domains have discontinuous log level + * values (a value can fall between two labels). In those cases, NULL is + * returned. + */ +static const char *get_pretty_loglevel_name( + enum lttng_domain_type domain, int loglevel) +{ + const char *name = NULL; + + switch (domain) { + case LTTNG_DOMAIN_UST: + name = loglevel_value_to_name(loglevel); + break; + case LTTNG_DOMAIN_LOG4J: + name = loglevel_log4j_value_to_name(loglevel); + break; + case LTTNG_DOMAIN_JUL: + name = loglevel_jul_value_to_name(loglevel); + break; + case LTTNG_DOMAIN_PYTHON: + name = loglevel_python_value_to_name(loglevel); + break; + default: + break; + } + + return name; +} + static void print_event_rule_tracepoint(const struct lttng_event_rule *event_rule) { @@ -43,6 +75,7 @@ void print_event_rule_tracepoint(const struct lttng_event_rule *event_rule) const char *pattern; const char *filter; int log_level; + const struct lttng_log_level_rule *log_level_rule = NULL; unsigned int exclusions_count; int i; @@ -65,23 +98,38 @@ void print_event_rule_tracepoint(const struct lttng_event_rule *event_rule) assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_UNSET); } - event_rule_status = lttng_event_rule_tracepoint_get_log_level( - event_rule, &log_level); + event_rule_status = lttng_event_rule_tracepoint_get_log_level_rule( + event_rule, &log_level_rule); if (event_rule_status == LTTNG_EVENT_RULE_STATUS_OK) { - enum lttng_loglevel_type log_level_type; + enum lttng_log_level_rule_status llr_status; const char *log_level_op; + const char *pretty_loglevel_name; + + switch (lttng_log_level_rule_get_type(log_level_rule)) { + case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY: + log_level_op = "is"; + llr_status = lttng_log_level_rule_exactly_get_level( + log_level_rule, &log_level); + break; + case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS: + log_level_op = "at least"; + llr_status = lttng_log_level_rule_at_least_as_severe_as_get_level( + log_level_rule, &log_level); + break; + default: + abort(); + } - event_rule_status = lttng_event_rule_tracepoint_get_log_level_type( - event_rule, &log_level_type); - assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK); - assert(log_level_type == LTTNG_EVENT_LOGLEVEL_RANGE || - log_level_type == LTTNG_EVENT_LOGLEVEL_SINGLE); - - log_level_op = (log_level_type == LTTNG_EVENT_LOGLEVEL_RANGE ? "<=" : "=="); + assert(llr_status == LTTNG_LOG_LEVEL_RULE_STATUS_OK); - _MSG(", log level %s %s", log_level_op, - mi_lttng_loglevel_string( - log_level, domain_type)); + pretty_loglevel_name = get_pretty_loglevel_name( + domain_type, log_level); + if (pretty_loglevel_name) { + _MSG(", log level %s %s", log_level_op, + pretty_loglevel_name); + } else { + _MSG(", log level %s %d", log_level_op, log_level); + } } else { assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_UNSET); } diff --git a/src/bin/lttng/loglevel.c b/src/bin/lttng/loglevel.c index ec82bfe11..c18bf381c 100644 --- a/src/bin/lttng/loglevel.c +++ b/src/bin/lttng/loglevel.c @@ -18,101 +18,101 @@ struct loglevel_name_value { static const struct loglevel_name_value loglevel_values[] = { - { .name = "TRACE_EMERG", .value = LTTNG_LOGLEVEL_EMERG }, { .name = "EMERG", .value = LTTNG_LOGLEVEL_EMERG }, - { .name = "TRACE_ALERT", .value = LTTNG_LOGLEVEL_ALERT }, + { .name = "TRACE_EMERG", .value = LTTNG_LOGLEVEL_EMERG }, { .name = "ALERT", .value = LTTNG_LOGLEVEL_ALERT }, - { .name = "TRACE_CRIT", .value = LTTNG_LOGLEVEL_CRIT }, + { .name = "TRACE_ALERT", .value = LTTNG_LOGLEVEL_ALERT }, { .name = "CRIT", .value = LTTNG_LOGLEVEL_CRIT }, - { .name = "TRACE_ERR", .value = LTTNG_LOGLEVEL_ERR }, + { .name = "TRACE_CRIT", .value = LTTNG_LOGLEVEL_CRIT }, { .name = "ERR", .value = LTTNG_LOGLEVEL_ERR }, - { .name = "TRACE_WARNING", .value = LTTNG_LOGLEVEL_WARNING }, + { .name = "TRACE_ERR", .value = LTTNG_LOGLEVEL_ERR }, { .name = "WARNING", .value = LTTNG_LOGLEVEL_WARNING }, - { .name = "TRACE_NOTICE", .value = LTTNG_LOGLEVEL_NOTICE }, + { .name = "TRACE_WARNING", .value = LTTNG_LOGLEVEL_WARNING }, { .name = "NOTICE", .value = LTTNG_LOGLEVEL_NOTICE }, - { .name = "TRACE_INFO", .value = LTTNG_LOGLEVEL_INFO }, + { .name = "TRACE_NOTICE", .value = LTTNG_LOGLEVEL_NOTICE }, { .name = "INFO", .value = LTTNG_LOGLEVEL_INFO }, - { .name = "TRACE_DEBUG_SYSTEM", .value = LTTNG_LOGLEVEL_DEBUG_SYSTEM }, + { .name = "TRACE_INFO", .value = LTTNG_LOGLEVEL_INFO }, { .name = "DEBUG_SYSTEM", .value = LTTNG_LOGLEVEL_DEBUG_SYSTEM }, + { .name = "TRACE_DEBUG_SYSTEM", .value = LTTNG_LOGLEVEL_DEBUG_SYSTEM }, { .name = "SYSTEM", .value = LTTNG_LOGLEVEL_DEBUG_SYSTEM }, - { .name = "TRACE_DEBUG_PROGRAM", .value = LTTNG_LOGLEVEL_DEBUG_PROGRAM }, { .name = "DEBUG_PROGRAM", .value = LTTNG_LOGLEVEL_DEBUG_PROGRAM }, + { .name = "TRACE_DEBUG_PROGRAM", .value = LTTNG_LOGLEVEL_DEBUG_PROGRAM }, { .name = "PROGRAM", .value = LTTNG_LOGLEVEL_DEBUG_PROGRAM }, - { .name = "TRACE_DEBUG_PROCESS", .value = LTTNG_LOGLEVEL_DEBUG_PROCESS }, { .name = "DEBUG_PROCESS", .value = LTTNG_LOGLEVEL_DEBUG_PROCESS }, + { .name = "TRACE_DEBUG_PROCESS", .value = LTTNG_LOGLEVEL_DEBUG_PROCESS }, { .name = "PROCESS", .value = LTTNG_LOGLEVEL_DEBUG_PROCESS }, - { .name = "TRACE_DEBUG_MODULE", .value = LTTNG_LOGLEVEL_DEBUG_MODULE }, { .name = "DEBUG_MODULE", .value = LTTNG_LOGLEVEL_DEBUG_MODULE }, + { .name = "TRACE_DEBUG_MODULE", .value = LTTNG_LOGLEVEL_DEBUG_MODULE }, { .name = "MODULE", .value = LTTNG_LOGLEVEL_DEBUG_MODULE }, - { .name = "TRACE_DEBUG_UNIT", .value = LTTNG_LOGLEVEL_DEBUG_UNIT }, { .name = "DEBUG_UNIT", .value = LTTNG_LOGLEVEL_DEBUG_UNIT }, + { .name = "TRACE_DEBUG_UNIT", .value = LTTNG_LOGLEVEL_DEBUG_UNIT }, { .name = "UNIT", .value = LTTNG_LOGLEVEL_DEBUG_UNIT }, - { .name = "TRACE_DEBUG_FUNCTION", .value = LTTNG_LOGLEVEL_DEBUG_FUNCTION }, { .name = "DEBUG_FUNCTION", .value = LTTNG_LOGLEVEL_DEBUG_FUNCTION }, + { .name = "TRACE_DEBUG_FUNCTION", .value = LTTNG_LOGLEVEL_DEBUG_FUNCTION }, { .name = "FUNCTION", .value = LTTNG_LOGLEVEL_DEBUG_FUNCTION }, - { .name = "TRACE_DEBUG_LINE", .value = LTTNG_LOGLEVEL_DEBUG_LINE }, { .name = "DEBUG_LINE", .value = LTTNG_LOGLEVEL_DEBUG_LINE }, + { .name = "TRACE_DEBUG_LINE", .value = LTTNG_LOGLEVEL_DEBUG_LINE }, { .name = "LINE", .value = LTTNG_LOGLEVEL_DEBUG_LINE }, - { .name = "TRACE_DEBUG", .value = LTTNG_LOGLEVEL_DEBUG }, { .name = "DEBUG", .value = LTTNG_LOGLEVEL_DEBUG }, + { .name = "TRACE_DEBUG", .value = LTTNG_LOGLEVEL_DEBUG }, }; static const struct loglevel_name_value loglevel_log4j_values[] = { - { .name = "LOG4J_OFF", .value = LTTNG_LOGLEVEL_LOG4J_OFF }, { .name = "OFF", .value = LTTNG_LOGLEVEL_LOG4J_OFF }, - { .name = "LOG4J_FATAL", .value = LTTNG_LOGLEVEL_LOG4J_FATAL }, + { .name = "LOG4J_OFF", .value = LTTNG_LOGLEVEL_LOG4J_OFF }, { .name = "FATAL", .value = LTTNG_LOGLEVEL_LOG4J_FATAL }, - { .name = "LOG4J_ERROR", .value = LTTNG_LOGLEVEL_LOG4J_ERROR }, + { .name = "LOG4J_FATAL", .value = LTTNG_LOGLEVEL_LOG4J_FATAL }, { .name = "ERROR", .value = LTTNG_LOGLEVEL_LOG4J_ERROR }, - { .name = "LOG4J_WARN", .value = LTTNG_LOGLEVEL_LOG4J_WARN }, + { .name = "LOG4J_ERROR", .value = LTTNG_LOGLEVEL_LOG4J_ERROR }, { .name = "WARN", .value = LTTNG_LOGLEVEL_LOG4J_WARN }, - { .name = "LOG4J_INFO", .value = LTTNG_LOGLEVEL_LOG4J_INFO }, + { .name = "LOG4J_WARN", .value = LTTNG_LOGLEVEL_LOG4J_WARN }, { .name = "INFO", .value = LTTNG_LOGLEVEL_LOG4J_INFO }, - { .name = "LOG4J_DEBUG", .value = LTTNG_LOGLEVEL_LOG4J_DEBUG }, + { .name = "LOG4J_INFO", .value = LTTNG_LOGLEVEL_LOG4J_INFO }, { .name = "DEBUG", .value = LTTNG_LOGLEVEL_LOG4J_DEBUG }, - { .name = "LOG4J_TRACE", .value = LTTNG_LOGLEVEL_LOG4J_TRACE }, + { .name = "LOG4J_DEBUG", .value = LTTNG_LOGLEVEL_LOG4J_DEBUG }, { .name = "TRACE", .value = LTTNG_LOGLEVEL_LOG4J_TRACE }, - { .name = "LOG4J_ALL", .value = LTTNG_LOGLEVEL_LOG4J_ALL }, + { .name = "LOG4J_TRACE", .value = LTTNG_LOGLEVEL_LOG4J_TRACE }, { .name = "ALL", .value = LTTNG_LOGLEVEL_LOG4J_ALL }, + { .name = "LOG4J_ALL", .value = LTTNG_LOGLEVEL_LOG4J_ALL }, }; static const struct loglevel_name_value loglevel_jul_values[] = { - { .name = "JUL_OFF", .value = LTTNG_LOGLEVEL_JUL_OFF }, { .name = "OFF", .value = LTTNG_LOGLEVEL_JUL_OFF }, - { .name = "JUL_SEVERE", .value = LTTNG_LOGLEVEL_JUL_SEVERE }, + { .name = "JUL_OFF", .value = LTTNG_LOGLEVEL_JUL_OFF }, { .name = "SEVERE", .value = LTTNG_LOGLEVEL_JUL_SEVERE }, - { .name = "JUL_WARNING", .value = LTTNG_LOGLEVEL_JUL_WARNING }, + { .name = "JUL_SEVERE", .value = LTTNG_LOGLEVEL_JUL_SEVERE }, { .name = "WARNING", .value = LTTNG_LOGLEVEL_JUL_WARNING }, - { .name = "JUL_INFO", .value = LTTNG_LOGLEVEL_JUL_INFO }, + { .name = "JUL_WARNING", .value = LTTNG_LOGLEVEL_JUL_WARNING }, { .name = "INFO", .value = LTTNG_LOGLEVEL_JUL_INFO }, - { .name = "JUL_CONFIG", .value = LTTNG_LOGLEVEL_JUL_CONFIG }, + { .name = "JUL_INFO", .value = LTTNG_LOGLEVEL_JUL_INFO }, { .name = "CONFIG", .value = LTTNG_LOGLEVEL_JUL_CONFIG }, - { .name = "JUL_FINE", .value = LTTNG_LOGLEVEL_JUL_FINE }, + { .name = "JUL_CONFIG", .value = LTTNG_LOGLEVEL_JUL_CONFIG }, { .name = "FINE", .value = LTTNG_LOGLEVEL_JUL_FINE }, - { .name = "JUL_FINER", .value = LTTNG_LOGLEVEL_JUL_FINER }, + { .name = "JUL_FINE", .value = LTTNG_LOGLEVEL_JUL_FINE }, { .name = "FINER", .value = LTTNG_LOGLEVEL_JUL_FINER }, - { .name = "JUL_FINEST", .value = LTTNG_LOGLEVEL_JUL_FINEST }, + { .name = "JUL_FINER", .value = LTTNG_LOGLEVEL_JUL_FINER }, { .name = "FINEST", .value = LTTNG_LOGLEVEL_JUL_FINEST }, - { .name = "JUL_ALL", .value = LTTNG_LOGLEVEL_JUL_ALL }, + { .name = "JUL_FINEST", .value = LTTNG_LOGLEVEL_JUL_FINEST }, { .name = "ALL", .value = LTTNG_LOGLEVEL_JUL_ALL }, + { .name = "JUL_ALL", .value = LTTNG_LOGLEVEL_JUL_ALL }, }; static const struct loglevel_name_value loglevel_python_values[] = { - { .name = "PYTHON_CRITICAL", .value = LTTNG_LOGLEVEL_PYTHON_CRITICAL }, { .name = "CRITICAL", .value = LTTNG_LOGLEVEL_PYTHON_CRITICAL }, - { .name = "PYTHON_ERROR", .value = LTTNG_LOGLEVEL_PYTHON_ERROR }, + { .name = "PYTHON_CRITICAL", .value = LTTNG_LOGLEVEL_PYTHON_CRITICAL }, { .name = "ERROR", .value = LTTNG_LOGLEVEL_PYTHON_ERROR }, - { .name = "PYTHON_WARNING", .value = LTTNG_LOGLEVEL_PYTHON_WARNING }, + { .name = "PYTHON_ERROR", .value = LTTNG_LOGLEVEL_PYTHON_ERROR }, { .name = "WARNING", .value = LTTNG_LOGLEVEL_PYTHON_WARNING }, - { .name = "PYTHON_INFO", .value = LTTNG_LOGLEVEL_PYTHON_INFO }, + { .name = "PYTHON_WARNING", .value = LTTNG_LOGLEVEL_PYTHON_WARNING }, { .name = "INFO", .value = LTTNG_LOGLEVEL_PYTHON_INFO }, - { .name = "PYTNON_DEBUG", .value = LTTNG_LOGLEVEL_PYTHON_DEBUG }, + { .name = "PYTHON_INFO", .value = LTTNG_LOGLEVEL_PYTHON_INFO }, { .name = "DEBUG", .value = LTTNG_LOGLEVEL_PYTHON_DEBUG }, - { .name = "PYTHON_NOTSET", .value = LTTNG_LOGLEVEL_PYTHON_NOTSET }, + { .name = "PYTNON_DEBUG", .value = LTTNG_LOGLEVEL_PYTHON_DEBUG }, { .name = "NOTSET", .value = LTTNG_LOGLEVEL_PYTHON_NOTSET }, + { .name = "PYTHON_NOTSET", .value = LTTNG_LOGLEVEL_PYTHON_NOTSET }, }; static @@ -205,3 +205,50 @@ int loglevel_python_name_to_value( return ret; } + +static +const char *lookup_name_from_value(const struct loglevel_name_value values[], + size_t values_count, int loglevel) +{ + size_t i; + const char *name = NULL; + + for (i = 0; i < values_count; i++) { + if (values[i].value == loglevel) { + /* Match found. */ + name = values[i].name; + goto end; + } + } + +end: + return name; +} + +LTTNG_HIDDEN +const char *loglevel_value_to_name(int loglevel) +{ + return lookup_name_from_value( + loglevel_values, ARRAY_SIZE(loglevel_values), loglevel); +} + +LTTNG_HIDDEN +const char *loglevel_log4j_value_to_name(int loglevel) +{ + return lookup_name_from_value(loglevel_log4j_values, + ARRAY_SIZE(loglevel_log4j_values), loglevel); +} + +LTTNG_HIDDEN +const char *loglevel_jul_value_to_name(int loglevel) +{ + return lookup_name_from_value(loglevel_jul_values, + ARRAY_SIZE(loglevel_jul_values), loglevel); +} + +LTTNG_HIDDEN +const char *loglevel_python_value_to_name(int loglevel) +{ + return lookup_name_from_value(loglevel_python_values, + ARRAY_SIZE(loglevel_python_values), loglevel); +} diff --git a/src/bin/lttng/loglevel.h b/src/bin/lttng/loglevel.h index 100d33267..78989504e 100644 --- a/src/bin/lttng/loglevel.h +++ b/src/bin/lttng/loglevel.h @@ -26,4 +26,16 @@ LTTNG_HIDDEN int loglevel_python_name_to_value( const char *name, enum lttng_loglevel_python *loglevel); +LTTNG_HIDDEN +const char *loglevel_value_to_name(int loglevel); + +LTTNG_HIDDEN +const char *loglevel_log4j_value_to_name(int loglevel); + +LTTNG_HIDDEN +const char *loglevel_jul_value_to_name(int loglevel); + +LTTNG_HIDDEN +const char *loglevel_python_value_to_name(int loglevel); + #endif /* _LTTNG_LOGLEVEL_UTILS_H */ diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 9aca16b2e..caf588e40 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -72,6 +72,7 @@ libcommon_la_SOURCES = \ futex.c futex.h \ kernel-probe.c \ location.c \ + log-level-rule.c \ mi-lttng.c mi-lttng.h \ notification.c \ optional.h \ diff --git a/src/common/event-rule/tracepoint.c b/src/common/event-rule/tracepoint.c index 93de1e98c..fbe1fc4bc 100644 --- a/src/common/event-rule/tracepoint.c +++ b/src/common/event-rule/tracepoint.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +17,7 @@ #include #include #include +#include #include #define IS_TRACEPOINT_EVENT_RULE(rule) \ @@ -75,18 +77,22 @@ static int lttng_event_rule_tracepoint_serialize( struct lttng_payload *payload) { int ret, i; - size_t pattern_len, filter_expression_len, exclusions_len; + size_t pattern_len, filter_expression_len, exclusions_len, header_offset; + size_t size_before_log_level_rule; struct lttng_event_rule_tracepoint *tracepoint; struct lttng_event_rule_tracepoint_comm tracepoint_comm; enum lttng_event_rule_status status; unsigned int exclusion_count; size_t exclusions_appended_len = 0; + struct lttng_event_rule_tracepoint_comm *header; if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule)) { ret = -1; goto end; } + header_offset = payload->buffer.size; + DBG("Serializing tracepoint event rule."); tracepoint = container_of( rule, struct lttng_event_rule_tracepoint, parent); @@ -118,8 +124,6 @@ static int lttng_event_rule_tracepoint_serialize( } tracepoint_comm.domain_type = (int8_t) tracepoint->domain; - tracepoint_comm.loglevel_type = (int8_t) tracepoint->loglevel.type; - tracepoint_comm.loglevel_value = tracepoint->loglevel.value; tracepoint_comm.pattern_len = pattern_len; tracepoint_comm.filter_expression_len = filter_expression_len; tracepoint_comm.exclusions_count = exclusion_count; @@ -143,6 +147,17 @@ static int lttng_event_rule_tracepoint_serialize( goto end; } + size_before_log_level_rule = payload->buffer.size; + + ret = lttng_log_level_rule_serialize(tracepoint->log_level_rule, payload); + if (ret < 0) { + goto end; + } + + header = (typeof(header)) ((char *) payload->buffer.data + header_offset); + header->log_level_rule_len = + payload->buffer.size - size_before_log_level_rule; + for (i = 0; i < exclusion_count; i++) { size_t len; const char *exclusion; @@ -224,11 +239,8 @@ static bool lttng_event_rule_tracepoint_is_equal( goto end; } - if (a->loglevel.type != b->loglevel.type) { - goto end; - } - - if (a->loglevel.value != b->loglevel.value) { + if (!lttng_log_level_rule_is_equal( + a->log_level_rule, b->log_level_rule)) { goto end; } @@ -266,7 +278,7 @@ static int generate_agent_filter( char *agent_filter = NULL; const char *pattern; const char *filter; - enum lttng_loglevel_type loglevel_type; + const struct lttng_log_level_rule *log_level_rule = NULL; enum lttng_event_rule_status status; assert(rule); @@ -286,12 +298,6 @@ static int generate_agent_filter( goto end; } - status = lttng_event_rule_tracepoint_get_log_level_type( - rule, &loglevel_type); - if (status != LTTNG_EVENT_RULE_STATUS_OK) { - ret = -1; - goto end; - } /* Don't add filter for the '*' event. */ if (strcmp(pattern, "*") != 0) { @@ -311,21 +317,32 @@ static int generate_agent_filter( } } - if (loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) { + status = lttng_event_rule_tracepoint_get_log_level_rule( + rule, &log_level_rule); + if (status == LTTNG_EVENT_RULE_STATUS_OK) { + enum lttng_log_level_rule_status llr_status; const char *op; - int loglevel_value; + int level; - status = lttng_event_rule_tracepoint_get_log_level( - rule, &loglevel_value); - if (status != LTTNG_EVENT_RULE_STATUS_OK) { - ret = -1; - goto end; + switch (lttng_log_level_rule_get_type(log_level_rule)) + { + case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY: + llr_status = lttng_log_level_rule_exactly_get_level( + log_level_rule, &level); + op = "=="; + break; + case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS: + llr_status = lttng_log_level_rule_at_least_as_severe_as_get_level( + log_level_rule, &level); + op = ">="; + break; + default: + abort(); } - if (loglevel_type == LTTNG_EVENT_LOGLEVEL_RANGE) { - op = ">="; - } else { - op = "=="; + if (llr_status != LTTNG_LOG_LEVEL_RULE_STATUS_OK) { + ret = -1; + goto end; } if (filter || agent_filter) { @@ -334,14 +351,14 @@ static int generate_agent_filter( err = asprintf(&new_filter, "(%s) && (int_loglevel %s %d)", agent_filter ? agent_filter : filter, - op, loglevel_value); + op, level); if (agent_filter) { free(agent_filter); } agent_filter = new_filter; } else { err = asprintf(&agent_filter, "int_loglevel %s %d", op, - loglevel_value); + level); } if (err < 0) { @@ -576,12 +593,8 @@ static unsigned long lttng_event_rule_tracepoint_hash( hash ^= hash_key_str(tp_rule->filter_expression, lttng_ht_seed); } - hash ^= hash_key_ulong((void *) tp_rule->loglevel.type, - lttng_ht_seed); - if (tp_rule->loglevel.type != LTTNG_EVENT_LOGLEVEL_ALL) { - hash ^= hash_key_ulong( - (void *) (unsigned long) tp_rule->loglevel.value, - lttng_ht_seed); + if (tp_rule->log_level_rule) { + hash ^= lttng_log_level_rule_hash(tp_rule->log_level_rule); } status = lttng_event_rule_tracepoint_get_exclusions_count(rule, @@ -607,6 +620,10 @@ static struct lttng_event *lttng_event_rule_tracepoint_generate_lttng_event( const struct lttng_event_rule_tracepoint *tracepoint; struct lttng_event *local_event = NULL; struct lttng_event *event = NULL; + enum lttng_loglevel_type loglevel_type; + int loglevel_value = 0; + enum lttng_event_rule_status status; + const struct lttng_log_level_rule *log_level_rule; tracepoint = container_of( rule, const struct lttng_event_rule_tracepoint, parent); @@ -625,8 +642,41 @@ static struct lttng_event *lttng_event_rule_tracepoint_generate_lttng_event( goto error; } - local_event->loglevel_type = tracepoint->loglevel.type; - local_event->loglevel = tracepoint->loglevel.value; + + /* Map the log level rule to an equivalent lttng_loglevel. */ + status = lttng_event_rule_tracepoint_get_log_level_rule( + rule, &log_level_rule); + if (status == LTTNG_EVENT_RULE_STATUS_UNSET) { + loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL; + loglevel_value = 0; + } else if (status == LTTNG_EVENT_RULE_STATUS_OK) { + enum lttng_log_level_rule_status llr_status; + + switch (lttng_log_level_rule_get_type(log_level_rule)) { + case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY: + llr_status = lttng_log_level_rule_exactly_get_level( + log_level_rule, &loglevel_value); + loglevel_type = LTTNG_EVENT_LOGLEVEL_SINGLE; + break; + case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS: + llr_status = lttng_log_level_rule_at_least_as_severe_as_get_level( + log_level_rule, &loglevel_value); + loglevel_type = LTTNG_EVENT_LOGLEVEL_RANGE; + break; + default: + abort(); + break; + } + + if (llr_status != LTTNG_LOG_LEVEL_RULE_STATUS_OK) { + goto error; + } + } else { + goto error; + } + + local_event->loglevel_type = loglevel_type; + local_event->loglevel = loglevel_value; event = local_event; local_event = NULL; @@ -670,7 +720,7 @@ struct lttng_event_rule *lttng_event_rule_tracepoint_create( lttng_event_rule_tracepoint_generate_lttng_event; tp_rule->domain = domain_type; - tp_rule->loglevel.type = LTTNG_EVENT_LOGLEVEL_ALL; + tp_rule->log_level_rule = NULL; lttng_dynamic_pointer_array_init(&tp_rule->exclusions, destroy_lttng_exclusions_element); @@ -695,7 +745,6 @@ ssize_t lttng_event_rule_tracepoint_create_from_payload( int i; enum lttng_event_rule_status status; enum lttng_domain_type domain_type; - enum lttng_loglevel_type loglevel_type; const struct lttng_event_rule_tracepoint_comm *tracepoint_comm; const char *pattern; const char *filter_expression = NULL; @@ -704,6 +753,7 @@ ssize_t lttng_event_rule_tracepoint_create_from_payload( const char *exclusion; struct lttng_buffer_view current_buffer_view; struct lttng_event_rule *rule = NULL; + struct lttng_log_level_rule *log_level_rule = NULL; if (!_event_rule) { ret = -1; @@ -737,32 +787,6 @@ ssize_t lttng_event_rule_tracepoint_create_from_payload( goto end; } - loglevel_type = (enum lttng_loglevel_type) - tracepoint_comm->loglevel_type; - switch (loglevel_type) { - case LTTNG_EVENT_LOGLEVEL_ALL: - status = lttng_event_rule_tracepoint_set_log_level_all(rule); - break; - case LTTNG_EVENT_LOGLEVEL_RANGE: - status = lttng_event_rule_tracepoint_set_log_level_range_lower_bound(rule, - (enum lttng_loglevel_type) tracepoint_comm - ->loglevel_value); - break; - case LTTNG_EVENT_LOGLEVEL_SINGLE: - status = lttng_event_rule_tracepoint_set_log_level(rule, - (enum lttng_loglevel_type) tracepoint_comm - ->loglevel_value); - break; - default: - ERR("Failed to set event rule tracepoint loglevel: unknown loglevel type."); - ret = -1; - goto end; - } - - if (status != LTTNG_EVENT_RULE_STATUS_OK) { - ERR("Failed to set event rule tracepoint loglevel."); - } - /* Skip to payload. */ offset += current_buffer_view.size; @@ -809,6 +833,30 @@ ssize_t lttng_event_rule_tracepoint_create_from_payload( offset += tracepoint_comm->filter_expression_len; skip_filter_expression: + if (!tracepoint_comm->log_level_rule_len) { + goto skip_log_level_rule; + } + + { + /* Map the log level rule. */ + struct lttng_payload_view current_payload_view = + lttng_payload_view_from_view(view, offset, + tracepoint_comm->log_level_rule_len); + + ret = lttng_log_level_rule_create_from_payload( + ¤t_payload_view, &log_level_rule); + if (ret < 0) { + ret = -1; + goto end; + } + + assert(ret == tracepoint_comm->log_level_rule_len); + } + + /* Skip after the log level rule. */ + offset += tracepoint_comm->log_level_rule_len; + +skip_log_level_rule: for (i = 0; i < tracepoint_comm->exclusions_count; i++) { current_buffer_view = lttng_buffer_view_from_view( &view->buffer, offset, sizeof(*exclusion_len)); @@ -863,11 +911,22 @@ skip_filter_expression: } } + if (log_level_rule) { + status = lttng_event_rule_tracepoint_set_log_level_rule( + rule, log_level_rule); + if (status != LTTNG_EVENT_RULE_STATUS_OK) { + ERR("Failed to set event rule tracepoint log level rule."); + ret = -1; + goto end; + } + } + *_event_rule = rule; rule = NULL; ret = offset; end: free(exclusions); + lttng_log_level_rule_destroy(log_level_rule); lttng_event_rule_destroy(rule); return ret; } @@ -998,13 +1057,31 @@ end: return status; } -static bool log_level_value_valid( - int level, enum lttng_domain_type domain) +static bool log_level_rule_valid(const struct lttng_log_level_rule *rule, + enum lttng_domain_type domain) { bool valid = false; + enum lttng_log_level_rule_status status; + int level; + + switch (lttng_log_level_rule_get_type(rule)) { + case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY: + status = lttng_log_level_rule_exactly_get_level(rule, &level); + break; + case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS: + status = lttng_log_level_rule_at_least_as_severe_as_get_level( + rule, &level); + break; + default: + abort(); + } + + assert(status == LTTNG_LOG_LEVEL_RULE_STATUS_OK); switch (domain) { case LTTNG_DOMAIN_KERNEL: + valid = false; + break; case LTTNG_DOMAIN_UST: if (level < LTTNG_LOGLEVEL_EMERG) { /* Invalid. */ @@ -1022,15 +1099,15 @@ static bool log_level_value_valid( case LTTNG_DOMAIN_PYTHON: /* * For both JUL and LOG4J custom log level are possible and can - * spawn the entire int32 range. + * span the entire int32 range. + * * For python, custom log level are possible, it is not clear if * negative value are accepted (NOTSET == 0) but the source code - * validate against the int type implying that negative values + * validates against the int type implying that negative values * are accepted. */ valid = true; goto end; - case LTTNG_DOMAIN_NONE: default: abort(); @@ -1040,11 +1117,13 @@ end: return valid; } -enum lttng_event_rule_status lttng_event_rule_tracepoint_set_log_level( - struct lttng_event_rule *rule, int level) +enum lttng_event_rule_status lttng_event_rule_tracepoint_set_log_level_rule( + struct lttng_event_rule *rule, + const struct lttng_log_level_rule *log_level_rule) { struct lttng_event_rule_tracepoint *tracepoint; enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; + struct lttng_log_level_rule *copy = NULL; if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule)) { status = LTTNG_EVENT_RULE_STATUS_INVALID; @@ -1054,99 +1133,48 @@ enum lttng_event_rule_status lttng_event_rule_tracepoint_set_log_level( tracepoint = container_of( rule, struct lttng_event_rule_tracepoint, parent); - if (!log_level_value_valid(level, tracepoint->domain)) { + if (!log_level_rule_valid(log_level_rule, tracepoint->domain)) { status = LTTNG_EVENT_RULE_STATUS_INVALID; goto end; } - tracepoint->loglevel.value = level; - tracepoint->loglevel.type = LTTNG_EVENT_LOGLEVEL_SINGLE; -end: - return status; -} - -enum lttng_event_rule_status -lttng_event_rule_tracepoint_set_log_level_range_lower_bound( - struct lttng_event_rule *rule, int level) -{ - struct lttng_event_rule_tracepoint *tracepoint; - enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; - - if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule)) { - status = LTTNG_EVENT_RULE_STATUS_INVALID; + copy = lttng_log_level_rule_copy(log_level_rule); + if (copy == NULL) { + status = LTTNG_EVENT_RULE_STATUS_ERROR; goto end; } - tracepoint = container_of( - rule, struct lttng_event_rule_tracepoint, parent); - - if (!log_level_value_valid(level, tracepoint->domain)) { - status = LTTNG_EVENT_RULE_STATUS_INVALID; - goto end; + if (tracepoint->log_level_rule) { + lttng_log_level_rule_destroy(tracepoint->log_level_rule); } - tracepoint->loglevel.value = level; - tracepoint->loglevel.type = LTTNG_EVENT_LOGLEVEL_RANGE; -end: - return status; -} - -enum lttng_event_rule_status lttng_event_rule_tracepoint_set_log_level_all( - struct lttng_event_rule *rule) -{ - struct lttng_event_rule_tracepoint *tracepoint; - enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; + tracepoint->log_level_rule = copy; - if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule)) { - status = LTTNG_EVENT_RULE_STATUS_INVALID; - goto end; - } - - tracepoint = container_of( - rule, struct lttng_event_rule_tracepoint, parent); - tracepoint->loglevel.type = LTTNG_EVENT_LOGLEVEL_ALL; end: return status; } -enum lttng_event_rule_status lttng_event_rule_tracepoint_get_log_level_type( +enum lttng_event_rule_status lttng_event_rule_tracepoint_get_log_level_rule( const struct lttng_event_rule *rule, - enum lttng_loglevel_type *type) -{ - struct lttng_event_rule_tracepoint *tracepoint; - enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; - - if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !type) { - status = LTTNG_EVENT_RULE_STATUS_INVALID; - goto end; - } - - tracepoint = container_of( - rule, struct lttng_event_rule_tracepoint, parent); - *type = tracepoint->loglevel.type; -end: - return status; -} - -enum lttng_event_rule_status lttng_event_rule_tracepoint_get_log_level( - const struct lttng_event_rule *rule, int *level) + const struct lttng_log_level_rule **log_level_rule + ) { struct lttng_event_rule_tracepoint *tracepoint; enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; - if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !level) { + if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !log_level_rule) { status = LTTNG_EVENT_RULE_STATUS_INVALID; goto end; } tracepoint = container_of( rule, struct lttng_event_rule_tracepoint, parent); - if (tracepoint->loglevel.type == LTTNG_EVENT_LOGLEVEL_ALL) { + if (tracepoint->log_level_rule == NULL) { status = LTTNG_EVENT_RULE_STATUS_UNSET; goto end; } - *level = tracepoint->loglevel.value; + *log_level_rule = tracepoint->log_level_rule; end: return status; } diff --git a/src/common/log-level-rule.c b/src/common/log-level-rule.c new file mode 100644 index 000000000..ca8e439e7 --- /dev/null +++ b/src/common/log-level-rule.c @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2020 Jonathan Rajotte + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool is_log_level_rule_exactly_type(const struct lttng_log_level_rule *rule) +{ + enum lttng_log_level_rule_type type = + lttng_log_level_rule_get_type(rule); + + return type == LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY; +} + +static bool is_log_level_rule_at_least_as_severe_type(const struct lttng_log_level_rule *rule) +{ + + enum lttng_log_level_rule_type type = + lttng_log_level_rule_get_type(rule); + + return type == LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS; +} + +enum lttng_log_level_rule_type lttng_log_level_rule_get_type( + const struct lttng_log_level_rule *rule) +{ + return rule ? rule->type : LTTNG_LOG_LEVEL_RULE_TYPE_UNKNOWN; +} + +struct lttng_log_level_rule *lttng_log_level_rule_exactly_create( + int level) +{ + struct lttng_log_level_rule *rule = NULL; + + rule = zmalloc(sizeof(struct lttng_log_level_rule)); + if (!rule) { + goto end; + } + + rule->type = LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY; + rule->level = level; + +end: + return rule; +} + +enum lttng_log_level_rule_status lttng_log_level_rule_exactly_get_level( + const struct lttng_log_level_rule *rule, int *level) +{ + enum lttng_log_level_rule_status status = + LTTNG_LOG_LEVEL_RULE_STATUS_OK; + + if (!rule || !level || !is_log_level_rule_exactly_type(rule)) { + status = LTTNG_LOG_LEVEL_RULE_STATUS_INVALID; + goto end; + } + + *level = rule->level; +end: + return status; +} + +struct lttng_log_level_rule * +lttng_log_level_rule_at_least_as_severe_as_create(int level) +{ + struct lttng_log_level_rule *rule = NULL; + + rule = zmalloc(sizeof(struct lttng_log_level_rule)); + if (!rule) { + goto end; + } + + rule->type = LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS; + rule->level = level; + +end: + return rule; +} + +enum lttng_log_level_rule_status +lttng_log_level_rule_at_least_as_severe_as_get_level( + const struct lttng_log_level_rule *rule, int *level) +{ + enum lttng_log_level_rule_status status = LTTNG_LOG_LEVEL_RULE_STATUS_OK; + + if (!rule || !level || + !is_log_level_rule_at_least_as_severe_type(rule)) { + status = LTTNG_LOG_LEVEL_RULE_STATUS_INVALID; + goto end; + } + + *level = rule->level; +end: + return status; +} + +void lttng_log_level_rule_destroy(struct lttng_log_level_rule *log_level_rule) +{ + free(log_level_rule); +} + +LTTNG_HIDDEN +ssize_t lttng_log_level_rule_create_from_payload( + struct lttng_payload_view *view, + struct lttng_log_level_rule **_rule) +{ + ssize_t ret; + size_t offset = 0; + struct lttng_log_level_rule *rule = NULL; + const struct lttng_log_level_rule_comm *comm = + (const struct lttng_log_level_rule_comm *) + view->buffer.data; + + offset += sizeof(*comm); + + if (!_rule) { + ret = -1; + goto end; + } + + if (view->buffer.size < sizeof(*comm)) { + ret = -1; + goto end; + } + + switch (comm->type) { + case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY: + rule = lttng_log_level_rule_exactly_create((int) comm->level); + break; + case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS: + rule = lttng_log_level_rule_at_least_as_severe_as_create( + (int) comm->level); + break; + default: + abort(); + } + + if (!rule) { + ret = -1; + goto end; + } + + *_rule = rule; + ret = offset; + +end: + return ret; +} + +LTTNG_HIDDEN +int lttng_log_level_rule_serialize(const struct lttng_log_level_rule *rule, + struct lttng_payload *payload) +{ + int ret; + struct lttng_log_level_rule_comm comm; + + + if (!rule) { + ret = 0; + goto end; + } + + comm.type = (int8_t) rule->type; + comm.level = (int32_t) rule->level; + + DBG("Serializing log level rule of type %d", rule->type); + ret = lttng_dynamic_buffer_append(&payload->buffer, &comm, + sizeof(comm)); + if (ret) { + goto end; + } + +end: + return ret; +} + +LTTNG_HIDDEN +bool lttng_log_level_rule_is_equal(const struct lttng_log_level_rule *a, + const struct lttng_log_level_rule *b) +{ + bool is_equal = false; + + if (a == NULL && b == NULL) { + /* Both are null. */ + is_equal = true; + goto end; + } + + if (a == NULL || b == NULL) { + /* One is NULL.*/ + goto end; + } + + if (a == b) { + /* Same object.*/ + is_equal = true; + goto end; + } + + if (a->type != b->type) { + goto end; + } + + if (a->level != b->level) { + goto end; + } + + is_equal = true; + +end: + return is_equal; +} + +LTTNG_HIDDEN +struct lttng_log_level_rule *lttng_log_level_rule_copy( + const struct lttng_log_level_rule *source) +{ + struct lttng_log_level_rule *copy = NULL; + + assert(source); + + copy = zmalloc(sizeof(struct lttng_log_level_rule)); + if (!copy) { + goto end; + } + + copy->type = source->type; + copy->level = source->level; +end: + return copy; +} + +LTTNG_HIDDEN +void lttng_log_level_rule_to_loglevel( + const struct lttng_log_level_rule *log_level_rule, + enum lttng_loglevel_type *loglevel_type, + int *loglevel_value) +{ + assert(log_level_rule); + + switch (log_level_rule->type) { + case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY: + *loglevel_type = LTTNG_EVENT_LOGLEVEL_SINGLE; + break; + case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS: + *loglevel_type = LTTNG_EVENT_LOGLEVEL_RANGE; + break; + default: + abort(); + } + + *loglevel_value = log_level_rule->level; +} + +LTTNG_HIDDEN +unsigned long lttng_log_level_rule_hash( + const struct lttng_log_level_rule *log_level_rule) +{ + unsigned long hash; + enum lttng_log_level_rule_status llr_status; + int log_level_value; + enum lttng_log_level_rule_type type; + + assert(log_level_rule); + + type = lttng_log_level_rule_get_type(log_level_rule); + + switch (type) { + case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY: + llr_status = lttng_log_level_rule_exactly_get_level( + log_level_rule, &log_level_value); + break; + case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS: + llr_status = lttng_log_level_rule_at_least_as_severe_as_get_level( + log_level_rule, &log_level_value); + break; + default: + abort(); + break; + } + + assert(llr_status == LTTNG_LOG_LEVEL_RULE_STATUS_OK); + + hash = hash_key_ulong((void *) (unsigned long) type, lttng_ht_seed); + + hash ^= hash_key_ulong((void *) (unsigned long) log_level_value, + lttng_ht_seed); + + return hash; +} diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index 97b84b6cf..6d33beafb 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -17,6 +17,7 @@ TESTS = \ test_fd_tracker \ test_kernel_data \ test_kernel_probe \ + test_log_level_rule \ test_notification \ test_payload \ test_relayd_backward_compat_group_by_session \ @@ -51,6 +52,7 @@ noinst_PROGRAMS = \ test_fd_tracker \ test_kernel_data \ test_kernel_probe \ + test_log_level_rule \ test_notification \ test_payload \ test_relayd_backward_compat_group_by_session \ @@ -254,3 +256,7 @@ test_kernel_probe_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBLTTNG_CTL) $(DL_LIBS) # Event expression to bytecode test test_event_expr_to_bytecode_SOURCES = test_event_expr_to_bytecode.c test_event_expr_to_bytecode_LDADD = $(LIBTAP) $(LIBLTTNG_CTL) $(LIBCOMMON) + +# Log level rule api +test_log_level_rule_SOURCES = test_log_level_rule.c +test_log_level_rule_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBLTTNG_CTL) $(DL_LIBS) diff --git a/tests/unit/test_condition.c b/tests/unit/test_condition.c index c5a94bb65..864c6a840 100644 --- a/tests/unit/test_condition.c +++ b/tests/unit/test_condition.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -45,10 +46,17 @@ void test_condition_event_rule(void) const char *pattern="my_event_*"; const char *filter="msg_id == 23 && size >= 2048"; const char *exclusions[] = { "my_event_test1", "my_event_test2", "my_event_test3" }; + struct lttng_log_level_rule *log_level_rule_at_least_as_severe = NULL; struct lttng_payload buffer; lttng_payload_init(&buffer); + /* Create log level rule. */ + log_level_rule_at_least_as_severe = + lttng_log_level_rule_at_least_as_severe_as_create( + LTTNG_LOGLEVEL_WARNING); + assert(log_level_rule_at_least_as_severe); + tracepoint = lttng_event_rule_tracepoint_create(LTTNG_DOMAIN_UST); ok(tracepoint, "tracepoint UST_DOMAIN"); @@ -58,8 +66,8 @@ void test_condition_event_rule(void) status = lttng_event_rule_tracepoint_set_filter(tracepoint, filter); ok(status == LTTNG_EVENT_RULE_STATUS_OK, "Setting filter"); - status = lttng_event_rule_tracepoint_set_log_level_range_lower_bound( - tracepoint, LTTNG_LOGLEVEL_WARNING); + status = lttng_event_rule_tracepoint_set_log_level_rule( + tracepoint, log_level_rule_at_least_as_severe); ok(status == LTTNG_EVENT_RULE_STATUS_OK, "Setting log level range"); for (i = 0; i < 3; i++) { @@ -98,6 +106,7 @@ void test_condition_event_rule(void) lttng_event_rule_destroy(tracepoint); lttng_condition_destroy(condition); lttng_condition_destroy(condition_from_buffer); + lttng_log_level_rule_destroy(log_level_rule_at_least_as_severe); } int main(int argc, const char *argv[]) diff --git a/tests/unit/test_event_rule.c b/tests/unit/test_event_rule.c index 72c37709f..050b9d119 100644 --- a/tests/unit/test_event_rule.c +++ b/tests/unit/test_event_rule.c @@ -37,7 +37,7 @@ int lttng_opt_quiet = 1; int lttng_opt_verbose; int lttng_opt_mi; -#define NUM_TESTS 184 +#define NUM_TESTS 144 struct tracepoint_test { enum lttng_domain_type type; @@ -47,17 +47,17 @@ struct tracepoint_test { static void test_event_rule_tracepoint_by_domain(const struct tracepoint_test *test) { - int ret; unsigned int count; struct lttng_event_rule *tracepoint = NULL; struct lttng_event_rule *tracepoint_from_buffer = NULL; enum lttng_event_rule_status status; enum lttng_domain_type domain_type, type; - enum lttng_loglevel_type log_level_type; const char *pattern="my_event_*"; const char *filter="msg_id == 23 && size >= 2048"; const char *tmp; const char *exclusions[] = {"my_event_test1", "my_event_test2" ,"my_event_test3"}; + struct lttng_log_level_rule *log_level_rule = NULL; + const struct lttng_log_level_rule *log_level_rule_return = NULL; struct lttng_payload payload; type = test->type; @@ -65,6 +65,9 @@ void test_event_rule_tracepoint_by_domain(const struct tracepoint_test *test) lttng_payload_init(&payload); + log_level_rule = lttng_log_level_rule_exactly_create(LTTNG_LOGLEVEL_INFO); + assert(log_level_rule); + tracepoint = lttng_event_rule_tracepoint_create(type); ok(tracepoint, "tracepoint object."); @@ -84,28 +87,13 @@ void test_event_rule_tracepoint_by_domain(const struct tracepoint_test *test) ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting filter."); ok(!strncmp(filter, tmp, strlen(filter)), "filter is equal."); - status = lttng_event_rule_tracepoint_set_log_level_all(tracepoint); - ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting all log level."); - status = lttng_event_rule_tracepoint_get_log_level_type(tracepoint, &log_level_type); - ok(log_level_type == LTTNG_EVENT_LOGLEVEL_ALL, "getting loglevel type all."); - status = lttng_event_rule_tracepoint_get_log_level(tracepoint, &ret); - ok(status == LTTNG_EVENT_RULE_STATUS_UNSET, "get unset loglevel value."); - - status = lttng_event_rule_tracepoint_set_log_level(tracepoint, LTTNG_LOGLEVEL_INFO); - ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting single loglevel."); - status = lttng_event_rule_tracepoint_get_log_level_type(tracepoint, &log_level_type); - ok(log_level_type == LTTNG_EVENT_LOGLEVEL_SINGLE, "getting loglevel type single."); - status = lttng_event_rule_tracepoint_get_log_level(tracepoint, &ret); - ok(status == LTTNG_EVENT_RULE_STATUS_OK, "get loglevel value."); - ok(ret == LTTNG_LOGLEVEL_INFO, "loglevel value is equal."); - - status = lttng_event_rule_tracepoint_set_log_level_range_lower_bound(tracepoint, LTTNG_LOGLEVEL_WARNING); - ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting range loglevel."); - status = lttng_event_rule_tracepoint_get_log_level_type(tracepoint, &log_level_type); - ok(log_level_type == LTTNG_EVENT_LOGLEVEL_RANGE, "getting loglevel type range."); - status = lttng_event_rule_tracepoint_get_log_level(tracepoint, &ret); - ok(status == LTTNG_EVENT_RULE_STATUS_OK, "get loglevel value."); - ok(ret == LTTNG_LOGLEVEL_WARNING, "loglevel valuei is equal."); + status = lttng_event_rule_tracepoint_get_log_level_rule(tracepoint, &log_level_rule_return); + ok(status == LTTNG_EVENT_RULE_STATUS_UNSET, "get unset log level rule."); + + status = lttng_event_rule_tracepoint_set_log_level_rule(tracepoint, log_level_rule); + ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting log level rule."); + status = lttng_event_rule_tracepoint_get_log_level_rule(tracepoint, &log_level_rule_return); + ok(status == LTTNG_EVENT_RULE_STATUS_OK, "get log level rule."); if (test->support_exclusion) { int i; @@ -154,6 +142,7 @@ void test_event_rule_tracepoint_by_domain(const struct tracepoint_test *test) lttng_payload_reset(&payload); lttng_event_rule_destroy(tracepoint); lttng_event_rule_destroy(tracepoint_from_buffer); + lttng_log_level_rule_destroy(log_level_rule); } static diff --git a/tests/unit/test_log_level_rule.c b/tests/unit/test_log_level_rule.c new file mode 100644 index 000000000..fb2e2daea --- /dev/null +++ b/tests/unit/test_log_level_rule.c @@ -0,0 +1,187 @@ +/* + * Unit tests for the log level rule API. + * + * Copyright (C) 2020 Jonathan Rajotte + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +/* For error.h. */ +int lttng_opt_quiet = 1; +int lttng_opt_verbose; +int lttng_opt_mi; + +#define NUM_TESTS 29 + +static void test_log_level_rule_error(void) +{ + int level = 9000; + struct lttng_log_level_rule *exactly = + lttng_log_level_rule_exactly_create(level); + struct lttng_log_level_rule *at_least_as_severe = + lttng_log_level_rule_at_least_as_severe_as_create( + level); + + ok(lttng_log_level_rule_get_type(NULL) == LTTNG_LOG_LEVEL_RULE_TYPE_UNKNOWN, "Get type on invalid pointer"); + + ok(lttng_log_level_rule_exactly_get_level(NULL, NULL) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_exactly_get_level (NULL, NULL) returns invalid"); + ok(lttng_log_level_rule_exactly_get_level(exactly, NULL) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_exactly_get_level (valid, NULL) returns invalid"); + ok(lttng_log_level_rule_exactly_get_level(NULL, &level) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_exactly_get_level (NULL, valid) returns invalid"); + + ok(lttng_log_level_rule_at_least_as_severe_as_get_level(NULL, NULL) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_at_least_as_severe_as_get_level (NULL, NULL) returns invalid"); + ok(lttng_log_level_rule_at_least_as_severe_as_get_level(exactly, NULL) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_at_least_as_severe_as_get_level (valid, NULL) returns invalid"); + ok(lttng_log_level_rule_at_least_as_severe_as_get_level(NULL, &level) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_at_least_as_severe_as_get_level (NULL, valid) returns invalid"); + + lttng_log_level_rule_destroy(exactly); + lttng_log_level_rule_destroy(at_least_as_severe); +} + +static +void test_log_level_rule_serialize_deserialize(const struct lttng_log_level_rule *rule) +{ + struct lttng_log_level_rule *log_level_rule_from_buffer = NULL; + struct lttng_payload payload; + + lttng_payload_init(&payload); + + ok(lttng_log_level_rule_serialize(rule, &payload) == 0, "Serializing."); + + { + struct lttng_payload_view view = + lttng_payload_view_from_payload( + &payload, 0, -1); + + ok(lttng_log_level_rule_create_from_payload( + &view, &log_level_rule_from_buffer) > 0, + "Deserializing."); + } + + ok(lttng_log_level_rule_is_equal(rule, log_level_rule_from_buffer), "Serialized and from buffer are equal"); + + lttng_log_level_rule_destroy(log_level_rule_from_buffer); +} + +static +void test_log_level_rule_is_equal_exactly(void) +{ + int level = 9000, no_eq_level = 420; + struct lttng_log_level_rule *a, *b, *different_level, *different_type; + + /* Identical log level rules. */ + a = lttng_log_level_rule_exactly_create(level); + b = lttng_log_level_rule_exactly_create(level); + + /* Different level, same type. */ + different_level = lttng_log_level_rule_exactly_create(no_eq_level); + + /* Different type. */ + different_type = lttng_log_level_rule_at_least_as_severe_as_create(level); + + assert(a && b && different_level && different_type); + + ok(lttng_log_level_rule_is_equal(a, a), "Same object is equal"); + ok(lttng_log_level_rule_is_equal(a, b), "Object a and b are equal"); + ok(!lttng_log_level_rule_is_equal(a, different_level), " Object of different levels are not equal"); + ok(!lttng_log_level_rule_is_equal(a, different_type), " Object of different types are not equal"); + + lttng_log_level_rule_destroy(a); + lttng_log_level_rule_destroy(b); + lttng_log_level_rule_destroy(different_level); + lttng_log_level_rule_destroy(different_type); +} + +static +void test_log_level_rule_is_equal_at_least_as_severe_as(void) +{ + int level = 9000, no_eq_level = 420; + struct lttng_log_level_rule *a, *b, *different_level, *different_type; + + /* Identical log level rules. */ + a = lttng_log_level_rule_at_least_as_severe_as_create(level); + b = lttng_log_level_rule_at_least_as_severe_as_create(level); + + /* Different level, same type. */ + different_level = lttng_log_level_rule_at_least_as_severe_as_create(no_eq_level); + + /* Different type. */ + different_type = lttng_log_level_rule_exactly_create(level); + + assert(a && b && different_level && different_type); + + ok(lttng_log_level_rule_is_equal(a, a), "Same object is equal"); + ok(lttng_log_level_rule_is_equal(a, b), "Object a and b are equal"); + ok(!lttng_log_level_rule_is_equal(a, different_level), " Object of different levels are not equal"); + ok(!lttng_log_level_rule_is_equal(a, different_type), " Object of different types are not equal"); + + lttng_log_level_rule_destroy(a); + lttng_log_level_rule_destroy(b); + lttng_log_level_rule_destroy(different_level); + lttng_log_level_rule_destroy(different_type); +} + +static void test_log_level_rule_exactly(void) +{ + int level = 9000; + int _level; + struct lttng_log_level_rule *exactly = NULL; + enum lttng_log_level_rule_status status; + + exactly = lttng_log_level_rule_exactly_create(level); + + ok(exactly, "Log level exactly allocated"); + ok(lttng_log_level_rule_get_type(exactly) == + LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY, + "Log level rule exactly type"); + + status = lttng_log_level_rule_exactly_get_level(exactly, &_level); + ok(status == LTTNG_LOG_LEVEL_RULE_STATUS_OK, "Get the level"); + ok(_level == level, "Level property is valid"); + + test_log_level_rule_is_equal_exactly(); + test_log_level_rule_serialize_deserialize(exactly); +} + +static void test_log_level_rule_at_least_as_severe_as(void) +{ + int level = 9000; + int _level; + struct lttng_log_level_rule *at_least_as_severe_as = NULL; + enum lttng_log_level_rule_status status; + + at_least_as_severe_as = lttng_log_level_rule_at_least_as_severe_as_create(level); + + ok(at_least_as_severe_as, "Log level at_least_as_severe_as allocated"); + ok(lttng_log_level_rule_get_type(at_least_as_severe_as) == + LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS, + "Log level rule at_least_as_severe_as type"); + + status = lttng_log_level_rule_at_least_as_severe_as_get_level(at_least_as_severe_as, &_level); + ok(status == LTTNG_LOG_LEVEL_RULE_STATUS_OK, "Get the level"); + ok(_level == level, "Level property is valid"); + + test_log_level_rule_is_equal_at_least_as_severe_as(); + test_log_level_rule_serialize_deserialize(at_least_as_severe_as); +} + +int main(int argc, const char *argv[]) +{ + plan_tests(NUM_TESTS); + test_log_level_rule_exactly(); + test_log_level_rule_at_least_as_severe_as(); + test_log_level_rule_error(); + return exit_status(); +}