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