From 595ed92e6d1d46347ac633315c5f711c2fc2015c Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Fri, 14 Feb 2020 18:26:39 -0500 Subject: [PATCH] Add trigger on event rule matches application example MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jonathan Rajotte Signed-off-by: Jérémie Galarneau Change-Id: Ice78e15aa1f4380925a272def8bcc7ca331c0aa0 --- .gitignore | 4 + Makefile.am | 6 +- configure.ac | 2 + doc/Makefile.am | 6 + doc/examples/Makefile.am | 3 + .../Makefile.am | 21 + .../trigger-condition-event-matches/README.md | 91 +++ .../trigger-condition-event-matches/demo.sh | 35 ++ .../instrumented-app.c | 37 ++ .../notification-client.c | 536 ++++++++++++++++++ .../tracepoint-trigger-example.c | 10 + .../tracepoint-trigger-example.h | 28 + 12 files changed, 777 insertions(+), 2 deletions(-) create mode 100644 doc/examples/Makefile.am create mode 100644 doc/examples/trigger-condition-event-matches/Makefile.am create mode 100644 doc/examples/trigger-condition-event-matches/README.md create mode 100755 doc/examples/trigger-condition-event-matches/demo.sh create mode 100644 doc/examples/trigger-condition-event-matches/instrumented-app.c create mode 100644 doc/examples/trigger-condition-event-matches/notification-client.c create mode 100644 doc/examples/trigger-condition-event-matches/tracepoint-trigger-example.c create mode 100644 doc/examples/trigger-condition-event-matches/tracepoint-trigger-example.h diff --git a/.gitignore b/.gitignore index 26d3511f0..aebc12bf8 100644 --- a/.gitignore +++ b/.gitignore @@ -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/ diff --git a/Makefile.am b/Makefile.am index 807d85b17..cf91f0f92 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/configure.ac b/configure.ac index 75240d836..ea8b15458 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/doc/Makefile.am b/doc/Makefile.am index 41fd10907..121db3b89 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -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 index 000000000..1b2d8456f --- /dev/null +++ b/doc/examples/Makefile.am @@ -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 index 000000000..bace545b9 --- /dev/null +++ b/doc/examples/trigger-condition-event-matches/Makefile.am @@ -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 index 000000000..217e5df97 --- /dev/null +++ b/doc/examples/trigger-condition-event-matches/README.md @@ -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 index 000000000..a50e9c38e --- /dev/null +++ b/doc/examples/trigger-condition-event-matches/demo.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# +# Copyright (C) 2020 Jérémie Galarneau +# +# 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 index 000000000..dce6e577f --- /dev/null +++ b/doc/examples/trigger-condition-event-matches/instrumented-app.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2020 Jérémie Galarneau + * + * SPDX-License-Identifier: MIT + * + */ + +#include "tracepoint-trigger-example.h" + +#include +#include +#include +#include +#include + +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 index 000000000..7437b6a3c --- /dev/null +++ b/doc/examples/trigger-condition-event-matches/notification-client.c @@ -0,0 +1,536 @@ +/* + * Copyright (C) 2020 Jérémie Galarneau + * + * SPDX-License-Identifier: MIT + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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, + ¬ification); + 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 index 000000000..3f781e3b8 --- /dev/null +++ b/doc/examples/trigger-condition-event-matches/tracepoint-trigger-example.c @@ -0,0 +1,10 @@ +/* + * Copyright (C) 2020 Jérémie Galarneau + * + * 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 index 000000000..e82e3c704 --- /dev/null +++ b/doc/examples/trigger-condition-event-matches/tracepoint-trigger-example.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2020 Jérémie Galarneau + * + * 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 + +TRACEPOINT_EVENT(trigger_example, my_event, + TP_ARGS(int, iteration), + TP_FIELDS( + ctf_integer(uint64_t, iteration, iteration) + ) +) + +#endif /* _TRACEPOINT_TRIGGER_EXAMPLE_H */ + +#include -- 2.34.1