Add Python agent support
authorDavid Goulet <dgoulet@efficios.com>
Tue, 14 Oct 2014 15:15:22 +0000 (11:15 -0400)
committerDavid Goulet <dgoulet@efficios.com>
Wed, 22 Oct 2014 15:24:36 +0000 (11:24 -0400)
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>
26 files changed:
configure.ac
doc/man/lttng.1
include/lttng/domain.h
include/lttng/event.h
src/bin/lttng-sessiond/agent.c
src/bin/lttng-sessiond/cmd.c
src/bin/lttng-sessiond/event.c
src/bin/lttng-sessiond/main.c
src/bin/lttng-sessiond/save.c
src/bin/lttng/commands/disable_events.c
src/bin/lttng/commands/enable_events.c
src/bin/lttng/commands/list.c
src/bin/lttng/utils.c
src/common/config/config.c
src/common/config/session.xsd
src/common/defaults.h
src/common/mi-lttng.c
src/common/mi-lttng.h
src/common/mi_lttng.xsd
src/lib/lttng-ctl/lttng-ctl.c
tests/fast_regression
tests/regression/ust/Makefile.am
tests/regression/ust/python-logging/LTTngTest.py [new file with mode: 0644]
tests/regression/ust/python-logging/Makefile.am [new file with mode: 0644]
tests/regression/ust/python-logging/test_python_logging [new file with mode: 0755]
tests/utils/utils.sh

