Fix mi: add support for Jul loglevel
[lttng-tools.git] / src / bin / lttng / commands / list.c
1 /*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2 only,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18 #define _GNU_SOURCE
19 #include <inttypes.h>
20 #include <popt.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <assert.h>
25
26 #include <common/mi-lttng.h>
27
28 #include "../command.h"
29
30 static int opt_userspace;
31 static int opt_kernel;
32 static int opt_jul;
33 static char *opt_channel;
34 static int opt_domain;
35 static int opt_fields;
36 #if 0
37 /* Not implemented yet */
38 static char *opt_cmd_name;
39 static pid_t opt_pid;
40 #endif
41
42 const char *indent4 = " ";
43 const char *indent6 = " ";
44 const char *indent8 = " ";
45
46 enum {
47 OPT_HELP = 1,
48 OPT_USERSPACE,
49 OPT_LIST_OPTIONS,
50 };
51
52 static struct lttng_handle *handle;
53 static struct mi_writer *writer;
54
55 static struct poptOption long_options[] = {
56 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
57 {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
58 {"kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
59 {"jul", 'j', POPT_ARG_VAL, &opt_jul, 1, 0, 0},
60 #if 0
61 /* Not implemented yet */
62 {"userspace", 'u', POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_cmd_name, OPT_USERSPACE, 0, 0},
63 {"pid", 'p', POPT_ARG_INT, &opt_pid, 0, 0, 0},
64 #else
65 {"userspace", 'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
66 #endif
67 {"channel", 'c', POPT_ARG_STRING, &opt_channel, 0, 0, 0},
68 {"domain", 'd', POPT_ARG_VAL, &opt_domain, 1, 0, 0},
69 {"fields", 'f', POPT_ARG_VAL, &opt_fields, 1, 0, 0},
70 {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
71 {0, 0, 0, 0, 0, 0, 0}
72 };
73
74 /*
75 * usage
76 */
77 static void usage(FILE *ofp)
78 {
79 fprintf(ofp, "usage: lttng list [OPTIONS] [SESSION [SESSION OPTIONS]]\n");
80 fprintf(ofp, "\n");
81 fprintf(ofp, "With no arguments, list available tracing session(s)\n");
82 fprintf(ofp, "\n");
83 fprintf(ofp, "Without a session, -k lists available kernel events\n");
84 fprintf(ofp, "Without a session, -u lists available userspace events\n");
85 fprintf(ofp, "\n");
86 fprintf(ofp, " -h, --help Show this help\n");
87 fprintf(ofp, " --list-options Simple listing of options\n");
88 fprintf(ofp, " -k, --kernel Select kernel domain\n");
89 fprintf(ofp, " -u, --userspace Select user-space domain.\n");
90 fprintf(ofp, " -j, --jul Apply for Java application using JUL\n");
91 fprintf(ofp, " -f, --fields List event fields.\n");
92 #if 0
93 fprintf(ofp, " -p, --pid PID List user-space events by PID\n");
94 #endif
95 fprintf(ofp, "\n");
96 fprintf(ofp, "Session Options:\n");
97 fprintf(ofp, " -c, --channel NAME List details of a channel\n");
98 fprintf(ofp, " -d, --domain List available domain(s)\n");
99 fprintf(ofp, "\n");
100 }
101
102 /*
103 * Get command line from /proc for a specific pid.
104 *
105 * On success, return an allocated string pointer to the proc cmdline.
106 * On error, return NULL.
107 */
108 static char *get_cmdline_by_pid(pid_t pid)
109 {
110 int ret;
111 FILE *fp;
112 char *cmdline = NULL;
113 char path[20]; /* Can't go bigger than /proc/65535/cmdline */
114
115 snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
116 fp = fopen(path, "r");
117 if (fp == NULL) {
118 goto end;
119 }
120
121 /* Caller must free() *cmdline */
122 cmdline = malloc(PATH_MAX);
123 if (!cmdline) {
124 perror("malloc cmdline");
125 goto end;
126 }
127 ret = fread(cmdline, 1, PATH_MAX, fp);
128 if (ret < 0) {
129 perror("fread proc list");
130 }
131 fclose(fp);
132
133 end:
134 return cmdline;
135 }
136
137 static
138 const char *active_string(int value)
139 {
140 switch (value) {
141 case 0: return "inactive";
142 case 1: return "active";
143 case -1: return "";
144 default: return NULL;
145 }
146 }
147
148 static const char *snapshot_string(int value)
149 {
150 switch (value) {
151 case 1:
152 return " snapshot";
153 default:
154 return "";
155 }
156 }
157
158 static
159 const char *enabled_string(int value)
160 {
161 switch (value) {
162 case 0: return " [disabled]";
163 case 1: return " [enabled]";
164 case -1: return "";
165 default: return NULL;
166 }
167 }
168
169 static
170 const char *filter_string(int value)
171 {
172 switch (value) {
173 case 1: return " [with filter]";
174 default: return "";
175 }
176 }
177
178 static
179 const char *exclusion_string(int value)
180 {
181 switch (value) {
182 case 1: return " [has exclusions]";
183 default: return "";
184 }
185 }
186
187 static const char *logleveltype_string(enum lttng_loglevel_type value)
188 {
189 switch (value) {
190 case LTTNG_EVENT_LOGLEVEL_ALL:
191 return ":";
192 case LTTNG_EVENT_LOGLEVEL_RANGE:
193 return " <=";
194 case LTTNG_EVENT_LOGLEVEL_SINGLE:
195 return " ==";
196 default:
197 return " <<TYPE UNKN>>";
198 }
199 }
200
201 /*
202 * Pretty print single event.
203 */
204 static void print_events(struct lttng_event *event)
205 {
206 switch (event->type) {
207 case LTTNG_EVENT_TRACEPOINT:
208 {
209 if (event->loglevel != -1) {
210 MSG("%s%s (loglevel%s %s (%d)) (type: tracepoint)%s%s%s",
211 indent6,
212 event->name,
213 logleveltype_string(event->loglevel_type),
214 mi_lttng_loglevel_string(event->loglevel),
215 event->loglevel,
216 enabled_string(event->enabled),
217 exclusion_string(event->exclusion),
218 filter_string(event->filter));
219 } else {
220 MSG("%s%s (type: tracepoint)%s%s%s",
221 indent6,
222 event->name,
223 enabled_string(event->enabled),
224 exclusion_string(event->exclusion),
225 filter_string(event->filter));
226 }
227 break;
228 }
229 case LTTNG_EVENT_FUNCTION:
230 MSG("%s%s (type: function)%s%s", indent6,
231 event->name, enabled_string(event->enabled),
232 filter_string(event->filter));
233 if (event->attr.probe.addr != 0) {
234 MSG("%saddr: 0x%" PRIx64, indent8, event->attr.probe.addr);
235 } else {
236 MSG("%soffset: 0x%" PRIx64, indent8, event->attr.probe.offset);
237 MSG("%ssymbol: %s", indent8, event->attr.probe.symbol_name);
238 }
239 break;
240 case LTTNG_EVENT_PROBE:
241 MSG("%s%s (type: probe)%s%s", indent6,
242 event->name, enabled_string(event->enabled),
243 filter_string(event->filter));
244 if (event->attr.probe.addr != 0) {
245 MSG("%saddr: 0x%" PRIx64, indent8, event->attr.probe.addr);
246 } else {
247 MSG("%soffset: 0x%" PRIx64, indent8, event->attr.probe.offset);
248 MSG("%ssymbol: %s", indent8, event->attr.probe.symbol_name);
249 }
250 break;
251 case LTTNG_EVENT_FUNCTION_ENTRY:
252 MSG("%s%s (type: function)%s%s", indent6,
253 event->name, enabled_string(event->enabled),
254 filter_string(event->filter));
255 MSG("%ssymbol: \"%s\"", indent8, event->attr.ftrace.symbol_name);
256 break;
257 case LTTNG_EVENT_SYSCALL:
258 MSG("%ssyscalls (type: syscall)%s%s", indent6,
259 enabled_string(event->enabled),
260 filter_string(event->filter));
261 break;
262 case LTTNG_EVENT_NOOP:
263 MSG("%s (type: noop)%s%s", indent6,
264 enabled_string(event->enabled),
265 filter_string(event->filter));
266 break;
267 case LTTNG_EVENT_ALL:
268 /* We should never have "all" events in list. */
269 assert(0);
270 break;
271 }
272 }
273
274 static const char *field_type(struct lttng_event_field *field)
275 {
276 switch(field->type) {
277 case LTTNG_EVENT_FIELD_INTEGER:
278 return "integer";
279 case LTTNG_EVENT_FIELD_ENUM:
280 return "enum";
281 case LTTNG_EVENT_FIELD_FLOAT:
282 return "float";
283 case LTTNG_EVENT_FIELD_STRING:
284 return "string";
285 case LTTNG_EVENT_FIELD_OTHER:
286 default: /* fall-through */
287 return "unknown";
288 }
289 }
290
291 /*
292 * Pretty print single event fields.
293 */
294 static void print_event_field(struct lttng_event_field *field)
295 {
296 if (!field->field_name[0]) {
297 return;
298 }
299 MSG("%sfield: %s (%s)%s", indent8, field->field_name,
300 field_type(field), field->nowrite ? " [no write]" : "");
301 }
302
303 /*
304 * Machine interface
305 * Jul and ust event listing
306 */
307 static int mi_list_jul_ust_events(struct lttng_event *events, int count,
308 struct lttng_domain *domain)
309 {
310 int ret, i;
311 pid_t cur_pid = 0;
312 char *cmdline = NULL;
313 int pid_element_open = 0;
314
315 /* Open domains element */
316 ret = mi_lttng_domains_open(writer);
317 if (ret) {
318 goto end;
319 }
320
321 /* Write domain */
322 ret = mi_lttng_domain(writer, domain, 1);
323 if (ret) {
324 goto end;
325 }
326
327 /* Open pids element */
328 ret = mi_lttng_pids_open(writer);
329 if (ret) {
330 goto end;
331 }
332
333 for (i = 0; i < count; i++) {
334 if (cur_pid != events[i].pid) {
335 if (pid_element_open) {
336 /* Close the previous events and pid element */
337 ret = mi_lttng_close_multi_element(writer, 2);
338 if (ret) {
339 goto end;
340 }
341 pid_element_open = 0;
342 }
343
344 cur_pid = events[i].pid;
345 cmdline = get_cmdline_by_pid(cur_pid);
346 if (!cmdline) {
347 ret = CMD_ERROR;
348 goto end;
349 }
350
351 if (!pid_element_open) {
352 /* Open and write a pid element */
353 ret = mi_lttng_pid(writer, cur_pid, cmdline, 1);
354 if (ret) {
355 goto error;
356 }
357
358 /* Open events element */
359 ret = mi_lttng_events_open(writer);
360 if (ret) {
361 goto error;
362 }
363
364 pid_element_open = 1;
365 }
366 free(cmdline);
367 }
368
369 /* Write an event */
370 ret = mi_lttng_event(writer, &events[i], 0);
371 if (ret) {
372 goto end;
373 }
374 }
375
376 /* Close pids */
377 ret = mi_lttng_writer_close_element(writer);
378 if (ret) {
379 goto end;
380 }
381
382 /* Close domain, domains */
383 ret = mi_lttng_close_multi_element(writer, 2);
384 end:
385 return ret;
386 error:
387 free(cmdline);
388 return ret;
389 }
390
391 static int list_jul_events(void)
392 {
393 int i, size, ret = CMD_SUCCESS;
394 struct lttng_domain domain;
395 struct lttng_handle *handle;
396 struct lttng_event *event_list;
397 pid_t cur_pid = 0;
398 char *cmdline = NULL;
399
400 DBG("Getting JUL tracing events");
401
402 memset(&domain, 0, sizeof(domain));
403 domain.type = LTTNG_DOMAIN_JUL;
404
405 handle = lttng_create_handle(NULL, &domain);
406 if (handle == NULL) {
407 ret = CMD_ERROR;
408 goto end;
409 }
410
411 size = lttng_list_tracepoints(handle, &event_list);
412 if (size < 0) {
413 ERR("Unable to list JUL events: %s", lttng_strerror(size));
414 ret = CMD_ERROR;
415 goto end;
416 }
417
418 if (lttng_opt_mi) {
419 /* Mi print */
420 ret = mi_list_jul_ust_events(event_list, size, &domain);
421 if (ret) {
422 ret = CMD_ERROR;
423 goto error;
424 }
425 } else {
426 /* Pretty print */
427 MSG("JUL events (Logger name):\n-------------------------");
428
429 if (size == 0) {
430 MSG("None");
431 }
432
433 for (i = 0; i < size; i++) {
434 if (cur_pid != event_list[i].pid) {
435 cur_pid = event_list[i].pid;
436 cmdline = get_cmdline_by_pid(cur_pid);
437 if (cmdline == NULL) {
438 ret = CMD_ERROR;
439 goto error;
440 }
441 MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
442 free(cmdline);
443 }
444 MSG("%s- %s", indent6, event_list[i].name);
445 }
446
447 MSG("");
448 }
449
450 error:
451 free(event_list);
452 end:
453 lttng_destroy_handle(handle);
454 return ret;
455 }
456
457 /*
458 * Ask session daemon for all user space tracepoints available.
459 */
460 static int list_ust_events(void)
461 {
462 int i, size, ret = CMD_SUCCESS;
463 struct lttng_domain domain;
464 struct lttng_handle *handle;
465 struct lttng_event *event_list;
466 pid_t cur_pid = 0;
467 char *cmdline = NULL;
468
469 memset(&domain, 0, sizeof(domain));
470
471 DBG("Getting UST tracing events");
472
473 domain.type = LTTNG_DOMAIN_UST;
474
475 handle = lttng_create_handle(NULL, &domain);
476 if (handle == NULL) {
477 ret = CMD_ERROR;
478 goto end;
479 }
480
481 size = lttng_list_tracepoints(handle, &event_list);
482 if (size < 0) {
483 ERR("Unable to list UST events: %s", lttng_strerror(size));
484 ret = CMD_ERROR;
485 goto error;
486 }
487
488 if (lttng_opt_mi) {
489 /* Mi print */
490 ret = mi_list_jul_ust_events(event_list, size, &domain);
491 } else {
492 /* Pretty print */
493 MSG("UST events:\n-------------");
494
495 if (size == 0) {
496 MSG("None");
497 }
498
499 for (i = 0; i < size; i++) {
500 if (cur_pid != event_list[i].pid) {
501 cur_pid = event_list[i].pid;
502 cmdline = get_cmdline_by_pid(cur_pid);
503 if (cmdline == NULL) {
504 ret = CMD_ERROR;
505 goto error;
506 }
507 MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
508 free(cmdline);
509 }
510 print_events(&event_list[i]);
511 }
512
513 MSG("");
514 }
515
516 error:
517 free(event_list);
518 end:
519 lttng_destroy_handle(handle);
520 return ret;
521 }
522
523 /*
524 * Machine interface
525 * List all ust event with their fields
526 */
527 static int mi_list_ust_event_fields(struct lttng_event_field *fields, int count,
528 struct lttng_domain *domain)
529 {
530 int ret, i;
531 pid_t cur_pid = 0;
532 char *cmdline = NULL;
533 int pid_element_open = 0;
534 int event_element_open = 0;
535 struct lttng_event cur_event;
536
537 /* Open domains element */
538 ret = mi_lttng_domains_open(writer);
539 if (ret) {
540 goto end;
541 }
542
543 /* Write domain */
544 ret = mi_lttng_domain(writer, domain, 1);
545 if (ret) {
546 goto end;
547 }
548
549 /* Open pids element */
550 ret = mi_lttng_pids_open(writer);
551 if (ret) {
552 goto end;
553 }
554
555 for (i = 0; i < count; i++) {
556 if (cur_pid != fields[i].event.pid) {
557 if (pid_element_open) {
558 if (event_element_open) {
559 /*
560 * Close the previous fields element
561 * and the previous event
562 */
563 ret = mi_lttng_close_multi_element(writer, 2);
564 if (ret) {
565 goto end;
566 }
567 event_element_open = 0;
568 }
569 /* Close the previous events, pid element */
570 ret = mi_lttng_close_multi_element(writer, 2);
571 if (ret) {
572 goto end;
573 }
574 pid_element_open = 0;
575 }
576
577 cur_pid = fields[i].event.pid;
578 cmdline = get_cmdline_by_pid(cur_pid);
579 if (!pid_element_open) {
580 /* Open and write a pid element */
581 ret = mi_lttng_pid(writer, cur_pid, cmdline, 1);
582 if (ret) {
583 goto error;
584 }
585
586 /* Open events element */
587 ret = mi_lttng_events_open(writer);
588 if (ret) {
589 goto error;
590 }
591 pid_element_open = 1;
592 }
593 free(cmdline);
594 /* Wipe current event since we are about to print a new PID. */
595 memset(&cur_event, 0, sizeof(cur_event));
596 }
597
598 if (strcmp(cur_event.name, fields[i].event.name) != 0) {
599 if (event_element_open) {
600 /* Close the previous fields element and the previous event */
601 ret = mi_lttng_close_multi_element(writer, 2);
602 if (ret) {
603 goto end;
604 }
605 event_element_open = 0;
606 }
607
608 memcpy(&cur_event, &fields[i].event,
609 sizeof(cur_event));
610
611 if (!event_element_open) {
612 /* Open and write the event */
613 ret = mi_lttng_event(writer, &cur_event, 1);
614 if (ret) {
615 goto end;
616 }
617
618 /* Open a fields element */
619 ret = mi_lttng_event_fields_open(writer);
620 if (ret) {
621 goto end;
622 }
623 event_element_open = 1;
624 }
625 }
626
627 /* Print the event_field */
628 ret = mi_lttng_event_field(writer, &fields[i]);
629 if (ret) {
630 goto end;
631 }
632 }
633
634 /* Close pids, domain, domains */
635 ret = mi_lttng_close_multi_element(writer, 3);
636 end:
637 return ret;
638 error:
639 free(cmdline);
640 return ret;
641 }
642
643 /*
644 * Ask session daemon for all user space tracepoint fields available.
645 */
646 static int list_ust_event_fields(void)
647 {
648 int i, size, ret = CMD_SUCCESS;
649 struct lttng_domain domain;
650 struct lttng_handle *handle;
651 struct lttng_event_field *event_field_list;
652 pid_t cur_pid = 0;
653 char *cmdline = NULL;
654
655 struct lttng_event cur_event;
656
657 memset(&domain, 0, sizeof(domain));
658 memset(&cur_event, 0, sizeof(cur_event));
659
660 DBG("Getting UST tracing event fields");
661
662 domain.type = LTTNG_DOMAIN_UST;
663
664 handle = lttng_create_handle(NULL, &domain);
665 if (handle == NULL) {
666 ret = CMD_ERROR;
667 goto end;
668 }
669
670 size = lttng_list_tracepoint_fields(handle, &event_field_list);
671 if (size < 0) {
672 ERR("Unable to list UST event fields: %s", lttng_strerror(size));
673 ret = CMD_ERROR;
674 goto end;
675 }
676
677 if (lttng_opt_mi) {
678 /* Mi print */
679 ret = mi_list_ust_event_fields(event_field_list, size, &domain);
680 if (ret) {
681 ret = CMD_ERROR;
682 goto error;
683 }
684 } else {
685 /* Pretty print */
686 MSG("UST events:\n-------------");
687
688 if (size == 0) {
689 MSG("None");
690 }
691
692 for (i = 0; i < size; i++) {
693 if (cur_pid != event_field_list[i].event.pid) {
694 cur_pid = event_field_list[i].event.pid;
695 cmdline = get_cmdline_by_pid(cur_pid);
696 if (cmdline == NULL) {
697 ret = CMD_ERROR;
698 goto error;
699 }
700 MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
701 free(cmdline);
702 /* Wipe current event since we are about to print a new PID. */
703 memset(&cur_event, 0, sizeof(cur_event));
704 }
705 if (strcmp(cur_event.name, event_field_list[i].event.name) != 0) {
706 print_events(&event_field_list[i].event);
707 memcpy(&cur_event, &event_field_list[i].event,
708 sizeof(cur_event));
709 }
710 print_event_field(&event_field_list[i]);
711 }
712
713 MSG("");
714 }
715
716 error:
717 free(event_field_list);
718 end:
719 lttng_destroy_handle(handle);
720 return ret;
721 }
722
723 /*
724 * Machine interface
725 * Print a list of kernel events
726 */
727 static int mi_list_kernel_events(struct lttng_event *events, int count,
728 struct lttng_domain *domain)
729 {
730 int ret, i;
731
732 /* Open domains element */
733 ret = mi_lttng_domains_open(writer);
734 if (ret) {
735 goto end;
736 }
737
738 /* Write domain */
739 ret = mi_lttng_domain(writer, domain, 1);
740 if (ret) {
741 goto end;
742 }
743
744 /* Open events */
745 ret = mi_lttng_events_open(writer);
746 if (ret) {
747 goto end;
748 }
749
750 for (i = 0; i < count; i++) {
751 mi_lttng_event(writer, &events[i], 0);
752 if (ret) {
753 goto end;
754 }
755 }
756
757 /* close events, domain and domains */
758 ret = mi_lttng_close_multi_element(writer, 3);
759 if (ret) {
760 goto end;
761 }
762
763 end:
764 return ret;
765 }
766
767 /*
768 * Ask for all trace events in the kernel
769 */
770 static int list_kernel_events(void)
771 {
772 int i, size, ret = CMD_SUCCESS;
773 struct lttng_domain domain;
774 struct lttng_handle *handle;
775 struct lttng_event *event_list;
776
777 memset(&domain, 0, sizeof(domain));
778
779 DBG("Getting kernel tracing events");
780
781 domain.type = LTTNG_DOMAIN_KERNEL;
782
783 handle = lttng_create_handle(NULL, &domain);
784 if (handle == NULL) {
785 ret = CMD_ERROR;
786 goto error;
787 }
788
789 size = lttng_list_tracepoints(handle, &event_list);
790 if (size < 0) {
791 ERR("Unable to list kernel events: %s", lttng_strerror(size));
792 lttng_destroy_handle(handle);
793 return CMD_ERROR;
794 }
795
796 if (lttng_opt_mi) {
797 /* Mi print */
798 ret = mi_list_kernel_events(event_list, size, &domain);
799 if (ret) {
800 ret = CMD_ERROR;
801 goto end;
802 }
803 } else {
804 MSG("Kernel events:\n-------------");
805
806 for (i = 0; i < size; i++) {
807 print_events(&event_list[i]);
808 }
809
810 MSG("");
811 }
812
813 end:
814 free(event_list);
815
816 lttng_destroy_handle(handle);
817 return ret;
818
819 error:
820 lttng_destroy_handle(handle);
821 return ret;
822 }
823
824 /*
825 * Machine Interface
826 * Print a list of jul events
827 */
828 static int mi_list_session_jul_events(struct lttng_event *events, int count)
829 {
830 int ret, i;
831
832 /* Open events element */
833 ret = mi_lttng_events_open(writer);
834 if (ret) {
835 goto end;
836 }
837
838 for (i = 0; i < count; i++) {
839 ret = mi_lttng_event(writer, &events[i], 0);
840 if (ret) {
841 goto end;
842 }
843 }
844
845 /* Close events element */
846 ret = mi_lttng_writer_close_element(writer);
847
848 end:
849 return ret;
850 }
851
852 /*
853 * List JUL events for a specific session using the handle.
854 *
855 * Return CMD_SUCCESS on success else a negative value.
856 */
857 static int list_session_jul_events(void)
858 {
859 int ret = CMD_SUCCESS, count, i;
860 struct lttng_event *events = NULL;
861
862 count = lttng_list_events(handle, "", &events);
863 if (count < 0) {
864 ret = CMD_ERROR;
865 ERR("%s", lttng_strerror(count));
866 goto error;
867 }
868
869 if (lttng_opt_mi) {
870 /* Mi print */
871 ret = mi_list_session_jul_events(events, count);
872 if (ret) {
873 ret = CMD_ERROR;
874 goto end;
875 }
876 } else {
877 /* Pretty print */
878 MSG("Events (Logger name):\n---------------------");
879 if (count == 0) {
880 MSG("%sNone\n", indent6);
881 goto end;
882 }
883
884 for (i = 0; i < count; i++) {
885 MSG("%s- %s%s (loglevel%s %s)", indent4, events[i].name,
886 enabled_string(events[i].enabled),
887 logleveltype_string(events[i].loglevel_type),
888 mi_lttng_loglevel_string(events[i].loglevel));
889 }
890
891 MSG("");
892 }
893
894 end:
895 free(events);
896 error:
897 return ret;
898 }
899
900 /*
901 * Machine interface
902 * print a list of event
903 */
904 static int mi_list_events(struct lttng_event *events, int count)
905 {
906 int ret, i;
907
908 /* Open events element */
909 ret = mi_lttng_events_open(writer);
910 if (ret) {
911 goto end;
912 }
913
914 for (i = 0; i < count; i++) {
915 ret = mi_lttng_event(writer, &events[i], 0);
916 if (ret) {
917 goto end;
918 }
919 }
920
921 /* Close events element */
922 ret = mi_lttng_writer_close_element(writer);
923
924 end:
925 return ret;
926 }
927
928 /*
929 * List events of channel of session and domain.
930 */
931 static int list_events(const char *channel_name)
932 {
933 int ret = CMD_SUCCESS, count, i;
934 struct lttng_event *events = NULL;
935
936 count = lttng_list_events(handle, channel_name, &events);
937 if (count < 0) {
938 ret = CMD_ERROR;
939 ERR("%s", lttng_strerror(count));
940 goto error;
941 }
942
943 if (lttng_opt_mi) {
944 /* Mi print */
945 ret = mi_list_events(events, count);
946 if (ret) {
947 ret = CMD_ERROR;
948 goto end;
949 }
950 } else {
951 /* Pretty print */
952 MSG("\n%sEvents:", indent4);
953 if (count == 0) {
954 MSG("%sNone\n", indent6);
955 goto end;
956 }
957
958 for (i = 0; i < count; i++) {
959 print_events(&events[i]);
960 }
961
962 MSG("");
963 }
964 end:
965 free(events);
966 error:
967 return ret;
968 }
969
970 /*
971 * Pretty print channel
972 */
973 static void print_channel(struct lttng_channel *channel)
974 {
975 MSG("- %s:%s\n", channel->name, enabled_string(channel->enabled));
976
977 MSG("%sAttributes:", indent4);
978 MSG("%soverwrite mode: %d", indent6, channel->attr.overwrite);
979 MSG("%ssubbufers size: %" PRIu64, indent6, channel->attr.subbuf_size);
980 MSG("%snumber of subbufers: %" PRIu64, indent6, channel->attr.num_subbuf);
981 MSG("%sswitch timer interval: %u", indent6, channel->attr.switch_timer_interval);
982 MSG("%sread timer interval: %u", indent6, channel->attr.read_timer_interval);
983 MSG("%strace file count: %" PRIu64, indent6, channel->attr.tracefile_count);
984 MSG("%strace file size (bytes): %" PRIu64, indent6, channel->attr.tracefile_size);
985 switch (channel->attr.output) {
986 case LTTNG_EVENT_SPLICE:
987 MSG("%soutput: splice()", indent6);
988 break;
989 case LTTNG_EVENT_MMAP:
990 MSG("%soutput: mmap()", indent6);
991 break;
992 }
993 }
994
995 /*
996 * Machine interface
997 * Print a list of channel
998 *
999 */
1000 static int mi_list_channels(struct lttng_channel *channels, int count,
1001 const char *channel_name)
1002 {
1003 int i, ret;
1004 unsigned int chan_found = 0;
1005
1006 /* Open channels element */
1007 ret = mi_lttng_channels_open(writer);
1008 if (ret) {
1009 goto error;
1010 }
1011
1012 for (i = 0; i < count; i++) {
1013 if (channel_name != NULL) {
1014 if (strncmp(channels[i].name, channel_name, NAME_MAX) == 0) {
1015 chan_found = 1;
1016 } else {
1017 continue;
1018 }
1019 }
1020
1021 /* Write channel element and leave it open */
1022 ret = mi_lttng_channel(writer, &channels[i], 1);
1023 if (ret) {
1024 goto error;
1025 }
1026
1027 /* Listing events per channel */
1028 ret = list_events(channels[i].name);
1029 if (ret) {
1030 goto error;
1031 }
1032
1033 /* Closing the channel element we opened earlier */
1034 ret = mi_lttng_writer_close_element(writer);
1035 if (ret) {
1036 goto error;
1037 }
1038
1039 if (chan_found) {
1040 break;
1041 }
1042 }
1043
1044 /* Close channels element */
1045 ret = mi_lttng_writer_close_element(writer);
1046 if (ret) {
1047 goto error;
1048 }
1049
1050 error:
1051 return ret;
1052 }
1053
1054 /*
1055 * List channel(s) of session and domain.
1056 *
1057 * If channel_name is NULL, all channels are listed.
1058 */
1059 static int list_channels(const char *channel_name)
1060 {
1061 int count, i, ret = CMD_SUCCESS;
1062 unsigned int chan_found = 0;
1063 struct lttng_channel *channels = NULL;
1064
1065 DBG("Listing channel(s) (%s)", channel_name ? : "<all>");
1066
1067 count = lttng_list_channels(handle, &channels);
1068 if (count < 0) {
1069 switch (-count) {
1070 case LTTNG_ERR_KERN_CHAN_NOT_FOUND:
1071 if (lttng_opt_mi) {
1072 /* When printing mi this is not an error
1073 * but an empty channels element */
1074 count = 0;
1075 } else {
1076 ret = CMD_SUCCESS;
1077 WARN("No kernel channel");
1078 goto error_channels;
1079 }
1080 break;
1081 default:
1082 /* We had a real error */
1083 ret = CMD_ERROR;
1084 ERR("%s", lttng_strerror(count));
1085 goto error_channels;
1086 break;
1087 }
1088 }
1089
1090 if (lttng_opt_mi) {
1091 /* Mi print */
1092 ret = mi_list_channels(channels, count, channel_name);
1093 if (ret) {
1094 ret = CMD_ERROR;
1095 goto error;
1096 }
1097 } else {
1098 /* Pretty print */
1099 if (channel_name == NULL) {
1100 MSG("Channels:\n-------------");
1101 }
1102
1103 for (i = 0; i < count; i++) {
1104 if (channel_name != NULL) {
1105 if (strncmp(channels[i].name, channel_name, NAME_MAX) == 0) {
1106 chan_found = 1;
1107 } else {
1108 continue;
1109 }
1110 }
1111 print_channel(&channels[i]);
1112
1113 /* Listing events per channel */
1114 ret = list_events(channels[i].name);
1115 if (ret) {
1116 goto error;
1117 }
1118
1119 if (chan_found) {
1120 break;
1121 }
1122 }
1123
1124 if (!chan_found && channel_name != NULL) {
1125 ret = CMD_ERROR;
1126 ERR("Channel %s not found", channel_name);
1127 goto error;
1128 }
1129 }
1130 error:
1131 free(channels);
1132
1133 error_channels:
1134 return ret;
1135 }
1136
1137 /*
1138 * Machine interface
1139 * Find the session with session_name as name
1140 * and print his informations.
1141 */
1142 static int mi_list_session(const char *session_name,
1143 struct lttng_session *sessions, int count)
1144 {
1145 int ret, i;
1146 unsigned int session_found = 0;
1147
1148 if (session_name == NULL) {
1149 ret = -LTTNG_ERR_SESS_NOT_FOUND;
1150 goto end;
1151 }
1152
1153 for (i = 0; i < count; i++) {
1154 if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
1155 /* We need to leave it open to append other informations
1156 * like domain, channel, events etc.*/
1157 session_found = 1;
1158 ret = mi_lttng_session(writer, &sessions[i], 1);
1159 if (ret) {
1160 goto end;
1161 }
1162 break;
1163 }
1164 }
1165
1166 if (!session_found) {
1167 ERR("Session '%s' not found", session_name);
1168 ret = -LTTNG_ERR_SESS_NOT_FOUND;
1169 goto end;
1170 }
1171
1172 end:
1173 return ret;
1174 }
1175
1176 /*
1177 * Machine interface
1178 * List all availables session
1179 */
1180 static int mi_list_sessions(struct lttng_session *sessions, int count)
1181 {
1182 int ret, i;
1183
1184 /* Opening sessions element */
1185 ret = mi_lttng_sessions_open(writer);
1186 if (ret) {
1187 goto end;
1188 }
1189
1190 /* Listing sessions */
1191 for (i = 0; i < count; i++) {
1192 ret = mi_lttng_session(writer, &sessions[i], 0);
1193 if (ret) {
1194 goto end;
1195 }
1196 }
1197
1198 /* Closing sessions element */
1199 ret = mi_lttng_writer_close_element(writer);
1200 if (ret) {
1201 goto end;
1202 }
1203
1204 end:
1205 return ret;
1206 }
1207
1208 /*
1209 * List available tracing session. List only basic information.
1210 *
1211 * If session_name is NULL, all sessions are listed.
1212 */
1213 static int list_sessions(const char *session_name)
1214 {
1215 int ret = CMD_SUCCESS;
1216 int count, i;
1217 unsigned int session_found = 0;
1218 struct lttng_session *sessions;
1219
1220 count = lttng_list_sessions(&sessions);
1221 DBG("Session count %d", count);
1222 if (count < 0) {
1223 ret = CMD_ERROR;
1224 ERR("%s", lttng_strerror(count));
1225 goto end;
1226 }
1227
1228 if (lttng_opt_mi) {
1229 /* Mi */
1230 if (session_name == NULL) {
1231 /* List all session */
1232 ret = mi_list_sessions(sessions, count);
1233 } else {
1234 /* Note : this return an open session element */
1235 ret = mi_list_session(session_name, sessions, count);
1236 }
1237 if (ret) {
1238 ret = CMD_ERROR;
1239 goto error;
1240 }
1241 } else {
1242 /* Pretty print */
1243 if (count == 0) {
1244 MSG("Currently no available tracing session");
1245 ret = CMD_ERROR;
1246 goto end;
1247 }
1248
1249 if (session_name == NULL) {
1250 MSG("Available tracing sessions:");
1251 }
1252
1253
1254 for (i = 0; i < count; i++) {
1255 if (session_name != NULL) {
1256 if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
1257 session_found = 1;
1258 MSG("Tracing session %s: [%s%s]", session_name,
1259 active_string(sessions[i].enabled),
1260 snapshot_string(sessions[i].snapshot_mode));
1261 MSG("%sTrace path: %s\n", indent4, sessions[i].path);
1262 break;
1263 }
1264 } else {
1265 MSG(" %d) %s (%s) [%s%s]", i + 1,
1266 sessions[i].name, sessions[i].path,
1267 active_string(sessions[i].enabled),
1268 snapshot_string(sessions[i].snapshot_mode));
1269 MSG("%sTrace path: %s", indent4, sessions[i].path);
1270 MSG("%sLive timer interval (usec): %u\n", indent4,
1271 sessions[i].live_timer_interval);
1272 break;
1273 }
1274 }
1275
1276 if (!session_found && session_name != NULL) {
1277 ERR("Session '%s' not found", session_name);
1278 ret = CMD_ERROR;
1279 goto error;
1280 }
1281
1282 if (session_name == NULL) {
1283 MSG("\nUse lttng list <session_name> for more details");
1284 }
1285 }
1286
1287 error:
1288 free(sessions);
1289 end:
1290 return ret;
1291 }
1292
1293
1294 /*
1295 * Machine Interface
1296 * list available domain(s) for a session.
1297 */
1298 static int mi_list_domains(struct lttng_domain *domains, int count)
1299 {
1300 int i, ret;
1301 /* Open domains element */
1302 ret = mi_lttng_domains_open(writer);
1303 if (ret) {
1304 goto end;
1305 }
1306
1307 for (i = 0; i < count; i++) {
1308 ret = mi_lttng_domain(writer, &domains[i] , 0);
1309 if (ret) {
1310 goto end;
1311 }
1312 }
1313
1314 /* Closing domains element */
1315 ret = mi_lttng_writer_close_element(writer);
1316 if (ret) {
1317 goto end;
1318 }
1319 end:
1320 return ret;
1321 }
1322
1323 /*
1324 * List available domain(s) for a session.
1325 */
1326 static int list_domains(const char *session_name)
1327 {
1328 int i, count, ret = CMD_SUCCESS;
1329 struct lttng_domain *domains = NULL;
1330
1331
1332 count = lttng_list_domains(session_name, &domains);
1333 if (count < 0) {
1334 ret = CMD_ERROR;
1335 ERR("%s", lttng_strerror(count));
1336 goto end;
1337 }
1338
1339 if (lttng_opt_mi) {
1340 /* Mi output */
1341 ret = mi_list_domains(domains, count);
1342 if (ret) {
1343 ret = CMD_ERROR;
1344 goto error;
1345 }
1346 } else {
1347 /* Pretty print */
1348 MSG("Domains:\n-------------");
1349 if (count == 0) {
1350 MSG(" None");
1351 goto end;
1352 }
1353
1354 for (i = 0; i < count; i++) {
1355 switch (domains[i].type) {
1356 case LTTNG_DOMAIN_KERNEL:
1357 MSG(" - Kernel");
1358 break;
1359 case LTTNG_DOMAIN_UST:
1360 MSG(" - UST global");
1361 break;
1362 case LTTNG_DOMAIN_JUL:
1363 MSG(" - JUL (Java Util Logging)");
1364 break;
1365 default:
1366 break;
1367 }
1368 }
1369 }
1370
1371 error:
1372 free(domains);
1373
1374 end:
1375 return ret;
1376 }
1377
1378 /*
1379 * The 'list <options>' first level command
1380 */
1381 int cmd_list(int argc, const char **argv)
1382 {
1383 int opt, ret = CMD_SUCCESS;
1384 const char *session_name;
1385 static poptContext pc;
1386 struct lttng_domain domain;
1387 struct lttng_domain *domains = NULL;
1388
1389 memset(&domain, 0, sizeof(domain));
1390
1391 if (argc < 1) {
1392 usage(stderr);
1393 ret = CMD_ERROR;
1394 goto end;
1395 }
1396
1397 pc = poptGetContext(NULL, argc, argv, long_options, 0);
1398 poptReadDefaultConfig(pc, 0);
1399
1400 while ((opt = poptGetNextOpt(pc)) != -1) {
1401 switch (opt) {
1402 case OPT_HELP:
1403 usage(stdout);
1404 goto end;
1405 case OPT_USERSPACE:
1406 opt_userspace = 1;
1407 break;
1408 case OPT_LIST_OPTIONS:
1409 list_cmd_options(stdout, long_options);
1410 goto end;
1411 default:
1412 usage(stderr);
1413 ret = CMD_UNDEFINED;
1414 goto end;
1415 }
1416 }
1417
1418 /* Mi check */
1419 if (lttng_opt_mi) {
1420 writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
1421 if (!writer) {
1422 ret = CMD_ERROR;
1423 goto end;
1424 }
1425
1426 /* Open command element */
1427 ret = mi_lttng_writer_command_open(writer,
1428 mi_lttng_element_command_list);
1429 if (ret) {
1430 ret = CMD_ERROR;
1431 goto end;
1432 }
1433
1434 /* Open output element */
1435 ret = mi_lttng_writer_open_element(writer,
1436 mi_lttng_element_command_output);
1437 if (ret) {
1438 ret = CMD_ERROR;
1439 goto end;
1440 }
1441 }
1442
1443 /* Get session name (trailing argument) */
1444 session_name = poptGetArg(pc);
1445 DBG2("Session name: %s", session_name);
1446
1447 if (opt_kernel) {
1448 domain.type = LTTNG_DOMAIN_KERNEL;
1449 } else if (opt_userspace) {
1450 DBG2("Listing userspace global domain");
1451 domain.type = LTTNG_DOMAIN_UST;
1452 } else if (opt_jul) {
1453 DBG2("Listing JUL domain");
1454 domain.type = LTTNG_DOMAIN_JUL;
1455 }
1456
1457 if (opt_kernel || opt_userspace || opt_jul) {
1458 handle = lttng_create_handle(session_name, &domain);
1459 if (handle == NULL) {
1460 ret = CMD_FATAL;
1461 goto end;
1462 }
1463 }
1464
1465 if (session_name == NULL) {
1466 if (!opt_kernel && !opt_userspace && !opt_jul) {
1467 ret = list_sessions(NULL);
1468 if (ret) {
1469 goto end;
1470 }
1471 }
1472 if (opt_kernel) {
1473 ret = list_kernel_events();
1474 if (ret) {
1475 goto end;
1476 }
1477 }
1478 if (opt_userspace) {
1479 if (opt_fields) {
1480 ret = list_ust_event_fields();
1481 } else {
1482 ret = list_ust_events();
1483 }
1484 if (ret) {
1485 goto end;
1486 }
1487 }
1488 if (opt_jul) {
1489 ret = list_jul_events();
1490 if (ret) {
1491 goto end;
1492 }
1493 }
1494 } else {
1495 /* List session attributes */
1496 if (lttng_opt_mi) {
1497 /* Open element sessions
1498 * Present for xml consistency */
1499 ret = mi_lttng_sessions_open(writer);
1500 if (ret) {
1501 goto end;
1502 }
1503 }
1504 /* MI: the ouptut of list_sessions is an unclosed session element */
1505 ret = list_sessions(session_name);
1506 if (ret) {
1507 goto end;
1508 }
1509
1510 /* Domain listing */
1511 if (opt_domain) {
1512 ret = list_domains(session_name);
1513 goto end;
1514 }
1515
1516 /* Channel listing */
1517 if (opt_kernel || opt_userspace) {
1518 if (lttng_opt_mi) {
1519 /* Add of domains and domain element for xml
1520 * consistency and validation
1521 */
1522 ret = mi_lttng_domains_open(writer);
1523 if (ret) {
1524 goto end;
1525 }
1526
1527 /* Open domain and leave it open for
1528 * nested channels printing */
1529 ret = mi_lttng_domain(writer, &domain, 1);
1530 if (ret) {
1531 goto end;
1532 }
1533
1534 }
1535
1536 ret = list_channels(opt_channel);
1537 if (ret) {
1538 goto end;
1539 }
1540
1541 if (lttng_opt_mi) {
1542 /* Close domain and domain element */
1543 ret = mi_lttng_close_multi_element(writer, 2);
1544 }
1545 if (ret) {
1546 goto end;
1547 }
1548
1549
1550 } else {
1551 int i, nb_domain;
1552
1553 /* We want all domain(s) */
1554 nb_domain = lttng_list_domains(session_name, &domains);
1555 if (nb_domain < 0) {
1556 ret = CMD_ERROR;
1557 ERR("%s", lttng_strerror(nb_domain));
1558 goto end;
1559 }
1560
1561 if (lttng_opt_mi) {
1562 ret = mi_lttng_domains_open(writer);
1563 if (ret) {
1564 ret = CMD_ERROR;
1565 goto end;
1566 }
1567 }
1568
1569 for (i = 0; i < nb_domain; i++) {
1570 switch (domains[i].type) {
1571 case LTTNG_DOMAIN_KERNEL:
1572 MSG("=== Domain: Kernel ===\n");
1573 break;
1574 case LTTNG_DOMAIN_UST:
1575 MSG("=== Domain: UST global ===\n");
1576 MSG("Buffer type: %s\n",
1577 domains[i].buf_type ==
1578 LTTNG_BUFFER_PER_PID ? "per PID" : "per UID");
1579 break;
1580 case LTTNG_DOMAIN_JUL:
1581 MSG("=== Domain: JUL (Java Util Logging) ===\n");
1582 break;
1583 default:
1584 MSG("=== Domain: Unimplemented ===\n");
1585 break;
1586 }
1587
1588 if (lttng_opt_mi) {
1589 ret = mi_lttng_domain(writer, &domains[i], 1);
1590 if (ret) {
1591 ret = CMD_ERROR;
1592 goto end;
1593 }
1594 }
1595
1596 /* Clean handle before creating a new one */
1597 if (handle) {
1598 lttng_destroy_handle(handle);
1599 }
1600
1601 handle = lttng_create_handle(session_name, &domains[i]);
1602 if (handle == NULL) {
1603 ret = CMD_FATAL;
1604 goto end;
1605 }
1606
1607 if (domains[i].type == LTTNG_DOMAIN_JUL) {
1608 ret = list_session_jul_events();
1609 if (ret) {
1610 goto end;
1611 }
1612 continue;
1613 }
1614
1615 ret = list_channels(opt_channel);
1616 if (ret) {
1617 goto end;
1618 }
1619
1620 if (lttng_opt_mi) {
1621 /* Close domain element */
1622 ret = mi_lttng_writer_close_element(writer);
1623 if (ret) {
1624 ret = CMD_ERROR;
1625 goto end;
1626 }
1627 }
1628
1629 }
1630 if (lttng_opt_mi) {
1631 /* Close the domains, session and sessions element */
1632 ret = mi_lttng_close_multi_element(writer, 3);
1633 if (ret) {
1634 ret = CMD_ERROR;
1635 goto end;
1636 }
1637 }
1638 }
1639 }
1640
1641 /* Mi closing */
1642 if (lttng_opt_mi) {
1643 /* Close output element */
1644 ret = mi_lttng_writer_close_element(writer);
1645 if (ret) {
1646 ret = CMD_ERROR;
1647 goto end;
1648 }
1649
1650 /* Command element close */
1651 ret = mi_lttng_writer_command_close(writer);
1652 if (ret) {
1653 ret = CMD_ERROR;
1654 goto end;
1655 }
1656 }
1657 end:
1658 /* Mi clean-up */
1659 if (writer && mi_lttng_writer_destroy(writer)) {
1660 /* Preserve original error code */
1661 ret = ret ? ret : -LTTNG_ERR_MI_IO_FAIL;
1662 }
1663
1664 free(domains);
1665 if (handle) {
1666 lttng_destroy_handle(handle);
1667 }
1668
1669 poptFreeContext(pc);
1670 return ret;
1671 }
This page took 0.097796 seconds and 4 git commands to generate.