Make captured field values available to event rule cond. evaluation
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Fri, 1 May 2020 20:33:26 +0000 (16:33 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Tue, 16 Mar 2021 20:40:01 +0000 (16:40 -0400)
liblttng-ctl:
    Add the public lttng_evaluation_get_captured_values() function.

    This function returns an array event field value which contains
    the captured field values as requested by the evaluation's
    condition's capture descriptors.

    This array event field value contains as many elements as returned
    by lttng_condition_event_rule_get_capture_descriptor_count() for the
    evaluation's condition. However,
    lttng_event_field_value_array_get_element_at_index() could return
    `LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE` for some or all indexes
    if there was no such field to capture at tracing time.

Common:
    Internally, an event rule evaluation now contains a captured field
    value payload (CFVP) as well as the array event field value to be
    returned by lttng_evaluation_get_captured_values().

    The CFVP is MessagePack-encoded.

    When you create an event rule evaluation with
    lttng_evaluation_event_rule_create(), you must pass the CFVP as well
    as the `decode_capture_payload` option parameter. If
    `decode_capture_payload` is `true`,
    lttng_evaluation_event_rule_create() creates the array event field
    value from the CFVP thanks to msgpack-c.

    lttng_evaluation_event_rule_create() also accepts the event rule
    condition now because it relies on the capture descriptors to create
    the event field values if `decode_capture_payload` is `true`.

    When an event rule evaluation is serialized:
        Only its CFVP is serialized (as is).

    When an event rule evaluation is deserialized:
        lttng_evaluation_event_rule_create() is called with the
        `decode_capture_payload` parameter set to `true`.

Session daemon:
    action_executor_notify_handler() calls
    lttng_evaluation_event_rule_create() with the
    `decode_capture_payload` parameter set to `false` to send the
    evaluation to the clients with the CFVP.

    This CFVP directly comes from the tracer.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: Ib2ae39dae005ad555eb8309e0bfd53f746d5e8dd
Depends-on: lttng-ust: I8423c510bf6af2f9bf85256e8d6f931d36f7054b

include/lttng/condition/evaluation-internal.h
include/lttng/condition/event-rule-internal.h
include/lttng/condition/event-rule.h
include/lttng/event-field-value.h
src/bin/lttng-sessiond/notification-thread-events.c
src/common/conditions/event-rule.c
src/common/evaluation.c
src/common/event-field-value.c
src/common/notification.c

index 15ae4af4d05d7205c434e8772f88c3acd4b06406..eaef721fb40b7030930f3fa18dd4cc50b2750d30 100644 (file)
@@ -9,6 +9,7 @@
 #define LTTNG_EVALUATION_INTERNAL_H
 
 #include <lttng/condition/evaluation.h>
+#include <lttng/condition/condition.h>
 #include <common/macros.h>
 #include <stdbool.h>
 #include <sys/types.h>
@@ -38,7 +39,9 @@ void lttng_evaluation_init(struct lttng_evaluation *evaluation,
                enum lttng_condition_type type);
 
 LTTNG_HIDDEN
-ssize_t lttng_evaluation_create_from_payload(struct lttng_payload_view *view,
+ssize_t lttng_evaluation_create_from_payload(
+               const struct lttng_condition *condition,
+               struct lttng_payload_view *view,
                struct lttng_evaluation **evaluation);
 
 LTTNG_HIDDEN
index 0f2f3fbf6c3e7971a587bdb2bcdff3b8a79e3087..6dd663d7c498637aac9e3f9b082458badc5b8455 100644 (file)
@@ -13,6 +13,7 @@
 #include <common/macros.h>
 #include <lttng/condition/evaluation-internal.h>
 #include <common/dynamic-array.h>
+#include <lttng/event-field-value.h>
 
 struct lttng_capture_descriptor {
        struct lttng_event_expr *event_expression;
@@ -30,6 +31,18 @@ struct lttng_condition_event_rule {
 struct lttng_evaluation_event_rule {
        struct lttng_evaluation parent;
        char *name;
+
+       /* MessagePack-encoded captured event field values. */
+       struct lttng_dynamic_buffer capture_payload;
+
+       /*
+        * The content of this array event field value is the decoded
+        * version of `capture_payload` above.
+        *
+        * This is a cache: it's not serialized/deserialized in
+        * communications from/to the library and the session daemon.
+        */
+       struct lttng_event_field_value *captured_values;
 };
 
 struct lttng_evaluation_event_rule_comm {
@@ -52,10 +65,14 @@ lttng_condition_event_rule_borrow_rule_mutable(
 
 LTTNG_HIDDEN
 struct lttng_evaluation *lttng_evaluation_event_rule_create(
-               const char* trigger_name);
+               const struct lttng_condition_event_rule *condition,
+               const char* trigger_name,
+               const char *capture_payload, size_t capture_payload_size,
+               bool decode_capture_payload);
 
 LTTNG_HIDDEN
 ssize_t lttng_evaluation_event_rule_create_from_payload(
+               const struct lttng_condition_event_rule *condition,
                struct lttng_payload_view *view,
                struct lttng_evaluation **_evaluation);
 
index 91fce32d63a22a91858866d8342bb0c599f051b9..02e7a20e78a5ee99ffa5ab7a86af85bfb1436a9c 100644 (file)
@@ -17,6 +17,7 @@ extern "C" {
 #endif
 
 struct lttng_event_expr;
+struct lttng_event_field_value;
 
 /**
  * Event rule conditions allows an action to be taken whenever an event matching
@@ -74,6 +75,30 @@ lttng_evaluation_event_rule_get_trigger_name(
                const struct lttng_evaluation *evaluation,
                const char **name);
 
+/*
+ * Sets `*field_val` to the array event field value of the event rule
+ * condition evaluation `evaluation` which contains its captured values.
+ *
+ * Returns:
+ *
+ * `LTTNG_EVALUATION_STATUS_OK`:
+ *     Success.
+ *
+ *     `*field_val` is an array event field value with a length of at
+ *     least one.
+ *
+ * `LTTNG_EVALUATION_STATUS_INVALID`:
+ *     * `evaluation` is `NULL`.
+ *     * The type of the condition of `evaluation` is not
+ *       `LTTNG_CONDITION_TYPE_EVENT_RULE_HIT`.
+ *     * The condition of `evaluation` has no capture descriptors.
+ *     * `field_val` is `NULL`.
+ */
+extern enum lttng_evaluation_status
+lttng_evaluation_event_rule_get_captured_values(
+               const struct lttng_evaluation *evaluation,
+               const struct lttng_event_field_value **field_val);
+
 /*
  * Appends (transfering the ownership) the capture descriptor `expr` to
  * the event rule condition `condition`.
index db4a4fb3b5c2a86da020d7483206cfd0031835eb..7fa851a79f04fd2f0038ef7e02d4bb14c6eaf563 100644 (file)
@@ -169,12 +169,18 @@ lttng_event_field_value_real_get_value(
  * Returns the raw value (an UTF-8 C string) of the string event field
  * value `field_val`, or `NULL` if:
  *
- * * `field_val` is `NULL`.
- * * The type of `field_val` is not
- *   `LTTNG_EVENT_FIELD_VALUE_TYPE_STRING`.
+ * `LTTNG_EVENT_FIELD_VALUE_STATUS_OK`:
+ *     Success.
+ *
+ * `LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID`:
+ *     * `field_val` is `NULL`.
+ *     * The type of `field_val` is not
+ *       `LTTNG_EVENT_FIELD_VALUE_TYPE_STRING`.
  */
-extern const char *lttng_event_field_value_string_get_value(
-               const struct lttng_event_field_value *field_val);
+extern enum lttng_event_field_value_status
+lttng_event_field_value_string_get_value(
+               const struct lttng_event_field_value *field_val,
+               const char **value);
 
 /*
  * Sets `*length` to the length (the number of contained elements) of
index 7fea927d8ba57015e5d5a228383ab0aec4f4de07..257fe1c739085b5973c8e01227f56060eea7d4d5 100644 (file)
@@ -4350,6 +4350,7 @@ int dispatch_one_event_notifier_notification(struct notification_thread_state *s
        struct notification_client_list *client_list = NULL;
        const char *trigger_name;
        int ret;
+       unsigned int capture_count = 0;
 
        /* Find triggers associated with this token. */
        rcu_read_lock();
@@ -4382,14 +4383,34 @@ int dispatch_one_event_notifier_notification(struct notification_thread_state *s
        trigger_status = lttng_trigger_get_name(element->trigger, &trigger_name);
        assert(trigger_status == LTTNG_TRIGGER_STATUS_OK);
 
+       if (lttng_condition_event_rule_get_capture_descriptor_count(
+                           lttng_trigger_get_const_condition(element->trigger),
+                           &capture_count) != LTTNG_CONDITION_STATUS_OK) {
+               ERR("Failed to get capture count");
+               ret = -1;
+               goto end;
+       }
+
+       if (!notification->capture_buffer && capture_count != 0) {
+               ERR("Expected capture but capture buffer is null");
+               ret = -1;
+               goto end;
+       }
+
        evaluation = lttng_evaluation_event_rule_create(
-                       trigger_name);
+                       container_of(lttng_trigger_get_const_condition(
+                                                    element->trigger),
+                                       struct lttng_condition_event_rule,
+                                       parent),
+                       trigger_name,
+                       notification->capture_buffer,
+                       notification->capture_buf_size, false);
+
        if (evaluation == NULL) {
                ERR("[notification-thread] Failed to create event rule hit evaluation while creating and enqueuing action executor job");
                ret = -1;
                goto end_unlock;
        }
-
        client_list = get_client_list_from_condition(state,
                        lttng_trigger_get_const_condition(element->trigger));
        executor_status = action_executor_enqueue(state->executor,
@@ -4460,6 +4481,7 @@ next_client:
 end_unlock:
        notification_client_list_put(client_list);
        rcu_read_unlock();
+end:
        return ret;
 }
 
index dcc31ef8622ccdc823d5f85e2ed382d55666fc12..3f6b96015de81d9df9b7c4cdef084d26cfff349a 100644 (file)
 #include <common/event-expr-to-bytecode.h>
 #include <common/macros.h>
 #include <inttypes.h>
+#include <limits.h>
 #include <lttng/condition/condition-internal.h>
 #include <lttng/event-rule/event-rule-internal.h>
 #include <lttng/condition/event-rule-internal.h>
 #include <lttng/condition/event-rule.h>
 #include <lttng/event-expr-internal.h>
 #include <lttng/event-expr.h>
+#include <lttng/event-field-value-internal.h>
+#include <lttng/event-rule/event-rule-internal.h>
 #include <lttng/lttng-error.h>
 #include <stdbool.h>
 #include <stdint.h>
@@ -56,7 +59,7 @@ static bool lttng_condition_event_rule_validate(
        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.");
+               ERR("Invalid event rule condition: a rule must be set");
                goto end;
        }
 
@@ -65,6 +68,52 @@ end:
        return valid;
 }
 
+static const char *msgpack_object_type_str(msgpack_object_type type)
+{
+       const char *name;
+
+       switch (type) {
+       case MSGPACK_OBJECT_NIL:
+               name = "MSGPACK_OBJECT_NIL";
+               break;
+       case MSGPACK_OBJECT_BOOLEAN:
+               name = "MSGPACK_OBJECT_BOOLEAN";
+               break;
+       case MSGPACK_OBJECT_POSITIVE_INTEGER:
+               name = "MSGPACK_OBJECT_POSITIVE_INTEGER";
+               break;
+       case MSGPACK_OBJECT_NEGATIVE_INTEGER:
+               name = "MSGPACK_OBJECT_NEGATIVE_INTEGER";
+               break;
+       case MSGPACK_OBJECT_FLOAT32:
+               name = "MSGPACK_OBJECT_FLOAT32";
+               break;
+       case MSGPACK_OBJECT_FLOAT:
+               /* Same value as MSGPACK_OBJECT_FLOAT64 */
+               name = "MSGPACK_OBJECT_FLOAT(64)";
+               break;
+       case MSGPACK_OBJECT_STR:
+               name = "MSGPACK_OBJECT_STR";
+               break;
+       case MSGPACK_OBJECT_ARRAY:
+               name = "MSGPACK_OBJECT_ARRAY";
+               break;
+       case MSGPACK_OBJECT_MAP:
+               name = "MSGPACK_OBJECT_MAP";
+               break;
+       case MSGPACK_OBJECT_BIN:
+               name = "MSGPACK_OBJECT_BIN";
+               break;
+       case MSGPACK_OBJECT_EXT:
+               name = "MSGPACK_OBJECT_EXT";
+               break;
+       default:
+               abort();
+       }
+
+       return name;
+}
+
 /*
  * Serializes the C string `str` into `buf`.
  *
@@ -178,7 +227,7 @@ int serialize_event_expr(const struct lttng_event_expr *expr,
 
                /* Serialize the parent array field expression. */
                DBG("Serializing array field element event expression's "
-                               "parent array field event expression.");
+                               "parent array field event expression");
                ret = serialize_event_expr(elem_expr->array_field_expr, payload);
                if (ret) {
                        goto end;
@@ -775,6 +824,7 @@ end:
 
 LTTNG_HIDDEN
 ssize_t lttng_evaluation_event_rule_create_from_payload(
+               const struct lttng_condition_event_rule *condition,
                struct lttng_payload_view *view,
                struct lttng_evaluation **_evaluation)
 {
@@ -785,6 +835,8 @@ ssize_t lttng_evaluation_event_rule_create_from_payload(
        const struct lttng_payload_view header_view =
                        lttng_payload_view_from_view(
                                        view, 0, sizeof(*header));
+       uint32_t capture_payload_size;
+       const char *capture_payload = NULL;
 
        if (!_evaluation) {
                ret = -1;
@@ -802,7 +854,7 @@ ssize_t lttng_evaluation_event_rule_create_from_payload(
        /* Map the originating trigger's name. */
        offset += sizeof(*header);
        {
-               struct lttng_payload_view current_view =
+               const struct lttng_payload_view current_view =
                                lttng_payload_view_from_view(view, offset,
                                                header->trigger_name_length);
 
@@ -822,13 +874,40 @@ ssize_t lttng_evaluation_event_rule_create_from_payload(
        }
 
        offset += header->trigger_name_length;
+       {
+               const struct lttng_payload_view current_view =
+                               lttng_payload_view_from_view(view, offset, -1);
+
+               if (current_view.buffer.size < sizeof(capture_payload_size)) {
+                       ret = -1;
+                       goto error;
+               }
 
-       evaluation = lttng_evaluation_event_rule_create(trigger_name);
+               memcpy(&capture_payload_size, current_view.buffer.data,
+                               sizeof(capture_payload_size));
+       }
+       offset += sizeof(capture_payload_size);
+
+       if (capture_payload_size > 0) {
+               const struct lttng_payload_view current_view =
+                               lttng_payload_view_from_view(view, offset, -1);
+
+               if (current_view.buffer.size < capture_payload_size) {
+                       ret = -1;
+                       goto error;
+               }
+
+               capture_payload = current_view.buffer.data;
+       }
+
+       evaluation = lttng_evaluation_event_rule_create(condition, trigger_name,
+                       capture_payload, capture_payload_size, true);
        if (!evaluation) {
                ret = -1;
                goto error;
        }
 
+       offset += capture_payload_size;
        *_evaluation = evaluation;
        evaluation = NULL;
        ret = offset;
@@ -845,6 +924,7 @@ static int lttng_evaluation_event_rule_serialize(
        int ret = 0;
        struct lttng_evaluation_event_rule *hit;
        struct lttng_evaluation_event_rule_comm comm;
+       uint32_t capture_payload_size;
 
        hit = container_of(
                        evaluation, struct lttng_evaluation_event_rule, parent);
@@ -860,6 +940,68 @@ static int lttng_evaluation_event_rule_serialize(
 
        ret = lttng_dynamic_buffer_append(
                        &payload->buffer, hit->name, comm.trigger_name_length);
+       if (ret) {
+               goto end;
+       }
+
+       capture_payload_size = (uint32_t) hit->capture_payload.size;
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &capture_payload_size,
+                       sizeof(capture_payload_size));
+       if (ret) {
+               goto end;
+       }
+
+       ret = lttng_dynamic_buffer_append(&payload->buffer, hit->capture_payload.data,
+                       hit->capture_payload.size);
+       if (ret) {
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+bool msgpack_str_is_equal(const struct msgpack_object *obj, const char *str)
+{
+       bool is_equal = true;
+
+       assert(obj->type == MSGPACK_OBJECT_STR);
+
+       if (obj->via.str.size != strlen(str)) {
+               is_equal = false;
+               goto end;
+       }
+
+       if (strncmp(obj->via.str.ptr, str, obj->via.str.size) != 0) {
+               is_equal = false;
+               goto end;
+       }
+
+end:
+       return is_equal;
+}
+
+static
+const msgpack_object *get_msgpack_map_obj(const struct msgpack_object *map_obj,
+               const char *name)
+{
+       const msgpack_object *ret = NULL;
+       size_t i;
+
+       assert(map_obj->type == MSGPACK_OBJECT_MAP);
+
+       for (i = 0; i < map_obj->via.map.size; i++) {
+               const struct msgpack_object_kv *kv = &map_obj->via.map.ptr[i];
+
+               assert(kv->key.type == MSGPACK_OBJECT_STR);
+
+               if (msgpack_str_is_equal(&kv->key, name)) {
+                       ret = &kv->val;
+                       goto end;
+               }
+       }
+
 end:
        return ret;
 }
@@ -872,24 +1014,333 @@ static void lttng_evaluation_event_rule_destroy(
        hit = container_of(
                        evaluation, struct lttng_evaluation_event_rule, parent);
        free(hit->name);
+       lttng_dynamic_buffer_reset(&hit->capture_payload);
+       lttng_event_field_value_destroy(hit->captured_values);
        free(hit);
 }
 
+static
+int event_field_value_from_obj(const msgpack_object *obj,
+               struct lttng_event_field_value **field_val)
+{
+       int ret = 0;
+
+       assert(obj);
+       assert(field_val);
+
+       switch (obj->type) {
+       case MSGPACK_OBJECT_NIL:
+               /* Unavailable. */
+               *field_val = NULL;
+               goto end;
+       case MSGPACK_OBJECT_POSITIVE_INTEGER:
+               *field_val = lttng_event_field_value_uint_create(
+                               obj->via.u64);
+               break;
+       case MSGPACK_OBJECT_NEGATIVE_INTEGER:
+               *field_val = lttng_event_field_value_int_create(
+                               obj->via.i64);
+               break;
+       case MSGPACK_OBJECT_FLOAT32:
+       case MSGPACK_OBJECT_FLOAT64:
+               *field_val = lttng_event_field_value_real_create(
+                               obj->via.f64);
+               break;
+       case MSGPACK_OBJECT_STR:
+               *field_val = lttng_event_field_value_string_create_with_size(
+                               obj->via.str.ptr, obj->via.str.size);
+               break;
+       case MSGPACK_OBJECT_ARRAY:
+       {
+               size_t i;
+
+               *field_val = lttng_event_field_value_array_create();
+               if (!*field_val) {
+                       goto error;
+               }
+
+               for (i = 0; i < obj->via.array.size; i++) {
+                       const msgpack_object *elem_obj = &obj->via.array.ptr[i];
+                       struct lttng_event_field_value *elem_field_val;
+
+                       ret = event_field_value_from_obj(elem_obj,
+                                       &elem_field_val);
+                       if (ret) {
+                               goto error;
+                       }
+
+                       if (elem_field_val) {
+                               ret = lttng_event_field_value_array_append(
+                                               *field_val, elem_field_val);
+                       } else {
+                               ret = lttng_event_field_value_array_append_unavailable(
+                                               *field_val);
+                       }
+
+                       if (ret) {
+                               lttng_event_field_value_destroy(elem_field_val);
+                               goto error;
+                       }
+               }
+
+               break;
+       }
+       case MSGPACK_OBJECT_MAP:
+       {
+               /*
+                * As of this version, the only valid map object is
+                * for an enumeration value, for example:
+                *
+                *     type: enum
+                *     value: 177
+                *     labels:
+                *     - Labatt 50
+                *     - Molson Dry
+                *     - Carling Black Label
+                */
+               const msgpack_object *inner_obj;
+               size_t label_i;
+
+               inner_obj = get_msgpack_map_obj(obj, "type");
+               if (!inner_obj) {
+                       ERR("Missing `type` entry in map object");
+                       goto error;
+               }
+
+               if (inner_obj->type != MSGPACK_OBJECT_STR) {
+                       ERR("Map object's `type` entry is not a string: type = %s",
+                                       msgpack_object_type_str(inner_obj->type));
+                       goto error;
+               }
+
+               if (!msgpack_str_is_equal(inner_obj, "enum")) {
+                       ERR("Map object's `type` entry: expecting `enum`");
+                       goto error;
+               }
+
+               inner_obj = get_msgpack_map_obj(obj, "value");
+               if (!inner_obj) {
+                       ERR("Missing `value` entry in map object");
+                       goto error;
+               }
+
+               if (inner_obj->type == MSGPACK_OBJECT_POSITIVE_INTEGER) {
+                       *field_val = lttng_event_field_value_enum_uint_create(
+                                       inner_obj->via.u64);
+               } else if (inner_obj->type == MSGPACK_OBJECT_NEGATIVE_INTEGER) {
+                       *field_val = lttng_event_field_value_enum_int_create(
+                                       inner_obj->via.i64);
+               } else {
+                       ERR("Map object's `value` entry is not an integer: type = %s",
+                                       msgpack_object_type_str(inner_obj->type));
+                       goto error;
+               }
+
+               if (!*field_val) {
+                       goto error;
+               }
+
+               inner_obj = get_msgpack_map_obj(obj, "labels");
+               if (!inner_obj) {
+                       /* No labels */
+                       goto end;
+               }
+
+               if (inner_obj->type != MSGPACK_OBJECT_ARRAY) {
+                       ERR("Map object's `labels` entry is not an array: type = %s",
+                                       msgpack_object_type_str(inner_obj->type));
+                       goto error;
+               }
+
+               for (label_i = 0; label_i < inner_obj->via.array.size;
+                               label_i++) {
+                       int iret;
+                       const msgpack_object *elem_obj =
+                                       &inner_obj->via.array.ptr[label_i];
+
+                       if (elem_obj->type != MSGPACK_OBJECT_STR) {
+                               ERR("Map object's `labels` entry's type is not a string: type = %s",
+                                               msgpack_object_type_str(elem_obj->type));
+                               goto error;
+                       }
+
+                       iret = lttng_event_field_value_enum_append_label_with_size(
+                                       *field_val, elem_obj->via.str.ptr,
+                                       elem_obj->via.str.size);
+                       if (iret) {
+                               goto error;
+                       }
+               }
+
+               break;
+       }
+       default:
+               ERR("Unexpected object type: type = %s",
+                               msgpack_object_type_str(obj->type));
+               goto error;
+       }
+
+       if (!*field_val) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       lttng_event_field_value_destroy(*field_val);
+       *field_val = NULL;
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static
+struct lttng_event_field_value *event_field_value_from_capture_payload(
+               const struct lttng_condition_event_rule *condition,
+               const char *capture_payload, size_t capture_payload_size)
+{
+       struct lttng_event_field_value *ret = NULL;
+       msgpack_unpacked unpacked;
+       msgpack_unpack_return unpack_return;
+       const msgpack_object *root_obj;
+       const msgpack_object_array *root_array_obj;
+       size_t i;
+       size_t count;
+
+       assert(condition);
+       assert(capture_payload);
+
+       /* Initialize value. */
+       msgpack_unpacked_init(&unpacked);
+
+       /* Decode. */
+       unpack_return = msgpack_unpack_next(&unpacked, capture_payload,
+                       capture_payload_size, NULL);
+       if (unpack_return != MSGPACK_UNPACK_SUCCESS) {
+               ERR("msgpack_unpack_next() failed to decode the "
+                               "MessagePack-encoded capture payload: "
+                               "size = %zu, ret = %d",
+                               capture_payload_size, unpack_return);
+               goto error;
+       }
+
+       /* Get root array. */
+       root_obj = &unpacked.data;
+
+       if (root_obj->type != MSGPACK_OBJECT_ARRAY) {
+               ERR("Expecting an array as the root object: type = %s",
+                               msgpack_object_type_str(root_obj->type));
+               goto error;
+       }
+
+       root_array_obj = &root_obj->via.array;
+
+       /* Create an empty root array event field value. */
+       ret = lttng_event_field_value_array_create();
+       if (!ret) {
+               goto error;
+       }
+
+       /*
+        * For each capture descriptor in the condition object:
+        *
+        * 1. Get its corresponding captured field value MessagePack
+        *    object.
+        *
+        * 2. Create a corresponding event field value.
+        *
+        * 3. Append it to `ret` (the root array event field value).
+        */
+       count = lttng_dynamic_pointer_array_get_count(
+                       &condition->capture_descriptors);
+       assert(count > 0);
+
+       for (i = 0; i < count; i++) {
+               const struct lttng_capture_descriptor *capture_descriptor =
+                               lttng_condition_event_rule_get_internal_capture_descriptor_at_index(
+                                               &condition->parent, i);
+               const msgpack_object *elem_obj;
+               struct lttng_event_field_value *elem_field_val;
+               int iret;
+
+               assert(capture_descriptor);
+
+               elem_obj = &root_array_obj->ptr[i];
+               iret = event_field_value_from_obj(elem_obj,
+                               &elem_field_val);
+               if (iret) {
+                       goto error;
+               }
+
+               if (elem_field_val) {
+                       iret = lttng_event_field_value_array_append(ret,
+                                       elem_field_val);
+               } else {
+                       iret = lttng_event_field_value_array_append_unavailable(
+                                       ret);
+               }
+
+               if (iret) {
+                       lttng_event_field_value_destroy(elem_field_val);
+                       goto error;
+               }
+       }
+
+       goto end;
+
+error:
+       lttng_event_field_value_destroy(ret);
+       ret = NULL;
+
+end:
+       msgpack_unpacked_destroy(&unpacked);
+       return ret;
+}
+
 LTTNG_HIDDEN
 struct lttng_evaluation *lttng_evaluation_event_rule_create(
-               const char *trigger_name)
+               const struct lttng_condition_event_rule *condition,
+               const char *trigger_name,
+               const char *capture_payload, size_t capture_payload_size,
+               bool decode_capture_payload)
 {
        struct lttng_evaluation_event_rule *hit;
        struct lttng_evaluation *evaluation = NULL;
 
        hit = zmalloc(sizeof(struct lttng_evaluation_event_rule));
        if (!hit) {
-               goto end;
+               goto error;
        }
 
        hit->name = strdup(trigger_name);
        if (!hit->name) {
-               goto end;
+               goto error;
+       }
+
+       lttng_dynamic_buffer_init(&hit->capture_payload);
+
+       if (capture_payload) {
+               const int ret = lttng_dynamic_buffer_append(
+                               &hit->capture_payload, capture_payload,
+                               capture_payload_size);
+               if (ret) {
+                       ERR("Failed to initialize capture payload of event rule evaluation");
+                       goto error;
+               }
+
+               if (decode_capture_payload) {
+                       hit->captured_values =
+                                       event_field_value_from_capture_payload(
+                                               condition,
+                                               capture_payload,
+                                               capture_payload_size);
+                       if (!hit->captured_values) {
+                               ERR("Failed to decode the capture payload: size = %zu",
+                                               capture_payload_size);
+                               goto error;
+                       }
+               }
        }
 
        hit->parent.type = LTTNG_CONDITION_TYPE_EVENT_RULE_HIT;
@@ -899,7 +1350,7 @@ struct lttng_evaluation *lttng_evaluation_event_rule_create(
        evaluation = &hit->parent;
        hit = NULL;
 
-end:
+error:
        if (hit) {
                lttng_evaluation_event_rule_destroy(&hit->parent);
        }
@@ -907,6 +1358,32 @@ end:
        return evaluation;
 }
 
+enum lttng_evaluation_status lttng_evaluation_event_rule_get_captured_values(
+               const struct lttng_evaluation *evaluation,
+               const struct lttng_event_field_value **field_val)
+{
+       struct lttng_evaluation_event_rule *hit;
+       enum lttng_evaluation_status status = LTTNG_EVALUATION_STATUS_OK;
+
+       if (!evaluation || !is_event_rule_evaluation(evaluation) ||
+                       !field_val) {
+               status = LTTNG_EVALUATION_STATUS_INVALID;
+               goto end;
+       }
+
+       hit = container_of(evaluation, struct lttng_evaluation_event_rule,
+                       parent);
+       if (!hit->captured_values) {
+               status = LTTNG_EVALUATION_STATUS_INVALID;
+               goto end;
+       }
+
+       *field_val = hit->captured_values;
+
+end:
+       return status;
+}
+
 enum lttng_evaluation_status lttng_evaluation_event_rule_get_trigger_name(
                const struct lttng_evaluation *evaluation, const char **name)
 {
index d8a68a7840429b44bf73679bd3b0abc1b30f6273..16c3ef39ca80b6a825f560619b29d3d0f7bdee71 100644 (file)
@@ -5,6 +5,7 @@
  *
  */
 
+#include <lttng/condition/condition-internal.h>
 #include <lttng/condition/evaluation-internal.h>
 #include <lttng/condition/buffer-usage-internal.h>
 #include <lttng/condition/session-consumed-size-internal.h>
@@ -49,6 +50,7 @@ end:
 
 LTTNG_HIDDEN
 ssize_t lttng_evaluation_create_from_payload(
+               const struct lttng_condition *condition,
                struct lttng_payload_view *src_view,
                struct lttng_evaluation **evaluation)
 {
@@ -116,7 +118,13 @@ ssize_t lttng_evaluation_create_from_payload(
                evaluation_size += ret;
                break;
        case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
-               ret = lttng_evaluation_event_rule_create_from_payload(&evaluation_view, evaluation);
+               assert(condition);
+               assert(condition->type == LTTNG_CONDITION_TYPE_EVENT_RULE_HIT);
+               ret = lttng_evaluation_event_rule_create_from_payload(
+                               container_of(condition,
+                                               const struct lttng_condition_event_rule,
+                                               parent),
+                               &evaluation_view, evaluation);
                if (ret < 0) {
                        goto end;
                }
index d7687880f6b8c575d0ae59584676848c29ce9745..b571f6246430ad7ba667b9d24c15a519fc7b7d31 100644 (file)
@@ -517,21 +517,23 @@ end:
        return ret;
 }
 
-const char *lttng_event_field_value_string_get_value(
-               const struct lttng_event_field_value *field_val)
+enum lttng_event_field_value_status lttng_event_field_value_string_get_value(
+               const struct lttng_event_field_value *field_val,
+               const char **value)
 {
-       const char *ret;
+       enum lttng_event_field_value_status status;
 
        if (!field_val || field_val->type != LTTNG_EVENT_FIELD_VALUE_TYPE_STRING) {
-               ret = NULL;
+               status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID;
                goto end;
        }
 
-       ret = container_of(field_val,
+       *value = container_of(field_val,
                        const struct lttng_event_field_value_string, parent)->val;
+       status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK;
 
 end:
-       return ret;
+       return status;
 }
 
 enum lttng_event_field_value_status lttng_event_field_value_array_get_length(
index c347b3ceac891b60ffc2ecb6a98df84653b857f5..a4e971bd572c159b4a54d90643965dd1479b937d 100644 (file)
@@ -122,7 +122,7 @@ ssize_t lttng_notification_create_from_payload(
                                                notification_size, -1);
 
                evaluation_size = lttng_evaluation_create_from_payload(
-                               &evaluation_view, &evaluation);
+                               condition, &evaluation_view, &evaluation);
        }
 
        if (evaluation_size < 0) {
This page took 0.037457 seconds and 4 git commands to generate.