SoW-2020-0002: Trace Hit Counters: trigger error reporting integration
[lttng-tools.git] / doc / examples / trigger-on-event / notification-client.c
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
21 static int print_capture(const struct lttng_condition *condition,
22 const struct lttng_event_field_value *capture,
23 unsigned int indent_level);
24 static int print_array(const struct lttng_condition *condition,
25 const struct lttng_event_field_value *array,
26 unsigned int indent_level);
27
28 static void indent(unsigned int indentation_level)
29 {
30 unsigned int i;
31 for (i = 0; i < indentation_level; i++) {
32 printf(" ");
33 }
34 }
35
36 static
37 void print_one_event_expr(const struct lttng_event_expr *event_expr)
38 {
39 enum lttng_event_expr_type type;
40
41 type = lttng_event_expr_get_type(event_expr);
42
43 switch (type) {
44 case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD: {
45 const char *name;
46
47 name = lttng_event_expr_event_payload_field_get_name(event_expr);
48 printf("%s", name);
49
50 break;
51 }
52
53 case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD: {
54 const char *name;
55
56 name = lttng_event_expr_channel_context_field_get_name(event_expr);
57 printf("$ctx.%s", name);
58
59 break;
60 }
61
62 case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD: {
63 const char *provider_name;
64 const char *type_name;
65
66 provider_name =
67 lttng_event_expr_app_specific_context_field_get_provider_name(
68 event_expr);
69 type_name =
70 lttng_event_expr_app_specific_context_field_get_type_name(
71 event_expr);
72
73 printf("$app.%s:%s", provider_name, type_name);
74
75 break;
76 }
77
78 case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT: {
79 unsigned int index;
80 const struct lttng_event_expr *parent_expr;
81 enum lttng_event_expr_status status;
82
83 parent_expr = lttng_event_expr_array_field_element_get_parent_expr(
84 event_expr);
85 assert(parent_expr != NULL);
86
87 print_one_event_expr(parent_expr);
88
89 status = lttng_event_expr_array_field_element_get_index(
90 event_expr, &index);
91 assert(status == LTTNG_EVENT_EXPR_STATUS_OK);
92
93 printf("[%u]", index);
94
95 break;
96 }
97
98 default:
99 abort();
100 }
101 }
102
103 static bool action_group_contains_notify(
104 const struct lttng_action *action_group)
105 {
106 unsigned int i, count;
107 enum lttng_action_status status =
108 lttng_action_group_get_count(action_group, &count);
109
110 if (status != LTTNG_ACTION_STATUS_OK) {
111 printf("Failed to get action count from action group\n");
112 exit(1);
113 }
114
115 for (i = 0; i < count; i++) {
116 const struct lttng_action *action =
117 lttng_action_group_get_at_index(
118 action_group, i);
119 const enum lttng_action_type action_type =
120 lttng_action_get_type(action);
121
122 if (action_type == LTTNG_ACTION_TYPE_NOTIFY) {
123 return true;
124 }
125 }
126 return false;
127 }
128
129 static int print_capture(const struct lttng_condition *condition,
130 const struct lttng_event_field_value *capture,
131 unsigned int indent_level)
132 {
133 int ret = 0;
134 enum lttng_event_field_value_status event_field_status;
135 enum lttng_event_field_value_type type;
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 string_val = lttng_event_field_value_string_get_value(capture);
209 if (string_val == NULL) {
210 ret = 1;
211 goto end;
212 }
213
214 printf("[String] %s", string_val);
215 break;
216 }
217 case LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY:
218 printf("[Array] [\n");
219 print_array(condition, capture, indent_level);
220 indent(indent_level);
221 printf("]\n");
222 break;
223 case LTTNG_EVENT_FIELD_VALUE_TYPE_UNKNOWN:
224 case LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID:
225 default:
226 ret = 1;
227 break;
228 }
229
230 end:
231 return ret;
232 }
233
234 static void print_unavailabe(void)
235 {
236 printf("Capture unavailable");
237 }
238
239 static int print_array(const struct lttng_condition *condition,
240 const struct lttng_event_field_value *array,
241 unsigned int indent_level)
242 {
243 int ret = 0;
244 enum lttng_event_field_value_status event_field_status;
245 unsigned int captured_field_count;
246
247 event_field_status = lttng_event_field_value_array_get_length(
248 array, &captured_field_count);
249 if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
250 ret = 1;
251 goto end;
252 }
253
254 for (unsigned int i = 0; i < captured_field_count; i++) {
255 const struct lttng_event_field_value *captured_field = NULL;
256 const struct lttng_event_expr *expr =
257 lttng_condition_event_rule_get_capture_descriptor_at_index(
258 condition, i);
259 assert(expr);
260
261 indent(indent_level + 1);
262
263 printf("Field: ");
264 print_one_event_expr(expr);
265 printf(" Value: ");
266
267 event_field_status =
268 lttng_event_field_value_array_get_element_at_index(
269 array, i, &captured_field);
270 if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
271 if (event_field_status ==
272 LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE) {
273 print_unavailabe();
274 } else {
275 ret = 1;
276 goto end;
277 }
278 } else {
279 print_capture(condition, captured_field, indent_level + 1);
280 }
281
282 if (i + 1 < captured_field_count) {
283 printf(",");
284 } else {
285 printf(".");
286 }
287 printf("\n");
288 }
289
290 end:
291 return ret;
292 }
293
294 static int print_captures(struct lttng_notification *notification)
295 {
296 int ret = 0;
297 const struct lttng_evaluation *evaluation =
298 lttng_notification_get_evaluation(notification);
299 const struct lttng_condition *condition =
300 lttng_notification_get_condition(notification);
301
302 /* Status */
303 enum lttng_condition_status condition_status;
304 enum lttng_evaluation_status evaluation_status;
305 enum lttng_event_field_value_status event_field_status;
306
307 const struct lttng_event_field_value *captured_field_array = NULL;
308 unsigned int expected_capture_field_count;
309 unsigned int captured_field_count;
310
311 assert(lttng_evaluation_get_type(evaluation) ==
312 LTTNG_CONDITION_TYPE_EVENT_RULE_HIT);
313
314 condition_status =
315 lttng_condition_event_rule_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 = lttng_evaluation_get_captured_values(
329 evaluation, &captured_field_array);
330 if (evaluation_status != LTTNG_EVALUATION_STATUS_OK) {
331 ret = 1;
332 goto end;
333 }
334
335 printf("Captured field values:\n");
336 print_array(condition, captured_field_array, 1);
337 end:
338 return ret;
339 }
340
341 static int print_notification(struct lttng_notification *notification)
342 {
343 int ret = 0;
344 const struct lttng_evaluation *evaluation =
345 lttng_notification_get_evaluation(notification);
346 const enum lttng_condition_type type =
347 lttng_evaluation_get_type(evaluation);
348
349 switch (type) {
350 case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
351 printf("Received consumed size notification\n");
352 break;
353 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
354 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
355 printf("Received buffer usage notification\n");
356 break;
357 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
358 printf("Received session rotation ongoing notification\n");
359 break;
360 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
361 printf("Received session rotation completed notification\n");
362 break;
363 case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
364 {
365 const char *trigger_name;
366 enum lttng_evaluation_status evaluation_status;
367 char time_str[64];
368 struct timeval tv;
369 time_t the_time;
370
371 gettimeofday(&tv, NULL);
372 the_time = tv.tv_sec;
373
374 strftime(time_str, sizeof(time_str), "[%m-%d-%Y] %T",
375 localtime(&the_time));
376 printf("%s.%ld - ", time_str, tv.tv_usec);
377
378 evaluation_status =
379 lttng_evaluation_event_rule_get_trigger_name(
380 evaluation, &trigger_name);
381 if (evaluation_status != LTTNG_EVALUATION_STATUS_OK) {
382 fprintf(stderr, "Failed to get trigger name of event rule notification\n");
383 ret = -1;
384 break;
385 }
386
387 printf("Received notification of event rule trigger \"%s\"\n",
388 trigger_name);
389 ret = print_captures(notification);
390 break;
391 }
392 default:
393 fprintf(stderr, "Unknown notification type (%d)\n", type);
394 }
395
396 return ret;
397 }
398
399 int main(int argc, char **argv)
400 {
401 int ret;
402 struct lttng_triggers *triggers = NULL;
403 unsigned int count, i, j, subcription_count = 0, trigger_count;
404 enum lttng_trigger_status trigger_status;
405 struct lttng_notification_channel *notification_channel = NULL;
406
407 if (argc < 2) {
408 fprintf(stderr, "Missing trigger name(s)\n");
409 fprintf(stderr, "Usage: notification-client TRIGGER_NAME ...");
410 ret = -1;
411 goto end;
412 }
413
414 trigger_count = argc - 1;
415
416 notification_channel = lttng_notification_channel_create(
417 lttng_session_daemon_notification_endpoint);
418 if (!notification_channel) {
419 fprintf(stderr, "Failed to create notification channel\n");
420 ret = -1;
421 goto end;
422 }
423
424 ret = lttng_list_triggers(&triggers);
425 if (ret != LTTNG_OK) {
426 fprintf(stderr, "Failed to list triggers\n");
427 goto end;
428 }
429
430 trigger_status = lttng_triggers_get_count(triggers, &count);
431 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
432 fprintf(stderr, "Failed to get trigger count\n");
433 ret = -1;
434 goto end;
435 }
436
437 for (i = 0; i < count; i++) {
438 const struct lttng_trigger *trigger =
439 lttng_triggers_get_at_index(triggers, i);
440 const struct lttng_condition *condition =
441 lttng_trigger_get_const_condition(trigger);
442 const struct lttng_action *action =
443 lttng_trigger_get_const_action(trigger);
444 const enum lttng_action_type action_type =
445 lttng_action_get_type(action);
446 enum lttng_notification_channel_status channel_status;
447 const char *trigger_name = NULL;
448 bool subscribe = false;
449
450 lttng_trigger_get_name(trigger, &trigger_name);
451 for (j = 0; j < trigger_count; j++) {
452 if (!strcmp(trigger_name, argv[j + 1])) {
453 subscribe = true;
454 break;
455 }
456 }
457
458 if (!subscribe) {
459 continue;
460 }
461
462 if (!((action_type == LTTNG_ACTION_TYPE_GROUP &&
463 action_group_contains_notify(action)) ||
464 action_type == LTTNG_ACTION_TYPE_NOTIFY)) {
465 printf("The action of trigger \"%s\" is not \"notify\", skipping.\n",
466 trigger_name);
467 continue;
468 }
469
470 channel_status = lttng_notification_channel_subscribe(
471 notification_channel, condition);
472 if (channel_status ==
473 LTTNG_NOTIFICATION_CHANNEL_STATUS_ALREADY_SUBSCRIBED) {
474 continue;
475 }
476 if (channel_status) {
477 fprintf(stderr, "Failed to subscribe to notifications of trigger \"%s\"\n",
478 trigger_name);
479 ret = -1;
480 goto end;
481 }
482
483 printf("Subscribed to notifications of trigger \"%s\"\n",
484 trigger_name);
485 subcription_count++;
486 }
487
488 if (subcription_count == 0) {
489 printf("No matching trigger with a notify action found.\n");
490 ret = 0;
491 goto end;
492 }
493
494 for (;;) {
495 struct lttng_notification *notification;
496 enum lttng_notification_channel_status channel_status;
497
498 channel_status =
499 lttng_notification_channel_get_next_notification(
500 notification_channel,
501 &notification);
502 switch (channel_status) {
503 case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
504 printf("Dropped notification\n");
505 break;
506 case LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED:
507 ret = 0;
508 goto end;
509 case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
510 break;
511 case LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED:
512 printf("Notification channel was closed by peer.\n");
513 break;
514 default:
515 fprintf(stderr, "A communication error occurred on the notification channel.\n");
516 ret = -1;
517 goto end;
518 }
519
520 ret = print_notification(notification);
521 lttng_notification_destroy(notification);
522 if (ret) {
523 goto end;
524 }
525 }
526 end:
527 lttng_triggers_destroy(triggers);
528 lttng_notification_channel_destroy(notification_channel);
529 return !!ret;
530 }
This page took 0.065369 seconds and 5 git commands to generate.