SoW-2019-0007-2: Dynamic Snapshot: Triggers send partial event payload with notifications
[lttng-tools.git] / doc / examples / trigger-on-event / notification-client.c
CommitLineData
5024c2ac
JR
1/*
2 * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 */
7
8#include <lttng/condition/event-rule.h>
9#include <lttng/lttng.h>
10
11#include <assert.h>
12#include <inttypes.h>
13#include <stdbool.h>
14#include <stddef.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <sys/time.h>
19#include <time.h>
20
21static int print_capture(const struct lttng_event_field_value *capture,
22 unsigned int indent_level);
23static int print_array(const struct lttng_event_field_value *array,
24 unsigned int indent_level);
25
26static void indent(unsigned int indentation_level)
27{
28 unsigned int i;
29 for (i = 0; i < indentation_level; i++) {
30 printf(" ");
31 }
32}
33
34static bool action_group_contains_notify(
35 const struct lttng_action *action_group)
36{
37 unsigned int i, count;
38 enum lttng_action_status status =
39 lttng_action_group_get_count(action_group, &count);
40
41 if (status != LTTNG_ACTION_STATUS_OK) {
42 printf("Failed to get action count from action group\n");
43 exit(1);
44 }
45
46 for (i = 0; i < count; i++) {
47 const struct lttng_action *action =
48 lttng_action_group_get_at_index_const(
49 action_group, i);
50 const enum lttng_action_type action_type =
51 lttng_action_get_type(action);
52
53 if (action_type == LTTNG_ACTION_TYPE_NOTIFY) {
54 return true;
55 }
56 }
57 return false;
58}
59
60static int print_capture(const struct lttng_event_field_value *capture,
61 unsigned int indent_level)
62{
63 int ret = 0;
64 enum lttng_event_field_value_status event_field_status;
65 enum lttng_event_field_value_type type;
66 uint64_t u_val;
67 int64_t s_val;
68 double d_val;
69 const char *string_val = NULL;
70
71 indent(indent_level);
72
73 switch (lttng_event_field_value_get_type(capture)) {
74 case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT:
75 {
76 event_field_status =
77 lttng_event_field_value_unsigned_int_get_value(
78 capture, &u_val);
79 if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
80 ret = 1;
81 goto end;
82 }
83
84 printf("Unsigned int: %" PRIu64, u_val);
85 break;
86 }
87 case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT:
88 {
89 event_field_status =
90 lttng_event_field_value_signed_int_get_value(
91 capture, &s_val);
92 if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
93 ret = 1;
94 goto end;
95 }
96
97 printf("Signed int: %" PRId64, s_val);
98 break;
99 }
100 case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM:
101 {
102 event_field_status =
103 lttng_event_field_value_unsigned_int_get_value(
104 capture, &u_val);
105 if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
106 ret = 1;
107 goto end;
108 }
109
110 printf("Unsigned enum: %" PRIu64, u_val);
111 break;
112 }
113 case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM:
114 {
115 event_field_status =
116 lttng_event_field_value_signed_int_get_value(
117 capture, &s_val);
118 if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
119 ret = 1;
120 goto end;
121 }
122
123 printf("Signed enum: %" PRId64, s_val);
124 break;
125 }
126 case LTTNG_EVENT_FIELD_VALUE_TYPE_REAL:
127 {
128 event_field_status = lttng_event_field_value_real_get_value(
129 capture, &d_val);
130 if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
131 ret = 1;
132 goto end;
133 }
134
135 printf("Real: %lf", d_val);
136 break;
137 }
138 case LTTNG_EVENT_FIELD_VALUE_TYPE_STRING:
139 {
140 string_val = lttng_event_field_value_string_get_value(capture);
141 if (string_val == NULL) {
142 ret = 1;
143 goto end;
144 }
145
146 printf("String: %s", string_val);
147 break;
148 }
149 case LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY:
150 printf("Array: [\n");
151 print_array(capture, indent_level);
152 indent(indent_level);
153 printf("]\n");
154 break;
155 case LTTNG_EVENT_FIELD_VALUE_TYPE_UNKNOWN:
156 case LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID:
157 default:
158 ret = 1;
159 break;
160 }
161
162end:
163 return ret;
164}
165
166static void print_unavailabe(unsigned int indent_level)
167{
168 indent(indent_level);
169 printf("CAPTURE UNAVAILABE");
170}
171
172static int print_array(const struct lttng_event_field_value *array,
173 unsigned int indent_level)
174{
175 int ret = 0;
176 enum lttng_event_field_value_status event_field_status;
177 unsigned int captured_field_count;
178
179 event_field_status = lttng_event_field_value_array_get_length(
180 array, &captured_field_count);
181 if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
182 ret = 1;
183 goto end;
184 }
185
186 for (unsigned int i = 0; i < captured_field_count; i++) {
187 const struct lttng_event_field_value *captured_field = NULL;
188 event_field_status =
189 lttng_event_field_value_array_get_element_at_index(
190 array, i, &captured_field);
191 if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
192 if (event_field_status ==
193 LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE) {
194 print_unavailabe(indent_level + 1);
195 } else {
196 ret = 1;
197 goto end;
198 }
199 }
200 print_capture(captured_field, indent_level + 1);
201
202 if (i + 1 < captured_field_count) {
203 printf(",");
204 }
205 printf("\n");
206 }
207
208end:
209 return ret;
210}
211
212static int print_captures(struct lttng_notification *notification)
213{
214 int ret = 0;
215 const struct lttng_evaluation *evaluation =
216 lttng_notification_get_evaluation(notification);
217 const struct lttng_condition *condition =
218 lttng_notification_get_condition(notification);
219
220 /* Status */
221 enum lttng_condition_status condition_status;
222 enum lttng_evaluation_status evaluation_status;
223 enum lttng_event_field_value_status event_field_status;
224
225 const struct lttng_event_field_value *captured_field_array = NULL;
226 unsigned int expected_capture_field_count;
227 unsigned int captured_field_count;
228
229 assert(lttng_evaluation_get_type(evaluation) ==
230 LTTNG_CONDITION_TYPE_EVENT_RULE_HIT);
231
232 condition_status =
233 lttng_condition_event_rule_get_capture_descriptor_count(
234 condition,
235 &expected_capture_field_count);
236 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
237 ret = 1;
238 goto end;
239 }
240
241 if (expected_capture_field_count == 0) {
242 ret = 0;
243 goto end;
244 }
245
246 evaluation_status = lttng_evaluation_get_captured_values(
247 evaluation, &captured_field_array);
248 if (evaluation_status != LTTNG_EVALUATION_STATUS_OK) {
249 ret = 1;
250 goto end;
251 }
252
253 printf("Captured field values:\n");
254 print_array(captured_field_array, 1);
255end:
256 return ret;
257}
258
259static int print_notification(struct lttng_notification *notification)
260{
261 int ret = 0;
262 const struct lttng_evaluation *evaluation =
263 lttng_notification_get_evaluation(notification);
264 const enum lttng_condition_type type =
265 lttng_evaluation_get_type(evaluation);
266
267 switch (type) {
268 case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
269 printf("Received consumed size notification\n");
270 break;
271 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
272 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
273 printf("Received buffer usage notification\n");
274 break;
275 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
276 printf("Received session rotation ongoing notification\n");
277 break;
278 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
279 printf("Received session rotation completed notification\n");
280 break;
281 case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
282 {
283 const char *trigger_name;
284 enum lttng_evaluation_status evaluation_status;
285 char time_str[64];
286 struct timeval tv;
287 time_t the_time;
288
289 gettimeofday(&tv, NULL);
290 the_time = tv.tv_sec;
291
292 strftime(time_str, sizeof(time_str), "[%m-%d-%Y] %T",
293 localtime(&the_time));
294 printf("%s.%ld - ", time_str, tv.tv_usec);
295
296 evaluation_status =
297 lttng_evaluation_event_rule_get_trigger_name(
298 evaluation, &trigger_name);
299 if (evaluation_status != LTTNG_EVALUATION_STATUS_OK) {
300 fprintf(stderr, "Failed to get trigger name of event rule notification\n");
301 ret = -1;
302 break;
303 }
304
305 printf("Received notification of event rule trigger \"%s\"\n",
306 trigger_name);
307 ret = print_captures(notification);
308 break;
309 }
310 default:
311 fprintf(stderr, "Unknown notification type (%d)\n", type);
312 }
313
314 return ret;
315}
316
317int main(int argc, char **argv)
318{
319 int ret;
320 struct lttng_triggers *triggers = NULL;
321 unsigned int count, i, j, subcription_count = 0, trigger_count;
322 enum lttng_trigger_status trigger_status;
323 struct lttng_notification_channel *notification_channel = NULL;
324
325 if (argc < 2) {
326 fprintf(stderr, "Missing trigger name(s)\n");
327 fprintf(stderr, "Usage: notification-client TRIGGER_NAME ...");
328 ret = -1;
329 goto end;
330 }
331
332 trigger_count = argc - 1;
333
334 notification_channel = lttng_notification_channel_create(
335 lttng_session_daemon_notification_endpoint);
336 if (!notification_channel) {
337 fprintf(stderr, "Failed to create notification channel\n");
338 ret = -1;
339 goto end;
340 }
341
342 ret = lttng_list_triggers(&triggers);
343 if (ret) {
344 fprintf(stderr, "Failed to list triggers\n");
345 goto end;
346 }
347
348 trigger_status = lttng_triggers_get_count(triggers, &count);
349 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
350 fprintf(stderr, "Failed to get trigger count\n");
351 ret = -1;
352 goto end;
353 }
354
355 for (i = 0; i < count; i++) {
356 const struct lttng_trigger *trigger =
357 lttng_triggers_get_at_index(triggers, i);
358 const struct lttng_condition *condition =
359 lttng_trigger_get_const_condition(trigger);
360 const struct lttng_action *action =
361 lttng_trigger_get_const_action(trigger);
362 const enum lttng_action_type action_type =
363 lttng_action_get_type(action);
364 enum lttng_notification_channel_status channel_status;
365 const char *trigger_name = NULL;
366 bool subscribe = false;
367
368 lttng_trigger_get_name(trigger, &trigger_name);
369 for (j = 0; j < trigger_count; j++) {
370 if (!strcmp(trigger_name, argv[j + 1])) {
371 subscribe = true;
372 break;
373 }
374 }
375
376 if (!subscribe) {
377 continue;
378 }
379
380 if (!((action_type == LTTNG_ACTION_TYPE_GROUP &&
381 action_group_contains_notify(action)) ||
382 action_type == LTTNG_ACTION_TYPE_NOTIFY)) {
383 printf("The action of trigger \"%s\" is not \"notify\", skipping.\n",
384 trigger_name);
385 continue;
386 }
387
388 channel_status = lttng_notification_channel_subscribe(
389 notification_channel, condition);
390 if (channel_status ==
391 LTTNG_NOTIFICATION_CHANNEL_STATUS_ALREADY_SUBSCRIBED) {
392 continue;
393 }
394 if (channel_status) {
395 fprintf(stderr, "Failed to subscribe to notifications of trigger \"%s\"\n",
396 trigger_name);
397 ret = -1;
398 goto end;
399 }
400
401 printf("Subscribed to notifications of trigger \"%s\"\n",
402 trigger_name);
403 subcription_count++;
404 }
405
406 if (subcription_count == 0) {
407 printf("No matching trigger with a notify action found.\n");
408 ret = 0;
409 goto end;
410 }
411
412 for (;;) {
413 struct lttng_notification *notification;
414 enum lttng_notification_channel_status channel_status;
415
416 channel_status =
417 lttng_notification_channel_get_next_notification(
418 notification_channel,
419 &notification);
420 switch (channel_status) {
421 case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
422 printf("Dropped notification\n");
423 break;
424 case LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED:
425 ret = 0;
426 goto end;
427 case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
428 break;
429 case LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED:
430 printf("Notification channel was closed by peer.\n");
431 break;
432 default:
433 fprintf(stderr, "A communication error occurred on the notification channel.\n");
434 ret = -1;
435 goto end;
436 }
437
438 ret = print_notification(notification);
439 lttng_notification_destroy(notification);
440 if (ret) {
441 goto end;
442 }
443 }
444end:
445 lttng_triggers_destroy(triggers);
446 lttng_notification_channel_destroy(notification_channel);
447 return !!ret;
448}
This page took 0.04029 seconds and 5 git commands to generate.