condition: implement event rule based condition
authorJonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Tue, 3 Dec 2019 20:57:08 +0000 (15:57 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Tue, 24 Nov 2020 19:42:36 +0000 (14:42 -0500)
An event rule condition is met when a tracer hit an event matching the
associated event rule.

Signed-off-by: Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: I550903c231d83cb3852e8ef8aee2abafe9069b10

include/Makefile.am
include/lttng/condition/condition.h
include/lttng/condition/event-rule-internal.h [new file with mode: 0644]
include/lttng/condition/event-rule.h [new file with mode: 0644]
include/lttng/lttng.h
src/common/Makefile.am
src/common/conditions/condition.c
src/common/conditions/event-rule.c [new file with mode: 0644]
src/common/event-rule/event-rule.c

index 5a3b5b5f3bbcfdbfcf49628d0c28d3091d27f2f2..957a01d25d171ed1000a099f6ec1dbb7a3002d02 100644 (file)
@@ -132,6 +132,7 @@ lttngactioninclude_HEADERS= \
 lttngconditioninclude_HEADERS= \
        lttng/condition/condition.h \
        lttng/condition/buffer-usage.h \
+       lttng/condition/event-rule.h \
        lttng/condition/session-consumed-size.h \
        lttng/condition/session-rotation.h \
        lttng/condition/evaluation.h
@@ -164,6 +165,7 @@ noinst_HEADERS = \
        lttng/action/stop-session-internal.h \
        lttng/condition/condition-internal.h \
        lttng/condition/buffer-usage-internal.h \
+       lttng/condition/event-rule-internal.h \
        lttng/condition/session-consumed-size-internal.h \
        lttng/condition/evaluation-internal.h \
        lttng/condition/session-rotation-internal.h \
index 877ccd1a39d0bcc9534c55e4fbc9b578b285cbd0..78a206df3180fd929d3c0b4225ac4f1810cf117f 100644 (file)
@@ -21,6 +21,7 @@ enum lttng_condition_type {
        LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW = 102,
        LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING = 103,
        LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED = 104,
+       LTTNG_CONDITION_TYPE_EVENT_RULE_HIT = 105,
 };
 
 enum lttng_condition_status {
diff --git a/include/lttng/condition/event-rule-internal.h b/include/lttng/condition/event-rule-internal.h
new file mode 100644 (file)
index 0000000..a4e02c5
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_CONDITION_EVENT_RULE_INTERNAL_H
+#define LTTNG_CONDITION_EVENT_RULE_INTERNAL_H
+
+#include <lttng/condition/condition-internal.h>
+#include <common/buffer-view.h>
+#include <common/macros.h>
+#include <lttng/condition/evaluation-internal.h>
+
+struct lttng_condition_event_rule {
+       struct lttng_condition parent;
+       struct lttng_event_rule *rule;
+};
+
+struct lttng_condition_event_rule_comm {
+       /* length excludes the header's length. */
+       uint32_t event_rule_length;
+       /* Event rule follows. */
+       char payload[];
+} LTTNG_PACKED;
+
+struct lttng_evaluation_event_rule {
+       struct lttng_evaluation parent;
+       char *name;
+};
+
+struct lttng_evaluation_event_rule_comm {
+       /* Includes the null terminator. */
+       uint32_t trigger_name_length;
+       /* Trigger name. */
+       char payload[];
+} LTTNG_PACKED;
+
+
+LTTNG_HIDDEN
+ssize_t lttng_condition_event_rule_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_condition **condition);
+
+LTTNG_HIDDEN
+enum lttng_condition_status
+lttng_condition_event_rule_borrow_rule_mutable(
+               const struct lttng_condition *condition,
+               struct lttng_event_rule **rule);
+
+LTTNG_HIDDEN
+struct lttng_evaluation *lttng_evaluation_event_rule_create(
+               const char* trigger_name);
+
+LTTNG_HIDDEN
+ssize_t lttng_evaluation_event_rule_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_evaluation **_evaluation);
+
+#endif /* LTTNG_CONDITION_EVENT_RULE_INTERNAL_H */
diff --git a/include/lttng/condition/event-rule.h b/include/lttng/condition/event-rule.h
new file mode 100644 (file)
index 0000000..973cbe6
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_CONDITION_EVENT_RULE_H
+#define LTTNG_CONDITION_EVENT_RULE_H
+
+#include <lttng/event-rule/event-rule.h>
+#include <lttng/condition/condition.h>
+#include <lttng/condition/evaluation.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Event rule conditions allows an action to be taken whenever an event matching
+ * the event rule is hit by the tracers.
+ *
+ * An event rule condition can also specify a payload to be captured at runtime.
+ * This is done via the capture descriptor.
+ *
+ * Note: the dynamic runtime capture of payload is only available for the
+ *       trigger notification subsystem.
+ */
+
+/*
+ * Create a newly allocated event rule condition.
+ *
+ * Returns a new condition on success, NULL on failure. This condition must be
+ * destroyed using lttng_condition_destroy().
+ */
+extern struct lttng_condition *lttng_condition_event_rule_create(
+               struct lttng_event_rule *rule);
+
+/*
+ * Get the rule property of a event rule condition.
+ *
+ * The caller does not assume the ownership of the returned rule. The
+ * rule shall only be used for the duration of the condition's
+ * lifetime.
+ *
+ * Returns LTTNG_CONDITION_STATUS_OK and a pointer to the condition's rule
+ * on success, LTTNG_CONDITION_STATUS_INVALID if an invalid
+ * parameter is passed. */
+extern enum lttng_condition_status lttng_condition_event_rule_get_rule(
+                const struct lttng_condition *condition,
+               const struct lttng_event_rule **rule);
+
+/**
+ * lttng_evaluation_event_rule_hit are specialised lttng_evaluations which
+ * allow users to query a number of properties resulting from the evaluation
+ * of a condition which evaluated to true.
+ *
+ * The evaluation of a event rule hit yields two different results:
+ *    TEMPORARY - The name of the triggers associated with the condition.
+ *    TODO - The captured event payload if any
+ */
+
+/*
+ * Get the trigger name property of a event rule hit evaluation.
+ *
+ * Returns LTTNG_EVALUATION_STATUS_OK on success and a trigger name
+ * or LTTNG_EVALUATION_STATUS_INVALID if
+ * an invalid parameter is passed.
+ */
+extern enum lttng_evaluation_status
+lttng_evaluation_event_rule_get_trigger_name(
+               const struct lttng_evaluation *evaluation,
+               const char **name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_CONDITION_EVENT_RULE_H */
index 1049e0f0d31e35fcebfedb3e440462007859966c..bc900e7f02789f4d8d8b2625ca479d2894a86ebd 100644 (file)
@@ -29,6 +29,7 @@
 #include <lttng/condition/buffer-usage.h>
 #include <lttng/condition/condition.h>
 #include <lttng/condition/evaluation.h>
+#include <lttng/condition/event-rule.h>
 #include <lttng/condition/session-consumed-size.h>
 #include <lttng/condition/session-rotation.h>
 #include <lttng/destruction-handle.h>
index 9df1790fba9841f12052a9b8634b3d0d142dcc6b..bbddbe7ebffc03e8b41953056e0748280c2ddd3b 100644 (file)
@@ -38,6 +38,7 @@ libcommon_la_SOURCES = \
        common.h \
        conditions/buffer-usage.c \
        conditions/condition.c \
+       conditions/event-rule.c \
        conditions/session-consumed-size.c \
        conditions/session-rotation.c \
        context.c context.h \
index cffe6cf5e2b7408034781f23063681bebe9f2f7c..d1990414c2fb759dd9de851306bf9db79c287fbe 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <lttng/condition/condition-internal.h>
 #include <lttng/condition/buffer-usage-internal.h>
+#include <lttng/condition/event-rule-internal.h>
 #include <lttng/condition/session-consumed-size-internal.h>
 #include <lttng/condition/session-rotation-internal.h>
 #include <common/macros.h>
@@ -169,6 +170,9 @@ ssize_t lttng_condition_create_from_payload(
        case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
                create_from_payload = lttng_condition_session_rotation_completed_create_from_payload;
                break;
+       case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
+               create_from_payload = lttng_condition_event_rule_create_from_payload;
+               break;
        default:
                ERR("Attempted to create condition of unknown type (%i)",
                                (int) condition_comm->condition_type);
diff --git a/src/common/conditions/event-rule.c b/src/common/conditions/event-rule.c
new file mode 100644 (file)
index 0000000..06ba18f
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2020 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <assert.h>
+#include <common/error.h>
+#include <common/macros.h>
+#include <lttng/condition/condition-internal.h>
+#include <lttng/condition/event-rule-internal.h>
+#include <lttng/condition/event-rule.h>
+#include <lttng/event-rule/event-rule-internal.h>
+#include <stdbool.h>
+
+#define IS_EVENT_RULE_CONDITION(condition)      \
+       (lttng_condition_get_type(condition) == \
+                       LTTNG_CONDITION_TYPE_EVENT_RULE_HIT)
+
+static bool is_event_rule_evaluation(const struct lttng_evaluation *evaluation)
+{
+       enum lttng_condition_type type = lttng_evaluation_get_type(evaluation);
+
+       return type == LTTNG_CONDITION_TYPE_EVENT_RULE_HIT;
+}
+
+static bool lttng_condition_event_rule_validate(
+               const struct lttng_condition *condition);
+static int lttng_condition_event_rule_serialize(
+               const struct lttng_condition *condition,
+               struct lttng_payload *payload);
+static bool lttng_condition_event_rule_is_equal(
+               const struct lttng_condition *_a,
+               const struct lttng_condition *_b);
+static void lttng_condition_event_rule_destroy(
+               struct lttng_condition *condition);
+
+static bool lttng_condition_event_rule_validate(
+               const struct lttng_condition *condition)
+{
+       bool valid = false;
+       struct lttng_condition_event_rule *event_rule;
+
+       if (!condition) {
+               goto end;
+       }
+
+       event_rule = container_of(
+                       condition, struct lttng_condition_event_rule, parent);
+       if (!event_rule->rule) {
+               ERR("Invalid event rule condition: a rule must be set.");
+               goto end;
+       }
+
+       valid = lttng_event_rule_validate(event_rule->rule);
+end:
+       return valid;
+}
+
+static int lttng_condition_event_rule_serialize(
+               const struct lttng_condition *condition,
+               struct lttng_payload *payload)
+{
+       int ret;
+       size_t header_offset, size_before_payload;
+       struct lttng_condition_event_rule *event_rule;
+       struct lttng_condition_event_rule_comm event_rule_comm = {};
+       struct lttng_condition_event_rule_comm *header = NULL;
+
+       if (!condition || !IS_EVENT_RULE_CONDITION(condition)) {
+               ret = -1;
+               goto end;
+       }
+
+       DBG("Serializing event rule condition");
+       event_rule = container_of(
+                       condition, struct lttng_condition_event_rule, parent);
+
+       header_offset = payload->buffer.size;
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &event_rule_comm,
+                       sizeof(event_rule_comm));
+       if (ret) {
+               goto end;
+       }
+
+       size_before_payload = payload->buffer.size;
+       ret = lttng_event_rule_serialize(event_rule->rule, payload);
+       if (ret) {
+               goto end;
+       }
+
+       /* Update payload size. */
+       header = (struct lttng_condition_event_rule_comm *)
+                       ((char *) payload->buffer.data + header_offset);
+       header->event_rule_length = payload->buffer.size - size_before_payload;
+
+end:
+       return ret;
+}
+
+static bool lttng_condition_event_rule_is_equal(
+               const struct lttng_condition *_a,
+               const struct lttng_condition *_b)
+{
+       bool is_equal = false;
+       struct lttng_condition_event_rule *a, *b;
+
+       a = container_of(_a, struct lttng_condition_event_rule, parent);
+       b = container_of(_b, struct lttng_condition_event_rule, parent);
+
+       /* Both event rules must be set or both must be unset. */
+       if ((a->rule && !b->rule) || (!a->rule && b->rule)) {
+               WARN("Comparing event_rule conditions with uninitialized rule");
+               goto end;
+       }
+
+       is_equal = lttng_event_rule_is_equal(a->rule, b->rule);
+end:
+       return is_equal;
+}
+
+static void lttng_condition_event_rule_destroy(
+               struct lttng_condition *condition)
+{
+       struct lttng_condition_event_rule *event_rule;
+
+       event_rule = container_of(
+                       condition, struct lttng_condition_event_rule, parent);
+
+       lttng_event_rule_put(event_rule->rule);
+       free(event_rule);
+}
+
+struct lttng_condition *lttng_condition_event_rule_create(
+               struct lttng_event_rule *rule)
+{
+       struct lttng_condition *parent = NULL;
+       struct lttng_condition_event_rule *condition = NULL;
+
+       if (!rule) {
+               goto end;
+       }
+
+       condition = zmalloc(sizeof(struct lttng_condition_event_rule));
+       if (!condition) {
+               return NULL;
+       }
+
+       lttng_condition_init(&condition->parent,
+                       LTTNG_CONDITION_TYPE_EVENT_RULE_HIT);
+       condition->parent.validate = lttng_condition_event_rule_validate,
+       condition->parent.serialize = lttng_condition_event_rule_serialize,
+       condition->parent.equal = lttng_condition_event_rule_is_equal,
+       condition->parent.destroy = lttng_condition_event_rule_destroy,
+
+       lttng_event_rule_get(rule);
+       condition->rule = rule;
+       rule = NULL;
+
+       parent = &condition->parent;
+end:
+       return parent;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_condition_event_rule_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_condition **_condition)
+{
+       ssize_t offset, event_rule_length;
+       struct lttng_condition *condition = NULL;
+       struct lttng_event_rule *event_rule = NULL;
+       const struct lttng_condition_event_rule_comm *header;
+       const struct lttng_payload_view header_view =
+                       lttng_payload_view_from_view(
+                                       view, 0, sizeof(*header));
+
+       if (!view || !_condition) {
+               goto error;
+       }
+
+       if (!lttng_payload_view_is_valid(&header_view)) {
+               ERR("Failed to initialize from malformed event rule condition: buffer too short to contain header");
+               goto error;
+       }
+
+       header = (const struct lttng_condition_event_rule_comm *)
+                              header_view.buffer.data;
+       offset = sizeof(*header);
+
+       /* lttng_event_rule payload. */
+       {
+               struct lttng_payload_view event_rule_view =
+                               lttng_payload_view_from_view(view, offset, -1);
+
+               event_rule_length = lttng_event_rule_create_from_payload(
+                               &event_rule_view, &event_rule);
+       }
+
+       if (event_rule_length < 0 || !event_rule) {
+               goto error;
+       }
+
+       if ((size_t) header->event_rule_length != event_rule_length) {
+               goto error;
+       }
+
+       /* Move to the end of the payload. */
+       offset += header->event_rule_length;
+
+       /* Acquires a reference to the event rule. */
+       condition = lttng_condition_event_rule_create(event_rule);
+       if (!condition) {
+               goto error;
+       }
+
+       *_condition = condition;
+       condition = NULL;
+       goto end;
+
+error:
+       offset = -1;
+
+end:
+       lttng_event_rule_put(event_rule);
+       lttng_condition_put(condition);
+       return offset;
+}
+
+LTTNG_HIDDEN
+enum lttng_condition_status lttng_condition_event_rule_borrow_rule_mutable(
+               const struct lttng_condition *condition,
+               struct lttng_event_rule **rule)
+{
+       struct lttng_condition_event_rule *event_rule;
+       enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
+
+       if (!condition || !IS_EVENT_RULE_CONDITION(condition) || !rule) {
+               status = LTTNG_CONDITION_STATUS_INVALID;
+               goto end;
+       }
+
+       event_rule = container_of(
+                       condition, struct lttng_condition_event_rule, parent);
+       if (!event_rule->rule) {
+               status = LTTNG_CONDITION_STATUS_UNSET;
+               goto end;
+       }
+
+       *rule = event_rule->rule;
+end:
+       return status;
+}
+
+enum lttng_condition_status lttng_condition_event_rule_get_rule(
+               const struct lttng_condition *condition,
+               const struct lttng_event_rule **rule)
+{
+       struct lttng_event_rule *mutable_rule = NULL;
+       const enum lttng_condition_status status =
+                       lttng_condition_event_rule_borrow_rule_mutable(
+                               condition, &mutable_rule);
+
+       *rule = mutable_rule;
+       return status;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_evaluation_event_rule_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_evaluation **_evaluation)
+{
+       ssize_t ret, offset = 0;
+       const char *trigger_name;
+       struct lttng_evaluation *evaluation = NULL;
+       const struct lttng_evaluation_event_rule_comm *header;
+       const struct lttng_payload_view header_view =
+                       lttng_payload_view_from_view(
+                                       view, 0, sizeof(*header));
+
+       if (!_evaluation) {
+               ret = -1;
+               goto error;
+       }
+
+       if (!lttng_payload_view_is_valid(&header_view)) {
+               ERR("Failed to initialize from malformed event rule evaluation: buffer too short to contain header");
+               ret = -1;
+               goto error;
+       }
+
+       header = (typeof(header)) header_view.buffer.data;
+
+       /* Map the originating trigger's name. */
+       offset += sizeof(*header);
+       {
+               struct lttng_payload_view current_view =
+                               lttng_payload_view_from_view(view, offset,
+                                               header->trigger_name_length);
+
+               if (!lttng_payload_view_is_valid(&current_view)) {
+                       ERR("Failed to initialize from malformed event rule evaluation: buffer too short to contain trigger name");
+                       ret = -1;
+                       goto error;
+               }
+
+               trigger_name = current_view.buffer.data;
+               if (!lttng_buffer_view_contains_string(&current_view.buffer,
+                                   trigger_name, header->trigger_name_length)) {
+                       ERR("Failed to initialize from malformed event rule evaluation: invalid trigger name");
+                       ret = -1;
+                       goto error;
+               }
+       }
+
+       offset += header->trigger_name_length;
+
+       evaluation = lttng_evaluation_event_rule_create(trigger_name);
+       if (!evaluation) {
+               ret = -1;
+               goto error;
+       }
+
+       *_evaluation = evaluation;
+       evaluation = NULL;
+       ret = offset;
+
+error:
+       lttng_evaluation_destroy(evaluation);
+       return ret;
+}
+
+static int lttng_evaluation_event_rule_serialize(
+               const struct lttng_evaluation *evaluation,
+               struct lttng_payload *payload)
+{
+       int ret = 0;
+       struct lttng_evaluation_event_rule *hit;
+       struct lttng_evaluation_event_rule_comm comm;
+
+       hit = container_of(
+                       evaluation, struct lttng_evaluation_event_rule, parent);
+
+       assert(hit->name);
+       comm.trigger_name_length = strlen(hit->name) + 1;
+
+       ret = lttng_dynamic_buffer_append(
+                       &payload->buffer, &comm, sizeof(comm));
+       if (ret) {
+               goto end;
+       }
+
+       ret = lttng_dynamic_buffer_append(
+                       &payload->buffer, hit->name, comm.trigger_name_length);
+end:
+       return ret;
+}
+
+static void lttng_evaluation_event_rule_destroy(
+               struct lttng_evaluation *evaluation)
+{
+       struct lttng_evaluation_event_rule *hit;
+
+       hit = container_of(
+                       evaluation, struct lttng_evaluation_event_rule, parent);
+       free(hit->name);
+       free(hit);
+}
+
+LTTNG_HIDDEN
+struct lttng_evaluation *lttng_evaluation_event_rule_create(
+               const char *trigger_name)
+{
+       struct lttng_evaluation_event_rule *hit;
+       struct lttng_evaluation *evaluation = NULL;
+
+       hit = zmalloc(sizeof(struct lttng_evaluation_event_rule));
+       if (!hit) {
+               goto end;
+       }
+
+       hit->name = strdup(trigger_name);
+       if (!hit->name) {
+               goto end;
+       }
+
+       hit->parent.type = LTTNG_CONDITION_TYPE_EVENT_RULE_HIT;
+       hit->parent.serialize = lttng_evaluation_event_rule_serialize;
+       hit->parent.destroy = lttng_evaluation_event_rule_destroy;
+
+       evaluation = &hit->parent;
+       hit = NULL;
+
+end:
+       if (hit) {
+               lttng_evaluation_event_rule_destroy(&hit->parent);
+       }
+
+       return evaluation;
+}
+
+enum lttng_evaluation_status lttng_evaluation_event_rule_get_trigger_name(
+               const struct lttng_evaluation *evaluation, const char **name)
+{
+       struct lttng_evaluation_event_rule *hit;
+       enum lttng_evaluation_status status = LTTNG_EVALUATION_STATUS_OK;
+
+       if (!evaluation || !is_event_rule_evaluation(evaluation) || !name) {
+               status = LTTNG_EVALUATION_STATUS_INVALID;
+               goto end;
+       }
+
+       hit = container_of(
+                       evaluation, struct lttng_evaluation_event_rule, parent);
+       *name = hit->name;
+end:
+       return status;
+}
index b6a0e96e7388cef1bdc4ef40f0a2e05e5545c40e..fbcb7a018a0c0889b32725877e850f1d85a81549 100644 (file)
@@ -161,7 +161,7 @@ ssize_t lttng_event_rule_create_from_payload(
                goto end;
        }
 
-       DBG("Deserializing event_rule from payload.");
+       DBG("Deserializing event_rule from payload");
        event_rule_comm = (const struct lttng_event_rule_comm *) event_rule_comm_view.buffer.data;
        consumed += sizeof(*event_rule_comm);
 
This page took 0.036777 seconds and 4 git commands to generate.