4 * Base client application for testing of LTTng notification API
6 * Copyright 2017 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
8 * SPDX-License-Identifier: MIT
19 #include <lttng/action/action.h>
20 #include <lttng/action/list.h>
21 #include <lttng/action/notify.h>
22 #include <lttng/condition/buffer-usage.h>
23 #include <lttng/condition/condition.h>
24 #include <lttng/condition/evaluation.h>
25 #include <lttng/domain.h>
26 #include <lttng/endpoint.h>
27 #include <lttng/notification/channel.h>
28 #include <lttng/notification/notification.h>
29 #include <lttng/trigger/trigger.h>
30 #include <lttng/lttng-error.h>
32 static unsigned int nr_notifications
= 0;
33 static unsigned int nr_expected_notifications
= 0;
34 static const char *session_name
= NULL
;
35 static const char *channel_name
= NULL
;
36 static double threshold_ratio
= 0.0;
37 static uint64_t threshold_bytes
= 0;
38 static bool is_threshold_ratio
= false;
39 static bool use_action_list
= false;
40 static enum lttng_condition_type buffer_usage_type
= LTTNG_CONDITION_TYPE_UNKNOWN
;
41 static enum lttng_domain_type domain_type
= LTTNG_DOMAIN_NONE
;
44 const struct lttng_condition
*condition
,
45 const struct lttng_evaluation
*condition_evaluation
);
48 int parse_arguments(char **argv
)
51 const char *domain_type_string
= NULL
;
52 const char *buffer_usage_type_string
= NULL
;
53 const char *buffer_usage_threshold_type
= NULL
;
54 const char *buffer_usage_threshold_value
= NULL
;
55 const char *nr_expected_notifications_string
= NULL
;
56 const char *use_action_list_value
= NULL
;
58 session_name
= argv
[1];
59 channel_name
= argv
[2];
60 domain_type_string
= argv
[3];
61 buffer_usage_type_string
= argv
[4];
62 buffer_usage_threshold_type
= argv
[5];
63 buffer_usage_threshold_value
= argv
[6];
64 nr_expected_notifications_string
= argv
[7];
65 use_action_list_value
= argv
[8];
69 if (!strcasecmp("LTTNG_DOMAIN_UST", domain_type_string
)) {
70 domain_type
= LTTNG_DOMAIN_UST
;
72 if (!strcasecmp("LTTNG_DOMAIN_KERNEL", domain_type_string
)) {
73 domain_type
= LTTNG_DOMAIN_KERNEL
;
75 if (domain_type
== LTTNG_DOMAIN_NONE
) {
76 printf("error: Unknown domain type\n");
80 /* Buffer usage condition type */
81 if (!strcasecmp("low", buffer_usage_type_string
)) {
82 buffer_usage_type
= LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
;
84 if (!strcasecmp("high", buffer_usage_type_string
)) {
85 buffer_usage_type
= LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
;
87 if (buffer_usage_type
== LTTNG_CONDITION_TYPE_UNKNOWN
) {
88 printf("error: Unknown condition type\n");
92 /* Ratio or bytes ? */
93 if (!strcasecmp("bytes", buffer_usage_threshold_type
)) {
94 is_threshold_ratio
= false;
95 sscanf_ret
= sscanf(buffer_usage_threshold_value
, "%" SCNu64
,
97 if (sscanf_ret
!= 1) {
98 printf("error: Invalid buffer usage threshold value bytes (integer), sscanf returned %d\n",
104 if (!strcasecmp("ratio", buffer_usage_threshold_type
)) {
105 is_threshold_ratio
= true;
106 sscanf_ret
= sscanf(buffer_usage_threshold_value
, "%lf",
108 if (sscanf_ret
!= 1) {
109 printf("error: Invalid buffer usage threshold value ratio (float), sscanf returned %d\n",
115 /* Number of notification to expect */
116 sscanf_ret
= sscanf(nr_expected_notifications_string
, "%d",
117 &nr_expected_notifications
);
118 if (sscanf_ret
!= 1) {
119 printf("error: Invalid nr_expected_notifications, sscanf returned %d\n",
124 /* Put notify action in a group. */
125 if (!strcasecmp("1", use_action_list_value
)) {
126 use_action_list
= true;
134 int main(int argc
, char **argv
)
137 enum lttng_condition_status condition_status
;
138 enum lttng_action_status action_status
;
139 enum lttng_notification_channel_status nc_status
;
140 struct lttng_notification_channel
*notification_channel
= NULL
;
141 struct lttng_condition
*condition
= NULL
;
142 struct lttng_action
*action
= NULL
;
143 struct lttng_trigger
*trigger
= NULL
;
144 enum lttng_error_code ret_code
;
147 * Disable buffering on stdout.
148 * Safety measure to prevent hang on the validation side since
149 * stdout is used for outside synchronization.
151 setbuf(stdout
, NULL
);
154 printf("error: Missing arguments for tests\n");
159 ret
= parse_arguments(argv
);
161 printf("error: Could not parse arguments\n");
166 notification_channel
= lttng_notification_channel_create(
167 lttng_session_daemon_notification_endpoint
);
168 if (!notification_channel
) {
169 printf("error: Could not create notification channel\n");
174 switch (buffer_usage_type
) {
175 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
:
176 condition
= lttng_condition_buffer_usage_low_create();
178 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
:
179 condition
= lttng_condition_buffer_usage_high_create();
182 printf("error: Invalid buffer_usage_type\n");
188 printf("error: Could not create condition object\n");
193 if (is_threshold_ratio
) {
194 condition_status
= lttng_condition_buffer_usage_set_threshold_ratio(
195 condition
, threshold_ratio
);
197 condition_status
= lttng_condition_buffer_usage_set_threshold(
198 condition
, threshold_bytes
);
201 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
202 printf("error: Could not set threshold\n");
207 condition_status
= lttng_condition_buffer_usage_set_session_name(
208 condition
, session_name
);
209 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
210 printf("error: Could not set session name\n");
214 condition_status
= lttng_condition_buffer_usage_set_channel_name(
215 condition
, channel_name
);
216 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
217 printf("error: Could not set channel name\n");
221 condition_status
= lttng_condition_buffer_usage_set_domain_type(
222 condition
, domain_type
);
223 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
224 printf("error: Could not set domain type\n");
229 if (use_action_list
) {
230 struct lttng_action
*notify
, *group
;
232 group
= lttng_action_list_create();
234 printf("error: Could not create action list\n");
239 notify
= lttng_action_notify_create();
241 lttng_action_destroy(group
);
242 printf("error: Could not create action notify\n");
247 action_status
= lttng_action_list_add_action(group
, notify
);
248 if (action_status
!= LTTNG_ACTION_STATUS_OK
) {
249 printf("error: Could not add action notify to action list\n");
250 lttng_action_destroy(group
);
251 lttng_action_destroy(notify
);
258 action
= lttng_action_notify_create();
260 printf("error: Could not create action notify\n");
266 trigger
= lttng_trigger_create(condition
, action
);
268 printf("error: Could not create trigger\n");
273 ret_code
= lttng_register_trigger_with_automatic_name(trigger
);
276 * An equivalent trigger might already be registered if an other app
277 * registered an equivalent trigger.
279 if (ret_code
!= LTTNG_OK
&& ret_code
!= LTTNG_ERR_TRIGGER_EXISTS
) {
280 printf("error: %s\n", lttng_strerror(-ret_code
));
285 nc_status
= lttng_notification_channel_subscribe(notification_channel
, condition
);
286 if (nc_status
!= LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
) {
287 printf("error: Could not subscribe\n");
292 /* Tell outside process that the client is ready */
293 printf("sync: ready\n");
296 struct lttng_notification
*notification
;
297 enum lttng_notification_channel_status status
;
298 const struct lttng_evaluation
*notification_evaluation
;
299 const struct lttng_condition
*notification_condition
;
301 if (nr_notifications
== nr_expected_notifications
) {
305 /* Receive the next notification. */
306 status
= lttng_notification_channel_get_next_notification(
307 notification_channel
,
311 case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
:
313 case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED
:
315 printf("error: No drop should be observed during this test app\n");
317 case LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED
:
319 * The notification channel has been closed by the
320 * session daemon. This is typically caused by a session
321 * daemon shutting down (cleanly or because of a crash).
323 printf("error: Notification channel was closed\n");
327 /* Unhandled conditions / errors. */
328 printf("error: Unknown notification channel status (%d) \n", status
);
333 notification_condition
= lttng_notification_get_condition(notification
);
334 notification_evaluation
= lttng_notification_get_evaluation(notification
);
336 ret
= handle_condition(notification_condition
, notification_evaluation
);
339 lttng_notification_destroy(notification
);
346 lttng_unregister_trigger(trigger
);
348 if (lttng_notification_channel_unsubscribe(notification_channel
, condition
)) {
349 printf("error: channel unsubscribe error\n");
351 lttng_trigger_destroy(trigger
);
352 lttng_condition_destroy(condition
);
353 lttng_action_destroy(action
);
354 lttng_notification_channel_destroy(notification_channel
);
355 printf("exit: %d\n", ret
);
359 int handle_condition(
360 const struct lttng_condition
*condition
,
361 const struct lttng_evaluation
*evaluation
)
364 const char *string_low
= "low";
365 const char *string_high
= "high";
366 const char *string_condition_type
= NULL
;
367 const char *condition_session_name
= NULL
;
368 const char *condition_channel_name
= NULL
;
369 enum lttng_condition_type condition_type
;
370 enum lttng_domain_type condition_domain_type
;
371 double buffer_usage_ratio
;
372 uint64_t buffer_usage_bytes
;
374 condition_type
= lttng_condition_get_type(condition
);
376 if (condition_type
!= buffer_usage_type
) {
378 printf("error: condition type and buffer usage type are not the same\n");
382 /* Fetch info to test */
383 ret
= lttng_condition_buffer_usage_get_session_name(condition
,
384 &condition_session_name
);
386 printf("error: session name could not be fetched\n");
390 ret
= lttng_condition_buffer_usage_get_channel_name(condition
,
391 &condition_channel_name
);
393 printf("error: channel name could not be fetched\n");
397 ret
= lttng_condition_buffer_usage_get_domain_type(condition
,
398 &condition_domain_type
);
400 printf("error: domain type could not be fetched\n");
405 if (strcmp(condition_session_name
, session_name
) != 0) {
406 printf("error: session name differs\n");
411 if (strcmp(condition_channel_name
, channel_name
) != 0) {
412 printf("error: channel name differs\n");
417 if (condition_domain_type
!= domain_type
) {
418 printf("error: domain type differs\n");
423 if (is_threshold_ratio
) {
424 lttng_evaluation_buffer_usage_get_usage_ratio(
425 evaluation
, &buffer_usage_ratio
);
426 switch (condition_type
) {
427 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
:
428 if (buffer_usage_ratio
> threshold_ratio
) {
429 printf("error: buffer usage ratio is bigger than set threshold ratio\n");
434 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
:
435 if (buffer_usage_ratio
< threshold_ratio
) {
436 printf("error: buffer usage ratio is lower than set threshold ratio\n");
442 printf("error: Unknown condition type\n");
447 lttng_evaluation_buffer_usage_get_usage(
448 evaluation
, &buffer_usage_bytes
);
449 switch (condition_type
) {
450 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
:
451 if (buffer_usage_bytes
> threshold_bytes
) {
452 printf("error: buffer usage ratio is bigger than set threshold bytes\n");
457 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
:
458 if (buffer_usage_bytes
< threshold_bytes
) {
459 printf("error: buffer usage ratio is lower than set threshold bytes\n");
465 printf("error: Unknown condition type\n");
471 switch (condition_type
) {
472 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
:
473 string_condition_type
= string_low
;
475 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
:
476 string_condition_type
= string_high
;
479 printf("error: Unknown condition type\n");
484 printf("notification: %s %d\n", string_condition_type
, nr_notifications
);