Support the new Python agent shipped in liblttng-ust.
This adds the -p, --python option to the list and enable/disable-event
command to control the domain exactly like JUL and LOG4J.
The agent support is for the Python "logging" module.
Signed-off-by: David Goulet <dgoulet@efficios.com>
tests/regression/ust/libc-wrapper/Makefile
tests/regression/ust/java-jul/Makefile
tests/regression/ust/java-log4j/Makefile
+ tests/regression/ust/python-logging/Makefile
tests/stress/Makefile
tests/unit/Makefile
tests/unit/ini_config/Makefile
those traces is done using the babeltrace(1) text viewer.
We introduce the notion of \fBtracing domains\fP which is essentially a type of
-tracer (kernel, user space, JUL or LOG4J for now). In the future, we could see
-more tracer like for instance an hypervisor. For some commands, you'll need to
-specify on which domain the command operates (\-u, \-k or \-j). For instance,
-the kernel domain must be specified when enabling a kernel event.
+tracer (kernel, user space, JUL, LOG4J or Python for now). In the future, we
+could see more tracer like for instance an hypervisor. For some commands,
+you'll need to specify on which domain the command operates (\-u, \-k, \-l, \-j
+or \-p). For instance, the kernel domain must be specified when enabling a
+kernel event.
In order to trace the kernel, the session daemon needs to be running as root.
LTTng provides the use of a \fBtracing group\fP (default: tracing). Whomever is
.BR "\-l, \-\-log4j"
Apply for Java application using LOG4J
.TP
+.BR "\-p, \-\-python"
+Apply for Python application using the logging module.
+.TP
.BR "\-\-tracepoint"
Tracepoint event (default). Userspace tracer supports wildcards at the end
of string. Don't forget to quote to deal with bash expansion.
option thus starting from SEVERE to FINEST.
For the LOG4J domain, loglevels range from FATAL to TRACE which are also
detailed in the help.
+For the Python domain, loglevels range from CRITICAL to DEBUG which are
+detailed in the help as well.
.TP
.BR "\-\-loglevel-only NAME"
Tracepoint loglevel (only this loglevel).
.TP
.BR "\-l, \-\-log4j"
Apply for Java application using LOG4J
+.TP
+.BR "\-p, \-\-python"
+Apply for Python application using the logging module.
.RE
.PP
list. The event corresponds to the Logger name in the Java JUL application.
With \-l alone, the available LOG4J event from registered application will be
list. The event corresponds to the Logger name in the Java LOG4J application.
+With \-p alone, the available Python event from registered application will be
+list. The event corresponds to the Logger name in the Python application.
With \-u alone, it will list all available user-space events from registered
applications. Here is an example of 'lttng list \-u':
.BR "\-j, \-\-jul"
Apply for Java application using JUL
.TP
-.TP
.BR "\-l, \-\-log4j"
Apply for Java application using LOG4J
+.TP
+.BR "\-p, \-\-python"
+Apply for Python application using the logging module.
+.TP
.BR "\-f, \-\-fields"
List event fields
LTTNG_DOMAIN_UST = 2, /* Global Userspace tracer. */
LTTNG_DOMAIN_JUL = 3, /* Java Util Logging. */
LTTNG_DOMAIN_LOG4J = 4, /* Java Log4j Framework. */
+ LTTNG_DOMAIN_PYTHON = 5, /* Python logging Framework. */
};
/* Buffer type for a specific domain. */
LTTNG_LOGLEVEL_LOG4J_ALL = INT32_MIN,
};
+/*
+ * Available loglevels for the Python domain. Those are an exact map from the
+ * Level class.
+ */
+enum lttng_loglevel_python {
+ LTTNG_LOGLEVEL_PYTHON_CRITICAL = 50,
+ LTTNG_LOGLEVEL_PYTHON_ERROR = 40,
+ LTTNG_LOGLEVEL_PYTHON_WARNING = 30,
+ LTTNG_LOGLEVEL_PYTHON_INFO = 20,
+ LTTNG_LOGLEVEL_PYTHON_DEBUG = 10,
+ LTTNG_LOGLEVEL_PYTHON_NOTSET = 0,
+};
+
/*
* LTTng consumer mode
*/
assert(events);
+ DBG2("Agent listing events for domain %d", domain);
+
nbmem = UST_APP_EVENT_LIST_SIZE;
tmp_events = zmalloc(nbmem * sizeof(*tmp_events));
if (!tmp_events) {
}
case LTTNG_DOMAIN_LOG4J:
case LTTNG_DOMAIN_JUL:
+ case LTTNG_DOMAIN_PYTHON:
{
struct agent *agt;
struct ltt_ust_session *usess = session->ust_session;
}
case LTTNG_DOMAIN_LOG4J:
case LTTNG_DOMAIN_JUL:
+ case LTTNG_DOMAIN_PYTHON:
{
const char *default_event_name, *default_chan_name;
struct agent *agt;
memcpy(&tmp_dom, domain, sizeof(tmp_dom));
tmp_dom.type = LTTNG_DOMAIN_UST;
- if (domain->type == LTTNG_DOMAIN_LOG4J) {
+ switch (domain->type) {
+ case LTTNG_DOMAIN_LOG4J:
default_chan_name = DEFAULT_LOG4J_CHANNEL_NAME;
- } else {
+ break;
+ case LTTNG_DOMAIN_JUL:
default_chan_name = DEFAULT_JUL_CHANNEL_NAME;
+ break;
+ case LTTNG_DOMAIN_PYTHON:
+ default_chan_name = DEFAULT_PYTHON_CHANNEL_NAME;
+ break;
+ default:
+ /* The switch/case we are in should avoid this else big problem */
+ assert(0);
}
ret = cmd_enable_event(session, &tmp_dom, (char *) default_chan_name,
break;
case LTTNG_DOMAIN_LOG4J:
case LTTNG_DOMAIN_JUL:
+ case LTTNG_DOMAIN_PYTHON:
nb_events = agent_list_events(events, domain);
if (nb_events < 0) {
ret = LTTNG_ERR_UST_LIST_FAIL;
}
case LTTNG_DOMAIN_LOG4J:
case LTTNG_DOMAIN_JUL:
+ case LTTNG_DOMAIN_PYTHON:
if (session->ust_session) {
struct lttng_ht_iter iter;
struct agent *agt;
{
const char *default_event_name = NULL;
- if (domain == LTTNG_DOMAIN_JUL) {
+ switch (domain) {
+ case LTTNG_DOMAIN_LOG4J:
if (is_root) {
- default_event_name = DEFAULT_SYS_JUL_EVENT_NAME;
+ default_event_name = DEFAULT_SYS_LOG4J_EVENT_NAME;
} else {
- default_event_name = DEFAULT_USER_JUL_EVENT_NAME;
+ default_event_name = DEFAULT_USER_LOG4J_EVENT_NAME;
}
- } else if (domain == LTTNG_DOMAIN_LOG4J) {
+ break;
+ case LTTNG_DOMAIN_JUL:
if (is_root) {
- default_event_name = DEFAULT_SYS_LOG4J_EVENT_NAME;
+ default_event_name = DEFAULT_SYS_JUL_EVENT_NAME;
} else {
- default_event_name = DEFAULT_USER_LOG4J_EVENT_NAME;
+ default_event_name = DEFAULT_USER_JUL_EVENT_NAME;
}
- } else {
+ break;
+ case LTTNG_DOMAIN_PYTHON:
+ default_event_name = DEFAULT_USER_PYTHON_EVENT_NAME;
+ break;
+ default:
assert(0);
}
return default_event_name;
}
-
/*
* Disable a single agent event for a given UST session.
*
ust_channel_name = DEFAULT_JUL_CHANNEL_NAME;
} else if (agt->domain == LTTNG_DOMAIN_LOG4J) {
ust_channel_name = DEFAULT_LOG4J_CHANNEL_NAME;
+ } else if (agt->domain == LTTNG_DOMAIN_PYTHON) {
+ ust_channel_name = DEFAULT_PYTHON_CHANNEL_NAME;
} else {
ret = LTTNG_ERR_INVALID;
goto error;
break;
case LTTNG_DOMAIN_JUL:
case LTTNG_DOMAIN_LOG4J:
+ case LTTNG_DOMAIN_PYTHON:
case LTTNG_DOMAIN_UST:
DBG3("Copying tracing session consumer output in UST session");
if (session->ust_session->consumer) {
switch (domain->type) {
case LTTNG_DOMAIN_JUL:
case LTTNG_DOMAIN_LOG4J:
+ case LTTNG_DOMAIN_PYTHON:
case LTTNG_DOMAIN_UST:
break;
default:
break;
case LTTNG_DOMAIN_JUL:
case LTTNG_DOMAIN_LOG4J:
+ case LTTNG_DOMAIN_PYTHON:
case LTTNG_DOMAIN_UST:
if (!cmd_ctx->session->ust_session) {
ret = LTTNG_ERR_NO_CHANNEL;
break;
case LTTNG_DOMAIN_JUL:
case LTTNG_DOMAIN_LOG4J:
+ case LTTNG_DOMAIN_PYTHON:
case LTTNG_DOMAIN_UST:
{
if (!ust_app_supported()) {
switch (cmd_ctx->lsm->domain.type) {
case LTTNG_DOMAIN_JUL:
case LTTNG_DOMAIN_LOG4J:
+ case LTTNG_DOMAIN_PYTHON:
case LTTNG_DOMAIN_UST:
if (uatomic_read(&ust_consumerd_state) != CONSUMER_STARTED) {
ret = LTTNG_ERR_NO_USTCONSUMERD;
ust_chan = caa_container_of(node, struct ltt_ust_channel, node);
agent_channel = !strcmp(DEFAULT_JUL_CHANNEL_NAME, ust_chan->name) ||
- !strcmp(DEFAULT_LOG4J_CHANNEL_NAME, ust_chan->name);
+ !strcmp(DEFAULT_LOG4J_CHANNEL_NAME, ust_chan->name) ||
+ !strcmp(DEFAULT_PYTHON_CHANNEL_NAME, ust_chan->name);
if (!(save_agent ^ agent_channel)) {
ret = save_ust_channel(writer, ust_chan, session->ust_session);
if (ret) {
static int opt_disable_all;
static int opt_jul;
static int opt_log4j;
+static int opt_python;
static int opt_event_type;
#if 0
/* Not implemented yet */
{"channel", 'c', POPT_ARG_STRING, &opt_channel_name, 0, 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},
{"kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
{"syscall", 0, POPT_ARG_NONE, 0, OPT_SYSCALL, 0, 0},
#if 0
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 to Java application using LOG4j\n");
+ fprintf(ofp, " -p, --python Apply to Python application using logging\n");
fprintf(ofp, "\n");
fprintf(ofp, "Event options:\n");
fprintf(ofp, " --syscall System call event\n");
dom.type = LTTNG_DOMAIN_JUL;
} else if (opt_log4j) {
dom.type = LTTNG_DOMAIN_LOG4J;
+ } else if (opt_python) {
+ dom.type = LTTNG_DOMAIN_PYTHON;
} else {
print_missing_domain();
ret = CMD_ERROR;
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;
{"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},
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 Java application using LOG4j\n");
fprintf(ofp, "\n");
fprintf(ofp, "Event options:\n");
fprintf(ofp, " --tracepoint Tracepoint event (default)\n");
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");
}
}
+/*
+ * 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];
+
+ /*
+ * 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
*/
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;
strcpy(ev.name, "*");
ev.loglevel_type = opt_loglevel_type;
if (opt_loglevel) {
- assert(opt_userspace || opt_jul || opt_log4j);
+ 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);
goto error;
}
} else {
- assert(opt_userspace || opt_jul || opt_log4j);
+ assert(opt_userspace || opt_jul || opt_log4j || opt_python);
if (opt_userspace) {
ev.loglevel = -1;
} else if (opt_jul || opt_log4j) {
ev.loglevel = LTTNG_LOGLEVEL_JUL_ALL;
+ } else if (opt_python) {
+ ev.loglevel = LTTNG_LOGLEVEL_PYTHON_DEBUG;
}
}
}
} else {
ev.loglevel = -1;
}
- } else if (opt_jul || opt_log4j) {
+ } 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 domain.");
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);
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;
static int opt_kernel;
static int opt_jul;
static int opt_log4j;
+static int opt_python;
static char *opt_channel;
static int opt_domain;
static int opt_fields;
{"kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, 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},
#if 0
/* Not implemented yet */
{"userspace", 'u', POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_cmd_name, OPT_USERSPACE, 0, 0},
fprintf(ofp, " -u, --userspace Select user-space domain.\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 using logging\n");
fprintf(ofp, " -f, --fields List event fields.\n");
fprintf(ofp, " --syscall List available system calls.\n");
#if 0
domain.type = LTTNG_DOMAIN_JUL;
} else if (opt_log4j) {
domain.type = LTTNG_DOMAIN_LOG4J;
+ } else if (opt_python) {
+ domain.type = LTTNG_DOMAIN_PYTHON;
}
agent_domain_str = get_domain_str(domain.type);
case LTTNG_DOMAIN_LOG4J:
MSG(" - LOG4j (Logging for Java)");
break;
+ case LTTNG_DOMAIN_PYTHON:
+ MSG(" - Python (logging)");
+ break;
default:
break;
}
domain.type = LTTNG_DOMAIN_JUL;
} else if (opt_log4j) {
domain.type = LTTNG_DOMAIN_LOG4J;
+ } else if (opt_python) {
+ domain.type = LTTNG_DOMAIN_PYTHON;
}
if (!opt_kernel && opt_syscall) {
goto end;
}
- if (opt_kernel || opt_userspace || opt_jul || opt_log4j) {
+ if (opt_kernel || opt_userspace || opt_jul || opt_log4j || opt_python) {
handle = lttng_create_handle(session_name, &domain);
if (handle == NULL) {
ret = CMD_FATAL;
}
if (session_name == NULL) {
- if (!opt_kernel && !opt_userspace && !opt_jul && !opt_log4j) {
+ if (!opt_kernel && !opt_userspace && !opt_jul && !opt_log4j
+ && !opt_python) {
ret = list_sessions(NULL);
if (ret) {
goto end;
goto end;
}
}
- if (opt_jul || opt_log4j) {
+ if (opt_jul || opt_log4j || opt_python) {
ret = list_agent_events();
if (ret) {
goto end;
case LTTNG_DOMAIN_LOG4J:
MSG("=== Domain: LOG4j (Logging for Java) ===\n");
break;
+ case LTTNG_DOMAIN_PYTHON:
+ MSG("=== Domain: Python (logging) ===\n");
+ break;
default:
MSG("=== Domain: Unimplemented ===\n");
break;
}
if (domains[i].type == LTTNG_DOMAIN_JUL ||
- domains[i].type == LTTNG_DOMAIN_LOG4J) {
+ domains[i].type == LTTNG_DOMAIN_LOG4J ||
+ domains[i].type == LTTNG_DOMAIN_PYTHON) {
ret = list_session_agent_events();
if (ret) {
goto end;
static const char *str_ust = "UST";
static const char *str_jul = "JUL";
static const char *str_log4j = "LOG4J";
+static const char *str_python = "Python";
/*
* get_session_name
case LTTNG_DOMAIN_LOG4J:
str_dom = str_log4j;
break;
+ case LTTNG_DOMAIN_PYTHON:
+ str_dom = str_python;
+ break;
default:
/* Should not have an unknown domain or else define it. */
assert(0);
const char * const config_domain_type_ust = "UST";
const char * const config_domain_type_jul = "JUL";
const char * const config_domain_type_log4j = "LOG4J";
+const char * const config_domain_type_python = "PYTHON";
const char * const config_buffer_type_per_pid = "PER_PID";
const char * const config_buffer_type_per_uid = "PER_UID";
ret = LTTNG_DOMAIN_JUL;
} else if (!strcmp((char *) domain, config_domain_type_log4j)) {
ret = LTTNG_DOMAIN_LOG4J;
+ } else if (!strcmp((char *) domain, config_domain_type_python)) {
+ ret = LTTNG_DOMAIN_PYTHON;
} else {
goto error;
}
struct lttng_domain *ust_domain = NULL;
struct lttng_domain *jul_domain = NULL;
struct lttng_domain *log4j_domain = NULL;
+ struct lttng_domain *python_domain = NULL;
for (node = xmlFirstElementChild(session_node); node;
node = xmlNextElementSibling(node)) {
}
log4j_domain = domain;
break;
+ case LTTNG_DOMAIN_PYTHON:
+ if (python_domain) {
+ /* Same domain seen twice, invalid! */
+ goto domain_init_error;
+ }
+ python_domain = domain;
+ break;
default:
WARN("Invalid domain type");
goto domain_init_error;
<xs:enumeration value="UST"/>
<xs:enumeration value="JUL"/>
<xs:enumeration value="LOG4J"/>
+ <xs:enumeration value="PYTHON"/>
</xs:restriction>
</xs:simpleType>
#define DEFAULT_SYS_LOG4J_EVENT_NAME "lttng_log4j:sys*"
#define DEFAULT_USER_LOG4J_EVENT_NAME "lttng_log4j:user*"
-/* JUL default channel name. */
+/* Default Python domain channel name. */
+#define DEFAULT_PYTHON_CHANNEL_NAME "lttng_python_channel"
+/* Default Python tracepoint name. This is a wildcard for the python domain. */
+#define DEFAULT_USER_PYTHON_EVENT_NAME "lttng_python:user*"
+
#define DEFAULT_CHANNEL_OVERWRITE 0
#define DEFAULT_CHANNEL_TRACEFILE_SIZE 0
#define DEFAULT_CHANNEL_TRACEFILE_COUNT 0
const char * const mi_lttng_loglevel_str_log4j_trace = "LOG4J_TRACE";
const char * const mi_lttng_loglevel_str_log4j_all = "LOG4J_ALL";
+/* String related to loglevel Python */
+const char * const mi_lttng_loglevel_str_python_critical = "PYTHON_CRITICAL";
+const char * const mi_lttng_loglevel_str_python_error = "PYTHON_ERROR";
+const char * const mi_lttng_loglevel_str_python_warning = "PYTHON_WARNING";
+const char * const mi_lttng_loglevel_str_python_info = "PYTHON_INFO";
+const char * const mi_lttng_loglevel_str_python_debug = "PYTHON_DEBUG";
+const char * const mi_lttng_loglevel_str_python_notset = "PYTHON_NOTSET";
+
/* String related to loglevel type */
const char * const mi_lttng_loglevel_type_all = "ALL";
const char * const mi_lttng_loglevel_type_range = "RANGE";
return mi_lttng_loglevel_str_unknown;
}
break;
+ case LTTNG_DOMAIN_PYTHON:
+ switch (value) {
+ case LTTNG_LOGLEVEL_PYTHON_CRITICAL:
+ return mi_lttng_loglevel_str_python_critical;
+ case LTTNG_LOGLEVEL_PYTHON_ERROR:
+ return mi_lttng_loglevel_str_python_error;
+ case LTTNG_LOGLEVEL_PYTHON_WARNING:
+ return mi_lttng_loglevel_str_python_warning;
+ case LTTNG_LOGLEVEL_PYTHON_INFO:
+ return mi_lttng_loglevel_str_python_info;
+ case LTTNG_LOGLEVEL_PYTHON_DEBUG:
+ return mi_lttng_loglevel_str_python_debug;
+ case LTTNG_LOGLEVEL_PYTHON_NOTSET:
+ return mi_lttng_loglevel_str_python_notset;
+ default:
+ return mi_lttng_loglevel_str_unknown;
+ }
+ break;
}
/* Reaching this means the domain is unknown. */
const char * const mi_lttng_loglevel_str_log4j_trace;
const char * const mi_lttng_loglevel_str_log4j_all;
+/* String related to loglevel Python */
+const char * const mi_lttng_loglevel_str_python_critical;
+const char * const mi_lttng_loglevel_str_python_error;
+const char * const mi_lttng_loglevel_str_python_warning;
+const char * const mi_lttng_loglevel_str_python_info;
+const char * const mi_lttng_loglevel_str_python_debug;
+const char * const mi_lttng_loglevel_str_python_notset;
+
/* String related to loglevel type */
const char * const mi_lttng_loglevel_type_all;
const char * const mi_lttng_loglevel_type_range;
<xs:enumeration value="LOG4J_DEBUG" />
<xs:enumeration value="LOG4J_TRACE" />
<xs:enumeration value="LOG4J_ALL" />
+ <xs:enumeration value="PYTHON_CRITICAL" />
+ <xs:enumeration value="PYTHON_ERROR" />
+ <xs:enumeration value="PYTHON_WARNING" />
+ <xs:enumeration value="PYTHON_INFO" />
+ <xs:enumeration value="PYTHON_DEBUG" />
+ <xs:enumeration value="PYTHON_NOTSET" />
<xs:enumeration value="UNKNOWN" />
</xs:restriction>
</xs:simpleType>
<xs:enumeration value="UST"/>
<xs:enumeration value="JUL"/>
<xs:enumeration value="LOG4J"/>
+ <xs:enumeration value="PYTHON"/>
</xs:restriction>
</xs:simpleType>
case LTTNG_DOMAIN_UST:
case LTTNG_DOMAIN_JUL:
case LTTNG_DOMAIN_LOG4J:
+ case LTTNG_DOMAIN_PYTHON:
memcpy(dst, src, sizeof(struct lttng_domain));
break;
default:
}
/*
- * Depending on the event, return a newly allocated JUL filter expression or
+ * Depending on the event, return a newly allocated agent filter expression or
* NULL if not applicable.
*
* An event with NO loglevel and the name is * will return NULL.
*/
-static char *set_jul_filter(const char *filter, struct lttng_event *ev)
+static char *set_agent_filter(const char *filter, struct lttng_event *ev)
{
int err;
- char *jul_filter = NULL;
+ char *agent_filter = NULL;
assert(ev);
/* Don't add filter for the '*' event. */
if (ev->name[0] != '*') {
if (filter) {
- err = asprintf(&jul_filter, "(%s) && (logger_name == \"%s\")", filter,
+ err = asprintf(&agent_filter, "(%s) && (logger_name == \"%s\")", filter,
ev->name);
} else {
- err = asprintf(&jul_filter, "logger_name == \"%s\"", ev->name);
+ err = asprintf(&agent_filter, "logger_name == \"%s\"", ev->name);
}
if (err < 0) {
PERROR("asprintf");
op = "==";
}
- if (filter || jul_filter) {
+ if (filter || agent_filter) {
char *new_filter;
err = asprintf(&new_filter, "(%s) && (int_loglevel %s %d)",
- jul_filter ? jul_filter : filter, op,
+ agent_filter ? agent_filter : filter, op,
ev->loglevel);
- if (jul_filter) {
- free(jul_filter);
+ if (agent_filter) {
+ free(agent_filter);
}
- jul_filter = new_filter;
+ agent_filter = new_filter;
} else {
- err = asprintf(&jul_filter, "int_loglevel %s %d", op,
+ err = asprintf(&agent_filter, "int_loglevel %s %d", op,
ev->loglevel);
}
if (err < 0) {
}
}
- return jul_filter;
+ return agent_filter;
error:
- free(jul_filter);
+ free(agent_filter);
return NULL;
}
*/
if (exclusion_count == 0 && filter_expression == NULL &&
(handle->domain.type != LTTNG_DOMAIN_JUL &&
- handle->domain.type != LTTNG_DOMAIN_LOG4J)) {
+ handle->domain.type != LTTNG_DOMAIN_LOG4J &&
+ handle->domain.type != LTTNG_DOMAIN_PYTHON)) {
goto ask_sessiond;
}
/* Parse filter expression */
if (filter_expression != NULL || handle->domain.type == LTTNG_DOMAIN_JUL
- || handle->domain.type == LTTNG_DOMAIN_LOG4J) {
+ || handle->domain.type == LTTNG_DOMAIN_LOG4J
+ || handle->domain.type == LTTNG_DOMAIN_PYTHON) {
if (handle->domain.type == LTTNG_DOMAIN_JUL ||
- handle->domain.type == LTTNG_DOMAIN_LOG4J) {
- char *jul_filter;
+ handle->domain.type == LTTNG_DOMAIN_LOG4J ||
+ handle->domain.type == LTTNG_DOMAIN_PYTHON) {
+ char *agent_filter;
/* Setup JUL filter if needed. */
- jul_filter = set_jul_filter(filter_expression, ev);
- if (!jul_filter) {
+ agent_filter = set_agent_filter(filter_expression, ev);
+ if (!agent_filter) {
if (!filter_expression) {
/* No JUL and no filter, just skip everything below. */
goto ask_sessiond;
}
} else {
/*
- * With a JUL filter, the original filter has been added to it
- * thus replace the filter expression.
+ * With an agent filter, the original filter has been added to
+ * it thus replace the filter expression.
*/
- filter_expression = jul_filter;
+ filter_expression = agent_filter;
free_filter_expression = 1;
}
}
*/
if (filter_expression == NULL &&
(handle->domain.type != LTTNG_DOMAIN_JUL &&
- handle->domain.type != LTTNG_DOMAIN_LOG4J)) {
+ handle->domain.type != LTTNG_DOMAIN_LOG4J &&
+ handle->domain.type != LTTNG_DOMAIN_PYTHON)) {
goto ask_sessiond;
}
/* Parse filter expression */
if (filter_expression != NULL || handle->domain.type == LTTNG_DOMAIN_JUL
- || handle->domain.type == LTTNG_DOMAIN_LOG4J) {
+ || handle->domain.type == LTTNG_DOMAIN_LOG4J
+ || handle->domain.type == LTTNG_DOMAIN_PYTHON) {
if (handle->domain.type == LTTNG_DOMAIN_JUL ||
- handle->domain.type == LTTNG_DOMAIN_LOG4J) {
- char *jul_filter;
+ handle->domain.type == LTTNG_DOMAIN_LOG4J ||
+ handle->domain.type == LTTNG_DOMAIN_PYTHON) {
+ char *agent_filter;
/* Setup JUL filter if needed. */
- jul_filter = set_jul_filter(filter_expression, ev);
- if (!jul_filter) {
+ agent_filter = set_agent_filter(filter_expression, ev);
+ if (!agent_filter) {
if (!filter_expression) {
/* No JUL and no filter, just skip everything below. */
goto ask_sessiond;
* With a JUL filter, the original filter has been added to it
* thus replace the filter expression.
*/
- filter_expression = jul_filter;
+ filter_expression = agent_filter;
free_filter_expression = 1;
}
}
regression/ust/overlap/test_overlap
regression/ust/java-jul/test_java_jul
regression/ust/java-log4j/test_java_log4j
+regression/ust/python-logging/test_python_logging
regression/ust/test_event_basic
regression/ust/test_event_tracef
regression/ust/test_event_wildcard
if HAVE_LIBLTTNG_UST_CTL
SUBDIRS = nprocesses high-throughput low-throughput before-after multi-session \
overlap buffers-pid linking daemon exit-fast fork libc-wrapper \
- periodical-metadata-flush java-jul java-log4j
+ periodical-metadata-flush java-jul java-log4j python-logging
EXTRA_DIST = test_event_basic test_event_wildcard test_event_tracef test_event_perf
--- /dev/null
+#!/usr/bin/env python
+#
+# Copyright (C) 2014 - David Goulet <dgoulet@efficios.com>
+#
+# This library is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; version 2.1 of the License.
+#
+# This library is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+import sys
+import logging
+import errno
+
+from time import sleep
+
+def cleanup(code, agent = None):
+ """
+ Cleanup agent and exit with given code.
+ """
+ if agent is not None:
+ agent.destroy()
+
+ sys.exit(code)
+
+try:
+ import lttng_agent
+except ImportError as e:
+ print("LTTng Agent not found. Aborting")
+ cleanup(errno.ENOSYS)
+
+def run():
+ """
+ Main for this test program. Based on the Java testing program that behaves
+ exactly the same.
+ """
+
+ agent = lttng_agent.LTTngAgent()
+ ev1 = logging.getLogger("python-ev-test1");
+ ev2 = logging.getLogger("python-ev-test2");
+
+ try:
+ nr_iter = int(sys.argv[1])
+ wait_time = int(sys.argv[2])
+ fire_debug_ev = 0
+ fire_second_ev = 0
+ except IndexError as e:
+ print("Missing arguments. Aborting")
+ cleanup(errno.EINVAL, agent)
+ except ValueError as e:
+ print("Invalid arguments. Aborting")
+ cleanup(errno.EINVAL, agent)
+
+ if len(sys.argv) > 3:
+ fire_debug_ev = int(sys.argv[3])
+ if len(sys.argv) > 4:
+ fire_second_ev = int(sys.argv[4])
+
+ for i in range(0, nr_iter):
+ ev1.info("%s fired" % ev1.name)
+ if fire_debug_ev != 0:
+ ev1.debug("%s DEBUG fired" % ev1.name)
+ sleep(wait_time)
+
+ if fire_second_ev != 0:
+ ev2.info("%s fired" % ev2.name)
+
+if __name__ == "__main__":
+ run()
--- /dev/null
+#if USE_PYTHON
+
+noinst_SCRIPTS = test_python_logging
+EXTRA_DIST = test_python_logging LTTngPython.py
+
+all-local:
+ @if [ x"$(srcdir)" != x"$(builddir)" ]; then \
+ for script in $(EXTRA_DIST); do \
+ cp -f $(srcdir)/$$script $(builddir); \
+ done; \
+ fi
+
+clean-local:
+ rm -f *.class
+ @if [ x"$(srcdir)" != x"$(builddir)" ]; then \
+ for script in $(EXTRA_DIST); do \
+ rm -f $(builddir)/$$script; \
+ done; \
+ fi
+
+#endif
--- /dev/null
+#!/bin/bash
+#
+# Copyright (C) - 2014 David Goulet <dgoulet@efficios.com>
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License, version 2 only, as published by
+# the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+TEST_DESC="Java Python support"
+
+CURDIR=$(dirname $0)/
+TESTDIR=$CURDIR/../../..
+NR_ITER=5
+NR_SEC_WAIT=1
+TESTAPP_NAME="LTTngTest"
+TESTAPP_BIN="$TESTAPP_NAME.py"
+TESTAPP_PATH="$CURDIR"
+SESSION_NAME="python-test"
+EVENT_NAME="python-ev-test1"
+EVENT_NAME2="python-ev-test2"
+OUTPUT_DEST="/dev/null"
+
+NUM_TESTS=156
+
+source $TESTDIR/utils/utils.sh
+
+function run_app
+{
+ local debug_tp=$1
+ local fire_second_tp=$2
+
+ python $TESTAPP_PATH/$TESTAPP_BIN $NR_ITER $NR_SEC_WAIT $debug_tp $fire_second_tp
+}
+
+function run_app_background
+{
+ run_app $@ &
+}
+
+function enable_python_loglevel_only()
+{
+ sess_name=$1
+ event_name="$2"
+ loglevel=$3
+ channel_name=$4
+
+ if [ -z $channel_name ]; then
+ # default channel if none specified
+ chan=""
+ else
+ chan="-c $channel_name"
+ fi
+
+ $TESTDIR/../src/bin/lttng/$LTTNG_BIN enable-event --loglevel-only $loglevel "$event_name" $chan -s $sess_name -p >$OUTPUT_DEST
+ ok $? "Enable Python event $event_name for session $sess_name with loglevel-only $loglevel"
+}
+
+function enable_python_filter()
+{
+ local sess_name="$1"
+ local event_name="$2"
+ local filter="$3"
+
+ $TESTDIR/../src/bin/lttng/$LTTNG_BIN enable-event "$event_name" -s $sess_name -p --filter "$filter" >/dev/null 2>&1
+ ok $? "Enable event $event_name with filter $filter for session $sess_name"
+}
+
+function enable_python_filter_loglevel_only()
+{
+ local sess_name="$1"
+ local event_name="$2"
+ local filter="$3"
+ local loglevel="$4"
+
+ $TESTDIR/../src/bin/lttng/$LTTNG_BIN enable-event --loglevel-only $loglevel "$event_name" -s $sess_name -p --filter "$filter" >$OUTPUT_DEST
+ ok $? "Enable event $event_name with filter \"$filter\" and loglevel-only $loglevel for session $sess_name"
+}
+
+# MUST set TESTDIR before calling those functions
+
+function test_python_before_start ()
+{
+ diag "Test Python application BEFORE tracing starts"
+ create_lttng_session $SESSION_NAME $TRACE_PATH
+ enable_python_lttng_event $SESSION_NAME $EVENT_NAME
+
+ # Run 5 times with a 1 second delay
+ run_app_background
+
+ start_lttng_tracing $SESSION_NAME
+
+ # Wait for the applications started in background
+ wait ${!}
+
+ stop_lttng_tracing $SESSION_NAME
+ destroy_lttng_session $SESSION_NAME
+
+ # Validate test. Expecting all events.
+ trace_match_only $EVENT_NAME $NR_ITER $TRACE_PATH
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+}
+
+function test_python_after_start ()
+{
+ diag "Test Python application AFTER tracing starts"
+
+ create_lttng_session $SESSION_NAME $TRACE_PATH
+ enable_python_lttng_event $SESSION_NAME $EVENT_NAME
+ start_lttng_tracing $SESSION_NAME
+
+ # Run 5 times with a 1 second delay
+ run_app
+
+ stop_lttng_tracing $SESSION_NAME
+ destroy_lttng_session $SESSION_NAME
+
+ # Validate test. Expecting all events.
+ trace_match_only $EVENT_NAME $NR_ITER $TRACE_PATH
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+}
+
+function test_python_loglevel ()
+{
+ diag "Test Python application with loglevel"
+
+ create_lttng_session $SESSION_NAME $TRACE_PATH
+ enable_python_lttng_event_loglevel $SESSION_NAME $EVENT_NAME "INFO"
+ start_lttng_tracing $SESSION_NAME
+
+ # Run 5 times with a 1 second delay
+ run_app
+
+ stop_lttng_tracing $SESSION_NAME
+ destroy_lttng_session $SESSION_NAME
+
+ # Validate test. Expecting all events.
+ trace_match_only $EVENT_NAME $NR_ITER $TRACE_PATH
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+
+ diag "Test Python applications with lower loglevel"
+
+ create_lttng_session $SESSION_NAME $TRACE_PATH
+ enable_python_lttng_event_loglevel $SESSION_NAME $EVENT_NAME "CRITICAL"
+ start_lttng_tracing $SESSION_NAME
+
+ # Run 5 times with a 1 second delay
+ run_app
+
+ stop_lttng_tracing $SESSION_NAME
+ destroy_lttng_session $SESSION_NAME
+
+ # Validate test. Expecting 0 events.
+ trace_match_only $EVENT_NAME 0 $TRACE_PATH
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+
+ diag "Test Python applications with higher loglevel"
+
+ create_lttng_session $SESSION_NAME $TRACE_PATH
+ enable_python_lttng_event_loglevel $SESSION_NAME $EVENT_NAME "DEBUG"
+ start_lttng_tracing $SESSION_NAME
+
+ # Run 5 times with a 1 second delay
+ run_app
+
+ stop_lttng_tracing $SESSION_NAME
+ destroy_lttng_session $SESSION_NAME
+
+ # Validate test. Expecting all events.
+ trace_match_only $EVENT_NAME $NR_ITER $TRACE_PATH
+ return $?
+}
+
+function test_python_loglevel_multiple ()
+{
+ diag "Test Python application with multiple loglevel"
+
+ create_lttng_session $SESSION_NAME $TRACE_PATH
+ enable_python_lttng_event_loglevel $SESSION_NAME $EVENT_NAME "INFO"
+ enable_python_lttng_event_loglevel $SESSION_NAME $EVENT_NAME "DEBUG"
+ start_lttng_tracing $SESSION_NAME
+
+ # Run 5 times with a 1 second delay and fire two TP.
+ run_app 1
+
+ stop_lttng_tracing $SESSION_NAME
+ destroy_lttng_session $SESSION_NAME
+
+ # Validate test. Expecting all events times two.
+ trace_match_only $EVENT_NAME $(($NR_ITER * 2)) $TRACE_PATH
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+
+ create_lttng_session $SESSION_NAME $TRACE_PATH
+ enable_python_lttng_event_loglevel $SESSION_NAME '*' "INFO"
+ enable_python_lttng_event_loglevel $SESSION_NAME '*' "DEBUG"
+ start_lttng_tracing $SESSION_NAME
+
+ # Run 5 times with a 1 second delay and fire two TP.
+ run_app 1
+
+ stop_lttng_tracing $SESSION_NAME
+ destroy_lttng_session $SESSION_NAME
+
+ # Validate test. Expecting all events times two.
+ trace_match_only $EVENT_NAME $(($NR_ITER * 2)) $TRACE_PATH
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+}
+
+function test_python_multi_session_loglevel()
+{
+ diag "Test Python with multiple session"
+
+ create_lttng_session $SESSION_NAME-1 $TRACE_PATH/$SESSION_NAME-1
+ enable_python_loglevel_only $SESSION_NAME-1 '*' "INFO"
+ start_lttng_tracing $SESSION_NAME-1
+
+ create_lttng_session $SESSION_NAME-2 $TRACE_PATH/$SESSION_NAME-2
+ enable_python_loglevel_only $SESSION_NAME-2 '*' "DEBUG"
+ start_lttng_tracing $SESSION_NAME-2
+
+ # Run 5 times with a 1 second delay and fire second TP.
+ run_app 1 1
+
+ stop_lttng_tracing $SESSION_NAME-1
+ stop_lttng_tracing $SESSION_NAME-2
+ destroy_lttng_session $SESSION_NAME-1
+ destroy_lttng_session $SESSION_NAME-2
+
+ # Expecting NR_ITER events being the main event and the second tp one.
+ trace_matches $EVENT_NAME $NR_ITER $TRACE_PATH/$SESSION_NAME-1
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+ trace_matches $EVENT_NAME2 1 $TRACE_PATH/$SESSION_NAME-1
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+
+ # Expectin NR_ITER events being the debug TP.
+ trace_match_only $EVENT_NAME $NR_ITER $TRACE_PATH/$SESSION_NAME-2
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+}
+
+function test_python_multi_session_disable()
+{
+ diag "Test Python with multiple session with disabled event"
+
+ create_lttng_session $SESSION_NAME-1 $TRACE_PATH/$SESSION_NAME-1
+ enable_python_lttng_event $SESSION_NAME-1 $EVENT_NAME
+ enable_python_lttng_event $SESSION_NAME-1 $EVENT_NAME2
+ disable_python_lttng_event $SESSION_NAME-1 $EVENT_NAME
+ start_lttng_tracing $SESSION_NAME-1
+
+ create_lttng_session $SESSION_NAME-2 $TRACE_PATH/$SESSION_NAME-2
+ enable_python_lttng_event $SESSION_NAME-2 $EVENT_NAME2
+ start_lttng_tracing $SESSION_NAME-2
+
+ # Run 5 times with a 1 second delay and fire second TP.
+ run_app 0 1
+
+ stop_lttng_tracing $SESSION_NAME-1
+ stop_lttng_tracing $SESSION_NAME-2
+ destroy_lttng_session $SESSION_NAME-1
+ destroy_lttng_session $SESSION_NAME-2
+
+ # Validate test. Expecting one event of the second TP.
+ trace_match_only $EVENT_NAME2 1 $TRACE_PATH/$SESSION_NAME-1
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+
+ # Validate test. Expecting one event of the second TP.
+ trace_match_only $EVENT_NAME2 1 $TRACE_PATH/$SESSION_NAME-2
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+}
+
+function test_python_multi_session_disable_wildcard()
+{
+ diag "Test Python with multiple session with disabled wildcard event"
+
+ create_lttng_session $SESSION_NAME-1 $TRACE_PATH/$SESSION_NAME-1
+ enable_python_lttng_event $SESSION_NAME-1 '*'
+
+ create_lttng_session $SESSION_NAME-2 $TRACE_PATH/$SESSION_NAME-2
+ enable_python_lttng_event $SESSION_NAME-2 '*'
+
+ disable_python_lttng_event $SESSION_NAME-1 '*'
+
+ start_lttng_tracing $SESSION_NAME-1
+ start_lttng_tracing $SESSION_NAME-2
+
+ run_app
+
+ stop_lttng_tracing $SESSION_NAME-1
+ stop_lttng_tracing $SESSION_NAME-2
+ destroy_lttng_session $SESSION_NAME-1
+ destroy_lttng_session $SESSION_NAME-2
+
+ # Validate test. Expecting NO event of the first TP.
+ trace_match_only $EVENT_NAME 0 $TRACE_PATH/$SESSION_NAME-1
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+
+ # Validate test. Expecting all events of the first TP.
+ trace_match_only $EVENT_NAME $NR_ITER $TRACE_PATH/$SESSION_NAME-2
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+}
+
+function test_python_disable_all()
+{
+ diag "Test Python with multiple session with disabled all event"
+
+ create_lttng_session $SESSION_NAME $TRACE_PATH/$SESSION_NAME
+ enable_python_lttng_event $SESSION_NAME '*'
+ enable_python_lttng_event $SESSION_NAME $EVENT_NAME
+ enable_python_lttng_event $SESSION_NAME $EVENT_NAME2
+
+ disable_python_lttng_event $SESSION_NAME '*'
+
+ start_lttng_tracing $SESSION_NAME
+
+ run_app 0 1
+
+ stop_lttng_tracing $SESSION_NAME
+ destroy_lttng_session $SESSION_NAME
+
+ # Validate test. Expecting NO event of the first TP and second TP.
+ trace_match_only $EVENT_NAME 0 $TRACE_PATH/$SESSION_NAME
+ trace_match_only $EVENT_NAME2 0 $TRACE_PATH/$SESSION_NAME
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+}
+
+function test_python_multi_session()
+{
+ diag "Test Python with multiple session"
+
+ create_lttng_session $SESSION_NAME-1 $TRACE_PATH/$SESSION_NAME-1
+ enable_python_lttng_event $SESSION_NAME-1 $EVENT_NAME
+ start_lttng_tracing $SESSION_NAME-1
+
+ create_lttng_session $SESSION_NAME-2 $TRACE_PATH/$SESSION_NAME-2
+ enable_python_lttng_event $SESSION_NAME-2 $EVENT_NAME2
+ start_lttng_tracing $SESSION_NAME-2
+
+ # Run 5 times with a 1 second delay and fire second TP.
+ run_app 0 1
+
+ stop_lttng_tracing $SESSION_NAME-1
+ stop_lttng_tracing $SESSION_NAME-2
+ destroy_lttng_session $SESSION_NAME-1
+ destroy_lttng_session $SESSION_NAME-2
+
+ # Validate test. Expecting all events of first TP
+ trace_match_only $EVENT_NAME $NR_ITER $TRACE_PATH/$SESSION_NAME-1
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+
+ # Validate test. Expecting one event of the second TP.
+ trace_match_only $EVENT_NAME2 1 $TRACE_PATH/$SESSION_NAME-2
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+}
+
+function test_python_destroy_session()
+{
+ diag "Test Python two session with destroy"
+
+ create_lttng_session $SESSION_NAME $TRACE_PATH/first-sess
+ enable_python_lttng_event $SESSION_NAME $EVENT_NAME
+ start_lttng_tracing $SESSION_NAME
+
+ # Run 5 times with a 1 second delay
+ run_app_background 0 1
+
+ sleep 1
+
+ stop_lttng_tracing $SESSION_NAME
+ destroy_lttng_session $SESSION_NAME
+
+ # Validate test. Expecting at least one event num 1
+ validate_trace $EVENT_NAME $TRACE_PATH/first-sess
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+
+ create_lttng_session $SESSION_NAME $TRACE_PATH/second-sess
+ enable_python_lttng_event $SESSION_NAME $EVENT_NAME2
+ start_lttng_tracing $SESSION_NAME
+
+ # Wait for the applications started in background
+ wait ${!}
+
+ stop_lttng_tracing $SESSION_NAME
+ destroy_lttng_session $SESSION_NAME
+
+ # Validate test. Expecting only one event num 2
+ trace_match_only $EVENT_NAME2 1 $TRACE_PATH/second-sess
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+}
+
+function test_python_filtering()
+{
+ diag "Test Python filtering"
+
+ create_lttng_session $SESSION_NAME $TRACE_PATH/$SESSION_NAME
+ # Enable all event with a filter.
+ enable_python_filter $SESSION_NAME '*' 'msg == "python-ev-test2 fired"'
+ start_lttng_tracing $SESSION_NAME
+
+ # Run 5 times with a 1 second delay and fire second TP.
+ run_app 0 1
+
+ stop_lttng_tracing $SESSION_NAME
+ destroy_lttng_session $SESSION_NAME
+
+ # Validate test. Expecting one event of the second TP only.
+ trace_match_only $EVENT_NAME2 1 $TRACE_PATH/$SESSION_NAME
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+
+ create_lttng_session $SESSION_NAME $TRACE_PATH/$SESSION_NAME
+ # Enable first Logger but filter msg payload for the INFO one while
+ # triggering the debug and second TP.
+ enable_python_filter $SESSION_NAME $EVENT_NAME 'msg == "python-ev-test1 fired"'
+ start_lttng_tracing $SESSION_NAME
+
+ # Run 5 times with a 1 second delay, fire debug and second TP.
+ run_app 1 1
+
+ stop_lttng_tracing $SESSION_NAME
+ destroy_lttng_session $SESSION_NAME
+
+ # Validate test. Expecting NR_ITER event of the main INFO tp.
+ trace_match_only $EVENT_NAME $NR_ITER $TRACE_PATH/$SESSION_NAME
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+}
+
+function test_python_disable()
+{
+ diag "Test Python disable event"
+
+ create_lttng_session $SESSION_NAME $TRACE_PATH/$SESSION_NAME
+ # Enable all event with a filter.
+ enable_python_lttng_event $SESSION_NAME $EVENT_NAME
+ enable_python_lttng_event $SESSION_NAME $EVENT_NAME2
+ disable_python_lttng_event $SESSION_NAME $EVENT_NAME
+ start_lttng_tracing $SESSION_NAME
+
+ # Run 5 times with a 1 second delay and fire second TP.
+ run_app 0 1
+
+ stop_lttng_tracing $SESSION_NAME
+ destroy_lttng_session $SESSION_NAME
+
+ # Validate test. Expecting one event of the second TP only.
+ trace_match_only $EVENT_NAME2 1 $TRACE_PATH/$SESSION_NAME
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+}
+
+function test_python_disable_enable()
+{
+ diag "Test Python disable event followed by an enable"
+
+ create_lttng_session $SESSION_NAME $TRACE_PATH/$SESSION_NAME
+ # Enable all event with a filter.
+ enable_python_lttng_event $SESSION_NAME $EVENT_NAME
+ disable_python_lttng_event $SESSION_NAME $EVENT_NAME
+ enable_python_lttng_event $SESSION_NAME $EVENT_NAME
+ start_lttng_tracing $SESSION_NAME
+
+ # Run 5 times with a 1 second delay and fire second TP.
+ run_app 0 1
+
+ stop_lttng_tracing $SESSION_NAME
+ destroy_lttng_session $SESSION_NAME
+
+ # Validate test. Expecting NR_ITER event of the main INFO tp.
+ trace_match_only $EVENT_NAME $NR_ITER $TRACE_PATH/$SESSION_NAME
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+}
+
+function test_python_filter_loglevel()
+{
+ local BOGUS_EVENT_NAME="not_a_real_event"
+ local FILTER="int_loglevel > 30 || int_loglevel < 30"
+ local ALL_EVENTS="."
+
+ diag "Test Python a filter with a loglevel"
+
+ create_lttng_session $SESSION_NAME $TRACE_PATH/$SESSION_NAME
+ # Enable an event with a filter and the loglevel-only option.
+ enable_python_filter_loglevel_only $SESSION_NAME $BOGUS_EVENT_NAME "$FILTER" "INFO"
+ disable_python_lttng_event $SESSION_NAME $BOGUS_EVENT_NAME
+ enable_python_filter_loglevel_only $SESSION_NAME $BOGUS_EVENT_NAME "$FILTER" "INFO"
+ start_lttng_tracing $SESSION_NAME
+
+ # Run 5 times with a 1 second delay and fire second TP.
+ run_app 0 1
+
+ stop_lttng_tracing $SESSION_NAME
+ destroy_lttng_session $SESSION_NAME
+
+ # Validate test. Expecting no events.
+ trace_match_only $ALL_EVENTS 0 $TRACE_PATH/$SESSION_NAME
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
+}
+
+plan_tests $NUM_TESTS
+
+print_test_banner "$TEST_DESC"
+
+if [ ! -f "$TESTAPP_BIN" ]; then
+ withapp=0
+else
+ withapp=1
+fi
+
+skip $withapp "Python support is needed. Skipping all tests." $NUM_TESTS ||
+{
+ start_lttng_sessiond
+
+ tests=(
+ test_python_multi_session_disable_wildcard
+ test_python_multi_session_disable
+ test_python_disable
+ test_python_disable_enable
+ test_python_disable_all
+ test_python_filtering
+ test_python_multi_session_loglevel
+ test_python_destroy_session
+ test_python_loglevel
+ test_python_loglevel_multiple
+ test_python_before_start
+ test_python_after_start
+ test_python_multi_session
+ test_python_filter_loglevel
+ )
+
+ for fct_test in ${tests[@]};
+ do
+ TRACE_PATH=$(mktemp -d)
+
+ ${fct_test}
+ if [ $? -ne 0 ]; then
+ break;
+ fi
+ rm -rf $TRACE_PATH
+ done
+
+ stop_lttng_sessiond
+}
ok $? "Enable LOG4J event $event_name for session $sess_name with loglevel $loglevel"
}
+function enable_python_lttng_event()
+{
+ sess_name=$1
+ event_name="$2"
+ channel_name=$3
+
+ if [ -z $channel_name ]; then
+ # default channel if none specified
+ chan=""
+ else
+ chan="-c $channel_name"
+ fi
+
+ $TESTDIR/../src/bin/lttng/$LTTNG_BIN enable-event "$event_name" $chan -s $sess_name -p >$OUTPUT_DEST
+ ok $? "Enable Python event $event_name for session $sess_name"
+}
+
+function enable_python_lttng_event_loglevel()
+{
+ local sess_name=$1
+ local event_name="$2"
+ local loglevel=$3
+ local channel_name=$4
+
+ if [ -z $channel_name ]; then
+ # default channel if none specified
+ chan=""
+ else
+ chan="-c $channel_name"
+ fi
+
+ $TESTDIR/../src/bin/lttng/$LTTNG_BIN enable-event --loglevel $loglevel "$event_name" $chan -s $sess_name -p >$OUTPUT_DEST
+ ok $? "Enable Python event $event_name for session $sess_name with loglevel $loglevel"
+}
+
function enable_ust_lttng_event_filter()
{
local sess_name="$1"
ok $? "Disable LOG4J event $event_name for session $sess_name"
}
+function disable_python_lttng_event ()
+{
+ local sess_name="$1"
+ local event_name="$2"
+
+ $TESTDIR/../src/bin/lttng/$LTTNG_BIN disable-event "$event_name" -s $sess_name -p >$OUTPUT_DEST
+ ok $? "Disable Python event $event_name for session $sess_name"
+}
+
function start_lttng_tracing ()
{
local sess_name=$1