Add trigger on event rule matches application example
authorJonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Fri, 14 Feb 2020 23:26:39 +0000 (18:26 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 7 May 2021 17:47:51 +0000 (13:47 -0400)
Signed-off-by: Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: Ice78e15aa1f4380925a272def8bcc7ca331c0aa0

12 files changed:
.gitignore
Makefile.am
configure.ac
doc/Makefile.am
doc/examples/Makefile.am [new file with mode: 0644]
doc/examples/trigger-condition-event-matches/Makefile.am [new file with mode: 0644]
doc/examples/trigger-condition-event-matches/README.md [new file with mode: 0644]
doc/examples/trigger-condition-event-matches/demo.sh [new file with mode: 0755]
doc/examples/trigger-condition-event-matches/instrumented-app.c [new file with mode: 0644]
doc/examples/trigger-condition-event-matches/notification-client.c [new file with mode: 0644]
doc/examples/trigger-condition-event-matches/tracepoint-trigger-example.c [new file with mode: 0644]
doc/examples/trigger-condition-event-matches/tracepoint-trigger-example.h [new file with mode: 0644]

index 26d3511f0fddc24f74b91241a5dcc123e4e0f776..aebc12bf833d36f2e68be6d30e92317f1836b26c 100644 (file)
@@ -171,6 +171,10 @@ compile_commands.json
 
 # examples
 /doc/examples/rotation/rotate-client
+/doc/examples/trigger-condition-event-matches/instrumented-app
+/doc/examples/trigger-condition-event-matches/libtracepoint-trigger-example.a
+/doc/examples/trigger-condition-event-matches/notification-client
+
 
 /benchmark/
 
index 807d85b1782ad11ce249f2a30f9c48c7b1ed1d5a..cf91f0f923b624fc32b0bda0aa0128ddcc93528f 100644 (file)
@@ -2,9 +2,11 @@
 
 ACLOCAL_AMFLAGS = -I m4
 
-DIST_SUBDIRS = include doc src extras tests
+DIST_SUBDIRS = include doc src extras tests doc/examples
 
-SUBDIRS = include doc src tests
+# `doc/examples` is placed last since it requires artifact from `src` and
+# `src` can require artifact from `doc` (--enable-embedded-help).
+SUBDIRS = include doc src tests doc/examples
 
 if BUILD_EXTRAS
 SUBDIRS += extras
index 75240d836151109a2ab017811677844acd7ced9a..ea8b15458427de279a1eaed56d12c6a3303b4f43 100644 (file)
@@ -1097,6 +1097,8 @@ AC_SUBST(lttnglibexecdir)
 AC_CONFIG_FILES([
        Makefile
        doc/Makefile
+       doc/examples/Makefile
+       doc/examples/trigger-condition-event-matches/Makefile
        doc/man/Makefile
        doc/man/asciidoc-attrs.conf
        include/Makefile
index 41fd10907d6c1a86f5287baeeb735a0ed5cce1f3..121db3b89c32dad14cb55b00f73abc5a7ff5387a 100644 (file)
@@ -1,5 +1,11 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
+# The `examples` directory is left out since the parent Makefile is responsible
+# of it. This is used to control when examples are built in the build process.
+# Since some examples require the presence of liblttng-ctl and that the `src`
+# objects might requires build artifacts from the `doc` directory, in build
+# scenarios such as `--enable-embedded-help`, a forced build order is required
+# at the parent level.
 SUBDIRS = man
 EXTRA_DIST = quickstart.txt streaming-howto.txt python-howto.txt \
        snapshot-howto.txt kernel-CodingStyle.txt \
diff --git a/doc/examples/Makefile.am b/doc/examples/Makefile.am
new file mode 100644 (file)
index 0000000..1b2d845
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+SUBDIRS = trigger-condition-event-matches
diff --git a/doc/examples/trigger-condition-event-matches/Makefile.am b/doc/examples/trigger-condition-event-matches/Makefile.am
new file mode 100644 (file)
index 0000000..bace545
--- /dev/null
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+AM_CPPFLAGS += -I$(srcdir)
+
+LIBLTTNG_CTL=$(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la
+dist_noinst_SCRIPTS = demo.sh
+EXTRA_DIST = README.md
+
+if HAVE_LIBLTTNG_UST_CTL
+noinst_PROGRAMS = instrumented-app notification-client
+noinst_LIBRARIES = libtracepoint-trigger-example.a
+
+libtracepoint_trigger_example_a_SOURCES = tracepoint-trigger-example.c tracepoint-trigger-example.h
+
+instrumented_app_SOURCES = instrumented-app.c
+instrumented_app_LDADD = libtracepoint-trigger-example.a $(UST_LIBS) $(DL_LIBS)
+
+notification_client_SOURCES = notification-client.c
+notification_client_LDADD = $(LIBLTTNG_CTL)
+
+endif
diff --git a/doc/examples/trigger-condition-event-matches/README.md b/doc/examples/trigger-condition-event-matches/README.md
new file mode 100644 (file)
index 0000000..217e5df
--- /dev/null
@@ -0,0 +1,91 @@
+# Trigger notification example
+
+## Description
+This example is made-up of three executables.
+
+### `notification-client`
+
+```
+Usage: notification-client TRIGGER_NAME TRIGGER_NAME2 ...
+```
+
+A simple client that subscribes to the notifications emitted by the `TRIGGER_NAME` trigger.
+
+Multiple trigger names can be passed and subscribed to.
+
+
+### `instrumented-app`
+
+An application that emits the `trigger_example:my_event` event every 2 seconds.
+
+### `demo.sh`
+
+This script adds a trigger named `demo_trigger` which emits a notification when
+the user-space `trigger_example:my_event` event occurs.
+
+This script also adds a trigger named `demo_trigger_capture` which emits a
+notification when the user-space `trigger_example:my_event` event occurs and
+provides captured fields if present.
+
+Once the triggers have been setup, the notification-client is launched to print
+all notifications emitted by the `demo_trigger` and `demo_trigger_capture`
+trigger.
+
+## Running the example
+
+1) Launch a session daemon using:
+        ```
+        $ lttng-sessiond
+        ```
+2) Launch the `demo.sh` script
+3) Launch the `instrumented-app`
+
+The following output should be produced:
+
+```
+$ ./demo.sh
+Registering a notification trigger named "demo_trigger" for the trigger_example:my_event user-space event
+Trigger registered successfully.
+Trigger registered successfully.
+Subscribed to notifications of trigger "demo_trigger_capture"
+Subscribed to notifications of trigger "demo_trigger"
+[08-24-2020] 17:20:33.598221 - Received notification of event rule matches trigger "demo_trigger"
+[08-24-2020] 17:20:33.598855 - Received notification of event rule matches trigger "demo_trigger_capture"
+Captured field values:
+  Field: iteration Value: [Unsigned int] 0,
+  Field: does_not_exist Value: Capture unavailable,
+  Field: $ctx.vtid Value: [Unsigned int] 2302494,
+  Field: $ctx.procname Value: [String] instrumented-ap.
+[08-24-2020] 17:20:35.598556 - Received notification of event rule matches trigger "demo_trigger"
+[08-24-2020] 17:20:35.599293 - Received notification of event rule matches trigger "demo_trigger_capture"
+Captured field values:
+  Field: iteration Value: [Unsigned int] 1,
+  Field: does_not_exist Value: Capture unavailable,
+  Field: $ctx.vtid Value: [Unsigned int] 2302494,
+  Field: $ctx.procname Value: [String] instrumented-ap.
+[08-24-2020] 17:20:37.598977 - Received notification of event rule matches trigger "demo_trigger"
+[08-24-2020] 17:20:37.599676 - Received notification of event rule matches trigger "demo_trigger_capture"
+Captured field values:
+  Field: iteration Value: [Unsigned int] 2,
+  Field: does_not_exist Value: Capture unavailable,
+  Field: $ctx.vtid Value: [Unsigned int] 2302494,
+  Field: $ctx.procname Value: [String] instrumented-ap.
+[08-24-2020] 17:20:39.599430 - Received notification of event rule matches trigger "demo_trigger"
+[08-24-2020] 17:20:39.600178 - Received notification of event rule matches trigger "demo_trigger_capture"
+Captured field values:
+  Field: iteration Value: [Unsigned int] 3,
+  Field: does_not_exist Value: Capture unavailable,
+  Field: $ctx.vtid Value: [Unsigned int] 2302494,
+  Field: $ctx.procname Value: [String] instrumented-ap.
+...
+```
+
+```
+$ ./instrumented-app
+[08-24-2020] 17:20:33.597441 - Tracing event "trigger_example:my_event"
+[08-24-2020] 17:20:35.597703 - Tracing event "trigger_example:my_event"
+[08-24-2020] 17:20:37.597997 - Tracing event "trigger_example:my_event"
+...
+```
+
+
diff --git a/doc/examples/trigger-condition-event-matches/demo.sh b/doc/examples/trigger-condition-event-matches/demo.sh
new file mode 100755 (executable)
index 0000000..a50e9c3
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/bash
+#
+# Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+#
+# SPDX-License-Identifier: MIT
+
+EVENT_NAME=trigger_example:my_event
+TRIGGER_NAME=demo_trigger
+TRIGGER_NAME_CAPTURE=demo_trigger_capture
+
+if ! lttng list > /dev/null 2>&1; then
+    echo "Could not connect to session daemon, are you sure it is running?"
+    exit 1
+fi
+
+echo "Registering a notification trigger named \"$TRIGGER_NAME\" for the $EVENT_NAME user-space event"
+lttng add-trigger --name $TRIGGER_NAME \
+       --condition event-rule-matches \
+       --domain=user \
+       --name=$EVENT_NAME \
+       --action notify
+
+
+echo "Registering a notification trigger named \"$TRIGGER_NAME_CAPTURE\" for the $EVENT_NAME user-space event with payload capture"
+lttng add-trigger --name $TRIGGER_NAME_CAPTURE \
+       --condition event-rule-matches \
+       --domain=user \
+       --name=$EVENT_NAME \
+       --capture 'iteration' \
+       --capture 'does_not_exist' \
+       --capture '$ctx.vtid' \
+       --capture '$ctx.procname'\
+       --action notify
+
+./notification-client $TRIGGER_NAME $TRIGGER_NAME_CAPTURE
diff --git a/doc/examples/trigger-condition-event-matches/instrumented-app.c b/doc/examples/trigger-condition-event-matches/instrumented-app.c
new file mode 100644 (file)
index 0000000..dce6e57
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ */
+
+#include "tracepoint-trigger-example.h"
+
+#include <lttng/tracepoint.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+
+int main(int argc, char **argv)
+{
+       uint64_t i;
+
+       for (i = 0; i < UINT64_MAX; i++) {
+               char time_str[64];
+               struct timeval tv;
+               time_t the_time;
+
+               gettimeofday(&tv, NULL);
+               the_time = tv.tv_sec;
+
+               strftime(time_str, sizeof(time_str), "[%m-%d-%Y] %T",
+                               localtime(&the_time));
+               printf("%s.%ld - Tracing event \"trigger_example:my_event\"\n",
+                               time_str, tv.tv_usec);
+
+               tracepoint(trigger_example, my_event, i);
+               sleep(2);
+       }
+       return 0;
+}
diff --git a/doc/examples/trigger-condition-event-matches/notification-client.c b/doc/examples/trigger-condition-event-matches/notification-client.c
new file mode 100644 (file)
index 0000000..7437b6a
--- /dev/null
@@ -0,0 +1,536 @@
+/*
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ */
+
+#include <lttng/lttng.h>
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+
+static int print_capture(const struct lttng_condition *condition,
+               const struct lttng_event_field_value *capture,
+               unsigned int indent_level);
+static int print_array(const struct lttng_condition *condition,
+               const struct lttng_event_field_value *array,
+               unsigned int indent_level);
+
+static void indent(unsigned int indentation_level)
+{
+       unsigned int i;
+       for (i = 0; i < indentation_level; i++) {
+               printf(" ");
+       }
+}
+
+static void print_one_event_expr(const struct lttng_event_expr *event_expr)
+{
+       enum lttng_event_expr_type type;
+
+       type = lttng_event_expr_get_type(event_expr);
+
+       switch (type) {
+       case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD:
+       {
+               const char *name;
+
+               name = lttng_event_expr_event_payload_field_get_name(
+                               event_expr);
+               printf("%s", name);
+
+               break;
+       }
+
+       case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD:
+       {
+               const char *name;
+
+               name = lttng_event_expr_channel_context_field_get_name(
+                               event_expr);
+               printf("$ctx.%s", name);
+
+               break;
+       }
+
+       case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD:
+       {
+               const char *provider_name;
+               const char *type_name;
+
+               provider_name = lttng_event_expr_app_specific_context_field_get_provider_name(
+                               event_expr);
+               type_name = lttng_event_expr_app_specific_context_field_get_type_name(
+                               event_expr);
+
+               printf("$app.%s:%s", provider_name, type_name);
+
+               break;
+       }
+
+       case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT:
+       {
+               unsigned int index;
+               const struct lttng_event_expr *parent_expr;
+               enum lttng_event_expr_status status;
+
+               parent_expr = lttng_event_expr_array_field_element_get_parent_expr(
+                               event_expr);
+               assert(parent_expr != NULL);
+
+               print_one_event_expr(parent_expr);
+
+               status = lttng_event_expr_array_field_element_get_index(
+                               event_expr, &index);
+               assert(status == LTTNG_EVENT_EXPR_STATUS_OK);
+
+               printf("[%u]", index);
+
+               break;
+       }
+
+       default:
+               abort();
+       }
+}
+
+static bool action_group_contains_notify(
+               const struct lttng_action *action_group)
+{
+       unsigned int i, count;
+       enum lttng_action_status status =
+                       lttng_action_list_get_count(action_group, &count);
+
+       if (status != LTTNG_ACTION_STATUS_OK) {
+               printf("Failed to get action count from action group\n");
+               exit(1);
+       }
+
+       for (i = 0; i < count; i++) {
+               const struct lttng_action *action =
+                               lttng_action_list_get_at_index(action_group, i);
+               const enum lttng_action_type action_type =
+                               lttng_action_get_type(action);
+
+               if (action_type == LTTNG_ACTION_TYPE_NOTIFY) {
+                       return true;
+               }
+       }
+       return false;
+}
+
+static int print_capture(const struct lttng_condition *condition,
+               const struct lttng_event_field_value *capture,
+               unsigned int indent_level)
+{
+       int ret = 0;
+       enum lttng_event_field_value_status event_field_status;
+       uint64_t u_val;
+       int64_t s_val;
+       double d_val;
+       const char *string_val = NULL;
+
+       switch (lttng_event_field_value_get_type(capture)) {
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT:
+       {
+               event_field_status =
+                               lttng_event_field_value_unsigned_int_get_value(
+                                               capture, &u_val);
+               if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+                       ret = 1;
+                       goto end;
+               }
+
+               printf("[Unsigned int] %" PRIu64, u_val);
+               break;
+       }
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT:
+       {
+               event_field_status =
+                               lttng_event_field_value_signed_int_get_value(
+                                               capture, &s_val);
+               if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+                       ret = 1;
+                       goto end;
+               }
+
+               printf("[Signed int]  %" PRId64, s_val);
+               break;
+       }
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM:
+       {
+               event_field_status =
+                               lttng_event_field_value_unsigned_int_get_value(
+                                               capture, &u_val);
+               if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+                       ret = 1;
+                       goto end;
+               }
+
+               printf("[Unsigned enum] %" PRIu64, u_val);
+               break;
+       }
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM:
+       {
+               event_field_status =
+                               lttng_event_field_value_signed_int_get_value(
+                                               capture, &s_val);
+               if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+                       ret = 1;
+                       goto end;
+               }
+
+               printf("[Signed enum] %" PRId64, s_val);
+               break;
+       }
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_REAL:
+       {
+               event_field_status = lttng_event_field_value_real_get_value(
+                               capture, &d_val);
+               if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+                       ret = 1;
+                       goto end;
+               }
+
+               printf("[Real] %lf", d_val);
+               break;
+       }
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_STRING:
+       {
+               event_field_status = lttng_event_field_value_string_get_value(
+                               capture, &string_val);
+               if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+                       ret = 1;
+                       goto end;
+               }
+
+               printf("[String] %s", string_val);
+               break;
+       }
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY:
+               printf("[Array] [\n");
+               print_array(condition, capture, indent_level);
+               indent(indent_level);
+               printf("]\n");
+               break;
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_UNKNOWN:
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID:
+       default:
+               ret = 1;
+               break;
+       }
+
+end:
+       return ret;
+}
+
+static void print_unavailabe(void)
+{
+       printf("Capture unavailable");
+}
+
+static int print_array(const struct lttng_condition *condition,
+               const struct lttng_event_field_value *array,
+               unsigned int indent_level)
+{
+       int ret = 0;
+       enum lttng_event_field_value_status event_field_status;
+       unsigned int captured_field_count;
+
+       event_field_status = lttng_event_field_value_array_get_length(
+                       array, &captured_field_count);
+       if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+               ret = 1;
+               goto end;
+       }
+
+       for (unsigned int i = 0; i < captured_field_count; i++) {
+               const struct lttng_event_field_value *captured_field = NULL;
+               const struct lttng_event_expr *expr =
+                               lttng_condition_event_rule_matches_get_capture_descriptor_at_index(
+                                               condition, i);
+               assert(expr);
+
+               indent(indent_level + 1);
+
+               printf("Field: ");
+               print_one_event_expr(expr);
+               printf(" Value: ");
+
+               event_field_status =
+                               lttng_event_field_value_array_get_element_at_index(
+                                               array, i, &captured_field);
+               if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+                       if (event_field_status ==
+                                       LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE) {
+                               print_unavailabe();
+                       } else {
+                               ret = 1;
+                               goto end;
+                       }
+               } else {
+                       print_capture(condition, captured_field,
+                                       indent_level + 1);
+               }
+
+               if (i + 1 < captured_field_count) {
+                       printf(",");
+               } else {
+                       printf(".");
+               }
+               printf("\n");
+       }
+
+end:
+       return ret;
+}
+
+static int print_captures(struct lttng_notification *notification)
+{
+       int ret = 0;
+       const struct lttng_evaluation *evaluation =
+                       lttng_notification_get_evaluation(notification);
+       const struct lttng_condition *condition =
+                       lttng_notification_get_condition(notification);
+
+       /* Status */
+       enum lttng_condition_status condition_status;
+       enum lttng_evaluation_event_rule_matches_status evaluation_status;
+
+       const struct lttng_event_field_value *captured_field_array = NULL;
+       unsigned int expected_capture_field_count;
+
+       assert(lttng_evaluation_get_type(evaluation) ==
+                       LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES);
+
+       condition_status =
+                       lttng_condition_event_rule_matches_get_capture_descriptor_count(
+                                       condition,
+                                       &expected_capture_field_count);
+       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+               ret = 1;
+               goto end;
+       }
+
+       if (expected_capture_field_count == 0) {
+               ret = 0;
+               goto end;
+       }
+
+       evaluation_status =
+                       lttng_evaluation_event_rule_matches_get_captured_values(
+                                       evaluation, &captured_field_array);
+       if (evaluation_status != LTTNG_EVALUATION_EVENT_RULE_MATCHES_STATUS_OK) {
+               ret = 1;
+               goto end;
+       }
+
+       printf("Captured field values:\n");
+       print_array(condition, captured_field_array, 1);
+end:
+       return ret;
+}
+
+static int print_notification(struct lttng_notification *notification)
+{
+       int ret = 0;
+       const struct lttng_evaluation *evaluation =
+                       lttng_notification_get_evaluation(notification);
+       const enum lttng_condition_type type =
+                       lttng_evaluation_get_type(evaluation);
+
+       switch (type) {
+       case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
+               printf("Received consumed size notification\n");
+               break;
+       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
+       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
+               printf("Received buffer usage notification\n");
+               break;
+       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
+               printf("Received session rotation ongoing notification\n");
+               break;
+       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
+               printf("Received session rotation completed notification\n");
+               break;
+       case LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES:
+       {
+               const char *trigger_name;
+               enum lttng_trigger_status trigger_status;
+               char time_str[64];
+               struct timeval tv;
+               time_t the_time;
+               const struct lttng_trigger *trigger = NULL;
+
+               gettimeofday(&tv, NULL);
+               the_time = tv.tv_sec;
+
+               strftime(time_str, sizeof(time_str), "[%m-%d-%Y] %T",
+                               localtime(&the_time));
+               printf("%s.%ld - ", time_str, tv.tv_usec);
+
+               trigger = lttng_notification_get_trigger(notification);
+               if (!trigger) {
+                       fprintf(stderr, "Failed to retrieve notification's trigger");
+                       goto end;
+               }
+
+               trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+               if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+                       fprintf(stderr, "Failed to retrieve trigger's name");
+                       goto end;
+               }
+
+               printf("Received notification of event rule matches trigger \"%s\"\n",
+                               trigger_name);
+               ret = print_captures(notification);
+               break;
+       }
+       default:
+               fprintf(stderr, "Unknown notification type (%d)\n", type);
+       }
+
+end:
+       return ret;
+}
+
+int main(int argc, char **argv)
+{
+       int ret;
+       struct lttng_triggers *triggers = NULL;
+       unsigned int count, i, j, subcription_count = 0, trigger_count;
+       enum lttng_trigger_status trigger_status;
+       struct lttng_notification_channel *notification_channel = NULL;
+
+       if (argc < 2) {
+               fprintf(stderr, "Missing trigger name(s)\n");
+               fprintf(stderr, "Usage: notification-client TRIGGER_NAME ...");
+               ret = -1;
+               goto end;
+       }
+
+       trigger_count = argc - 1;
+
+       notification_channel = lttng_notification_channel_create(
+                       lttng_session_daemon_notification_endpoint);
+       if (!notification_channel) {
+               fprintf(stderr, "Failed to create notification channel\n");
+               ret = -1;
+               goto end;
+       }
+
+       ret = lttng_list_triggers(&triggers);
+       if (ret != LTTNG_OK) {
+               fprintf(stderr, "Failed to list triggers\n");
+               goto end;
+       }
+
+       trigger_status = lttng_triggers_get_count(triggers, &count);
+       if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+               fprintf(stderr, "Failed to get trigger count\n");
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; i < count; i++) {
+               const struct lttng_trigger *trigger =
+                               lttng_triggers_get_at_index(triggers, i);
+               const struct lttng_condition *condition =
+                               lttng_trigger_get_const_condition(trigger);
+               const struct lttng_action *action =
+                               lttng_trigger_get_const_action(trigger);
+               const enum lttng_action_type action_type =
+                               lttng_action_get_type(action);
+               enum lttng_notification_channel_status channel_status;
+               const char *trigger_name = NULL;
+               bool subscribe = false;
+
+               lttng_trigger_get_name(trigger, &trigger_name);
+               for (j = 0; j < trigger_count; j++) {
+                       if (!strcmp(trigger_name, argv[j + 1])) {
+                               subscribe = true;
+                               break;
+                       }
+               }
+
+               if (!subscribe) {
+                       continue;
+               }
+
+               if (!((action_type == LTTNG_ACTION_TYPE_LIST &&
+                                     action_group_contains_notify(action)) ||
+                                   action_type == LTTNG_ACTION_TYPE_NOTIFY)) {
+                       printf("The action of trigger \"%s\" is not \"notify\", skipping.\n",
+                                       trigger_name);
+                       continue;
+               }
+
+               channel_status = lttng_notification_channel_subscribe(
+                               notification_channel, condition);
+               if (channel_status ==
+                               LTTNG_NOTIFICATION_CHANNEL_STATUS_ALREADY_SUBSCRIBED) {
+                       continue;
+               }
+               if (channel_status) {
+                       fprintf(stderr, "Failed to subscribe to notifications of trigger \"%s\"\n",
+                                       trigger_name);
+                       ret = -1;
+                       goto end;
+               }
+
+               printf("Subscribed to notifications of trigger \"%s\"\n",
+                               trigger_name);
+               subcription_count++;
+       }
+
+       if (subcription_count == 0) {
+               printf("No matching trigger with a notify action found.\n");
+               ret = 0;
+               goto end;
+       }
+
+       for (;;) {
+               struct lttng_notification *notification;
+               enum lttng_notification_channel_status channel_status;
+
+               channel_status =
+                               lttng_notification_channel_get_next_notification(
+                                               notification_channel,
+                                               &notification);
+               switch (channel_status) {
+               case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
+                       printf("Dropped notification\n");
+                       break;
+               case LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED:
+                       ret = 0;
+                       goto end;
+               case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
+                       break;
+               case LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED:
+                       printf("Notification channel was closed by peer.\n");
+                       break;
+               default:
+                       fprintf(stderr, "A communication error occurred on the notification channel.\n");
+                       ret = -1;
+                       goto end;
+               }
+
+               ret = print_notification(notification);
+               lttng_notification_destroy(notification);
+               if (ret) {
+                       goto end;
+               }
+       }
+end:
+       lttng_triggers_destroy(triggers);
+       lttng_notification_channel_destroy(notification_channel);
+       return !!ret;
+}
diff --git a/doc/examples/trigger-condition-event-matches/tracepoint-trigger-example.c b/doc/examples/trigger-condition-event-matches/tracepoint-trigger-example.c
new file mode 100644 (file)
index 0000000..3f781e3
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ */
+
+#define TRACEPOINT_DEFINE
+#define TRACEPOINT_CREATE_PROBES
+#include "tracepoint-trigger-example.h"
diff --git a/doc/examples/trigger-condition-event-matches/tracepoint-trigger-example.h b/doc/examples/trigger-condition-event-matches/tracepoint-trigger-example.h
new file mode 100644 (file)
index 0000000..e82e3c7
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ */
+
+#undef TRACEPOINT_PROVIDER
+#define TRACEPOINT_PROVIDER trigger_example
+
+#undef TRACEPOINT_INCLUDE
+#define TRACEPOINT_INCLUDE "./tracepoint-trigger-example.h"
+
+#if !defined(_TRACEPOINT_TRIGGER_EXAMPLE_H) || defined(TRACEPOINT_HEADER_MULTI_READ)
+#define _TRACEPOINT_TRIGGER_EXAMPLE_H
+
+#include <lttng/tracepoint.h>
+
+TRACEPOINT_EVENT(trigger_example, my_event,
+       TP_ARGS(int, iteration),
+       TP_FIELDS(
+               ctf_integer(uint64_t, iteration, iteration)
+       )
+)
+
+#endif /* _TRACEPOINT_TRIGGER_EXAMPLE_H */
+
+#include <lttng/tracepoint-event.h>
This page took 0.035973 seconds and 4 git commands to generate.