X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng%2Fcommands%2Fenable_events.c;h=07f5f1a9876c49c3d8214e026ed4fb1132a31d89;hp=556538daddd87444019e7013933803599c48c50c;hb=313f1ac75c27b873b80e519ce0003fda3c3b2740;hpb=b2064f542c84041bf0b991d7d83f9e85db8adc19 diff --git a/src/bin/lttng/commands/enable_events.c b/src/bin/lttng/commands/enable_events.c index 556538dad..07f5f1a98 100644 --- a/src/bin/lttng/commands/enable_events.c +++ b/src/bin/lttng/commands/enable_events.c @@ -16,6 +16,7 @@ */ #define _GNU_SOURCE +#define _LGPL_SOURCE #include #include #include @@ -27,9 +28,17 @@ #include #include -#include "../command.h" #include +/* Mi dependancy */ +#include + +#include "../command.h" + +#if (LTTNG_SYMBOL_NAME_LEN == 256) +#define LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "255" +#endif + static char *opt_event_list; static int opt_event_type; static const char *opt_loglevel; @@ -38,25 +47,20 @@ static int opt_kernel; static char *opt_session_name; static int opt_userspace; static int opt_jul; +static int opt_log4j; +static int opt_python; static int opt_enable_all; static char *opt_probe; static char *opt_function; -static char *opt_function_entry_symbol; static char *opt_channel_name; static char *opt_filter; static char *opt_exclude; -#if 0 -/* Not implemented yet */ -static char *opt_cmd_name; -static pid_t opt_pid; -#endif enum { OPT_HELP = 1, OPT_TRACEPOINT, OPT_PROBE, OPT_FUNCTION, - OPT_FUNCTION_ENTRY, OPT_SYSCALL, OPT_USERSPACE, OPT_LOGLEVEL, @@ -67,6 +71,7 @@ enum { }; static struct lttng_handle *handle; +static struct mi_writer *writer; static struct poptOption long_options[] = { /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ @@ -77,16 +82,11 @@ static struct poptOption long_options[] = { {"kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0}, {"userspace", 'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0}, {"jul", 'j', POPT_ARG_VAL, &opt_jul, 1, 0, 0}, + {"log4j", 'l', POPT_ARG_VAL, &opt_log4j, 1, 0, 0}, + {"python", 'p', POPT_ARG_VAL, &opt_python, 1, 0, 0}, {"tracepoint", 0, POPT_ARG_NONE, 0, OPT_TRACEPOINT, 0, 0}, {"probe", 0, POPT_ARG_STRING, &opt_probe, OPT_PROBE, 0, 0}, {"function", 0, POPT_ARG_STRING, &opt_function, OPT_FUNCTION, 0, 0}, -#if 0 - /* - * Currently removed from lttng kernel tracer. Removed from - * lttng UI to discourage its use. - */ - {"function:entry", 0, POPT_ARG_STRING, &opt_function_entry_symbol, OPT_FUNCTION_ENTRY, 0, 0}, -#endif {"syscall", 0, POPT_ARG_NONE, 0, OPT_SYSCALL, 0, 0}, {"loglevel", 0, POPT_ARG_STRING, 0, OPT_LOGLEVEL, 0, 0}, {"loglevel-only", 0, POPT_ARG_STRING, 0, OPT_LOGLEVEL_ONLY, 0, 0}, @@ -101,7 +101,7 @@ static struct poptOption long_options[] = { */ static void usage(FILE *ofp) { - fprintf(ofp, "usage: lttng enable-event NAME[,NAME2,...] [-k|-u] [OPTIONS] \n"); + fprintf(ofp, "usage: lttng enable-event NAME[,NAME2,...] (-k | -u | -j | -l | -p) [OPTIONS] \n"); fprintf(ofp, "\n"); fprintf(ofp, "Options:\n"); fprintf(ofp, " -h, --help Show this help\n"); @@ -112,6 +112,8 @@ static void usage(FILE *ofp) fprintf(ofp, " -k, --kernel Apply for the kernel tracer\n"); fprintf(ofp, " -u, --userspace Apply to the user-space tracer\n"); fprintf(ofp, " -j, --jul Apply for Java application using JUL\n"); + fprintf(ofp, " -l, --log4j Apply for Java application using LOG4j\n"); + fprintf(ofp, " -p, --python Apply for Python application\n"); fprintf(ofp, "\n"); fprintf(ofp, "Event options:\n"); fprintf(ofp, " --tracepoint Tracepoint event (default)\n"); @@ -128,14 +130,11 @@ static void usage(FILE *ofp) fprintf(ofp, " Dynamic function entry/return probe.\n"); fprintf(ofp, " Addr and offset can be octal (0NNN...),\n"); fprintf(ofp, " decimal (NNN...) or hexadecimal (0xNNN...)\n"); -#if 0 - fprintf(ofp, " --function:entry symbol\n"); - fprintf(ofp, " Function tracer event\n"); -#endif fprintf(ofp, " --syscall System call event\n"); fprintf(ofp, "\n"); fprintf(ofp, " --loglevel name\n"); - fprintf(ofp, " Tracepoint loglevel range from 0 to loglevel\n"); + fprintf(ofp, " Tracepoint loglevel range from 0 to loglevel.\n"); + fprintf(ofp, " For JUL/LOG4j domain, see the table below for the range values.\n"); fprintf(ofp, " --loglevel-only name\n"); fprintf(ofp, " Tracepoint loglevel (only this loglevel)\n"); fprintf(ofp, "\n"); @@ -173,6 +172,26 @@ static void usage(FILE *ofp) fprintf(ofp, " JUL_ALL = INT32_MIN\n"); fprintf(ofp, " (shortcuts such as \"severe\" are allowed)\n"); fprintf(ofp, "\n"); + fprintf(ofp, " Available LOG4j domain loglevels:\n"); + fprintf(ofp, " LOG4J_OFF = INT32_MAX\n"); + fprintf(ofp, " LOG4J_FATAL = %d\n", LTTNG_LOGLEVEL_LOG4J_FATAL); + fprintf(ofp, " LOG4J_ERROR = %d\n", LTTNG_LOGLEVEL_LOG4J_ERROR); + fprintf(ofp, " LOG4J_WARN = %d\n", LTTNG_LOGLEVEL_LOG4J_WARN); + fprintf(ofp, " LOG4J_INFO = %d\n", LTTNG_LOGLEVEL_LOG4J_INFO); + fprintf(ofp, " LOG4J_DEBUG = %d\n", LTTNG_LOGLEVEL_LOG4J_DEBUG); + fprintf(ofp, " LOG4J_TRACE = %d\n", LTTNG_LOGLEVEL_LOG4J_TRACE); + fprintf(ofp, " LOG4J_ALL = INT32_MIN\n"); + fprintf(ofp, " (shortcuts such as \"severe\" are allowed)\n"); + fprintf(ofp, "\n"); + fprintf(ofp, " Available Python domain loglevels:\n"); + fprintf(ofp, " PYTHON_CRITICAL = %d\n", LTTNG_LOGLEVEL_PYTHON_CRITICAL); + fprintf(ofp, " PYTHON_ERROR = %d\n", LTTNG_LOGLEVEL_PYTHON_ERROR); + fprintf(ofp, " PYTHON_WARNING = %d\n", LTTNG_LOGLEVEL_PYTHON_WARNING); + fprintf(ofp, " PYTHON_INFO = %d\n", LTTNG_LOGLEVEL_PYTHON_INFO); + fprintf(ofp, " PYTHON_DEBUG = %d\n", LTTNG_LOGLEVEL_PYTHON_DEBUG); + fprintf(ofp, " PYTHON_NOTSET = %d\n", LTTNG_LOGLEVEL_PYTHON_NOTSET); + fprintf(ofp, " (shortcuts such as \"critical\" are allowed)\n"); + fprintf(ofp, "\n"); fprintf(ofp, " -f, --filter \'expression\'\n"); fprintf(ofp, " Filter expression on event fields and context.\n"); fprintf(ofp, " Event recording depends on evaluation.\n"); @@ -223,24 +242,27 @@ static void usage(FILE *ofp) */ static int parse_probe_opts(struct lttng_event *ev, char *opt) { - int ret; + int ret = CMD_SUCCESS; + int match; char s_hex[19]; +#define S_HEX_LEN_SCANF_IS_A_BROKEN_API "18" /* 18 is (19 - 1) (\0 is extra) */ char name[LTTNG_SYMBOL_NAME_LEN]; if (opt == NULL) { - ret = -1; + ret = CMD_ERROR; goto end; } /* Check for symbol+offset */ - ret = sscanf(opt, "%[^'+']+%s", name, s_hex); - if (ret == 2) { + match = sscanf(opt, "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API + "[^'+']+%" S_HEX_LEN_SCANF_IS_A_BROKEN_API "s", name, s_hex); + if (match == 2) { strncpy(ev->attr.probe.symbol_name, name, LTTNG_SYMBOL_NAME_LEN); ev->attr.probe.symbol_name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0'; DBG("probe symbol %s", ev->attr.probe.symbol_name); if (*s_hex == '\0') { ERR("Invalid probe offset %s", s_hex); - ret = -1; + ret = CMD_ERROR; goto end; } ev->attr.probe.offset = strtoul(s_hex, NULL, 0); @@ -251,8 +273,9 @@ static int parse_probe_opts(struct lttng_event *ev, char *opt) /* Check for symbol */ if (isalpha(name[0])) { - ret = sscanf(opt, "%s", name); - if (ret == 1) { + match = sscanf(opt, "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "s", + name); + if (match == 1) { strncpy(ev->attr.probe.symbol_name, name, LTTNG_SYMBOL_NAME_LEN); ev->attr.probe.symbol_name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0'; DBG("probe symbol %s", ev->attr.probe.symbol_name); @@ -264,11 +287,11 @@ static int parse_probe_opts(struct lttng_event *ev, char *opt) } /* Check for address */ - ret = sscanf(opt, "%s", s_hex); - if (ret > 0) { + match = sscanf(opt, "%" S_HEX_LEN_SCANF_IS_A_BROKEN_API "s", s_hex); + if (match > 0) { if (*s_hex == '\0') { ERR("Invalid probe address %s", s_hex); - ret = -1; + ret = CMD_ERROR; goto end; } ev->attr.probe.addr = strtoul(s_hex, NULL, 0); @@ -279,12 +302,55 @@ static int parse_probe_opts(struct lttng_event *ev, char *opt) } /* No match */ - ret = -1; + ret = CMD_ERROR; end: return ret; } +/* + * Maps LOG4j loglevel from string to value + */ +static int loglevel_log4j_str_to_value(const char *inputstr) +{ + int i = 0; + char str[LTTNG_SYMBOL_NAME_LEN]; + + if (!inputstr || strlen(inputstr) == 0) { + return -1; + } + + /* + * Loop up to LTTNG_SYMBOL_NAME_LEN minus one because the NULL bytes is + * added at the end of the loop so a the upper bound we avoid the overflow. + */ + while (i < (LTTNG_SYMBOL_NAME_LEN - 1) && inputstr[i] != '\0') { + str[i] = toupper(inputstr[i]); + i++; + } + str[i] = '\0'; + + if (!strcmp(str, "LOG4J_OFF") || !strcmp(str, "OFF")) { + return LTTNG_LOGLEVEL_LOG4J_OFF; + } else if (!strcmp(str, "LOG4J_FATAL") || !strcmp(str, "FATAL")) { + return LTTNG_LOGLEVEL_LOG4J_FATAL; + } else if (!strcmp(str, "LOG4J_ERROR") || !strcmp(str, "ERROR")) { + return LTTNG_LOGLEVEL_LOG4J_ERROR; + } else if (!strcmp(str, "LOG4J_WARN") || !strcmp(str, "WARN")) { + return LTTNG_LOGLEVEL_LOG4J_WARN; + } else if (!strcmp(str, "LOG4J_INFO") || !strcmp(str, "INFO")) { + return LTTNG_LOGLEVEL_LOG4J_INFO; + } else if (!strcmp(str, "LOG4J_DEBUG") || !strcmp(str, "DEBUG")) { + return LTTNG_LOGLEVEL_LOG4J_DEBUG; + } else if (!strcmp(str, "LOG4J_TRACE") || !strcmp(str, "TRACE")) { + return LTTNG_LOGLEVEL_LOG4J_TRACE; + } else if (!strcmp(str, "LOG4J_ALL") || !strcmp(str, "ALL")) { + return LTTNG_LOGLEVEL_LOG4J_ALL; + } else { + return -1; + } +} + /* * Maps JUL loglevel from string to value */ @@ -293,6 +359,10 @@ static int loglevel_jul_str_to_value(const char *inputstr) int i = 0; char str[LTTNG_SYMBOL_NAME_LEN]; + if (!inputstr || strlen(inputstr) == 0) { + return -1; + } + /* * Loop up to LTTNG_SYMBOL_NAME_LEN minus one because the NULL bytes is * added at the end of the loop so a the upper bound we avoid the overflow. @@ -326,6 +396,45 @@ static int loglevel_jul_str_to_value(const char *inputstr) } } +/* + * Maps Python loglevel from string to value + */ +static int loglevel_python_str_to_value(const char *inputstr) +{ + int i = 0; + char str[LTTNG_SYMBOL_NAME_LEN]; + + if (!inputstr || strlen(inputstr) == 0) { + return -1; + } + + /* + * Loop up to LTTNG_SYMBOL_NAME_LEN minus one because the NULL bytes is + * added at the end of the loop so a the upper bound we avoid the overflow. + */ + while (i < (LTTNG_SYMBOL_NAME_LEN - 1) && inputstr[i] != '\0') { + str[i] = toupper(inputstr[i]); + i++; + } + str[i] = '\0'; + + if (!strcmp(str, "PYTHON_CRITICAL") || !strcmp(str, "CRITICAL")) { + return LTTNG_LOGLEVEL_PYTHON_CRITICAL; + } else if (!strcmp(str, "PYTHON_ERROR") || !strcmp(str, "ERROR")) { + return LTTNG_LOGLEVEL_PYTHON_ERROR; + } else if (!strcmp(str, "PYTHON_WARNING") || !strcmp(str, "WARNING")) { + return LTTNG_LOGLEVEL_PYTHON_WARNING; + } else if (!strcmp(str, "PYTHON_INFO") || !strcmp(str, "INFO")) { + return LTTNG_LOGLEVEL_PYTHON_INFO; + } else if (!strcmp(str, "PYTNON_DEBUG") || !strcmp(str, "DEBUG")) { + return LTTNG_LOGLEVEL_PYTHON_DEBUG; + } else if (!strcmp(str, "PYTHON_NOTSET") || !strcmp(str, "NOTSET")) { + return LTTNG_LOGLEVEL_PYTHON_NOTSET; + } else { + return -1; + } +} + /* * Maps loglevel from string to value */ @@ -335,6 +444,10 @@ int loglevel_str_to_value(const char *inputstr) int i = 0; char str[LTTNG_SYMBOL_NAME_LEN]; + if (!inputstr || strlen(inputstr) == 0) { + return -1; + } + /* * Loop up to LTTNG_SYMBOL_NAME_LEN minus one because the NULL bytes is * added at the end of the loop so a the upper bound we avoid the overflow. @@ -391,6 +504,40 @@ const char *print_raw_channel_name(const char *name) return name ? : ""; } +/* + * Mi print exlcusion list + */ +static +int mi_print_exclusion(int count, char **names) +{ + int i, ret; + + assert(writer); + + if (count == 0) { + ret = 0; + goto end; + } + ret = mi_lttng_writer_open_element(writer, config_element_exclusions); + if (ret) { + goto end; + } + + for (i = 0; i < count; i++) { + ret = mi_lttng_writer_write_element_string(writer, + config_element_exclusion, names[i]); + if (ret) { + goto end; + } + } + + /* Close exclusions element */ + ret = mi_lttng_writer_close_element(writer); + +end: + return ret; +} + /* * Return allocated string for pretty-printing exclusion names. */ @@ -413,7 +560,10 @@ char *print_exclusions(int count, char **names) /* add length of preamble + one for NUL - one for last (missing) comma */ length += strlen(preamble); - ret = malloc(length); + ret = zmalloc(length); + if (!ret) { + return NULL; + } strncpy(ret, preamble, length); for (i = 0; i < count; i++) { strcat(ret, names[i]); @@ -421,6 +571,7 @@ char *print_exclusions(int count, char **names) strcat(ret, ","); } } + return ret; } @@ -471,11 +622,25 @@ int check_exclusion_subsets(const char *event_name, goto error; } if (e == '*') { + char *string; + char **new_exclusion_list; + /* Excluder is a proper subset of event */ + string = strndup(next_excluder, excluder_length); + if (!string) { + PERROR("strndup error"); + goto error; + } + new_exclusion_list = realloc(exclusion_list, + sizeof(char *) * (exclusion_count + 1)); + if (!new_exclusion_list) { + PERROR("realloc"); + free(string); + goto error; + } + exclusion_list = new_exclusion_list; exclusion_count++; - exclusion_list = realloc(exclusion_list, sizeof(char **) * exclusion_count); - exclusion_list[exclusion_count - 1] = strndup(next_excluder, excluder_length); - + exclusion_list[exclusion_count - 1] = string; break; } if (x != e) { @@ -514,10 +679,12 @@ end: } /* * Enabling event using the lttng API. + * Note: in case of error only the last error code will be return. */ static int enable_events(char *session_name) { - int ret = CMD_SUCCESS, warn = 0; + int ret = CMD_SUCCESS, command_ret = CMD_SUCCESS; + int error_holder = CMD_SUCCESS, warn = 0, error = 0, success = 1; char *event_name, *channel_name = NULL; struct lttng_event ev; struct lttng_domain dom; @@ -528,11 +695,6 @@ static int enable_events(char *session_name) memset(&dom, 0, sizeof(dom)); if (opt_kernel) { - if (opt_filter) { - ERR("Filter not implement for kernel tracing yet"); - ret = CMD_ERROR; - goto error; - } if (opt_loglevel) { WARN("Kernel loglevels are not supported."); } @@ -550,6 +712,14 @@ static int enable_events(char *session_name) dom.type = LTTNG_DOMAIN_JUL; /* Default. */ dom.buf_type = LTTNG_BUFFER_PER_UID; + } else if (opt_log4j) { + dom.type = LTTNG_DOMAIN_LOG4J; + /* Default. */ + dom.buf_type = LTTNG_BUFFER_PER_UID; + } else if (opt_python) { + dom.type = LTTNG_DOMAIN_PYTHON; + /* Default. */ + dom.buf_type = LTTNG_BUFFER_PER_UID; } else { print_missing_domain(); ret = CMD_ERROR; @@ -570,11 +740,21 @@ static int enable_events(char *session_name) goto error; } + /* Prepare Mi */ + if (lttng_opt_mi) { + /* Open a events element */ + ret = mi_lttng_writer_open_element(writer, config_element_events); + if (ret) { + ret = CMD_ERROR; + goto error; + } + } + if (opt_enable_all) { /* Default setup for enable all */ if (opt_kernel) { ev.type = opt_event_type; - ev.name[0] = '\0'; + strcpy(ev.name, "*"); /* kernel loglevels not implemented */ ev.loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL; } else { @@ -582,11 +762,15 @@ static int enable_events(char *session_name) strcpy(ev.name, "*"); ev.loglevel_type = opt_loglevel_type; if (opt_loglevel) { - assert(opt_userspace || opt_jul); + assert(opt_userspace || opt_jul || opt_log4j || opt_python); if (opt_userspace) { ev.loglevel = loglevel_str_to_value(opt_loglevel); } else if (opt_jul) { ev.loglevel = loglevel_jul_str_to_value(opt_loglevel); + } else if (opt_log4j) { + ev.loglevel = loglevel_log4j_str_to_value(opt_loglevel); + } else if (opt_python) { + ev.loglevel = loglevel_python_str_to_value(opt_loglevel); } if (ev.loglevel == -1) { ERR("Unknown loglevel %s", opt_loglevel); @@ -594,11 +778,13 @@ static int enable_events(char *session_name) goto error; } } else { - assert(opt_userspace || opt_jul); + assert(opt_userspace || opt_jul || opt_log4j || opt_python); if (opt_userspace) { ev.loglevel = -1; - } else if (opt_jul) { + } else if (opt_jul || opt_log4j) { ev.loglevel = LTTNG_LOGLEVEL_JUL_ALL; + } else if (opt_python) { + ev.loglevel = LTTNG_LOGLEVEL_PYTHON_DEBUG; } } } @@ -609,6 +795,7 @@ static int enable_events(char *session_name) if (ret == CMD_ERROR) { goto error; } + ev.exclusion = 1; } if (!opt_filter) { ret = lttng_enable_event_with_exclusions(handle, @@ -620,7 +807,18 @@ static int enable_events(char *session_name) case LTTNG_ERR_KERN_EVENT_EXIST: WARN("Kernel events already enabled (channel %s, session %s)", print_channel_name(channel_name), session_name); + warn = 1; + break; + case LTTNG_ERR_TRACE_ALREADY_STARTED: + { + const char *msg = "The command tried to enable an event in a new domain for a session that has already been started once."; + ERR("Events: %s (channel %s, session %s)", + msg, + print_channel_name(channel_name), + session_name); + error = 1; break; + } default: ERR("Events: %s (channel %s, session %s)", lttng_strerror(ret), @@ -628,6 +826,7 @@ static int enable_events(char *session_name) ? print_raw_channel_name(channel_name) : print_channel_name(channel_name), session_name); + error = 1; break; } goto end; @@ -637,6 +836,12 @@ static int enable_events(char *session_name) case LTTNG_EVENT_TRACEPOINT: if (opt_loglevel && dom.type != LTTNG_DOMAIN_KERNEL) { char *exclusion_string = print_exclusions(exclusion_count, exclusion_list); + + if (!exclusion_string) { + PERROR("Cannot allocate exclusion_string"); + error = 1; + goto end; + } MSG("All %s tracepoints%s are enabled in channel %s for loglevel %s", get_domain_str(dom.type), exclusion_string, @@ -645,6 +850,12 @@ static int enable_events(char *session_name) free(exclusion_string); } else { char *exclusion_string = print_exclusions(exclusion_count, exclusion_list); + + if (!exclusion_string) { + PERROR("Cannot allocate exclusion_string"); + error = 1; + goto end; + } MSG("All %s tracepoints%s are enabled in channel %s", get_domain_str(dom.type), exclusion_string, @@ -654,13 +865,20 @@ static int enable_events(char *session_name) break; case LTTNG_EVENT_SYSCALL: if (opt_kernel) { - MSG("All kernel system calls are enabled in channel %s", + MSG("All %s system calls are enabled in channel %s", + get_domain_str(dom.type), print_channel_name(channel_name)); } break; case LTTNG_EVENT_ALL: if (opt_loglevel && dom.type != LTTNG_DOMAIN_KERNEL) { char *exclusion_string = print_exclusions(exclusion_count, exclusion_list); + + if (!exclusion_string) { + PERROR("Cannot allocate exclusion_string"); + error = 1; + goto end; + } MSG("All %s events%s are enabled in channel %s for loglevel %s", get_domain_str(dom.type), exclusion_string, @@ -669,6 +887,12 @@ static int enable_events(char *session_name) free(exclusion_string); } else { char *exclusion_string = print_exclusions(exclusion_count, exclusion_list); + + if (!exclusion_string) { + PERROR("Cannot allocate exclusion_string"); + error = 1; + goto end; + } MSG("All %s events%s are enabled in channel %s", get_domain_str(dom.type), exclusion_string, @@ -684,30 +908,91 @@ static int enable_events(char *session_name) goto error; } } + if (opt_filter) { - ret = lttng_enable_event_with_exclusions(handle, &ev, channel_name, + command_ret = lttng_enable_event_with_exclusions(handle, &ev, channel_name, opt_filter, exclusion_count, exclusion_list); - if (ret < 0) { - switch (-ret) { + if (command_ret < 0) { + switch (-command_ret) { case LTTNG_ERR_FILTER_EXIST: WARN("Filter on all events is already enabled" " (channel %s, session %s)", print_channel_name(channel_name), session_name); + warn = 1; + break; + case LTTNG_ERR_TRACE_ALREADY_STARTED: + { + const char *msg = "The command tried to enable an event in a new domain for a session that has already been started once."; + ERR("All events: %s (channel %s, session %s, filter \'%s\')", + msg, + print_channel_name(channel_name), + session_name, opt_filter); + error = 1; break; + } default: ERR("All events: %s (channel %s, session %s, filter \'%s\')", - lttng_strerror(ret), - ret == -LTTNG_ERR_NEED_CHANNEL_NAME + lttng_strerror(command_ret), + command_ret == -LTTNG_ERR_NEED_CHANNEL_NAME ? print_raw_channel_name(channel_name) : print_channel_name(channel_name), session_name, opt_filter); + error = 1; break; } - goto error; + error_holder = command_ret; } else { + ev.filter = 1; MSG("Filter '%s' successfully set", opt_filter); } } + + if (lttng_opt_mi) { + /* The wildcard * is used for kernel and ust domain to + * represent ALL. We copy * in event name to force the wildcard use + * for kernel domain + * + * Note: this is strictly for semantic and printing while in + * machine interface mode. + */ + strcpy(ev.name, "*"); + + /* If we reach here the events are enabled */ + if (!error && !warn) { + ev.enabled = 1; + } else { + ev.enabled = 0; + success = 0; + } + ret = mi_lttng_event(writer, &ev, 1, handle->domain.type); + if (ret) { + ret = CMD_ERROR; + goto error; + } + + /* print exclusion */ + ret = mi_print_exclusion(exclusion_count, exclusion_list); + if (ret) { + ret = CMD_ERROR; + goto error; + } + + /* Success ? */ + ret = mi_lttng_writer_write_element_bool(writer, + mi_lttng_element_command_success, success); + if (ret) { + ret = CMD_ERROR; + goto error; + } + + /* Close event element */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + ret = CMD_ERROR; + goto error; + } + } + goto end; } @@ -726,14 +1011,17 @@ static int enable_events(char *session_name) print_channel_name(channel_name)); switch (opt_event_type) { - case LTTNG_EVENT_ALL: /* Default behavior is tracepoint */ - ev.type = LTTNG_EVENT_TRACEPOINT; - /* Fall-through */ + case LTTNG_EVENT_ALL: /* Enable tracepoints and syscalls */ + /* If event name differs from *, select tracepoint. */ + if (strcmp(ev.name, "*")) { + ev.type = LTTNG_EVENT_TRACEPOINT; + } + break; case LTTNG_EVENT_TRACEPOINT: break; case LTTNG_EVENT_PROBE: ret = parse_probe_opts(&ev, opt_probe); - if (ret < 0) { + if (ret) { ERR("Unable to parse probe options"); ret = 0; goto error; @@ -741,20 +1029,15 @@ static int enable_events(char *session_name) break; case LTTNG_EVENT_FUNCTION: ret = parse_probe_opts(&ev, opt_function); - if (ret < 0) { + if (ret) { ERR("Unable to parse function probe options"); ret = 0; goto error; } break; - case LTTNG_EVENT_FUNCTION_ENTRY: - strncpy(ev.attr.ftrace.symbol_name, opt_function_entry_symbol, - LTTNG_SYMBOL_NAME_LEN); - ev.attr.ftrace.symbol_name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0'; - break; case LTTNG_EVENT_SYSCALL: - MSG("per-syscall selection not supported yet. Use \"-a\" " - "for all syscalls."); + ev.type = LTTNG_EVENT_SYSCALL; + break; default: ret = CMD_UNDEFINED; goto error; @@ -763,14 +1046,6 @@ static int enable_events(char *session_name) /* kernel loglevels not implemented */ ev.loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL; } else if (opt_userspace) { /* User-space tracer action */ -#if 0 - if (opt_cmd_name != NULL || opt_pid) { - MSG("Only supporting tracing all UST processes (-u) for now."); - ret = CMD_UNDEFINED; - goto error; - } -#endif - DBG("Enabling UST event %s for channel %s, loglevel %s", event_name, print_channel_name(channel_name), opt_loglevel ? : ""); @@ -785,7 +1060,6 @@ static int enable_events(char *session_name) break; case LTTNG_EVENT_PROBE: case LTTNG_EVENT_FUNCTION: - case LTTNG_EVENT_FUNCTION_ENTRY: case LTTNG_EVENT_SYSCALL: default: ERR("Event type not available for user-space tracing"); @@ -794,6 +1068,7 @@ static int enable_events(char *session_name) } if (opt_exclude) { + ev.exclusion = 1; if (opt_event_type != LTTNG_EVENT_ALL && opt_event_type != LTTNG_EVENT_TRACEPOINT) { ERR("Exclusion option can only be used with tracepoint events"); ret = CMD_ERROR; @@ -826,24 +1101,36 @@ static int enable_events(char *session_name) } else { ev.loglevel = -1; } - } else if (opt_jul) { + } else if (opt_jul || opt_log4j || opt_python) { if (opt_event_type != LTTNG_EVENT_ALL && opt_event_type != LTTNG_EVENT_TRACEPOINT) { - ERR("Event type not supported for JUL domain."); + ERR("Event type not supported for domain."); ret = CMD_UNSUPPORTED; goto error; } ev.loglevel_type = opt_loglevel_type; if (opt_loglevel) { - ev.loglevel = loglevel_jul_str_to_value(opt_loglevel); + if (opt_jul) { + ev.loglevel = loglevel_jul_str_to_value(opt_loglevel); + } else if (opt_log4j) { + ev.loglevel = loglevel_log4j_str_to_value(opt_loglevel); + } else if (opt_python) { + ev.loglevel = loglevel_python_str_to_value(opt_loglevel); + } if (ev.loglevel == -1) { ERR("Unknown loglevel %s", opt_loglevel); ret = -LTTNG_ERR_INVALID; goto error; } } else { - ev.loglevel = LTTNG_LOGLEVEL_JUL_ALL; + if (opt_jul) { + ev.loglevel = LTTNG_LOGLEVEL_JUL_ALL; + } else if (opt_log4j) { + ev.loglevel = LTTNG_LOGLEVEL_LOG4J_ALL; + } else if (opt_python) { + ev.loglevel = LTTNG_LOGLEVEL_PYTHON_DEBUG; + } } ev.type = LTTNG_EVENT_TRACEPOINT; strncpy(ev.name, event_name, LTTNG_SYMBOL_NAME_LEN); @@ -857,35 +1144,61 @@ static int enable_events(char *session_name) if (!opt_filter) { char *exclusion_string; - ret = lttng_enable_event_with_exclusions(handle, + command_ret = lttng_enable_event_with_exclusions(handle, &ev, channel_name, NULL, exclusion_count, exclusion_list); exclusion_string = print_exclusions(exclusion_count, exclusion_list); - if (ret < 0) { + if (!exclusion_string) { + PERROR("Cannot allocate exclusion_string"); + error = 1; + goto end; + } + if (command_ret < 0) { /* Turn ret to positive value to handle the positive error code */ - switch (-ret) { + switch (-command_ret) { case LTTNG_ERR_KERN_EVENT_EXIST: WARN("Kernel event %s%s already enabled (channel %s, session %s)", event_name, exclusion_string, print_channel_name(channel_name), session_name); + warn = 1; + break; + case LTTNG_ERR_TRACE_ALREADY_STARTED: + { + const char *msg = "The command tried to enable an event in a new domain for a session that has already been started once."; + ERR("Event %s%s: %s (channel %s, session %s)", event_name, + exclusion_string, + msg, + print_channel_name(channel_name), + session_name); + error = 1; break; + } default: ERR("Event %s%s: %s (channel %s, session %s)", event_name, exclusion_string, - lttng_strerror(ret), - ret == -LTTNG_ERR_NEED_CHANNEL_NAME + lttng_strerror(command_ret), + command_ret == -LTTNG_ERR_NEED_CHANNEL_NAME ? print_raw_channel_name(channel_name) : print_channel_name(channel_name), session_name); + error = 1; break; } - warn = 1; + error_holder = command_ret; } else { - MSG("%s event %s%s created in channel %s", - get_domain_str(dom.type), event_name, - exclusion_string, - print_channel_name(channel_name)); + /* So we don't print the default channel name for agent domain. */ + if (dom.type == LTTNG_DOMAIN_JUL || + dom.type == LTTNG_DOMAIN_LOG4J) { + MSG("%s event %s%s enabled.", + get_domain_str(dom.type), event_name, + exclusion_string); + } else { + MSG("%s event %s%s created in channel %s", + get_domain_str(dom.type), event_name, + exclusion_string, + print_channel_name(channel_name)); + } } free(exclusion_string); } @@ -893,31 +1206,51 @@ static int enable_events(char *session_name) if (opt_filter) { char *exclusion_string; - ret = lttng_enable_event_with_exclusions(handle, &ev, channel_name, + /* Filter present */ + ev.filter = 1; + + command_ret = lttng_enable_event_with_exclusions(handle, &ev, channel_name, opt_filter, exclusion_count, exclusion_list); exclusion_string = print_exclusions(exclusion_count, exclusion_list); - - if (ret < 0) { - switch (-ret) { + if (!exclusion_string) { + PERROR("Cannot allocate exclusion_string"); + error = 1; + goto end; + } + if (command_ret < 0) { + switch (-command_ret) { case LTTNG_ERR_FILTER_EXIST: WARN("Filter on event %s%s is already enabled" " (channel %s, session %s)", event_name, exclusion_string, print_channel_name(channel_name), session_name); + warn = 1; + break; + case LTTNG_ERR_TRACE_ALREADY_STARTED: + { + const char *msg = "The command tried to enable an event in a new domain for a session that has already been started once."; + ERR("Event %s%s: %s (channel %s, session %s, filter \'%s\')", ev.name, + exclusion_string, + msg, + print_channel_name(channel_name), + session_name, opt_filter); + error = 1; break; + } default: ERR("Event %s%s: %s (channel %s, session %s, filter \'%s\')", ev.name, exclusion_string, - lttng_strerror(ret), - ret == -LTTNG_ERR_NEED_CHANNEL_NAME + lttng_strerror(command_ret), + command_ret == -LTTNG_ERR_NEED_CHANNEL_NAME ? print_raw_channel_name(channel_name) : print_channel_name(channel_name), session_name, opt_filter); + error = 1; break; } - free(exclusion_string); - goto error; + error_holder = command_ret; + } else { MSG("Event %s%s: Filter '%s' successfully set", event_name, exclusion_string, @@ -926,15 +1259,66 @@ static int enable_events(char *session_name) free(exclusion_string); } + if (lttng_opt_mi) { + if (command_ret) { + success = 0; + ev.enabled = 0; + } else { + ev.enabled = 1; + } + + ret = mi_lttng_event(writer, &ev, 1, handle->domain.type); + if (ret) { + ret = CMD_ERROR; + goto error; + } + + /* print exclusion */ + ret = mi_print_exclusion(exclusion_count, exclusion_list); + if (ret) { + ret = CMD_ERROR; + goto error; + } + + /* Success ? */ + ret = mi_lttng_writer_write_element_bool(writer, + mi_lttng_element_command_success, success); + if (ret) { + ret = CMD_ERROR; + goto end; + } + + /* Close event element */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + ret = CMD_ERROR; + goto end; + } + } + /* Next event */ event_name = strtok(NULL, ","); + /* Reset warn, error and success */ + success = 1; } end: + /* Close Mi */ + if (lttng_opt_mi) { + /* Close events element */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + ret = CMD_ERROR; + goto error; + } + } error: if (warn) { ret = CMD_WARNING; } + if (error) { + ret = CMD_ERROR; + } lttng_destroy_handle(handle); if (exclusion_list != NULL) { @@ -944,6 +1328,11 @@ error: free(exclusion_list); } + /* Overwrite ret with error_holder if there was an actual error with + * enabling an event. + */ + ret = error_holder ? error_holder : ret; + return ret; } @@ -952,7 +1341,7 @@ error: */ int cmd_enable_events(int argc, const char **argv) { - int opt, ret = CMD_SUCCESS; + int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1; static poptContext pc; char *session_name = NULL; int event_type = -1; @@ -977,9 +1366,6 @@ int cmd_enable_events(int argc, const char **argv) case OPT_FUNCTION: opt_event_type = LTTNG_EVENT_FUNCTION; break; - case OPT_FUNCTION_ENTRY: - opt_event_type = LTTNG_EVENT_FUNCTION_ENTRY; - break; case OPT_SYSCALL: opt_event_type = LTTNG_EVENT_SYSCALL; break; @@ -1019,6 +1405,31 @@ int cmd_enable_events(int argc, const char **argv) } } + /* Mi check */ + if (lttng_opt_mi) { + writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi); + if (!writer) { + ret = -LTTNG_ERR_NOMEM; + goto end; + } + + /* Open command element */ + ret = mi_lttng_writer_command_open(writer, + mi_lttng_element_command_enable_event); + if (ret) { + ret = CMD_ERROR; + goto end; + } + + /* Open output element */ + ret = mi_lttng_writer_open_element(writer, + mi_lttng_element_command_output); + if (ret) { + ret = CMD_ERROR; + goto end; + } + } + opt_event_list = (char*) poptGetArg(pc); if (opt_event_list == NULL && opt_enable_all == 0) { ERR("Missing event name(s).\n"); @@ -1030,20 +1441,59 @@ int cmd_enable_events(int argc, const char **argv) if (!opt_session_name) { session_name = get_session_name(); if (session_name == NULL) { - ret = CMD_ERROR; - goto end; + command_ret = CMD_ERROR; + success = 0; + goto mi_closing; } } else { session_name = opt_session_name; } - ret = enable_events(session_name); + command_ret = enable_events(session_name); + if (command_ret) { + success = 0; + goto mi_closing; + } + +mi_closing: + /* Mi closing */ + if (lttng_opt_mi) { + /* Close output element */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + ret = CMD_ERROR; + goto end; + } + + ret = mi_lttng_writer_write_element_bool(writer, + mi_lttng_element_command_success, success); + if (ret) { + ret = CMD_ERROR; + goto end; + } + + /* Command element close */ + ret = mi_lttng_writer_command_close(writer); + if (ret) { + ret = CMD_ERROR; + goto end; + } + } end: + /* Mi clean-up */ + if (writer && mi_lttng_writer_destroy(writer)) { + /* Preserve original error code */ + ret = ret ? ret : LTTNG_ERR_MI_IO_FAIL; + } + if (opt_session_name == NULL) { free(session_name); } + /* Overwrite ret if an error occurred in enable_events */ + ret = command_ret ? command_ret : ret; + poptFreeContext(pc); return ret; }