index 487a2b9783b1a12d4570d95ad2d5b7ea044bc90b..8d1ff86ade00157200bc8df65990f22c19be0734 100644 (file)
@@ -497,6 +497,7 @@ AC_CONFIG_FILES([
        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
index f6d21e7ad4b9663a8100110a984c41329d41799b..47f273144c797cc3970a2e1b42b54e1fff6d29e5 100644 (file)
@@ -27,10 +27,11 @@ kernel and/or instrumented applications (lttng-ust(3)). Aggregating and reading
 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
@@ -542,6 +543,9 @@ Apply for Java application using Java Util Logging interface (JUL)
 .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.
@@ -557,6 +561,8 @@ For the JUL domain, the loglevel ranges are detailed with the \-\-help
 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).
@@ -708,6 +714,9 @@ Apply for Java application using Java Util Logging interface (JUL)
 .TP
 .BR "\-l, \-\-log4j"
 Apply for Java application using LOG4J
+.TP
+.BR "\-p, \-\-python"
+Apply for Python application using the logging module.
 .RE
 .PP
 
@@ -728,6 +737,8 @@ With \-j alone, the available JUL event from registered application will be
 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':
 
@@ -758,9 +769,12 @@ Select user-space domain.
 .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
 
index becebe2dd96b59537678c75c2b362269416b9553..3ee04191c45411b11cab7c782b44795280ac88ff 100644 (file)
@@ -32,6 +32,7 @@ enum lttng_domain_type {
        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. */
index f1d8e6581252d3c03165e469ada60c1b47b21125..3e8fbe3e83f5f6b92269771fa5f8391a6811a6d4 100644 (file)
@@ -98,6 +98,19 @@ enum lttng_loglevel_log4j {
        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
  */
index 1c1c6ab18ad4fc341f805288de1092f667bedb85..5cb8336c361d4377973b365608ec603597564afe 100644 (file)
@@ -539,6 +539,8 @@ int agent_list_events(struct lttng_event **events,
 
        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) {
index 2a1bfb5f4670110e24ffab931f085dac4ed57f0c..d882b074d54cd4f0348365ab4adb218ce263c48b 100644 (file)
@@ -1138,6 +1138,7 @@ int cmd_disable_event(struct ltt_session *session, int domain,
        }
        case LTTNG_DOMAIN_LOG4J:
        case LTTNG_DOMAIN_JUL:
+       case LTTNG_DOMAIN_PYTHON:
        {
                struct agent *agt;
                struct ltt_ust_session *usess = session->ust_session;
@@ -1542,6 +1543,7 @@ int cmd_enable_event(struct ltt_session *session, struct lttng_domain *domain,
        }
        case LTTNG_DOMAIN_LOG4J:
        case LTTNG_DOMAIN_JUL:
+       case LTTNG_DOMAIN_PYTHON:
        {
                const char *default_event_name, *default_chan_name;
                struct agent *agt;
@@ -1581,10 +1583,19 @@ int cmd_enable_event(struct ltt_session *session, struct lttng_domain *domain,
                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,
@@ -1756,6 +1767,7 @@ ssize_t cmd_list_tracepoints(int domain, struct lttng_event **events)
                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;
@@ -2492,6 +2504,7 @@ ssize_t cmd_list_events(int domain, struct ltt_session *session,
        }
        case LTTNG_DOMAIN_LOG4J:
        case LTTNG_DOMAIN_JUL:
+       case LTTNG_DOMAIN_PYTHON:
                if (session->ust_session) {
                        struct lttng_ht_iter iter;
                        struct agent *agt;
index 099cbd18db8ea42d767951f094df5dfd81856fbe..181926b415f3e2ed9b50fcb35f25d60d515e48e5 100644 (file)
@@ -715,26 +715,31 @@ const char *event_get_default_agent_ust_name(enum lttng_domain_type domain)
 {
        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.
  *
@@ -770,6 +775,8 @@ int event_agent_disable(struct ltt_ust_session *usess, struct agent *agt,
                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;
index fa09758baa7083ed1a0b5c660fdf9f2e2b9ef03c..699d53323dd3b7eefe313d006f3b0e0605941336 100644 (file)
@@ -2603,6 +2603,7 @@ static int copy_session_consumer(int domain, struct ltt_session *session)
                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) {
@@ -2648,6 +2649,7 @@ static int create_ust_session(struct ltt_session *session,
        switch (domain->type) {
        case LTTNG_DOMAIN_JUL:
        case LTTNG_DOMAIN_LOG4J:
+       case LTTNG_DOMAIN_PYTHON:
        case LTTNG_DOMAIN_UST:
                break;
        default:
@@ -2895,6 +2897,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
                        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;
@@ -2977,6 +2980,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
                break;
        case LTTNG_DOMAIN_JUL:
        case LTTNG_DOMAIN_LOG4J:
+       case LTTNG_DOMAIN_PYTHON:
        case LTTNG_DOMAIN_UST:
        {
                if (!ust_app_supported()) {
@@ -3071,6 +3075,7 @@ skip_domain:
                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;
index 908e5f8fd2924d67223ffbdcbf8a04dfc158a502..aae56a8954a081d11508fa8a02f6dc081b7aafb5 100644 (file)
@@ -1161,7 +1161,8 @@ int save_ust_session(struct config_writer *writer,
 
                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) {
index 1ce687aa422aebc2eb96e76e348b4552d3fdd565..e833fe9572141baf13c6a47ca7c922fb647d1155 100644 (file)
@@ -37,6 +37,7 @@ static int opt_userspace;
 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 */
@@ -62,6 +63,7 @@ static struct poptOption long_options[] = {
        {"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
@@ -92,6 +94,7 @@ static void usage(FILE *ofp)
        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");
@@ -178,6 +181,8 @@ static int disable_events(char *session_name)
                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;
index 8b1215b111cfae31c2721c4a61f22211efd79d8e..84bdb83c86466eb7489627bcc783d00e5323d713 100644 (file)
@@ -47,6 +47,7 @@ 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;
@@ -88,6 +89,7 @@ static struct poptOption long_options[] = {
        {"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},
@@ -124,6 +126,7 @@ static void usage(FILE *ofp)
        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");
@@ -197,6 +200,15 @@ static void usage(FILE *ofp)
        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");
@@ -393,6 +405,41 @@ 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];
+
+       /*
+        * 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
  */
@@ -658,6 +705,10 @@ static int enable_events(char *session_name)
                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;
@@ -700,13 +751,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 || 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);
@@ -714,11 +767,13 @@ static int enable_events(char *session_name)
                                        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;
                                }
                        }
                }
@@ -1002,7 +1057,7 @@ static int enable_events(char *session_name)
                        } 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.");
@@ -1016,6 +1071,8 @@ static int enable_events(char *session_name)
                                        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);
@@ -1027,6 +1084,8 @@ static int enable_events(char *session_name)
                                        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;
index ea9427f4770f158458f6e8e79456f2f7d7b6c91b..7c3211a5927ffc2c34a0f3f5e72528be8c8c4575 100644 (file)
@@ -31,6 +31,7 @@ static int opt_userspace;
 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;
@@ -60,6 +61,7 @@ static struct poptOption long_options[] = {
        {"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},
@@ -93,6 +95,7 @@ static void usage(FILE *ofp)
        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
@@ -427,6 +430,8 @@ static int list_agent_events(void)
                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);
@@ -1469,6 +1474,9 @@ static int list_domains(const char *session_name)
                        case LTTNG_DOMAIN_LOG4J:
                                MSG("  - LOG4j (Logging for Java)");
                                break;
+                       case LTTNG_DOMAIN_PYTHON:
+                               MSG("  - Python (logging)");
+                               break;
                        default:
                                break;
                        }
@@ -1561,6 +1569,8 @@ int cmd_list(int argc, const char **argv)
                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) {
@@ -1569,7 +1579,7 @@ int cmd_list(int argc, const char **argv)
                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;
@@ -1578,7 +1588,8 @@ int cmd_list(int argc, const char **argv)
        }
 
        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;
@@ -1607,7 +1618,7 @@ int cmd_list(int argc, const char **argv)
                                goto end;
                        }
                }
-               if (opt_jul || opt_log4j) {
+               if (opt_jul || opt_log4j || opt_python) {
                        ret = list_agent_events();
                        if (ret) {
                                goto end;
@@ -1705,6 +1716,9 @@ int cmd_list(int argc, const char **argv)
                                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;
@@ -1730,7 +1744,8 @@ int cmd_list(int argc, const char **argv)
                                }
 
                                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;
index fc592ebdeee16f68df1a52ad9c0bf2b770ed8466..c518405cae2944c6fd3e6e997f024eed307ad0ff 100644 (file)
@@ -37,6 +37,7 @@ static const char *str_kernel = "Kernel";
 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
@@ -278,6 +279,9 @@ const char *get_domain_str(enum lttng_domain_type domain)
        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);
index e44710b5ae0872b7e3eded59460a6f70865b30f7..feb3334cffbaba06a39c7fd1f24b60835db33bd5 100644 (file)
@@ -118,6 +118,7 @@ const char * const config_domain_type_kernel = "KERNEL";
 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";
@@ -752,6 +753,8 @@ int get_domain_type(xmlChar *domain)
                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;
        }
@@ -2154,6 +2157,7 @@ int process_session_node(xmlNodePtr session_node, const char *session_name,
        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)) {
@@ -2287,6 +2291,13 @@ int process_session_node(xmlNodePtr session_node, const char *session_name,
                        }
                        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;
index 3023216ea23e23eff437b9c52e96892e7a151d40..6d74e85f78744f6d30935c2a6d45dd0dc317cf43 100644 (file)
@@ -193,6 +193,7 @@ elementFormDefault="qualified" version="2.5">
                <xs:enumeration value="UST"/>
                <xs:enumeration value="JUL"/>
                <xs:enumeration value="LOG4J"/>
+               <xs:enumeration value="PYTHON"/>
        </xs:restriction>
 </xs:simpleType>
 
index 25d7b327b02799f2ce8dc39ed05a8ad64271bad4..c7e801d14d79bd8aadfa52bcd2bee01f69fce2a9 100644 (file)
 #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
index c21ed5a6311491cd875d246c6d4244fb8dda26f9..882afc1b6e5a3828cf029f1f4f19aa7133a14bd5 100644 (file)
@@ -135,6 +135,14 @@ const char * const mi_lttng_loglevel_str_log4j_debug = "LOG4J_DEBUG";
 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";
@@ -250,6 +258,24 @@ const char *mi_lttng_loglevel_string(int value, enum lttng_domain_type domain)
                        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. */
index a181e0b1045cc9fd95c8d5880f3f985c51b1a80b..fd1ef936eb4167fb409c4c34a5cb5f55ac7b9d42 100644 (file)
@@ -159,6 +159,14 @@ const char * const mi_lttng_loglevel_str_log4j_debug;
 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;
index f5fc7293c044c9156aeb945b48ecf97b21578d72..3f0894e83960bd1a80f88cedbfc186a6d4288405 100644 (file)
@@ -140,6 +140,12 @@ THE SOFTWARE.
                        <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>
@@ -228,6 +234,7 @@ THE SOFTWARE.
                        <xs:enumeration value="UST"/>
                        <xs:enumeration value="JUL"/>
                        <xs:enumeration value="LOG4J"/>
+                       <xs:enumeration value="PYTHON"/>
                </xs:restriction>
        </xs:simpleType>
 
index ff57a0d1a7a70237e396274b8a4847f1194beb3d..aae0e4fa5708ed4fd6c6416d5074c867da4bc62f 100644 (file)
@@ -106,6 +106,7 @@ void lttng_ctl_copy_lttng_domain(struct lttng_domain *dst,
                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:
@@ -690,25 +691,25 @@ int lttng_enable_event_with_filter(struct lttng_handle *handle,
 }
 
 /*
- * 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");
@@ -726,18 +727,18 @@ static char *set_jul_filter(const char *filter, struct lttng_event *ev)
                        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) {
@@ -746,9 +747,9 @@ static char *set_jul_filter(const char *filter, struct lttng_event *ev)
                }
        }
 
-       return jul_filter;
+       return agent_filter;
 error:
-       free(jul_filter);
+       free(agent_filter);
        return NULL;
 }
 
@@ -941,7 +942,8 @@ int lttng_enable_event_with_exclusions(struct lttng_handle *handle,
         */
        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;
        }
 
@@ -952,24 +954,26 @@ int lttng_enable_event_with_exclusions(struct lttng_handle *handle,
 
        /* 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;
                        }
                }
@@ -1102,7 +1106,8 @@ int lttng_disable_event_ext(struct lttng_handle *handle,
         */
        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;
        }
 
@@ -1113,14 +1118,16 @@ int lttng_disable_event_ext(struct lttng_handle *handle,
 
        /* 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;
@@ -1130,7 +1137,7 @@ int lttng_disable_event_ext(struct lttng_handle *handle,
                                 * 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;
                        }
                }
index af478abda65c199813513c7a04e08d87edaca654..c14f7f215b57eed3d01003b5c01655ab9951f9d1 100644 (file)
@@ -21,6 +21,7 @@ regression/ust/nprocesses/test_nprocesses
 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
index 273994a770ed05e380dbaebfa24f8ccad01230fa..0d11f90883da89d9fa1849fdc6d3fdb0e5eb4275 100644 (file)
@@ -1,7 +1,7 @@
 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
 
diff --git a/tests/regression/ust/python-logging/LTTngTest.py b/tests/regression/ust/python-logging/LTTngTest.py
new file mode 100644 (file)
index 0000000..a3ed8f9
--- /dev/null
@@ -0,0 +1,76 @@
+#!/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()
diff --git a/tests/regression/ust/python-logging/Makefile.am b/tests/regression/ust/python-logging/Makefile.am
new file mode 100644 (file)
index 0000000..34a8dee
--- /dev/null
@@ -0,0 +1,21 @@
+#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
diff --git a/tests/regression/ust/python-logging/test_python_logging b/tests/regression/ust/python-logging/test_python_logging
new file mode 100755 (executable)
index 0000000..b2fa6fb
--- /dev/null
@@ -0,0 +1,593 @@
+#!/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
+}
index e2cd7f881630b3013cb7e40e3990f1f18f64ee24..fe75461fc8603aafce928db1b292ae2cd2a3ea85 100644 (file)
@@ -514,6 +514,41 @@ function enable_log4j_lttng_event_loglevel()
        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"
@@ -579,6 +614,15 @@ function disable_log4j_lttng_event ()
        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
This page took 0.050729 seconds and 4 git commands to generate.