Fix: example: print_notification is called on status all returned status
[lttng-tools.git] / doc / examples / trigger-condition-event-matches / notification-client.cpp
CommitLineData
595ed92e
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/lttng.h>
9
595ed92e
JR
10#include <inttypes.h>
11#include <stdbool.h>
12#include <stddef.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <sys/time.h>
17#include <time.h>
18
c9e313bc 19#include <common/macros.hpp>
a0377dfe 20
595ed92e
JR
21static int print_capture(const struct lttng_condition *condition,
22 const struct lttng_event_field_value *capture,
23 unsigned int indent_level);
24static int print_array(const struct lttng_condition *condition,
25 const struct lttng_event_field_value *array,
26 unsigned int indent_level);
27
28static void indent(unsigned int indentation_level)
29{
30 unsigned int i;
31 for (i = 0; i < indentation_level; i++) {
32 printf(" ");
33 }
34}
35
36static void print_one_event_expr(const struct lttng_event_expr *event_expr)
37{
38 enum lttng_event_expr_type type;
39
40 type = lttng_event_expr_get_type(event_expr);
41
42 switch (type) {
43 case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD:
44 {
45 const char *name;
46
47 name = lttng_event_expr_event_payload_field_get_name(
48 event_expr);
49 printf("%s", name);
50
51 break;
52 }
53
54 case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD:
55 {
56 const char *name;
57
58 name = lttng_event_expr_channel_context_field_get_name(
59 event_expr);
60 printf("$ctx.%s", name);
61
62 break;
63 }
64
65 case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD:
66 {
67 const char *provider_name;
68 const char *type_name;
69
70 provider_name = lttng_event_expr_app_specific_context_field_get_provider_name(
71 event_expr);
72 type_name = lttng_event_expr_app_specific_context_field_get_type_name(
73 event_expr);
74
75 printf("$app.%s:%s", provider_name, type_name);
76
77 break;
78 }
79
80 case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT:
81 {
82 unsigned int index;
83 const struct lttng_event_expr *parent_expr;
84 enum lttng_event_expr_status status;
85
86 parent_expr = lttng_event_expr_array_field_element_get_parent_expr(
87 event_expr);
a0377dfe 88 LTTNG_ASSERT(parent_expr != NULL);
595ed92e
JR
89
90 print_one_event_expr(parent_expr);
91
92 status = lttng_event_expr_array_field_element_get_index(
93 event_expr, &index);
a0377dfe 94 LTTNG_ASSERT(status == LTTNG_EVENT_EXPR_STATUS_OK);
595ed92e
JR
95
96 printf("[%u]", index);
97
98 break;
99 }
100
101 default:
102 abort();
103 }
104}
105
106static bool action_group_contains_notify(
107 const struct lttng_action *action_group)
108{
109 unsigned int i, count;
110 enum lttng_action_status status =
111 lttng_action_list_get_count(action_group, &count);
112
113 if (status != LTTNG_ACTION_STATUS_OK) {
114 printf("Failed to get action count from action group\n");
115 exit(1);
116 }
117
118 for (i = 0; i < count; i++) {
119 const struct lttng_action *action =
120 lttng_action_list_get_at_index(action_group, i);
121 const enum lttng_action_type action_type =
122 lttng_action_get_type(action);
123
124 if (action_type == LTTNG_ACTION_TYPE_NOTIFY) {
125 return true;
126 }
127 }
128 return false;
129}
130
131static int print_capture(const struct lttng_condition *condition,
132 const struct lttng_event_field_value *capture,
133 unsigned int indent_level)
134{
135 int ret = 0;
136 enum lttng_event_field_value_status event_field_status;
137 uint64_t u_val;
138 int64_t s_val;
139 double d_val;
140 const char *string_val = NULL;
141
142 switch (lttng_event_field_value_get_type(capture)) {
143 case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT:
144 {
145 event_field_status =
146 lttng_event_field_value_unsigned_int_get_value(
147 capture, &u_val);
148 if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
149 ret = 1;
150 goto end;
151 }
152
153 printf("[Unsigned int] %" PRIu64, u_val);
154 break;
155 }
156 case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT:
157 {
158 event_field_status =
159 lttng_event_field_value_signed_int_get_value(
160 capture, &s_val);
161 if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
162 ret = 1;
163 goto end;
164 }
165
166 printf("[Signed int] %" PRId64, s_val);
167 break;
168 }
169 case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM:
170 {
171 event_field_status =
172 lttng_event_field_value_unsigned_int_get_value(
173 capture, &u_val);
174 if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
175 ret = 1;
176 goto end;
177 }
178
179 printf("[Unsigned enum] %" PRIu64, u_val);
180 break;
181 }
182 case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM:
183 {
184 event_field_status =
185 lttng_event_field_value_signed_int_get_value(
186 capture, &s_val);
187 if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
188 ret = 1;
189 goto end;
190 }
191
192 printf("[Signed enum] %" PRId64, s_val);
193 break;
194 }
195 case LTTNG_EVENT_FIELD_VALUE_TYPE_REAL:
196 {
197 event_field_status = lttng_event_field_value_real_get_value(
198 capture, &d_val);
199 if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
200 ret = 1;
201 goto end;
202 }
203
204 printf("[Real] %lf", d_val);
205 break;
206 }
207 case LTTNG_EVENT_FIELD_VALUE_TYPE_STRING:
208 {
209 event_field_status = lttng_event_field_value_string_get_value(
210 capture, &string_val);
211 if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
212 ret = 1;
213 goto end;
214 }
215
216 printf("[String] %s", string_val);
217 break;
218 }
219 case LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY:
220 printf("[Array] [\n");
221 print_array(condition, capture, indent_level);
222 indent(indent_level);
223 printf("]\n");
224 break;
225 case LTTNG_EVENT_FIELD_VALUE_TYPE_UNKNOWN:
226 case LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID:
227 default:
228 ret = 1;
229 break;
230 }
231
232end:
233 return ret;
234}
235
236static void print_unavailabe(void)
237{
238 printf("Capture unavailable");
239}
240
241static int print_array(const struct lttng_condition *condition,
242 const struct lttng_event_field_value *array,
243 unsigned int indent_level)
244{
245 int ret = 0;
246 enum lttng_event_field_value_status event_field_status;
247 unsigned int captured_field_count;
248
249 event_field_status = lttng_event_field_value_array_get_length(
250 array, &captured_field_count);
251 if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
252 ret = 1;
253 goto end;
254 }
255
256 for (unsigned int i = 0; i < captured_field_count; i++) {
257 const struct lttng_event_field_value *captured_field = NULL;
258 const struct lttng_event_expr *expr =
259 lttng_condition_event_rule_matches_get_capture_descriptor_at_index(
260 condition, i);
a0377dfe 261 LTTNG_ASSERT(expr);
595ed92e
JR
262
263 indent(indent_level + 1);
264
265 printf("Field: ");
266 print_one_event_expr(expr);
267 printf(" Value: ");
268
269 event_field_status =
270 lttng_event_field_value_array_get_element_at_index(
271 array, i, &captured_field);
272 if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
273 if (event_field_status ==
274 LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE) {
275 print_unavailabe();
276 } else {
277 ret = 1;
278 goto end;
279 }
280 } else {
281 print_capture(condition, captured_field,
282 indent_level + 1);
283 }
284
285 if (i + 1 < captured_field_count) {
286 printf(",");
287 } else {
288 printf(".");
289 }
290 printf("\n");
291 }
292
293end:
294 return ret;
295}
296
297static int print_captures(struct lttng_notification *notification)
298{
299 int ret = 0;
300 const struct lttng_evaluation *evaluation =
301 lttng_notification_get_evaluation(notification);
302 const struct lttng_condition *condition =
303 lttng_notification_get_condition(notification);
304
305 /* Status */
306 enum lttng_condition_status condition_status;
307 enum lttng_evaluation_event_rule_matches_status evaluation_status;
308
309 const struct lttng_event_field_value *captured_field_array = NULL;
310 unsigned int expected_capture_field_count;
311
a0377dfe 312 LTTNG_ASSERT(lttng_evaluation_get_type(evaluation) ==
595ed92e
JR
313 LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES);
314
315 condition_status =
316 lttng_condition_event_rule_matches_get_capture_descriptor_count(
317 condition,
318 &expected_capture_field_count);
319 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
320 ret = 1;
321 goto end;
322 }
323
324 if (expected_capture_field_count == 0) {
325 ret = 0;
326 goto end;
327 }
328
329 evaluation_status =
330 lttng_evaluation_event_rule_matches_get_captured_values(
331 evaluation, &captured_field_array);
332 if (evaluation_status != LTTNG_EVALUATION_EVENT_RULE_MATCHES_STATUS_OK) {
333 ret = 1;
334 goto end;
335 }
336
337 printf("Captured field values:\n");
338 print_array(condition, captured_field_array, 1);
339end:
340 return ret;
341}
342
343static int print_notification(struct lttng_notification *notification)
344{
345 int ret = 0;
346 const struct lttng_evaluation *evaluation =
347 lttng_notification_get_evaluation(notification);
348 const enum lttng_condition_type type =
349 lttng_evaluation_get_type(evaluation);
350
351 switch (type) {
352 case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
353 printf("Received consumed size notification\n");
354 break;
355 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
356 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
357 printf("Received buffer usage notification\n");
358 break;
359 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
360 printf("Received session rotation ongoing notification\n");
361 break;
362 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
363 printf("Received session rotation completed notification\n");
364 break;
365 case LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES:
366 {
367 const char *trigger_name;
368 enum lttng_trigger_status trigger_status;
369 char time_str[64];
370 struct timeval tv;
371 time_t the_time;
372 const struct lttng_trigger *trigger = NULL;
373
374 gettimeofday(&tv, NULL);
375 the_time = tv.tv_sec;
376
377 strftime(time_str, sizeof(time_str), "[%m-%d-%Y] %T",
378 localtime(&the_time));
379 printf("%s.%ld - ", time_str, tv.tv_usec);
380
381 trigger = lttng_notification_get_trigger(notification);
382 if (!trigger) {
383 fprintf(stderr, "Failed to retrieve notification's trigger");
384 goto end;
385 }
386
387 trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
388 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
389 fprintf(stderr, "Failed to retrieve trigger's name");
390 goto end;
391 }
392
393 printf("Received notification of event rule matches trigger \"%s\"\n",
394 trigger_name);
395 ret = print_captures(notification);
396 break;
397 }
398 default:
399 fprintf(stderr, "Unknown notification type (%d)\n", type);
400 }
401
402end:
403 return ret;
404}
405
406int main(int argc, char **argv)
407{
408 int ret;
409 struct lttng_triggers *triggers = NULL;
410 unsigned int count, i, j, subcription_count = 0, trigger_count;
411 enum lttng_trigger_status trigger_status;
412 struct lttng_notification_channel *notification_channel = NULL;
413
414 if (argc < 2) {
415 fprintf(stderr, "Missing trigger name(s)\n");
416 fprintf(stderr, "Usage: notification-client TRIGGER_NAME ...");
417 ret = -1;
418 goto end;
419 }
420
421 trigger_count = argc - 1;
422
423 notification_channel = lttng_notification_channel_create(
424 lttng_session_daemon_notification_endpoint);
425 if (!notification_channel) {
426 fprintf(stderr, "Failed to create notification channel\n");
427 ret = -1;
428 goto end;
429 }
430
431 ret = lttng_list_triggers(&triggers);
432 if (ret != LTTNG_OK) {
433 fprintf(stderr, "Failed to list triggers\n");
434 goto end;
435 }
436
437 trigger_status = lttng_triggers_get_count(triggers, &count);
438 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
439 fprintf(stderr, "Failed to get trigger count\n");
440 ret = -1;
441 goto end;
442 }
443
444 for (i = 0; i < count; i++) {
445 const struct lttng_trigger *trigger =
446 lttng_triggers_get_at_index(triggers, i);
447 const struct lttng_condition *condition =
448 lttng_trigger_get_const_condition(trigger);
449 const struct lttng_action *action =
450 lttng_trigger_get_const_action(trigger);
451 const enum lttng_action_type action_type =
452 lttng_action_get_type(action);
453 enum lttng_notification_channel_status channel_status;
454 const char *trigger_name = NULL;
455 bool subscribe = false;
456
457 lttng_trigger_get_name(trigger, &trigger_name);
458 for (j = 0; j < trigger_count; j++) {
459 if (!strcmp(trigger_name, argv[j + 1])) {
460 subscribe = true;
461 break;
462 }
463 }
464
465 if (!subscribe) {
466 continue;
467 }
468
469 if (!((action_type == LTTNG_ACTION_TYPE_LIST &&
470 action_group_contains_notify(action)) ||
471 action_type == LTTNG_ACTION_TYPE_NOTIFY)) {
472 printf("The action of trigger \"%s\" is not \"notify\", skipping.\n",
473 trigger_name);
474 continue;
475 }
476
477 channel_status = lttng_notification_channel_subscribe(
478 notification_channel, condition);
479 if (channel_status ==
480 LTTNG_NOTIFICATION_CHANNEL_STATUS_ALREADY_SUBSCRIBED) {
481 continue;
482 }
483 if (channel_status) {
484 fprintf(stderr, "Failed to subscribe to notifications of trigger \"%s\"\n",
485 trigger_name);
486 ret = -1;
487 goto end;
488 }
489
490 printf("Subscribed to notifications of trigger \"%s\"\n",
491 trigger_name);
492 subcription_count++;
493 }
494
495 if (subcription_count == 0) {
496 printf("No matching trigger with a notify action found.\n");
497 ret = 0;
498 goto end;
499 }
500
501 for (;;) {
502 struct lttng_notification *notification;
503 enum lttng_notification_channel_status channel_status;
504
505 channel_status =
506 lttng_notification_channel_get_next_notification(
507 notification_channel,
508 &notification);
509 switch (channel_status) {
510 case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
511 printf("Dropped notification\n");
512 break;
513 case LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED:
514 ret = 0;
515 goto end;
516 case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
bdfd0a8e
JR
517 ret = print_notification(notification);
518 lttng_notification_destroy(notification);
519 if (ret) {
520 goto end;
521 }
595ed92e
JR
522 break;
523 case LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED:
524 printf("Notification channel was closed by peer.\n");
525 break;
526 default:
527 fprintf(stderr, "A communication error occurred on the notification channel.\n");
528 ret = -1;
529 goto end;
530 }
595ed92e
JR
531 }
532end:
533 lttng_triggers_destroy(triggers);
534 lttng_notification_channel_destroy(notification_channel);
535 return !!ret;
536}
This page took 0.046196 seconds and 4 git commands to generate.