lttng-ctl: Introduce lttng_log_level_rule
authorJonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Fri, 6 Nov 2020 15:06:23 +0000 (10:06 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Thu, 18 Mar 2021 15:31:09 +0000 (11:31 -0400)
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 <jonathan.rajotte-julien@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: Iefd361d1b7d85c6803e891166429a2830e2404a2

20 files changed:
.gitignore
include/Makefile.am
include/lttng/event-rule/tracepoint-internal.h
include/lttng/event-rule/tracepoint.h
include/lttng/log-level-rule-internal.h [new file with mode: 0644]
include/lttng/log-level-rule.h [new file with mode: 0644]
include/lttng/lttng.h
src/bin/lttng-sessiond/agent.c
src/bin/lttng-sessiond/ust-app.c
src/bin/lttng/commands/add_trigger.c
src/bin/lttng/commands/list_triggers.c
src/bin/lttng/loglevel.c
src/bin/lttng/loglevel.h
src/common/Makefile.am
src/common/event-rule/tracepoint.c
src/common/log-level-rule.c [new file with mode: 0644]
tests/unit/Makefile.am
tests/unit/test_condition.c
tests/unit/test_event_rule.c
tests/unit/test_log_level_rule.c [new file with mode: 0644]

index 3c76b61f23eb7da9af088ab118c8d938100bcc7f..5e2b0a189ce9ad2ce41ad73dfbc3a7dbecd2d9af 100644 (file)
@@ -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
index 96e541332f99378f54a3a0cc3d30979ece3818ac..994c511663da0e157445cc3940d0bb7cfcbdac5d 100644 (file)
@@ -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 \
index 227fe6de92aa1f885e9cdf1160f2c577aabe0211..6c4d438d5d02f63b599be29979d85db1eb60ae6a 100644 (file)
 
 #include <common/payload-view.h>
 #include <common/macros.h>
+#include <common/optional.h>
 #include <lttng/domain.h>
 #include <lttng/event-rule/event-rule-internal.h>
 #include <lttng/event-rule/tracepoint.h>
 #include <lttng/event.h>
+#include <lttng/log-level-rule-internal.h>
 
 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[];
index 5e83076d5db2091440c609bb7ee23a517119cff5..d86b53fedceb59fda4cb9938242edf669cd8de01 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <lttng/domain.h>
 #include <lttng/event-rule/event-rule.h>
+#include <lttng/log-level-rule.h>
 #include <lttng/event.h>
 
 #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 (file)
index 0000000..f0ca632
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_LOG_LEVEL_RULE_INTERNAL_H
+#define LTTNG_LOG_LEVEL_RULE_INTERNAL_H
+
+#include <stdint.h>
+
+#include <common/buffer-view.h>
+#include <common/dynamic-array.h>
+#include <common/macros.h>
+#include <common/payload-view.h>
+#include <common/payload.h>
+#include <lttng/event.h>
+#include <lttng/log-level-rule.h>
+
+/*
+ * 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 (file)
index 0000000..ea9045d
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2020 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * 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 */
index 790943edf208850335b1bebe45ad4d7457d5cfc5..5cdf1aa838eee65cbb45f0a4527bf79e3e4f88ec 100644 (file)
@@ -50,6 +50,7 @@
 #include <lttng/load.h>
 #include <lttng/location.h>
 #include <lttng/lttng-error.h>
+#include <lttng/log-level-rule.h>
 #include <lttng/notification/channel.h>
 #include <lttng/notification/notification.h>
 #include <lttng/rotation.h>
index 9832e5ef99b921c46577a6fdc83358712519e778..b726e0184124a3732641611694031116f54f92c7 100644 (file)
@@ -17,6 +17,7 @@
 #include <lttng/condition/condition.h>
 #include <lttng/condition/on-event.h>
 #include <lttng/domain-internal.h>
+#include <lttng/log-level-rule-internal.h>
 
 #include <common/common.h>
 #include <common/sessiond-comm/agent.h>
@@ -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,
index 81e3bd848a2b492695ef942df8928ee018f6987b..6d71df5c0ce7b003b8a1e588a56eded479ae2a87 100644 (file)
@@ -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();
                }
        }
 
index 776e24470aabdb78607ad9ffa4fb9fe01c0ea782..f1b505f25ffb0adcd769684c0d216dea37f401af 100644 (file)
@@ -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;
 }
 
index 054b3fb725027c5c5b8fadfd5967db425c47e3ff..b8fb64a0a8424ea6ce4995e16b5c8dd08428bae3 100644 (file)
@@ -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);
        }
index ec82bfe11aeb85f278ea2d549eb302c0733b8f83..c18bf381c2e030f045a87e4dbef6dc896482f0d0 100644 (file)
@@ -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);
+}
index 100d33267f719627662f61175bec7ed20d60d8fc..78989504e72f91c80d1d674aa6d9c466770ba9a6 100644 (file)
@@ -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 */
index 9aca16b2ec9b3eed392c539d4d85e61e3ddcb9e8..caf588e4093e9017a8138a3883c934bed6bef57c 100644 (file)
@@ -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 \
index 93de1e98ce936c28ffe1dfb6a634595e51b8353b..fbe1fc4bc8e1e7e62fc5534f40d18a47b5e1f61a 100644 (file)
@@ -9,6 +9,7 @@
 #include <common/credentials.h>
 #include <common/error.h>
 #include <common/macros.h>
+#include <common/optional.h>
 #include <common/payload.h>
 #include <common/payload-view.h>
 #include <common/runas.h>
@@ -16,6 +17,7 @@
 #include <common/hashtable/utils.h>
 #include <lttng/event-rule/event-rule-internal.h>
 #include <lttng/event-rule/tracepoint-internal.h>
+#include <lttng/log-level-rule.h>
 #include <lttng/event.h>
 
 #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(
+                               &current_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 (file)
index 0000000..ca8e439
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2020 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <assert.h>
+#include <common/dynamic-buffer.h>
+#include <common/error.h>
+#include <common/macros.h>
+#include <common/hashtable/hashtable.h>
+#include <common/hashtable/utils.h>
+#include <lttng/log-level-rule-internal.h>
+#include <lttng/log-level-rule.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+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;
+}
index 97b84b6cf6ee969b7460c91ee2092ad80c9ed924..6d33beafb6cb03d6efdec2cb7a43c0d62865602f 100644 (file)
@@ -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)
index c5a94bb6519781da908e3d3475c5c570a77afcd6..864c6a840eff692080df098c4186061576189903 100644 (file)
@@ -22,6 +22,7 @@
 #include <lttng/condition/condition-internal.h>
 #include <lttng/condition/on-event.h>
 #include <lttng/domain.h>
+#include <lttng/log-level-rule.h>
 #include <common/dynamic-buffer.h>
 #include <common/buffer-view.h>
 
@@ -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[])
index 72c37709faab7d5346e5fe6221ea2a974b231f7b..050b9d119d53fdefee413d36e131310fe4bcf7fe 100644 (file)
@@ -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 (file)
index 0000000..fb2e2da
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Unit tests for the log level rule API.
+ *
+ * Copyright (C) 2020 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tap/tap.h>
+
+#include <common/payload-view.h>
+#include <common/payload.h>
+#include <lttng/log-level-rule-internal.h>
+#include <lttng/log-level-rule.h>
+
+/* 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();
+}
This page took 0.051652 seconds and 4 git commands to generate.