[lttng-dev] Patch mi lttng
David Goulet
dgoulet at efficios.com
Tue May 13 13:32:57 EDT 2014
As discussed on #lttng, this looks good to me.
Since you might continue working on this to support all command, I would
be more keen to merge that in 2.6 with every command working instead of
half of it.
It's important to consider the fact that once merged and released this
becomes a public ABI thus we'll be committed to it. I'll be way more
comfortable with all the commands implemented so we can expose at once
the full ABI and maybe fix issues on the way without having the burden
of backward compatibility.
Please raise your hand if you are not happy nor ok with this or have a
better idea :).
Cheers!
David
On 21 Apr (17:05:24), Jonathan Rajotte wrote:
> Salut,
>
> Donc voici les patchs réalisés dans le cadre du projet.(sans compter la
> premiere qui est sur la branche à David déja [1]). Elles sont basées sur
> cet branche [1].
>
> J'étais en train de mettre en place des tests mais le temps me manque et
> je ne suis pas un expert bash, ce qui ralentit un peu les choses car
> manipuler du xml en bash c'est pas facile (en tout cas pas pour moi).
>
> J'ai une patch de bash completion. Cependant elle force une dépendance vers
> xmllint... et bon j'ai pas trouvé de commande bash afin de vérifier la
> présence de xmllint qui soit fiable à tout coup.
>
> Je suis en fin de session pour l'instant donc je ne pourrais pas assurer un
> suivi efficace de tout cela. Mais je veux vraiment que cette feature soit
> accepté au final.
>
> Bref voilà !
>
> Merci encore pour l'expérience. Si ce n'était pas de vous mon projet 4
> aurait été pénible.
>
> https://github.com/dgoulet/lttng-tools-dev/tree/mi
>
> --
> Jonathan Rajotte Julien
> Chargé de laboratoire, INF1995
> Polytechnique Montréal
> From 1652234b660950b84b4eb7bdc924092761c4cdb8 Mon Sep 17 00:00:00 2001
> From: Jonathan Rajotte <jonathan.r.julien at gmail.com>
> Date: Wed, 16 Apr 2014 16:08:38 -0400
> Subject: [PATCH 1/5] Mi: add mi support for lttng struct
>
> Add mi-lttng support to the following struct:
> lttng_domain
> lttng_channel
> lttng_channel_attr
> lttng_event
> +multiple mi utility format:
> common attribute
> tracepoint_loglevel
> tracepoint_no_loglevel
> function probe
> function entry
> lttng_event_field
>
> mi-lttng other element
> pid element
>
> Signed-off-by: Jonathan Rajotte <jonathan.r.julien at gmail.com>
> ---
> src/common/mi-lttng.c | 668 +++++++++++++++++++++++++++++++++++++++++++++++++-
> src/common/mi-lttng.h | 296 +++++++++++++++++++++-
> 2 files changed, 949 insertions(+), 15 deletions(-)
>
> diff --git a/src/common/mi-lttng.c b/src/common/mi-lttng.c
> index 052b542..2e4c366 100644
> --- a/src/common/mi-lttng.c
> +++ b/src/common/mi-lttng.c
> @@ -16,11 +16,13 @@
> * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> */
>
> +
> #include <include/config.h>
> #include <common/config/config.h>
> -
> #include "mi-lttng.h"
>
> +#include <assert.h>
> +
> /* Strings related to command */
> const char * const mi_lttng_element_command = "command";
> const char * const mi_lttng_element_command_version = "version";
> @@ -38,6 +40,133 @@ const char * const mi_lttng_element_version_license = "license";
> const char * const mi_lttng_element_version_patch_level = "patchLevel";
> const char * const mi_lttng_element_version_description = "description";
>
> +/* Strings related to pid */
> +const char * const mi_lttng_element_pids = "pids";
> +const char * const mi_lttng_element_pid = "pid";
> +const char * const mi_lttng_element_pid_id = "id";
> +
> +/* String related to a lttng_event_field */
> +const char * const mi_lttng_element_event_field = "event_field";
> +const char * const mi_lttng_element_event_fields = "event_fields";
> +
> +/* General elements of mi_lttng */
> +const char * const mi_lttng_element_type_other = "OTHER";
> +const char * const mi_lttng_element_type_integer = "INTEGER";
> +const char * const mi_lttng_element_type_enum = "ENUM";
> +const char * const mi_lttng_element_type_float = "FLOAT";
> +const char * const mi_lttng_element_type_string = "STRING";
> +const char * const mi_lttng_element_nowrite = "nowrite";
> +
> +const char * const mi_lttng_element_empty = "";
> +
> +const char *mi_lttng_loglevel_string(int value)
> +{
> + switch (value) {
> + case -1:
> + return "";
> + case LTTNG_LOGLEVEL_EMERG:
> + return "TRACE_EMERG";
> + case LTTNG_LOGLEVEL_ALERT:
> + return "TRACE_ALERT";
> + case LTTNG_LOGLEVEL_CRIT:
> + return "TRACE_CRIT";
> + case LTTNG_LOGLEVEL_ERR:
> + return "TRACE_ERR";
> + case LTTNG_LOGLEVEL_WARNING:
> + return "TRACE_WARNING";
> + case LTTNG_LOGLEVEL_NOTICE:
> + return "TRACE_NOTICE";
> + case LTTNG_LOGLEVEL_INFO:
> + return "TRACE_INFO";
> + case LTTNG_LOGLEVEL_DEBUG_SYSTEM:
> + return "TRACE_DEBUG_SYSTEM";
> + case LTTNG_LOGLEVEL_DEBUG_PROGRAM:
> + return "TRACE_DEBUG_PROGRAM";
> + case LTTNG_LOGLEVEL_DEBUG_PROCESS:
> + return "TRACE_DEBUG_PROCESS";
> + case LTTNG_LOGLEVEL_DEBUG_MODULE:
> + return "TRACE_DEBUG_MODULE";
> + case LTTNG_LOGLEVEL_DEBUG_UNIT:
> + return "TRACE_DEBUG_UNIT";
> + case LTTNG_LOGLEVEL_DEBUG_FUNCTION:
> + return "TRACE_DEBUG_FUNCTION";
> + case LTTNG_LOGLEVEL_DEBUG_LINE:
> + return "TRACE_DEBUG_LINE";
> + case LTTNG_LOGLEVEL_DEBUG:
> + return "TRACE_DEBUG";
> + default:
> + return "UNKNOWN";
> + }
> +}
> +
> +const char *mi_lttng_logleveltype_string(enum lttng_loglevel_type value)
> +{
> + switch (value) {
> + case LTTNG_EVENT_LOGLEVEL_ALL:
> + return "ALL";
> + case LTTNG_EVENT_LOGLEVEL_RANGE:
> + return "RANGE";
> + case LTTNG_EVENT_LOGLEVEL_SINGLE:
> + return "SINGLE";
> + default:
> + return "UNKNOWN";
> + }
> +}
> +
> +const char *mi_lttng_eventtype_string(enum lttng_event_type value)
> +{
> + switch (value) {
> + case LTTNG_EVENT_ALL:
> + return config_event_type_all;
> + break;
> + case LTTNG_EVENT_TRACEPOINT:
> + return config_event_type_tracepoint;
> + break;
> + case LTTNG_EVENT_PROBE:
> + return config_event_type_probe;
> + break;
> + case LTTNG_EVENT_FUNCTION:
> + return config_event_type_function;
> + break;
> + case LTTNG_EVENT_FUNCTION_ENTRY:
> + return config_event_type_function_entry;
> + break;
> + case LTTNG_EVENT_SYSCALL:
> + return config_event_type_syscall;
> + break;
> + case LTTNG_EVENT_NOOP:
> + return config_event_type_noop;
> + break;
> + default:
> + return mi_lttng_element_empty;
> + break;
> + }
> +}
> +
> +const char *eventfieldtype_string(enum lttng_event_field_type val)
> +{
> + const char *ret;
> +
> + switch (val) {
> + case(LTTNG_EVENT_FIELD_INTEGER):
> + ret = mi_lttng_element_type_integer;
> + break;
> + case(LTTNG_EVENT_FIELD_ENUM):
> + ret = mi_lttng_element_type_enum;
> + break;
> + case(LTTNG_EVENT_FIELD_FLOAT):
> + ret = mi_lttng_element_type_float;
> + break;
> + case(LTTNG_EVENT_FIELD_STRING):
> + ret = mi_lttng_element_type_string;
> + break;
> + default:
> + ret = mi_lttng_element_type_other;
> + break;
> + }
> + return ret;
> +}
> +
> LTTNG_HIDDEN
> struct mi_writer *mi_lttng_writer_create(int fd_output, int mi_output_type)
> {
> @@ -90,7 +219,6 @@ LTTNG_HIDDEN
> int mi_lttng_writer_command_open(struct mi_writer *writer, const char *command)
> {
> int ret;
> -
> ret = mi_lttng_writer_open_element(writer, mi_lttng_element_command);
> if (ret) {
> goto end;
> @@ -121,6 +249,25 @@ int mi_lttng_writer_close_element(struct mi_writer *writer)
> }
>
> LTTNG_HIDDEN
> +int mi_lttng_close_multi_element(struct mi_writer *writer,
> + unsigned int nb_element)
> +{
> + int ret, i;
> + if (nb_element < 1) {
> + ret = 0;
> + goto end;
> + }
> + for (i = 0; i < nb_element; i++) {
> + ret = mi_lttng_writer_close_element(writer);
> + if (ret) {
> + goto end;
> + }
> + }
> +end:
> + return ret;
> +}
> +
> +LTTNG_HIDDEN
> int mi_lttng_writer_write_element_unsigned_int(struct mi_writer *writer,
> const char *element_name, uint64_t value)
> {
> @@ -228,12 +375,20 @@ end:
> }
>
> LTTNG_HIDDEN
> +int mi_lttng_sessions_open(struct mi_writer *writer)
> +{
> + return mi_lttng_writer_open_element(writer, config_element_sessions);
> +}
> +
> +LTTNG_HIDDEN
> int mi_lttng_session(struct mi_writer *writer,
> struct lttng_session *session, int is_open)
> {
> int ret;
>
> - /* open sessions element */
> + assert(session);
> +
> + /* Open sessions element */
> ret = mi_lttng_writer_open_element(writer,
> config_element_session);
> if (ret) {
> @@ -247,28 +402,28 @@ int mi_lttng_session(struct mi_writer *writer,
> goto end;
> }
>
> - /* path */
> + /* Path */
> ret = mi_lttng_writer_write_element_string(writer,
> config_element_path, session->path);
> if (ret) {
> goto end;
> }
>
> - /* enabled ? */
> - ret = mi_lttng_writer_write_element_unsigned_int(writer,
> + /* Enabled ? */
> + ret = mi_lttng_writer_write_element_bool(writer,
> config_element_enabled, session->enabled);
> if (ret) {
> goto end;
> }
>
> - /* snapshot mode */
> + /* Snapshot mode */
> ret = mi_lttng_writer_write_element_unsigned_int(writer,
> config_element_snapshot_mode, session->snapshot_mode);
> if (ret) {
> goto end;
> }
>
> - /* live timer interval in usec */
> + /* Live timer interval in usec */
> ret = mi_lttng_writer_write_element_unsigned_int(writer,
> config_element_live_timer_interval,
> session->live_timer_interval);
> @@ -284,3 +439,500 @@ end:
> return ret;
>
> }
> +
> +LTTNG_HIDDEN
> +int mi_lttng_domains_open(struct mi_writer *writer)
> +{
> + return mi_lttng_writer_open_element(writer, config_element_domains);
> +}
> +
> +LTTNG_HIDDEN
> +int mi_lttng_domain(struct mi_writer *writer,
> + struct lttng_domain *domain, int is_open)
> +{
> + int ret = 0;
> + const char *str_domain;
> + const char *str_buffer;
> +
> + assert(domain);
> +
> + /* Open domain element */
> + ret = mi_lttng_writer_open_element(writer, config_element_domain);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Type
> + * Note: This is a *duplicate* of get_domain_str from bin/lttng/utils.c
> + */
> + switch (domain->type) {
> + case LTTNG_DOMAIN_KERNEL:
> + str_domain = config_domain_type_kernel;
> + break;
> + case LTTNG_DOMAIN_UST:
> + str_domain = config_domain_type_ust;
> + break;
> + case LTTNG_DOMAIN_JUL:
> + str_domain = config_domain_type_jul;
> + break;
> + default:
> + /* Should not have an unknown domain */
> + assert(0);
> + }
> +
> + ret = mi_lttng_writer_write_element_string(writer, config_element_type,
> + str_domain);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Buffer Type */
> + switch (domain->buf_type) {
> + case LTTNG_BUFFER_PER_PID:
> + str_buffer = config_buffer_type_per_pid;
> + break;
> + case LTTNG_BUFFER_PER_UID:
> + str_buffer = config_buffer_type_per_uid;
> + break;
> + case LTTNG_BUFFER_GLOBAL:
> + str_buffer = config_buffer_type_global;
> + break;
> + default:
> + /* Shoul not have an unknow buffer type */
> + assert(0);
> + }
> +
> + ret = mi_lttng_writer_write_element_string(writer,
> + config_element_buffer_type, str_buffer);
> + if (ret) {
> + goto end;
> + }
> +
> + /* TODO: attr... not sure how to use the union.... */
> +
> + if (!is_open) {
> + /* Closing domain element */
> + ret = mi_lttng_writer_close_element(writer);
> + }
> +
> +end:
> + return ret;
> +
> +}
> +
> +LTTNG_HIDDEN
> +int mi_lttng_channels_open(struct mi_writer *writer)
> +{
> + return mi_lttng_writer_open_element(writer, config_element_channels);
> +}
> +
> +LTTNG_HIDDEN
> +int mi_lttng_channel(struct mi_writer *writer,
> + struct lttng_channel *channel, int is_open)
> +{
> + int ret = 0;
> +
> + assert(channel);
> +
> + /* Opening channel element */
> + ret = mi_lttng_writer_open_element(writer, config_element_channel);
> + if (ret) {
> + goto end;
> + }
> + /* Name */
> + ret = mi_lttng_writer_write_element_string(writer, config_element_name,
> + channel->name);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Enabled ? */
> + ret = mi_lttng_writer_write_element_bool(writer,
> + config_element_enabled, channel->enabled);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Attribute */
> + ret = mi_lttng_channel_attr(writer, &channel->attr);
> + if (ret) {
> + goto end;
> + }
> +
> + if (!is_open) {
> + /* Closing channel element */
> + ret = mi_lttng_writer_close_element(writer);
> + if (ret) {
> + goto end;
> + }
> + }
> +end:
> + return ret;
> +}
> +
> +LTTNG_HIDDEN
> +int mi_lttng_channel_attr(struct mi_writer *writer,
> + struct lttng_channel_attr *attr)
> +{
> + int ret = 0;
> +
> + assert(attr);
> +
> + /* Opening Attributes */
> + ret = mi_lttng_writer_open_element(writer, config_element_attributes);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Overwrite */
> + ret = mi_lttng_writer_write_element_string(writer,
> + config_element_overwrite_mode,
> + attr->overwrite ? config_overwrite_mode_overwrite :
> + config_overwrite_mode_discard);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Sub buffer size in byte */
> + ret = mi_lttng_writer_write_element_unsigned_int(writer,
> + config_element_subbuf_size, attr->subbuf_size);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Number of sub buffer (power of two) */
> + ret = mi_lttng_writer_write_element_unsigned_int(writer,
> + config_element_num_subbuf,
> + attr->num_subbuf);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Switch timer interval in usec */
> + ret = mi_lttng_writer_write_element_unsigned_int(writer,
> + config_element_switch_timer_interval,
> + attr->switch_timer_interval);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Read timer interval in usec */
> + ret = mi_lttng_writer_write_element_unsigned_int(writer,
> + config_element_read_timer_interval,
> + attr->read_timer_interval);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Event output */
> + ret = mi_lttng_writer_write_element_string(writer,
> + config_element_output_type,
> + attr->output == LTTNG_EVENT_SPLICE ?
> + config_output_type_splice : config_output_type_mmap);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Tracefile size in bytes */
> + ret = mi_lttng_writer_write_element_unsigned_int(writer,
> + config_element_tracefile_size, attr->tracefile_size);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Count of tracefiles */
> + ret = mi_lttng_writer_write_element_unsigned_int(writer,
> + config_element_tracefile_count,
> + attr->tracefile_count);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Live timer interval in usec*/
> + ret = mi_lttng_writer_write_element_unsigned_int(writer,
> + config_element_live_timer_interval,
> + attr->live_timer_interval);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Closing attributes */
> + ret = mi_lttng_writer_close_element(writer);
> + if (ret) {
> + goto end;
> + }
> +end:
> + return ret;
> +
> +}
> +
> +LTTNG_HIDDEN
> +int mi_lttng_event_common_attributes(struct mi_writer *writer,
> + struct lttng_event *event)
> +{
> + int ret;
> +
> + /* Open event element */
> + ret = mi_lttng_writer_open_element(writer, config_element_event);
> + if (ret) {
> + goto end;
> + }
> +
> + /* event name */
> + ret = mi_lttng_writer_write_element_string(writer,
> + config_element_name, event->name);
> + if (ret) {
> + goto end;
> + }
> +
> + /* event type */
> + ret = mi_lttng_writer_write_element_string(writer,
> + config_element_type, mi_lttng_eventtype_string(event->type));
> + if (ret) {
> + goto end;
> + }
> +
> + /* is event enabled */
> + ret = mi_lttng_writer_write_element_bool(writer,
> + config_element_enabled, event->enabled);
> + if (ret) {
> + goto end;
> + }
> +
> + /* event filter enabled? */
> + ret = mi_lttng_writer_write_element_bool(writer,
> + config_element_filter, event->filter);
> +
> +end:
> + return ret;
> +}
> +
> +LTTNG_HIDDEN
> +int mi_lttng_event_tracepoint_loglevel(struct mi_writer *writer,
> + struct lttng_event *event)
> +{
> + int ret;
> +
> + /* event loglevel */
> + ret = mi_lttng_writer_write_element_string(writer,
> + config_element_loglevel, mi_lttng_loglevel_string(event->loglevel));
> + if (ret) {
> + goto end;
> + }
> +
> + ret = mi_lttng_writer_write_element_string(writer,
> + config_element_loglevel_type,
> + mi_lttng_logleveltype_string(event->loglevel_type));
> + if (ret) {
> + goto end;
> + }
> +
> + /* event exclusion filter */
> + ret = mi_lttng_writer_write_element_bool(writer,
> + config_element_exclusion, event->exclusion);
> + if (ret) {
> + goto end;
> + }
> +
> +end:
> + return ret;
> +}
> +
> +LTTNG_HIDDEN
> +int mi_lttng_event_tracepoint_no_loglevel(struct mi_writer *writer,
> + struct lttng_event *event)
> +{
> + /* event exclusion filter */
> + return mi_lttng_writer_write_element_bool(writer,
> + config_element_exclusion, event->exclusion);
> +}
> +
> +LTTNG_HIDDEN
> +int mi_lttng_event_function_probe(struct mi_writer *writer,
> + struct lttng_event *event)
> +{
> + int ret;
> +
> + if (event->attr.probe.addr != 0) {
> + /* event probe address */
> + ret = mi_lttng_writer_write_element_unsigned_int(writer,
> + config_element_address, event->attr.probe.addr);
> + if (ret) {
> + goto end;
> + }
> + } else {
> + /* event probe offset */
> + ret = mi_lttng_writer_write_element_unsigned_int(writer,
> + config_element_offset, event->attr.probe.offset);
> + if (ret) {
> + goto end;
> + }
> +
> + /* event probe symbol_name */
> + ret = mi_lttng_writer_write_element_string(writer,
> + config_element_symbol_name, event->attr.probe.symbol_name);
> + if (ret) {
> + goto end;
> + }
> + }
> +end:
> + return ret;
> +}
> +
> +LTTNG_HIDDEN
> +int mi_lttng_event_function_entry(struct mi_writer *writer,
> + struct lttng_event *event)
> +{
> + /* event probe symbol_name */
> + return mi_lttng_writer_write_element_string(writer,
> + config_element_symbol_name, event->attr.ftrace.symbol_name);
> +}
> +
> +LTTNG_HIDDEN
> +int mi_lttng_events_open(struct mi_writer *writer)
> +{
> + return mi_lttng_writer_open_element(writer, config_element_events);
> +}
> +
> +LTTNG_HIDDEN
> +int mi_lttng_event(struct mi_writer *writer,
> + struct lttng_event *event, int is_open)
> +{
> + int ret;
> +
> + ret = mi_lttng_event_common_attributes(writer, event);
> + if (ret) {
> + goto end;
> + }
> +
> + switch (event->type) {
> + case LTTNG_EVENT_ALL:
> + /* We should never have "all" events in list. */
> + assert(0);
> + break;
> + case LTTNG_EVENT_TRACEPOINT:
> + {
> + if (event->loglevel != -1) {
> + ret = mi_lttng_event_tracepoint_loglevel(writer, event);
> + } else {
> + ret = mi_lttng_event_tracepoint_no_loglevel(writer, event);
> + }
> + break;
> + }
> + case LTTNG_EVENT_PROBE:
> + ret = mi_lttng_event_function_probe(writer, event);
> + break;
> + case LTTNG_EVENT_FUNCTION_ENTRY:
> + ret = mi_lttng_event_function_entry(writer, event);
> + break;
> + default:
> + break;
> + }
> +
> + if (!is_open) {
> + ret = mi_lttng_writer_close_element(writer);
> + }
> +
> +end:
> + return ret;
> +}
> +
> +LTTNG_HIDDEN
> +int mi_lttng_pids_open(struct mi_writer *writer)
> +{
> + return mi_lttng_writer_open_element(writer, mi_lttng_element_pids);
> +}
> +
> +LTTNG_HIDDEN
> +int mi_lttng_pid(struct mi_writer *writer, pid_t pid , const char *cmdline,
> + int is_open)
> +{
> + int ret;
> +
> + /* Open element pid */
> + ret = mi_lttng_writer_open_element(writer, mi_lttng_element_pid);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Writing pid number */
> + ret = mi_lttng_writer_write_element_signed_int(writer,
> + mi_lttng_element_pid_id, (int)pid);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Writing name of the process */
> + ret = mi_lttng_writer_write_element_string(writer, config_element_name,
> + cmdline);
> + if (ret) {
> + goto end;
> + }
> +
> + if (!is_open) {
> + /* Closing Pid */
> + ret = mi_lttng_writer_close_element(writer);
> + }
> +
> +end:
> + return ret;
> +}
> +
> +LTTNG_HIDDEN
> +int mi_lttng_event_fields_open(struct mi_writer *writer)
> +{
> + return mi_lttng_writer_open_element(writer, mi_lttng_element_event_fields);
> +}
> +
> +LTTNG_HIDDEN
> +int mi_lttng_event_field(struct mi_writer *writer,
> + struct lttng_event_field *field)
> +{
> + int ret;
> +
> + if (!field->field_name[0]) {
> + /* To Review: not sure if legal david ?
> + * how should this be handle ?
> + */
> + ret = 0;
> + goto end;
> + }
> +
> + /* Open field */
> + ret = mi_lttng_writer_open_element(writer, mi_lttng_element_event_field);
> + if (ret) {
> + goto end;
> + }
> +
> + if (!field->field_name[0]) {
> + goto close;
> + }
> +
> + /* Name */
> + ret = mi_lttng_writer_write_element_string(writer, config_element_name,
> + field->field_name);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Type */
> + ret = mi_lttng_writer_write_element_string(writer, config_element_type,
> + eventfieldtype_string(field->type));
> + if (ret) {
> + goto end;
> + }
> +
> + /* nowrite */
> + ret = mi_lttng_writer_write_element_signed_int(writer,
> + mi_lttng_element_nowrite, field->nowrite);
> + if (ret) {
> + goto end;
> + }
> +
> +close:
> + /* Close field element */
> + ret = mi_lttng_writer_close_element(writer);
> +
> +end:
> + return ret;
> +}
> diff --git a/src/common/mi-lttng.h b/src/common/mi-lttng.h
> index bdc4a05..2dca80c 100644
> --- a/src/common/mi-lttng.h
> +++ b/src/common/mi-lttng.h
> @@ -61,6 +61,28 @@ const char * const mi_lttng_element_version_license;
> const char * const mi_lttng_element_version_patch_level;
> const char * const mi_lttng_element_version_description;
>
> +/* String related to a lttng_event_field */
> +const char * const mi_lttng_element_event_field;
> +const char * const mi_lttng_element_event_fields;
> +
> +/* Strings related to pid */
> +const char * const mi_lttng_element_pids;
> +const char * const mi_lttng_element_pid;
> +const char * const mi_lttng_element_pid_id;
> +
> +/* General element of mi_lttng */
> +const char * const mi_lttng_element_type_other;
> +const char * const mi_lttng_element_type_integer;
> +const char * const mi_lttng_element_type_enum;
> +const char * const mi_lttng_element_type_float;
> +const char * const mi_lttng_element_type_string;
> +const char * const mi_lttng_element_nowrite;
> +
> +/* Utility string function */
> +const char *mi_lttng_loglevel_string(int value);
> +const char *mi_lttng_logleveltype_string(enum lttng_loglevel_type value);
> +const char *mi_lttng_eventfieldtype_string(enum lttng_event_field_type value);
> +
> /*
> * Create an instance of a machine interface writer.
> *
> @@ -128,6 +150,19 @@ int mi_lttng_writer_open_element(struct mi_writer *writer,
> int mi_lttng_writer_close_element(struct mi_writer *writer);
>
> /*
> + * Close multiple element.
> + *
> + * writer An instance of a machine interface writer.
> + *
> + * nb_element
> + *
> + * Returns zero if the XML document could be closed cleanly.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_close_multi_element(struct mi_writer *writer,
> + unsigned int nb_element);
> +
> +/*
> * Write an element of type unsigned int.
> *
> * writer An instance of a machine interface writer.
> @@ -205,24 +240,271 @@ int mi_lttng_version(struct mi_writer *writer, struct mi_lttng_version *version,
> const char *lttng_description, const char *lttng_license);
>
> /*
> + * Machine interface: open a sessions element.
> + *
> + * writer An instance of a machine interface writer
> + *
> + * Returns zero if the element's value could be written.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_sessions_open(struct mi_writer *writer);
> +
> +/*
> * Machine interface of struct session.
> *
> * writer An instance of a machine interface writer
> *
> * session An instance of a session
> *
> - * isOpen Define if we close the session element
> - * This should be use carefully and the client
> - * need to close the session element.
> - * Use case: nested addition information on a session
> + * is_open Define if we close the session element
> + * This should be used carefully and the client
> + * need to close the session element.
> + * Use case: nested addtionnal information on a session
> * ex: domain,channel event.
> - * 0-> False
> - * 1-> True
> + * 0-> False
> + * 1-> True
> *
> * Returns zero if the element's value could be written.
> * Negative values indicate an error.
> */
> int mi_lttng_session(struct mi_writer *writer,
> - struct lttng_session *session, int isOpen);
> + struct lttng_session *session, int is_open);
> +
> +/*
> + * Machine interface: open a domains element.
> + *
> + * writer An instance of a machine interface writer
> + *
> + * Returns zero if the element's value could be written.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_domains_open(struct mi_writer *writer);
> +
> +/*
> + * Machine interface of struct domain.
> + *
> + * writer An instance of a machine interface writer
> + *
> + * domain An instance of a domain
> + *
> + * is_open Define if we close the domain element
> + * This should be used carefully and the client
> + * need to close the domain element.
> + * Use case: nested addition information on a domain
> + * ex: channel event.
> + * 0-> False
> + * 1-> True
> + *
> + * Returns zero if the element's value could be written.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_domain(struct mi_writer *writer,
> + struct lttng_domain *domain, int is_open);
> +
> +/*
> + * Machine interface: open a channels element.
> + *
> + * writer An instance of a machine interface writer
> + *
> + * Returns zero if the element's value could be written.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_channels_open(struct mi_writer *writer);
> +
> +/*
> + * Machine interface of struct channel.
> + *
> + * writer An instance of a machine interface writer
> + *
> + * channel An instance of a channel
> + *
> + * is_open Define if we close the channel element
> + * This should be used carefully and the client
> + * need to close the channel element.
> + * Use case: nested addition information on a domain
> + * ex: channel event.
> + * 0-> False
> + * 1-> True
> + *
> + * Returns zero if the element's value could be written.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_channel(struct mi_writer *writer,
> + struct lttng_channel *channel, int is_open);
> +
> +/*
> + * Machine interface of struct channel_attr.
> + *
> + * writer An instance of a machine interface writer
> + *
> + * attr An instance of a channel_attr struct
> + *
> + * Returns zero if the element's value could be written.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_channel_attr(struct mi_writer *writer,
> + struct lttng_channel_attr *attr);
> +
> +/*
> +* Machine interface for event common attribute.
> +*
> +* writer An instance of a mi writer.
> +*
> +* event single trace event.
> +*
> +* The common attribute are:
> +* - mi event element
> +* - event name
> +* - event type
> +* - enabled tag
> +* - event filter
> +*
> +* Returns zero if the element's value could be written.
> +* Negative values indicate an error.
> +*/
> +int mi_lttng_event_common_attributes(struct mi_writer *writer,
> + struct lttng_event *event);
> +
> +/*
> + * Machine interface for kernel tracepoint event with a loglevel.
> + *
> + * writer An instance of a mi writer.
> + *
> + * event single trace event.
> + *
> + * Returns zero if the element's value could be written.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_event_tracepoint_loglevel(struct mi_writer *writer,
> + struct lttng_event *event);
> +
> +/*
> + * Machine interface for kernel tracepoint event with no loglevel.
> + *
> + * writer An instance of a mi writer.
> + *
> + * event single trace event.
> + *
> + * Returns zero if the element's value could be written.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_event_tracepoint_no_loglevel(struct mi_writer *writer,
> + struct lttng_event *event);
> +
> +/*
> + * Machine interface for kernel function and probe event.
> + *
> + * writer An instance of a mi writer.
> + *
> + * event single trace event.
> + *
> + * Returns zero if the element's value could be written.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_event_function_probe(struct mi_writer *writer,
> + struct lttng_event *event);
> +
> +/*
> + * Machine interface for kernel function entry event.
> + *
> + * writer An instance of a mi writer.
> + *
> + * event single trace event.
> + *
> + * Returns zero if the element's value could be written.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_event_function_entry(struct mi_writer *writer,
> + struct lttng_event *event);
> +
> +/*
> + * Machine interface: open an events element.
> + *
> + * writer An instance of a machine interface writer
> + *
> + * Returns zero if the element's value could be written.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_events_open(struct mi_writer *writer);
> +
> +/*
> + * Machine interface for printing an event.
> + * The trace event type currently supported are:
> + * TRACEPOINT,
> + * PROBE,
> + * FUNCTION,
> + * FUNCTION_ENTRY,
> + * SYSCALL
> + *
> + * writer An instance of a mi writer.
> + *
> + * event single trace event.
> + *
> + * is_open Define if we close the event element
> + * This should be used carefully and the client
> + * need to close the event element.
> + * Use case: nested additional information
> + * 0-> False
> + * 1-> True
> + *
> + * Returns zero if the element's value could be written.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_event(struct mi_writer *writer, struct lttng_event *event,
> + int is_open);
> +
> +/*
> + * Machine interface for struct lttng_event_field .
> + *
> + * writer An instance of a mi writer.
> + *
> + * field An event_field instance.
> + *
> + * Returns zero if the element's value could be written.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_event_field(struct mi_writer *writer,
> + struct lttng_event_field *field);
> +
> +/*
> + * Machine interface: open a event_fields element.
> + *
> + * writer An instance of a machine interface writer
> + *
> + * Returns zero if the element's value could be written.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_event_fields_open(struct mi_writer *writer);
> +
> +/*
> + * Machine interface: open a pids element.
> + *
> + * writer An instance of a machine interface writer
> + *
> + * Returns zero if the element's value could be written.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_pids_open(struct mi_writer *writer);
> +
> +/*
> + * Machine interface of a pid.
> + *
> + * writer An instance of a machine interface writer
> + *
> + * pid A pid
> + *
> + * is_open Define if we close the pid element
> + * This should be used carefully and the client
> + * need to close the pid element.
> + * Use case: nested addition information on a domain
> + * ex: channel event.
> + * 0-> False
> + * 1-> True
> + *
> + * Returns zero if the element's value could be written.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_pid(struct mi_writer *writer, pid_t pid , const char *cmdline,
> + int is_open);
>
> #endif /* _MI_LTTNG_H */
> --
> 1.9.1
>
> From 72a6be5b35ed54aeec90a602683a7431618f56e0 Mon Sep 17 00:00:00 2001
> From: Jonathan Rajotte <jonathan.r.julien at gmail.com>
> Date: Wed, 16 Apr 2014 17:03:31 -0400
> Subject: [PATCH 2/5] Mi: support for command list
>
> Signed-off-by: Jonathan Rajotte <jonathan.r.julien at gmail.com>
> ---
> src/bin/lttng/commands/list.c | 1031 ++++++++++++++++++++++++++++++++---------
> 1 file changed, 801 insertions(+), 230 deletions(-)
>
> diff --git a/src/bin/lttng/commands/list.c b/src/bin/lttng/commands/list.c
> index bbd674c..355375a 100644
> --- a/src/bin/lttng/commands/list.c
> +++ b/src/bin/lttng/commands/list.c
> @@ -23,6 +23,8 @@
> #include <string.h>
> #include <assert.h>
>
> +#include <common/mi-lttng.h>
> +
> #include "../command.h"
>
> static int opt_userspace;
> @@ -48,6 +50,7 @@ enum {
> };
>
> static struct lttng_handle *handle;
> +static struct mi_writer *writer;
>
> static struct poptOption long_options[] = {
> /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
> @@ -177,46 +180,6 @@ const char *exclusion_string(int value)
> }
> }
>
> -static const char *loglevel_string(int value)
> -{
> - switch (value) {
> - case -1:
> - return "";
> - case LTTNG_LOGLEVEL_EMERG:
> - return "TRACE_EMERG";
> - case LTTNG_LOGLEVEL_ALERT:
> - return "TRACE_ALERT";
> - case LTTNG_LOGLEVEL_CRIT:
> - return "TRACE_CRIT";
> - case LTTNG_LOGLEVEL_ERR:
> - return "TRACE_ERR";
> - case LTTNG_LOGLEVEL_WARNING:
> - return "TRACE_WARNING";
> - case LTTNG_LOGLEVEL_NOTICE:
> - return "TRACE_NOTICE";
> - case LTTNG_LOGLEVEL_INFO:
> - return "TRACE_INFO";
> - case LTTNG_LOGLEVEL_DEBUG_SYSTEM:
> - return "TRACE_DEBUG_SYSTEM";
> - case LTTNG_LOGLEVEL_DEBUG_PROGRAM:
> - return "TRACE_DEBUG_PROGRAM";
> - case LTTNG_LOGLEVEL_DEBUG_PROCESS:
> - return "TRACE_DEBUG_PROCESS";
> - case LTTNG_LOGLEVEL_DEBUG_MODULE:
> - return "TRACE_DEBUG_MODULE";
> - case LTTNG_LOGLEVEL_DEBUG_UNIT:
> - return "TRACE_DEBUG_UNIT";
> - case LTTNG_LOGLEVEL_DEBUG_FUNCTION:
> - return "TRACE_DEBUG_FUNCTION";
> - case LTTNG_LOGLEVEL_DEBUG_LINE:
> - return "TRACE_DEBUG_LINE";
> - case LTTNG_LOGLEVEL_DEBUG:
> - return "TRACE_DEBUG";
> - default:
> - return "<<UNKNOWN>>";
> - }
> -}
> -
> static const char *logleveltype_string(enum lttng_loglevel_type value)
> {
> switch (value) {
> @@ -244,7 +207,7 @@ static void print_events(struct lttng_event *event)
> indent6,
> event->name,
> logleveltype_string(event->loglevel_type),
> - loglevel_string(event->loglevel),
> + mi_lttng_loglevel_string(event->loglevel),
> event->loglevel,
> enabled_string(event->enabled),
> exclusion_string(event->exclusion),
> @@ -333,9 +296,91 @@ static void print_event_field(struct lttng_event_field *field)
> field_type(field), field->nowrite ? " [no write]" : "");
> }
>
> +/*
> + * Machine interface
> + * Jul and ust event listing
> + */
> +static int mi_list_jul_ust_events(struct lttng_event *events, int count,
> + struct lttng_domain *domain)
> +{
> + int ret, i;
> + pid_t cur_pid = 0;
> + char *cmdline = NULL;
> + int pid_element_open = 0;
> +
> + /* Open domains element */
> + ret = mi_lttng_domains_open(writer);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Write domain */
> + ret = mi_lttng_domain(writer, domain, 1);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Open pids element */
> + ret = mi_lttng_pids_open(writer);
> + if (ret) {
> + goto end;
> + }
> +
> + for (i = 0; i < count; i++) {
> + if (cur_pid != events[i].pid) {
> + if (pid_element_open) {
> + /* Close the previous envents and pid element */
> + ret = mi_lttng_close_multi_element(writer, 2);
> + if (ret) {
> + goto end;
> + }
> + pid_element_open = !pid_element_open;
> + }
> +
> + cur_pid = events[i].pid;
> + cmdline = get_cmdline_by_pid(cur_pid);
> +
> + if (!pid_element_open) {
> + /* Open and write a pid elemen */
> + ret = mi_lttng_pid(writer, cur_pid, cmdline, 1);
> + if (ret) {
> + goto error;
> + }
> +
> + /* Open events element */
> + ret = mi_lttng_events_open(writer);
> + if (ret) {
> + goto error;
> + }
> +
> + pid_element_open = !pid_element_open;
> + }
> + free(cmdline);
> + }
> +
> + /* Write an event */
> + ret = mi_lttng_event(writer, &events[i], 0);
> + if (ret) {
> + goto end;
> + }
> + }
> +
> +
> + /* Close pids */
> + ret = mi_lttng_writer_close_element(writer);
> +
> + /* Close domain, domains */
> + ret = mi_lttng_close_multi_element(writer, 2);
> +end:
> + return ret;
> +error:
> + free(cmdline);
> + return ret;
> +}
> +
> static int list_jul_events(void)
> {
> - int i, size;
> + int i, size, ret = CMD_SUCCESS;
> struct lttng_domain domain;
> struct lttng_handle *handle;
> struct lttng_event *event_list;
> @@ -349,42 +394,45 @@ static int list_jul_events(void)
>
> handle = lttng_create_handle(NULL, &domain);
> if (handle == NULL) {
> + ret = -1;
> goto error;
> }
>
> size = lttng_list_tracepoints(handle, &event_list);
> if (size < 0) {
> ERR("Unable to list JUL events: %s", lttng_strerror(size));
> - lttng_destroy_handle(handle);
> - return size;
> + ret = size;
> + goto error;
> }
>
> - MSG("JUL events (Logger name):\n-------------------------");
> -
> - if (size == 0) {
> - MSG("None");
> - }
> + if (lttng_opt_mi) {
> + /* Mi print */
> + ret = mi_list_jul_ust_events(event_list, size, &domain);
> + } else {
> + /* Pretty print */
> + MSG("JUL events (Logger name):\n-------------------------");
>
> - for (i = 0; i < size; i++) {
> - if (cur_pid != event_list[i].pid) {
> - cur_pid = event_list[i].pid;
> - cmdline = get_cmdline_by_pid(cur_pid);
> - MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
> - free(cmdline);
> + if (size == 0) {
> + MSG("None");
> }
> - MSG("%s- %s", indent6, event_list[i].name);
> - }
>
> - MSG("");
> + for (i = 0; i < size; i++) {
> + if (cur_pid != event_list[i].pid) {
> + cur_pid = event_list[i].pid;
> + cmdline = get_cmdline_by_pid(cur_pid);
> + MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
> + free(cmdline);
> + }
> + MSG("%s- %s", indent6, event_list[i].name);
> + }
>
> + MSG("");
> + }
> free(event_list);
> - lttng_destroy_handle(handle);
> -
> - return CMD_SUCCESS;
>
> error:
> lttng_destroy_handle(handle);
> - return -1;
> + return ret;
> }
>
> /*
> @@ -392,7 +440,7 @@ error:
> */
> static int list_ust_events(void)
> {
> - int i, size;
> + int i, size, ret = CMD_SUCCESS;
> struct lttng_domain domain;
> struct lttng_handle *handle;
> struct lttng_event *event_list;
> @@ -407,42 +455,162 @@ static int list_ust_events(void)
>
> handle = lttng_create_handle(NULL, &domain);
> if (handle == NULL) {
> + ret = -1;
> goto error;
> }
>
> size = lttng_list_tracepoints(handle, &event_list);
> if (size < 0) {
> ERR("Unable to list UST events: %s", lttng_strerror(size));
> - lttng_destroy_handle(handle);
> - return size;
> + ret = size;
> + goto error;
> }
>
> - MSG("UST events:\n-------------");
> + if (lttng_opt_mi) {
> + /* Mi print */
> + ret = mi_list_jul_ust_events(event_list, size, &domain);
> + } else {
> + /* Pretty print */
> + MSG("UST events:\n-------------");
> +
> + if (size == 0) {
> + MSG("None");
> + }
> +
> + for (i = 0; i < size; i++) {
> + if (cur_pid != event_list[i].pid) {
> + cur_pid = event_list[i].pid;
> + cmdline = get_cmdline_by_pid(cur_pid);
> + MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
> + free(cmdline);
> + }
> + print_events(&event_list[i]);
> + }
>
> - if (size == 0) {
> - MSG("None");
> + MSG("");
> }
> + free(event_list);
> +
> +error:
> + lttng_destroy_handle(handle);
> + return ret;
> +}
> +
> +/*
> + * Machine interface
> + * List all ust event with their fields
> + */
> +static int mi_list_ust_event_fields(struct lttng_event_field *fields, int count,
> + struct lttng_domain *domain)
> +{
> + int ret, i;
> + pid_t cur_pid = 0;
> + char *cmdline = NULL;
> + int pid_element_open = 0;
> + int event_element_open = 0;
>
> - for (i = 0; i < size; i++) {
> - if (cur_pid != event_list[i].pid) {
> - cur_pid = event_list[i].pid;
> + struct lttng_event cur_event;
> +
> + /* Open domains element */
> + ret = mi_lttng_domains_open(writer);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Write domain */
> + ret = mi_lttng_domain(writer, domain, 1);
> +
> + /* Open pids element */
> + ret = mi_lttng_pids_open(writer);
> + if (ret) {
> + goto end;
> + }
> +
> + for (i = 0; i < count; i++) {
> + if (cur_pid != fields[i].event.pid) {
> + if (pid_element_open) {
> + if (event_element_open) {
> + /* Close the previous fields element
> + * and the previous event
> + */
> + ret = mi_lttng_close_multi_element(writer, 2);
> + if (ret) {
> + goto end;
> + }
> + event_element_open = !event_element_open ;
> + }
> + /* Close the previous events, pid element */
> + ret = mi_lttng_close_multi_element(writer, 2);
> + if (ret) {
> + goto end;
> + }
> + pid_element_open = !pid_element_open;
> + }
> +
> + cur_pid = fields[i].event.pid;
> cmdline = get_cmdline_by_pid(cur_pid);
> - MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
> + if (!pid_element_open) {
> + /* Open and write a pid elemen */
> + ret = mi_lttng_pid(writer, cur_pid, cmdline, 1);
> + if (ret) {
> + goto error;
> + }
> +
> + /* Open events element */
> + ret = mi_lttng_events_open(writer);
> + if (ret) {
> + goto error;
> + }
> + pid_element_open = !pid_element_open;
> + }
> free(cmdline);
> + /* Wipe current event since we are about to print a new PID. */
> + memset(&cur_event, 0, sizeof(cur_event));
> }
> - print_events(&event_list[i]);
> - }
>
> - MSG("");
> + if (strcmp(cur_event.name, fields[i].event.name) != 0) {
> + if (event_element_open) {
> + /* Close the previous fields element and the previous event */
> + ret = mi_lttng_close_multi_element(writer, 2);
> + if (ret) {
> + goto end;
> + }
> + event_element_open = !event_element_open ;
> + }
>
> - free(event_list);
> - lttng_destroy_handle(handle);
> + memcpy(&cur_event, &fields[i].event,
> + sizeof(cur_event));
>
> - return CMD_SUCCESS;
> + if (!event_element_open) {
> + /* Open and write the event */
> + ret = mi_lttng_event(writer, &cur_event, 1);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Open a fields element */
> + ret = mi_lttng_event_fields_open(writer);
> + if (ret) {
> + goto end;
> + }
> + event_element_open = !event_element_open ;
> + }
> + }
>
> + /* Print the event_field */
> + ret = mi_lttng_event_field(writer, &fields[i]);
> + if (ret) {
> + goto end;
> + }
> + }
> +
> + /* Close pids, domain, domains */
> + ret = mi_lttng_close_multi_element(writer, 3);
> +end:
> + return ret;
> error:
> - lttng_destroy_handle(handle);
> - return -1;
> + free(cmdline);
> + return ret;
> }
>
> /*
> @@ -450,7 +618,7 @@ error:
> */
> static int list_ust_event_fields(void)
> {
> - int i, size;
> + int i, size, ret = CMD_SUCCESS;
> struct lttng_domain domain;
> struct lttng_handle *handle;
> struct lttng_event_field *event_field_list;
> @@ -468,57 +636,104 @@ static int list_ust_event_fields(void)
>
> handle = lttng_create_handle(NULL, &domain);
> if (handle == NULL) {
> + ret = -1;
> goto error;
> }
>
> size = lttng_list_tracepoint_fields(handle, &event_field_list);
> if (size < 0) {
> ERR("Unable to list UST event fields: %s", lttng_strerror(size));
> - lttng_destroy_handle(handle);
> - return size;
> + ret = size;
> + goto error;
> }
>
> - MSG("UST events:\n-------------");
> -
> - if (size == 0) {
> - MSG("None");
> - }
> + if (lttng_opt_mi) {
> + /* Mi print */
> + ret = mi_list_ust_event_fields(event_field_list, size, &domain);
> + } else {
> + /* Pretty print */
> + MSG("UST events:\n-------------");
>
> - for (i = 0; i < size; i++) {
> - if (cur_pid != event_field_list[i].event.pid) {
> - cur_pid = event_field_list[i].event.pid;
> - cmdline = get_cmdline_by_pid(cur_pid);
> - MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
> - free(cmdline);
> - /* Wipe current event since we are about to print a new PID. */
> - memset(&cur_event, 0, sizeof(cur_event));
> + if (size == 0) {
> + MSG("None");
> }
> - if (strcmp(cur_event.name, event_field_list[i].event.name) != 0) {
> - print_events(&event_field_list[i].event);
> - memcpy(&cur_event, &event_field_list[i].event,
> - sizeof(cur_event));
> - }
> - print_event_field(&event_field_list[i]);
> - }
>
> - MSG("");
> + for (i = 0; i < size; i++) {
> + if (cur_pid != event_field_list[i].event.pid) {
> + cur_pid = event_field_list[i].event.pid;
> + cmdline = get_cmdline_by_pid(cur_pid);
> + MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
> + free(cmdline);
> + /* Wipe current event since we are about to print a new PID. */
> + memset(&cur_event, 0, sizeof(cur_event));
> + }
> + if (strcmp(cur_event.name, event_field_list[i].event.name) != 0) {
> + print_events(&event_field_list[i].event);
> + memcpy(&cur_event, &event_field_list[i].event,
> + sizeof(cur_event));
> + }
> + print_event_field(&event_field_list[i]);
> + }
>
> + MSG("");
> + }
> free(event_field_list);
> - lttng_destroy_handle(handle);
> -
> - return CMD_SUCCESS;
>
> error:
> lttng_destroy_handle(handle);
> - return -1;
> + return ret;
> }
>
> /*
> - * Ask for all trace events in the kernel and pretty print them.
> + * Machine interface
> + * Print a list of kernel events
> + */
> +static int mi_list_kernel_events(struct lttng_event *events, int count,
> + struct lttng_domain *domain)
> +{
> + int ret, i;
> +
> + /* Open domains element */
> + ret = mi_lttng_domains_open(writer);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Write domain */
> + ret = mi_lttng_domain(writer, domain, 1);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Open events */
> + ret = mi_lttng_events_open(writer);
> + if (ret) {
> + goto end;
> + }
> +
> + for (i = 0; i < count; i++) {
> + mi_lttng_event(writer, &events[i], 0);
> + if (ret) {
> + goto end;
> + }
> + }
> +
> + /* close events, domain and domains */
> + ret = mi_lttng_close_multi_element(writer, 3);
> + if (ret) {
> + goto end;
> + }
> +
> +end:
> + return ret;
> +}
> +
> +/*
> + * Ask for all trace events in the kernel
> */
> static int list_kernel_events(void)
> {
> - int i, size;
> + int i, size, ret = CMD_SUCCESS;
> struct lttng_domain domain;
> struct lttng_handle *handle;
> struct lttng_event *event_list;
> @@ -541,18 +756,27 @@ static int list_kernel_events(void)
> return size;
> }
>
> - MSG("Kernel events:\n-------------");
> + if (lttng_opt_mi) {
> + /* Mi print */
> + ret = mi_list_kernel_events(event_list, size, &domain);
> + if (ret) {
> + goto end;
> + }
> + } else {
> + MSG("Kernel events:\n-------------");
>
> - for (i = 0; i < size; i++) {
> - print_events(&event_list[i]);
> - }
> + for (i = 0; i < size; i++) {
> + print_events(&event_list[i]);
> + }
>
> - MSG("");
> + MSG("");
> + }
>
> +end:
> free(event_list);
>
> lttng_destroy_handle(handle);
> - return CMD_SUCCESS;
> + return ret;
>
> error:
> lttng_destroy_handle(handle);
> @@ -560,13 +784,41 @@ error:
> }
>
> /*
> + * Machine Interface
> + * Print a list of jul events
> + */
> +static int mi_list_session_jul_events(struct lttng_event *events, int count)
> +{
> + int ret, i;
> +
> + /* Open events element */
> + ret = mi_lttng_events_open(writer);
> + if (ret) {
> + goto end;
> + }
> +
> + for (i = 0; i < count; i++) {
> + ret = mi_lttng_event(writer, &events[i], 0);
> + if (ret) {
> + goto end;
> + }
> + }
> +
> + /* Close events element */
> + ret = mi_lttng_writer_close_element(writer);
> +
> +end:
> + return ret;
> +}
> +
> +/*
> * List JUL events for a specific session using the handle.
> *
> * Return CMD_SUCCESS on success else a negative value.
> */
> static int list_session_jul_events(void)
> {
> - int ret, count, i;
> + int ret = CMD_SUCCESS, count, i;
> struct lttng_event *events = NULL;
>
> count = lttng_list_events(handle, "", &events);
> @@ -576,24 +828,56 @@ static int list_session_jul_events(void)
> goto error;
> }
>
> - MSG("Events (Logger name):\n---------------------");
> - if (count == 0) {
> - MSG("%sNone\n", indent6);
> + if (lttng_opt_mi) {
> + /* Mi print */
> + ret = mi_list_session_jul_events(events, count);
> + } else {
> + /* Pretty print */
> + MSG("Events (Logger name):\n---------------------");
> + if (count == 0) {
> + MSG("%sNone\n", indent6);
> + goto end;
> + }
> +
> + for (i = 0; i < count; i++) {
> + MSG("%s- %s%s", indent4, events[i].name,
> + enabled_string(events[i].enabled));
> + }
> +
> + MSG("");
> + }
> +
> +end:
> + free(events);
> +error:
> + return ret;
> +}
> +
> +/*
> + * Machine interface
> + * print a list of event
> + */
> +static int mi_list_events(struct lttng_event *events, int count)
> +{
> + int ret, i;
> +
> + /* Open events element */
> + ret = mi_lttng_events_open(writer);
> + if (ret) {
> goto end;
> }
>
> for (i = 0; i < count; i++) {
> - MSG("%s- %s%s", indent4, events[i].name,
> - enabled_string(events[i].enabled));
> + ret = mi_lttng_event(writer, &events[i], 0);
> + if (ret) {
> + goto end;
> + }
> }
>
> - MSG("");
> + /* Close events element */
> + ret = mi_lttng_writer_close_element(writer);
>
> end:
> - free(events);
> - ret = CMD_SUCCESS;
> -
> -error:
> return ret;
> }
>
> @@ -602,7 +886,7 @@ error:
> */
> static int list_events(const char *channel_name)
> {
> - int ret, count, i;
> + int ret = CMD_SUCCESS, count, i;
> struct lttng_event *events = NULL;
>
> count = lttng_list_events(handle, channel_name, &events);
> @@ -612,22 +896,25 @@ static int list_events(const char *channel_name)
> goto error;
> }
>
> - MSG("\n%sEvents:", indent4);
> - if (count == 0) {
> - MSG("%sNone\n", indent6);
> - goto end;
> - }
> -
> - for (i = 0; i < count; i++) {
> - print_events(&events[i]);
> - }
> + if (lttng_opt_mi) {
> + /* Mi print */
> + ret = mi_list_events(events, count);
> + } else {
> + /* Pretty print */
> + MSG("\n%sEvents:", indent4);
> + if (count == 0) {
> + MSG("%sNone\n", indent6);
> + goto end;
> + }
>
> - MSG("");
> + for (i = 0; i < count; i++) {
> + print_events(&events[i]);
> + }
>
> + MSG("");
> + }
> end:
> free(events);
> - ret = CMD_SUCCESS;
> -
> error:
> return ret;
> }
> @@ -656,6 +943,62 @@ static void print_channel(struct lttng_channel *channel)
> }
>
> /*
> + * Machine interface
> + * Print a list of channel
> + *
> + */
> +static int mi_list_channels(struct lttng_channel *channels, int count,
> + const char *channel_name)
> +{
> + int i, ret;
> + unsigned int chan_found = 0;
> +
> + /* Open channels element */
> + ret = mi_lttng_channels_open(writer);
> + if (ret) {
> + goto error;
> + }
> +
> + for (i = 0; i < count; i++) {
> + if (channel_name != NULL) {
> + if (strncmp(channels[i].name, channel_name, NAME_MAX) == 0) {
> + chan_found = 1;
> + } else {
> + continue;
> + }
> + }
> +
> + /* Write channel element and leave it open */
> + ret = mi_lttng_channel(writer, &channels[i], 1);
> +
> + /* Listing events per channel */
> + ret = list_events(channels[i].name);
> + if (ret) {
> + goto error;
> + }
> +
> + /* Closing the channel element we opened earlier */
> + ret = mi_lttng_writer_close_element(writer);
> + if (ret) {
> + goto error;
> + }
> +
> + if (chan_found) {
> + break;
> + }
> + }
> +
> + /* Close channels element */
> + ret = mi_lttng_writer_close_element(writer);
> + if (ret) {
> + goto error;
> + }
> +
> +error:
> + return ret;
> +}
> +
> +/*
> * List channel(s) of session and domain.
> *
> * If channel_name is NULL, all channels are listed.
> @@ -672,54 +1015,136 @@ static int list_channels(const char *channel_name)
> if (count < 0) {
> switch (-count) {
> case LTTNG_ERR_KERN_CHAN_NOT_FOUND:
> - ret = CMD_SUCCESS;
> - WARN("No kernel channel");
> + if (lttng_opt_mi) {
> + /* When printing mi this is not an error
> + * but an empty channels element */
> + count = 0;
> + } else {
> + ret = CMD_SUCCESS;
> + WARN("No kernel channel");
> + goto error_channels;
> + }
> break;
> default:
> /* We had a real error */
> ret = count;
> ERR("%s", lttng_strerror(ret));
> + goto error_channels;
> break;
> }
> - goto error_channels;
> }
>
> - if (channel_name == NULL) {
> - MSG("Channels:\n-------------");
> - }
> + if (lttng_opt_mi) {
> + /* Mi print */
> + ret = mi_list_channels(channels, count, channel_name);
> + } else {
> + /* Pretty print */
> + if (channel_name == NULL) {
> + MSG("Channels:\n-------------");
> + }
>
> - for (i = 0; i < count; i++) {
> - if (channel_name != NULL) {
> - if (strncmp(channels[i].name, channel_name, NAME_MAX) == 0) {
> - chan_found = 1;
> - } else {
> - continue;
> + for (i = 0; i < count; i++) {
> + if (channel_name != NULL) {
> + if (strncmp(channels[i].name, channel_name, NAME_MAX) == 0) {
> + chan_found = 1;
> + } else {
> + continue;
> + }
> }
> - }
> - print_channel(&channels[i]);
> + print_channel(&channels[i]);
>
> - /* Listing events per channel */
> - ret = list_events(channels[i].name);
> - if (ret < 0) {
> - ERR("%s", lttng_strerror(ret));
> + /* Listing events per channel */
> + ret = list_events(channels[i].name);
> + if (ret < 0) {
> + ERR("%s", lttng_strerror(ret));
> + goto error;
> + }
> +
> + if (chan_found) {
> + break;
> + }
> }
>
> - if (chan_found) {
> - break;
> + if (!chan_found && channel_name != NULL) {
> + ERR("Channel %s not found", channel_name);
> + goto error;
> }
> }
> +error:
> + free(channels);
>
> - if (!chan_found && channel_name != NULL) {
> - ERR("Channel %s not found", channel_name);
> - goto error;
> +error_channels:
> + return ret;
> +}
> +
> +/*
> + * Machine interface
> + * Find the session with session_name as name
> + * and print his informations.
> + */
> +static int mi_list_session(const char *session_name,
> + struct lttng_session *sessions, int count)
> +{
> + int ret, i;
> + unsigned int session_found = 0;
> +
> + if (session_name == NULL) {
> + ret = -LTTNG_ERR_SESS_NOT_FOUND;
> + goto end;
> + }
> +
> + for (i = 0; i < count; i++) {
> + if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
> + /* We need to leave it open to append other informations
> + * like domain, channel, events etc.*/
> + session_found = 1;
> + ret = mi_lttng_session(writer, &sessions[i], 1);
> + if (ret) {
> + goto end;
> + }
> + break;
> + }
> }
>
> - ret = CMD_SUCCESS;
> + if (!session_found) {
> + ERR("Session not found");
> + ret = -LTTNG_ERR_SESS_NOT_FOUND;
> + goto end;
> + }
>
> -error:
> - free(channels);
> +end:
> + return ret;
> +}
>
> -error_channels:
> +/*
> + * Machine interface
> + * List all availables session
> + */
> +static int mi_list_sessions(struct lttng_session *sessions, int count)
> +{
> + int ret, i;
> +
> + /* Opening sessions element */
> + ret = mi_lttng_sessions_open(writer);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Listing sessions */
> + for (i = 0; i < count; i++) {
> + ret = mi_lttng_session(writer, &sessions[i], 0);
> + if (ret) {
> + goto end;
> + }
> + }
> +
> + /* Closing sessions element */
> + ret = mi_lttng_writer_close_element(writer);
> + if (ret) {
> + goto end;
> + }
> +
> +end:
> return ret;
> }
>
> @@ -730,7 +1155,8 @@ error_channels:
> */
> static int list_sessions(const char *session_name)
> {
> - int ret, count, i;
> + int ret = CMD_SUCCESS;
> + int count, i;
> unsigned int session_found = 0;
> struct lttng_session *sessions;
>
> @@ -740,48 +1166,85 @@ static int list_sessions(const char *session_name)
> ret = count;
> ERR("%s", lttng_strerror(ret));
> goto error;
> - } else if (count == 0) {
> - MSG("Currently no available tracing session");
> - goto end;
> }
>
> - if (session_name == NULL) {
> - MSG("Available tracing sessions:");
> - }
> + if (lttng_opt_mi) {
> + /* Mi */
> + if (session_name == NULL) {
> + /* List all session */
> + ret = mi_list_sessions(sessions, count);
> + } else {
> + /* Note : this return an open session element */
> + ret = mi_list_session(session_name, sessions, count);
> + }
> + } else {
> + /* Pretty print */
> + if (count == 0) {
> + MSG("Currently no available tracing session");
> + goto end;
> + }
>
> - for (i = 0; i < count; i++) {
> - if (session_name != NULL) {
> - if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
> - session_found = 1;
> - MSG("Tracing session %s: [%s%s]", session_name,
> + if (session_name == NULL) {
> + MSG("Available tracing sessions:");
> + }
> +
> +
> + for (i = 0; i < count; i++) {
> + if (session_name != NULL) {
> + if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
> + session_found = 1;
> + MSG("Tracing session %s: [%s%s]", session_name,
> + active_string(sessions[i].enabled),
> + snapshot_string(sessions[i].snapshot_mode));
> + MSG("%sTrace path: %s\n", indent4, sessions[i].path);
> + break;
> + }
> + } else {
> + MSG(" %d) %s (%s) [%s%s]", i + 1,
> + sessions[i].name, sessions[i].path,
> active_string(sessions[i].enabled),
> snapshot_string(sessions[i].snapshot_mode));
> - MSG("%sTrace path: %s\n", indent4, sessions[i].path);
> - break;
> }
> - } else {
> - MSG(" %d) %s (%s) [%s%s]", i + 1, sessions[i].name, sessions[i].path,
> - active_string(sessions[i].enabled),
> - snapshot_string(sessions[i].snapshot_mode));
> + }
> +
> + if (!session_found && session_name != NULL) {
> + ERR("Session '%s' not found", session_name);
> + ret = CMD_ERROR;
> + goto error;
> + }
> +
> + if (session_name == NULL) {
> + MSG("\nUse lttng list <session_name> for more details");
> }
> }
>
> +error:
> free(sessions);
> +end:
> + return ret;
> +}
>
> - if (!session_found && session_name != NULL) {
> - ERR("Session '%s' not found", session_name);
> - ret = CMD_ERROR;
> - goto error;
> +
> +/*
> + * Machine Interface
> + * list available domain(s) for a session.
> + */
> +static int mi_list_domains(struct lttng_domain *domains, int count)
> +{
> + int i, ret;
> + /* Open domains element */
> + ret = mi_lttng_domains_open(writer);
> + if (ret) {
> + goto end;
> }
>
> - if (session_name == NULL) {
> - MSG("\nUse lttng list <session_name> for more details");
> + for (i = 0; i < count; i++) {
> + ret = mi_lttng_domain(writer, &domains[i] , 0);
> }
>
> + /* Closing domains element */
> + ret = mi_lttng_writer_close_element(writer);
> end:
> - return CMD_SUCCESS;
> -
> -error:
> return ret;
> }
>
> @@ -793,31 +1256,39 @@ static int list_domains(const char *session_name)
> int i, count, ret = CMD_SUCCESS;
> struct lttng_domain *domains = NULL;
>
> - MSG("Domains:\n-------------");
>
> count = lttng_list_domains(session_name, &domains);
> if (count < 0) {
> ret = count;
> ERR("%s", lttng_strerror(ret));
> goto error;
> - } else if (count == 0) {
> - MSG(" None");
> - goto end;
> }
>
> - for (i = 0; i < count; i++) {
> - switch (domains[i].type) {
> - case LTTNG_DOMAIN_KERNEL:
> - MSG(" - Kernel");
> - break;
> - case LTTNG_DOMAIN_UST:
> - MSG(" - UST global");
> - break;
> - case LTTNG_DOMAIN_JUL:
> - MSG(" - JUL (Java Util Logging)");
> - break;
> - default:
> - break;
> + if (lttng_opt_mi) {
> + /* Mi output */
> + ret = mi_list_domains(domains, count);
> + } else {
> + /* Pretty print */
> + MSG("Domains:\n-------------");
> + if (count == 0) {
> + MSG(" None");
> + goto end;
> + }
> +
> + for (i = 0; i < count; i++) {
> + switch (domains[i].type) {
> + case LTTNG_DOMAIN_KERNEL:
> + MSG(" - Kernel");
> + break;
> + case LTTNG_DOMAIN_UST:
> + MSG(" - UST global");
> + break;
> + case LTTNG_DOMAIN_JUL:
> + MSG(" - JUL (Java Util Logging)");
> + break;
> + default:
> + break;
> + }
> }
> }
>
> @@ -850,13 +1321,6 @@ int cmd_list(int argc, const char **argv)
> pc = poptGetContext(NULL, argc, argv, long_options, 0);
> poptReadDefaultConfig(pc, 0);
>
> - /* TODO: mi support */
> - if (lttng_opt_mi) {
> - ret = -LTTNG_ERR_MI_NOT_IMPLEMENTED;
> - ERR("mi option not supported");
> - goto end;
> - }
> -
> while ((opt = poptGetNextOpt(pc)) != -1) {
> switch (opt) {
> case OPT_HELP:
> @@ -875,6 +1339,29 @@ int cmd_list(int argc, const char **argv)
> }
> }
>
> + /* Mi check */
> + if (lttng_opt_mi) {
> + writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
> + if (!writer) {
> + ret = -LTTNG_ERR_NOMEM;
> + goto end;
> + }
> +
> + /* Open command element */
> + ret = mi_lttng_writer_command_open(writer,
> + mi_lttng_element_command_list);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Open output element */
> + ret = mi_lttng_writer_open_element(writer,
> + mi_lttng_element_command_output);
> + if (ret) {
> + goto end;
> + }
> + }
> +
> /* Get session name (trailing argument) */
> session_name = poptGetArg(pc);
> DBG2("Session name: %s", session_name);
> @@ -900,14 +1387,13 @@ int cmd_list(int argc, const char **argv)
> if (session_name == NULL) {
> if (!opt_kernel && !opt_userspace && !opt_jul) {
> ret = list_sessions(NULL);
> - if (ret != 0) {
> + if (ret) {
> goto end;
> }
> }
> if (opt_kernel) {
> ret = list_kernel_events();
> - if (ret < 0) {
> - ret = CMD_ERROR;
> + if (ret) {
> goto end;
> }
> }
> @@ -917,22 +1403,29 @@ int cmd_list(int argc, const char **argv)
> } else {
> ret = list_ust_events();
> }
> - if (ret < 0) {
> - ret = CMD_ERROR;
> + if (ret) {
> goto end;
> }
> }
> if (opt_jul) {
> ret = list_jul_events();
> - if (ret < 0) {
> - ret = CMD_ERROR;
> + if (ret) {
> goto end;
> }
> }
> } else {
> /* List session attributes */
> + if (lttng_opt_mi) {
> + /* Open element sessions
> + * Present for xml consistency */
> + ret = mi_lttng_sessions_open(writer);
> + if (ret) {
> + goto end;
> + }
> + }
> + /* MI: the ouptut of list_sessions is an unclosed session element */
> ret = list_sessions(session_name);
> - if (ret != 0) {
> + if (ret) {
> goto end;
> }
>
> @@ -942,12 +1435,40 @@ int cmd_list(int argc, const char **argv)
> goto end;
> }
>
> + /* Channel listing */
> if (opt_kernel || opt_userspace) {
> - /* Channel listing */
> + if (lttng_opt_mi) {
> + /* Add of domains and domain element for xml
> + * consistency and validation
> + */
> + ret = mi_lttng_domains_open(writer);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Open domain and leave it open for
> + * nested channels printing */
> + ret = mi_lttng_domain(writer, &domain, 1);
> + if (ret) {
> + goto end;
> + }
> +
> + }
> +
> ret = list_channels(opt_channel);
> - if (ret < 0) {
> + if (ret) {
> + goto end;
> + }
> +
> + if (lttng_opt_mi) {
> + /* Close domain and domain element */
> + ret = mi_lttng_close_multi_element(writer, 2);
> + }
> + if (ret) {
> goto end;
> }
> +
> +
> } else {
> int i, nb_domain;
>
> @@ -959,6 +1480,13 @@ int cmd_list(int argc, const char **argv)
> goto end;
> }
>
> + if (lttng_opt_mi) {
> + ret = mi_lttng_domains_open(writer);
> + if (ret) {
> + goto end;
> + }
> + }
> +
> for (i = 0; i < nb_domain; i++) {
> switch (domains[i].type) {
> case LTTNG_DOMAIN_KERNEL:
> @@ -978,6 +1506,13 @@ int cmd_list(int argc, const char **argv)
> break;
> }
>
> + if (lttng_opt_mi) {
> + ret = mi_lttng_domain(writer, &domains[i], 1);
> + if (ret) {
> + goto end;
> + }
> + }
> +
> /* Clean handle before creating a new one */
> if (handle) {
> lttng_destroy_handle(handle);
> @@ -991,21 +1526,57 @@ int cmd_list(int argc, const char **argv)
>
> if (domains[i].type == LTTNG_DOMAIN_JUL) {
> ret = list_session_jul_events();
> - if (ret < 0) {
> + if (ret) {
> goto end;
> }
> continue;
> }
>
> ret = list_channels(opt_channel);
> - if (ret < 0) {
> + if (ret) {
> + goto end;
> + }
> +
> + if (lttng_opt_mi) {
> + /* Close domain element */
> + ret = mi_lttng_writer_close_element(writer);
> + if (ret) {
> + goto end;
> + }
> + }
> +
> + }
> + if (lttng_opt_mi) {
> + /* Close the domains, session and sessions element */
> + ret = mi_lttng_close_multi_element(writer, 3);
> + if (ret) {
> goto end;
> }
> }
> }
> }
>
> + /* Mi closing */
> + if (lttng_opt_mi) {
> + /* Close output element */
> + ret = mi_lttng_writer_close_element(writer);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Command element close */
> + ret = mi_lttng_writer_command_close(writer);
> + if (ret) {
> + goto end;
> + }
> + }
> end:
> + /* Mi clean-up */
> + if (writer && mi_lttng_writer_destroy(writer)) {
> + /* Preserve original error code */
> + ret = ret ? ret : LTTNG_ERR_MI_IO_FAIL;
> + }
> +
> free(domains);
> if (handle) {
> lttng_destroy_handle(handle);
> --
> 1.9.1
>
> From f478c2feebbf136bacf571e42054312a01ba6074 Mon Sep 17 00:00:00 2001
> From: Jonathan Rajotte <jonathan.r.julien at gmail.com>
> Date: Wed, 16 Apr 2014 17:14:08 -0400
> Subject: [PATCH 3/5] Mi: mi xsd validation
>
> Command list and version supported
>
> Signed-off-by: Jonathan Rajotte <jonathan.r.julien at gmail.com>
> ---
> src/common/mi_lttng.xsd | 320 ++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 320 insertions(+)
> create mode 100644 src/common/mi_lttng.xsd
>
> diff --git a/src/common/mi_lttng.xsd b/src/common/mi_lttng.xsd
> new file mode 100644
> index 0000000..6fc25c6
> --- /dev/null
> +++ b/src/common/mi_lttng.xsd
> @@ -0,0 +1,320 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<!--
> +Copyright (c) 2014 - Oliver Cotte <olivier.cotte at polymtl.ca>
> + - Jonathan Rajotte <jonathan.r.julien at gmail.com>
> +
> +Permission is hereby granted, free of charge, to any person obtaining a copy
> +of this software and associated documentation files (the "Software"), to deal
> +in the Software without restriction, including without limitation the rights
> +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> +copies of the Software, and to permit persons to whom the Software is
> +furnished to do so, subject to the following conditions:
> +
> +The above copyright notice and this permission notice shall be included in
> +all copies or substantial portions of the Software.
> +
> +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> +THE SOFTWARE.
> +-->
> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
> + elementFormDefault="qualified" version="2.5">
> +
> + <!-- Maps to the uint32_t type -->
> + <xs:simpleType name="uint32_type">
> + <xs:restriction base="xs:integer">
> + <xs:minInclusive value="0" />
> + <xs:maxInclusive value="4294967295" />
> + </xs:restriction>
> + </xs:simpleType>
> +
> + <!-- Maps to the uint64_t type -->
> + <xs:simpleType name="uint64_type">
> + <xs:restriction base="xs:integer">
> + <xs:minInclusive value="0" />
> + <xs:maxInclusive value="18446744073709551615" />
> + </xs:restriction>
> + </xs:simpleType>
> +
> + <!-- Maps to the char name[LTTNG_SYMBOL_NAME_LEN] -->
> + <xs:simpleType name="name_type">
> + <xs:restriction base="xs:string">
> + <xs:maxLength value="255" />
> + </xs:restriction>
> + </xs:simpleType>
> +
> + <!-- Maps to the lttng_event_type enum -->
> + <xs:simpleType name="event_type_type">
> + <xs:restriction base="xs:string">
> + <xs:enumeration value="ALL" />
> + <xs:enumeration value="TRACEPOINT" />
> + <xs:enumeration value="PROBE" />
> + <xs:enumeration value="FUNCTION" />
> + <xs:enumeration value="FUNCTION_ENTRY" />
> + <xs:enumeration value="NOOP" />
> + <xs:enumeration value="SYSCALL" />
> + <xs:enumeration value="KPROBE" />
> + <xs:enumeration value="KRETPROBE" />
> + </xs:restriction>
> + </xs:simpleType>
> +
> + <!-- Maps to the lttng_event_field_type enum -->
> + <xs:simpleType name="event_field_type_type">
> + <xs:restriction base="xs:string">
> + <xs:enumeration value="OTHER" />
> + <xs:enumeration value="INTEGER" />
> + <xs:enumeration value="ENUM" />
> + <xs:enumeration value="FLOAT" />
> + <xs:enumeration value="STRING" />
> + </xs:restriction>
> + </xs:simpleType>
> +
> + <!-- Maps to the lttng_loglevel_type enum -->
> + <xs:simpleType name="loglevel_type">
> + <xs:restriction base="xs:string">
> + <xs:enumeration value="ALL" />
> + <xs:enumeration value="RANGE" />
> + <xs:enumeration value="SINGLE" />
> + <xs:enumeration value="UNKNOWN" />
> + </xs:restriction>
> + </xs:simpleType>
> +
> + <!-- Maps to loglevel_string char * -->
> + <xs:simpleType name="loglevel_string_type">
> + <xs:restriction base="xs:string">
> + <xs:enumeration value="" />
> + <xs:enumeration value="TRACE_EMERG" />
> + <xs:enumeration value="TRACE_ALERT" />
> + <xs:enumeration value="TRACE_CRIT" />
> + <xs:enumeration value="TRACE_ERR" />
> + <xs:enumeration value="TRACE_WARNING" />
> + <xs:enumeration value="TRACE_NOTICE" />
> + <xs:enumeration value="TRACE_INFO" />
> + <xs:enumeration value="TRACE_DEBUG_SYSTEM" />
> + <xs:enumeration value="TRACE_DEBUG_PROGRAM" />
> + <xs:enumeration value="TRACE_DEBUG_PROCESS" />
> + <xs:enumeration value="TRACE_DEBUG_MODULE" />
> + <xs:enumeration value="TRACE_DEBUG_UNIT" />
> + <xs:enumeration value="TRACE_DEBUG_FUNCTION" />
> + <xs:enumeration value="TRACE_DEBUG_LINE" />
> + <xs:enumeration value="TRACE_DEBUG" />
> + <xs:enumeration value="UNKNOWN" />
> + </xs:restriction>
> + </xs:simpleType>
> +
> + <!-- Maps to the lttng_event_probe_attr struct -->
> + <xs:complexType name="event_probe_attributes_type">
> + <xs:all>
> + <xs:element name="address" type="uint64_type" />
> + <xs:element name="offset" type="uint64_type" />
> + <xs:element name="symbol_name" type="name_type" />
> + </xs:all>
> + </xs:complexType>
> +
> + <!-- Maps to the lttng_event_function_attr struct -->
> + <xs:complexType name="event_ftrace_attributes_type">
> + <xs:all>
> + <xs:element name="symbol_name" type="name_type" />
> + </xs:all>
> + </xs:complexType>
> +
> + <!-- Maps to per event type configuration -->
> + <xs:complexType name="event_attributes_type">
> + <xs:choice>
> + <xs:element name="probe_attributes" type="event_probe_attributes_type" />
> + <xs:element name="function_attributes" type="event_ftrace_attributes_type" />
> + </xs:choice>
> + </xs:complexType>
> +
> + <!-- Maps to lttng_event struct -->
> + <xs:complexType name="event_type">
> + <xs:all>
> + <xs:element name="type" type="event_type_type" default="TRACEPOINT" minOccurs="0" />
> + <xs:element name="name" type="name_type" minOccurs="0" />
> + <xs:element name="loglevel_type" type="loglevel_type" default="ALL" minOccurs="0" />
> + <xs:element name="loglevel" type="loglevel_string_type" default="" minOccurs="0" />
> + <xs:element name="enabled" type="xs:boolean" default="false" minOccurs="0" />
> + <xs:element name="filter" type="xs:boolean" minOccurs="0" />
> + <xs:element name="exclusion" type="xs:boolean" minOccurs="0" />
> + <xs:element name="attributes" type="event_attributes_type" minOccurs="0" />
> + <xs:element name="event_fields" type="event_fields_type" minOccurs="0" />
> + </xs:all>
> + </xs:complexType>
> +
> + <!-- Maps to mi_lttng_version struct -->
> + <xs:complexType name="version_type">
> + <xs:all>
> + <xs:element name="name" type="name_type" />
> + <xs:element name="string" type="name_type" />
> + <xs:element name="major" type="uint32_type" />
> + <xs:element name="url" type="xs:string" />
> + <xs:element name="minor" type="uint32_type" />
> + <xs:element name="license" type="xs:string" />
> + <xs:element name="patchLevel" type="uint32_type" />
> + <xs:element name="description" type="xs:string" />
> + </xs:all>
> + </xs:complexType>
> +
> + <xs:complexType name="event_list_type">
> + <xs:sequence>
> + <xs:element name="event" type="event_type" minOccurs="0" maxOccurs="unbounded" />
> + </xs:sequence>
> + </xs:complexType>
> +
> + <!-- Maps to the lttng_domain_type enum -->
> + <xs:simpleType name="domain_type_type">
> + <xs:restriction base="xs:string">
> + <xs:enumeration value="KERNEL"/>
> + <xs:enumeration value="UST"/>
> + <xs:enumeration value="JUL"/>
> + </xs:restriction>
> + </xs:simpleType>
> +
> + <!-- Maps to the lttng_buffer_type enum -->
> + <xs:simpleType name="domain_buffer_type">
> + <xs:restriction base="xs:string">
> + <xs:enumeration value="PER_PID"/>
> + <xs:enumeration value="PER_UID"/>
> + <xs:enumeration value="GLOBAL"/>
> + </xs:restriction>
> + </xs:simpleType>
> +
> + <xs:simpleType name="channel_overwrite_mode_type">
> + <xs:restriction base="xs:string">
> + <xs:enumeration value="DISCARD" />
> + <xs:enumeration value="OVERWRITE" />
> + </xs:restriction>
> + </xs:simpleType>
> +
> + <!-- Maps to the lttng_event_output enum -->
> + <xs:simpleType name="event_output_type">
> + <xs:restriction base="xs:string">
> + <xs:enumeration value="SPLICE" />
> + <xs:enumeration value="MMAP" />
> + </xs:restriction>
> + </xs:simpleType>
> +
> + <xs:complexType name="pid_type">
> + <xs:all>
> + <xs:element name="id" type="xs:int"/>
> + <xs:element name="name" type="name_type"/>
> + <xs:element name="events" type="event_list_type" minOccurs="0" />
> + </xs:all>
> + </xs:complexType>
> +
> + <xs:complexType name="pids_type">
> + <xs:sequence>
> + <xs:element name="pid" type="pid_type" minOccurs="0" maxOccurs="unbounded" />
> + </xs:sequence>
> + </xs:complexType>
> +
> + <!-- Maps to struct lttng_domain and contains channels -->
> + <xs:complexType name="domain_type">
> + <xs:all>
> + <xs:element name="type" type="domain_type_type"/>
> + <xs:element name="buffer_type" type="domain_buffer_type"/>
> + <xs:element name="pids" type="pids_type" minOccurs="0" />
> + <xs:element name="channels" type="channels_type" minOccurs="0" />
> + <xs:element name="events" type="event_list_type" minOccurs="0" />
> + </xs:all>
> + </xs:complexType>
> +
> + <!-- Maps to struct lttng_channel -->
> + <xs:complexType name="channel_type">
> + <xs:all>
> + <xs:element name="name" type="name_type"/>
> + <xs:element name="enabled" type="xs:boolean" default="true" minOccurs="0"/>
> + <xs:element name="attributes" type="channel_attributes_type" minOccurs="0"/>
> + <xs:element name="events" type="event_list_type"/>
> + </xs:all>
> + </xs:complexType>
> +
> + <!-- Maps to struct lttng_channel_attr -->
> + <xs:complexType name="channel_attributes_type">
> + <xs:all>
> + <xs:element name="overwrite_mode" type="channel_overwrite_mode_type" default="DISCARD" minOccurs="0"/>
> + <xs:element name="subbuffer_size" type="uint64_type" minOccurs="0"/> <!-- bytes -->
> + <xs:element name="subbuffer_count" type="uint64_type" default="4" minOccurs="0"/>
> + <xs:element name="switch_timer_interval" type="uint32_type" default="0" minOccurs="0"/> <!-- usec -->
> + <xs:element name="read_timer_interval" type="uint32_type"/> <!-- usec -->
> + <xs:element name="output_type" type="event_output_type"/>
> + <xs:element name="tracefile_size" type="uint64_type" default="0" minOccurs="0"/> <!-- bytes -->
> + <xs:element name="tracefile_count" type="uint64_type" default="0" minOccurs="0"/>
> + <xs:element name="live_timer_interval" type="uint32_type" default="0" minOccurs="0"/> <!-- usec -->
> + </xs:all>
> + </xs:complexType>
> +
> + <xs:complexType name="channels_type">
> + <xs:sequence>
> + <xs:element name="channel" type="channel_type" minOccurs="0" maxOccurs="unbounded" />
> + </xs:sequence>
> + </xs:complexType>
> +
> + <xs:complexType name="session_type">
> + <xs:all>
> + <xs:element name="name" type="name_type" />
> + <xs:element name="path" type="name_type" />
> + <xs:element name="enabled" type="xs:boolean" default="false" />
> + <xs:element name="snapshot_mode" type="uint32_type" />
> + <xs:element name="live_timer_interval" type="uint32_type" />
> + <xs:element name="channels" type="channels_type" minOccurs="0" />
> + <xs:element name="domains" type="domains_type" minOccurs="0" />
> + </xs:all>
> + </xs:complexType>
> +
> + <xs:complexType name="event_field_type">
> + <xs:all>
> + <xs:element name="name" type="name_type" />
> + <xs:element name="type" type="event_field_type_type"/>
> + <xs:element name="nowrite" type="xs:int"/>
> + </xs:all>
> + </xs:complexType>
> +
> +
> + <xs:complexType name="domains_type">
> + <xs:sequence>
> + <xs:element name="domain" type="domain_type" minOccurs="0" maxOccurs="unbounded" />
> + </xs:sequence>
> + </xs:complexType>
> +
> + <xs:complexType name="sessions_type">
> + <xs:sequence>
> + <xs:element name="session" type="session_type" minOccurs="0" maxOccurs="unbounded" />
> + </xs:sequence>
> + </xs:complexType>
> +
> + <xs:complexType name="event_fields_type">
> + <xs:sequence>
> + <xs:element name="event_field" type="event_field_type" minOccurs="0" maxOccurs="unbounded" />
> + </xs:sequence>
> + </xs:complexType>
> +
> + <xs:complexType name="output_type">
> + <xs:choice>
> + <xs:element name="domains" type="domains_type" minOccurs="0" />
> + <xs:element name="sessions" type="sessions_type" minOccurs="0" />
> + <xs:element name="version" type="version_type" minOccurs="0" />
> + </xs:choice>
> + </xs:complexType>
> +
> + <!-- Maps to the mi_lttng commands -->
> + <xs:simpleType name="command_string_type">
> + <xs:restriction base="xs:string">
> + <xs:enumeration value="list" />
> + <xs:enumeration value="version" />
> + </xs:restriction>
> + </xs:simpleType>
> +
> + <xs:element name="command">
> + <xs:complexType>
> + <xs:all>
> + <xs:element name="name" type="command_string_type" maxOccurs="1" />
> + <xs:element name="output" type="output_type" maxOccurs="1" />
> + </xs:all>
> + </xs:complexType>
> + </xs:element>
> +</xs:schema>
> --
> 1.9.1
>
> From 06fd69b77160dc43c01597796048c88b9ddcd18e Mon Sep 17 00:00:00 2001
> From: Jonathan Rajotte <jonathan.r.julien at gmail.com>
> Date: Thu, 17 Apr 2014 15:32:40 -0400
> Subject: [PATCH 5/5] Mi: add mi to snapshot command
>
> Signed-off-by: Jonathan Rajotte <jonathan.r.julien at gmail.com>
> ---
> src/bin/lttng/commands/snapshot.c | 244 +++++++++++++++++++++++++++++++++++--
> src/common/mi-lttng.c | 247 +++++++++++++++++++++++++++++++++++++-
> src/common/mi-lttng.h | 130 ++++++++++++++++++++
> src/common/mi_lttng.xsd | 34 ++++++
> 4 files changed, 641 insertions(+), 14 deletions(-)
>
> diff --git a/src/bin/lttng/commands/snapshot.c b/src/bin/lttng/commands/snapshot.c
> index 21b5a05..46a863d 100644
> --- a/src/bin/lttng/commands/snapshot.c
> +++ b/src/bin/lttng/commands/snapshot.c
> @@ -27,6 +27,7 @@
> #include <unistd.h>
>
> #include <common/utils.h>
> +#include <common/mi-lttng.h>
> #include <lttng/snapshot.h>
>
> #include "../command.h"
> @@ -53,6 +54,8 @@ enum {
> OPT_LIST_COMMANDS,
> };
>
> +static struct mi_writer *writer;
> +
> static struct poptOption snapshot_opts[] = {
> /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
> {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
> @@ -181,6 +184,44 @@ error_create:
> return NULL;
> }
>
> +static int mi_list_output(void)
> +{
> + int ret;
> + struct lttng_snapshot_output *s_iter;
> + struct lttng_snapshot_output_list *list;
> +
> + ret = lttng_snapshot_list_output(current_session_name, &list);
> + if (ret < 0) {
> + goto error;
> + }
> +
> + ret = mi_lttng_snapshot_output_session_name(writer, current_session_name);
> + if (ret) {
> + goto error;
> + }
> +
> + while ((s_iter = lttng_snapshot_output_list_get_next(list)) != NULL) {
> + ret = mi_lttng_snapshot_list_output(writer, s_iter);
> + if (ret) {
> + goto error;
> + }
> + }
> +
> + lttng_snapshot_output_list_destroy(list);
> +
> + /* Close snapshot snapshots element */
> + ret = mi_lttng_writer_close_element(writer);
> + if (ret) {
> + goto error;
> + }
> +
> + /* Close snapshot session element */
> + ret = mi_lttng_writer_close_element(writer);
> +
> +error:
> + return ret;
> +}
> +
> static int list_output(void)
> {
> int ret, output_seen = 0;
> @@ -213,6 +254,45 @@ error:
> }
>
> /*
> + * Delete output by ID (machine interface version).
> + */
> +static int mi_del_output(uint32_t id, const char *name)
> +{
> + int ret;
> + struct lttng_snapshot_output *output = NULL;
> +
> + output = lttng_snapshot_output_create();
> + if (!output) {
> + ret = CMD_FATAL;
> + goto error;
> + }
> +
> + if (name) {
> + ret = lttng_snapshot_output_set_name(name, output);
> + } else if (id != UINT32_MAX) {
> + ret = lttng_snapshot_output_set_id(id, output);
> + } else {
> + ret = CMD_ERROR;
> + goto error;
> + }
> + if (ret < 0) {
> + ret = CMD_FATAL;
> + goto error;
> + }
> +
> + ret = lttng_snapshot_del_output(current_session_name, output);
> + if (ret < 0) {
> + goto error;
> + }
> +
> + ret = mi_lttng_snapshot_del_output(writer, id, name, current_session_name);
> +
> +error:
> + lttng_snapshot_output_destroy(output);
> + return ret;
> +}
> +
> +/*
> * Delete output by ID.
> */
> static int del_output(uint32_t id, const char *name)
> @@ -258,6 +338,52 @@ error:
> }
>
> /*
> + * Add output from the user URL (machine interface).
> + */
> +static int mi_add_output(const char *url)
> +{
> + int ret;
> + struct lttng_snapshot_output *output = NULL;
> + char name[NAME_MAX];
> + const char *n_ptr;
> +
> + if (!url && (!opt_data_url || !opt_ctrl_url)) {
> + ret = CMD_ERROR;
> + goto error;
> + }
> +
> + output = create_output_from_args(url);
> + if (!output) {
> + ret = CMD_FATAL;
> + goto error;
> + }
> +
> + /* This call, if successful, populates the id of the output object. */
> + ret = lttng_snapshot_add_output(current_session_name, output);
> + if (ret < 0) {
> + goto error;
> + }
> +
> + n_ptr = lttng_snapshot_output_get_name(output);
> + if (*n_ptr == '\0') {
> + int pret;
> + pret = snprintf(name, sizeof(name), DEFAULT_SNAPSHOT_NAME "-%" PRIu32,
> + lttng_snapshot_output_get_id(output));
> + if (pret < 0) {
> + PERROR("snprintf add output name");
> + }
> + n_ptr = name;
> + }
> +
> + ret = mi_lttng_snapshot_add_output(writer, current_session_name, n_ptr,
> + output);
> +
> +error:
> + lttng_snapshot_output_destroy(output);
> + return ret;
> +}
> +
> +/*
> * Add output from the user URL.
> */
> static int add_output(const char *url)
> @@ -308,7 +434,7 @@ error:
>
> static int cmd_add_output(int argc, const char **argv)
> {
> - int ret = CMD_SUCCESS;
> + int ret;
>
> if (argc < 2 && (!opt_data_url || !opt_ctrl_url)) {
> usage(stderr);
> @@ -316,7 +442,11 @@ static int cmd_add_output(int argc, const char **argv)
> goto end;
> }
>
> - ret = add_output(argv[1]);
> + if (lttng_opt_mi) {
> + ret = mi_add_output(argv[1]);
> + } else {
> + ret = add_output(argv[1]);
> + }
>
> end:
> return ret;
> @@ -324,7 +454,7 @@ end:
>
> static int cmd_del_output(int argc, const char **argv)
> {
> - int ret = CMD_SUCCESS;
> + int ret;
> char *name;
> long id;
>
> @@ -337,9 +467,17 @@ static int cmd_del_output(int argc, const char **argv)
> errno = 0;
> id = strtol(argv[1], &name, 10);
> if (id == 0 && errno == 0) {
> - ret = del_output(UINT32_MAX, name);
> + if (lttng_opt_mi) {
> + ret = mi_del_output(UINT32_MAX, name);
> + } else {
> + ret = del_output(UINT32_MAX, name);
> + }
> } else if (errno == 0 && *name == '\0') {
> - ret = del_output(id, NULL);
> + if (lttng_opt_mi) {
> + ret = mi_del_output(id, NULL);
> + } else {
> + ret = del_output(id, NULL);
> + }
> } else {
> ERR("Argument %s not recognized", argv[1]);
> ret = -1;
> @@ -352,7 +490,42 @@ end:
>
> static int cmd_list_output(int argc, const char **argv)
> {
> - return list_output();
> + int ret;
> +
> + if (lttng_opt_mi) {
> + ret = mi_list_output();
> + } else {
> + ret = list_output();
> + }
> +
> + return ret;
> +}
> +
> +/*
> + * Do a snapshot record with the URL if one is given (machine interface).
> + */
> +static int mi_record(const char *url)
> +{
> + int ret;
> + struct lttng_snapshot_output *output = NULL;
> +
> + output = create_output_from_args(url);
> + if (!output) {
> + ret = CMD_FATAL;
> + goto error;
> + }
> +
> + ret = lttng_snapshot_record(current_session_name, output, 0);
> + if (ret < 0) {
> + goto error;
> + }
> +
> + ret = mi_lttng_snapshot_record(writer, current_session_name, url,
> + opt_ctrl_url, opt_data_url);
> +
> +error:
> + lttng_snapshot_output_destroy(output);
> + return ret;
> }
>
> /*
> @@ -394,9 +567,17 @@ static int cmd_record(int argc, const char **argv)
>
> if (argc == 2) {
> /* With a given URL */
> - ret = record(argv[1]);
> + if (lttng_opt_mi) {
> + ret = mi_record(argv[1]);
> + } else {
> + ret = record(argv[1]);
> + }
> } else {
> - ret = record(NULL);
> + if (lttng_opt_mi) {
> + ret = mi_record(NULL);
> + } else {
> + ret = record(NULL);
> + }
> }
>
> return ret;
> @@ -420,6 +601,23 @@ static int handle_command(const char **argv)
> while (cmd->func != NULL) {
> /* Find command */
> if (strcmp(argv[0], cmd->name) == 0) {
> + if (lttng_opt_mi) {
> + /* Type of the action */
> + ret = mi_lttng_writer_write_element_string(writer,
> + mi_lttng_element_command_action,
> + argv[0]);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Open output element */
> + ret = mi_lttng_writer_open_element(writer,
> + mi_lttng_element_command_output);
> + if (ret) {
> + goto end;
> + }
> + }
> +
> ret = cmd->func(argc, argv);
> goto end;
> }
> @@ -431,6 +629,11 @@ static int handle_command(const char **argv)
> ret = CMD_UNDEFINED;
>
> end:
> + if (lttng_opt_mi) {
> + /* Close output element */
> + ret = mi_lttng_writer_close_element(writer);
> + }
> +
> return ret;
> }
>
> @@ -439,18 +642,27 @@ end:
> */
> int cmd_snapshot(int argc, const char **argv)
> {
> - int opt, ret = CMD_SUCCESS;
> + int opt, ret;
> char *session_name = NULL;
> static poptContext pc;
>
> pc = poptGetContext(NULL, argc, argv, snapshot_opts, 0);
> poptReadDefaultConfig(pc, 0);
>
> - /* TODO: mi support */
> + /* Mi check */
> if (lttng_opt_mi) {
> - ret = -LTTNG_ERR_MI_NOT_IMPLEMENTED;
> - ERR("mi option not supported");
> - goto end;
> + writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
> + if (!writer) {
> + ret = -LTTNG_ERR_NOMEM;
> + goto end;
> + }
> +
> + /* Open command element */
> + ret = mi_lttng_writer_command_open(writer,
> + mi_lttng_element_command_snapshot);
> + if (ret) {
> + goto end;
> + }
> }
>
> while ((opt = poptGetNextOpt(pc)) != -1) {
> @@ -514,6 +726,12 @@ int cmd_snapshot(int argc, const char **argv)
> }
>
> end:
> + /* Mi clean-up */
> + if (writer && mi_lttng_writer_destroy(writer)) {
> + /* Preserve original error code */
> + ret = ret ? ret : LTTNG_ERR_MI_IO_FAIL;
> + }
> +
> if (!opt_session_name) {
> free(session_name);
> }
> diff --git a/src/common/mi-lttng.c b/src/common/mi-lttng.c
> index 2e4c366..ff689f5 100644
> --- a/src/common/mi-lttng.c
> +++ b/src/common/mi-lttng.c
> @@ -19,12 +19,14 @@
>
> #include <include/config.h>
> #include <common/config/config.h>
> +#include <lttng/snapshot-internal.h>
> #include "mi-lttng.h"
>
> #include <assert.h>
>
> /* Strings related to command */
> const char * const mi_lttng_element_command = "command";
> +const char * const mi_lttng_element_command_action = "action";
> const char * const mi_lttng_element_command_version = "version";
> const char * const mi_lttng_element_command_list = "list";
> const char * const mi_lttng_element_command_name = "name";
> @@ -39,6 +41,11 @@ const char * const mi_lttng_element_version_minor = "minor";
> const char * const mi_lttng_element_version_license = "license";
> const char * const mi_lttng_element_version_patch_level = "patchLevel";
> const char * const mi_lttng_element_version_description = "description";
> +const char * const mi_lttng_element_command_snapshot = "snapshot";
> +const char * const mi_lttng_element_command_list_snapshot = "list_snapshot";
> +const char * const mi_lttng_element_command_del_snapshot = "del_snapshot";
> +const char * const mi_lttng_element_command_add_snapshot = "add_snapshot";
> +const char * const mi_lttng_element_command_record_snapshot = "record_snapshot";
>
> /* Strings related to pid */
> const char * const mi_lttng_element_pids = "pids";
> @@ -56,9 +63,18 @@ const char * const mi_lttng_element_type_enum = "ENUM";
> const char * const mi_lttng_element_type_float = "FLOAT";
> const char * const mi_lttng_element_type_string = "STRING";
> const char * const mi_lttng_element_nowrite = "nowrite";
> -
> +const char * const mi_lttng_element_id = "id";
> const char * const mi_lttng_element_empty = "";
>
> +/* String related to a lttng_snapshot_output */
> +const char * const mi_lttng_element_snapshots = "snapshots";
> +const char * const mi_lttng_element_snapshot_session_name = "session_name";
> +const char * const mi_lttng_element_snapshot_n_ptr = "n_ptr";
> +const char * const mi_lttng_element_snapshot_data_url = "data_url";
> +const char * const mi_lttng_element_snapshot_ctrl_url = "ctrl_url";
> +const char * const mi_lttng_element_snapshot_max_size = "max_size";
> +
> +
> const char *mi_lttng_loglevel_string(int value)
> {
> switch (value) {
> @@ -936,3 +952,232 @@ close:
> end:
> return ret;
> }
> +
> +LTTNG_HIDDEN
> +int mi_lttng_snapshot_output_session_name(struct mi_writer *writer,
> + const char *session_name)
> +{
> + int ret;
> +
> + /* Open session element */
> + ret = mi_lttng_writer_open_element(writer, config_element_session);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Snapshot output list for current session name */
> + ret = mi_lttng_writer_write_element_string(writer, config_element_name,
> + session_name);
> +
> + /* Open element snapshots (sequence one snapshot) */
> + ret = mi_lttng_writer_open_element(writer, mi_lttng_element_snapshots);
> + if (ret) {
> + goto end;
> + }
> +
> +end:
> + return ret;
> +}
> +
> +LTTNG_HIDDEN
> +int mi_lttng_snapshot_list_output(struct mi_writer *writer,
> + struct lttng_snapshot_output *output)
> +{
> + int ret;
> +
> + /* Open element snapshot output */
> + ret = mi_lttng_writer_open_element(writer, mi_lttng_element_command_snapshot);
> + if (ret) {
> + goto end;
> + }
> +
> + /* ID of the snapshot output */
> + ret = mi_lttng_writer_write_element_unsigned_int(writer,
> + mi_lttng_element_id, output->id);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Name of the output */
> + ret = mi_lttng_writer_write_element_string(writer, config_element_name,
> + output->name);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Destination of the output (ctrl_url)*/
> + ret = mi_lttng_writer_write_element_string(writer,
> + mi_lttng_element_snapshot_ctrl_url, output->ctrl_url);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Destination of the output (data_url) */
> + ret = mi_lttng_writer_write_element_string(writer,
> + mi_lttng_element_snapshot_data_url, output->data_url);
> + if (ret) {
> + goto end;
> + }
> +
> + /* total size of all stream combined */
> + ret = mi_lttng_writer_write_element_unsigned_int(writer,
> + mi_lttng_element_snapshot_max_size, output->max_size);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Close snapshot output element */
> + ret = mi_lttng_writer_close_element(writer);
> +
> +end:
> + return ret;
> +}
> +
> +LTTNG_HIDDEN
> +int mi_lttng_snapshot_del_output(struct mi_writer *writer, int id,
> + const char *name, const char *current_session_name)
> +{
> + int ret;
> +
> + /* Open element del_snapshot */
> + ret = mi_lttng_writer_open_element(writer,
> + mi_lttng_element_command_snapshot);
> + if (ret) {
> + goto end;
> + }
> +
> +
> + if (id != UINT32_MAX) {
> + /* "Snapshot output "id" successfully deleted for "current_session_name" */
> + /* ID of the snapshot output */
> + ret = mi_lttng_writer_write_element_unsigned_int(writer,
> + mi_lttng_element_id, id);
> + if (ret) {
> + goto end;
> + }
> + } else {
> + /* "Snapshot output "name" successfully deleted for session "current_session_name" */
> + /* Name of the output */
> + ret = mi_lttng_writer_write_element_string(writer, config_element_name,
> + name);
> + if (ret) {
> + goto end;
> + }
> + }
> +
> + /* Snapshot was deleted for session "current_session_name"*/
> + ret = mi_lttng_writer_write_element_string(writer,
> + mi_lttng_element_snapshot_session_name,
> + current_session_name);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Close snapshot element */
> + ret = mi_lttng_writer_close_element(writer);
> +
> +end:
> + return ret;
> +}
> +
> +LTTNG_HIDDEN
> +int mi_lttng_snapshot_add_output(struct mi_writer *writer,
> + const char *current_session_name, const char *n_ptr,
> + struct lttng_snapshot_output *output)
> +{
> + int ret;
> +
> + /* Open element snapshot */
> + ret = mi_lttng_writer_open_element(writer,
> + mi_lttng_element_command_snapshot);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Snapshot output id */
> + ret = mi_lttng_writer_write_element_unsigned_int(writer, mi_lttng_element_id,
> + output->id);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Snapshot output names */
> + ret = mi_lttng_writer_write_element_string(writer,
> + config_element_name, n_ptr);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Destination of the output (ctrl_url)*/
> + ret = mi_lttng_writer_write_element_string(writer,
> + mi_lttng_element_snapshot_ctrl_url, output->ctrl_url);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Snapshot added for session "current_session_name"*/
> + ret = mi_lttng_writer_write_element_string(writer,
> + mi_lttng_element_snapshot_session_name, current_session_name);
> + if (ret) {
> + goto end;
> + }
> +
> + /* total size of all stream combined */
> + ret = mi_lttng_writer_write_element_unsigned_int(writer,
> + mi_lttng_element_snapshot_max_size, output->max_size);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Close snapshot element */
> + ret = mi_lttng_writer_close_element(writer);
> +
> +end:
> + return ret;
> +}
> +
> +LTTNG_HIDDEN
> +int mi_lttng_snapshot_record(struct mi_writer *writer,
> + const char *current_session_name, const char *url,
> + const char *cmdline_ctrl_url, const char *cmdline_data_url)
> +{
> + int ret;
> +
> + /* Open element snapshot */
> + ret = mi_lttng_writer_open_element(writer,
> + mi_lttng_element_command_snapshot);
> + if (ret) {
> + goto end;
> + }
> +
> + /* If a valid an url was given, serialize it,
> + * else take the command line data and ctrl urls*/
> + if (url) {
> + /* Destination of the output (ctrl_url)*/
> + ret = mi_lttng_writer_write_element_string(writer,
> + mi_lttng_element_snapshot_ctrl_url, url);
> + if (ret) {
> + goto end;
> + }
> + } else if (cmdline_ctrl_url) {
> + /* Destination of the output (ctrl_url)*/
> + ret = mi_lttng_writer_write_element_string(writer,
> + mi_lttng_element_snapshot_ctrl_url, cmdline_ctrl_url);
> + if (ret) {
> + goto end;
> + }
> +
> + /* Destination of the output (data_url) */
> + ret = mi_lttng_writer_write_element_string(writer,
> + mi_lttng_element_snapshot_data_url, cmdline_data_url);
> + if (ret) {
> + goto end;
> + }
> + }
> +
> + /* Close record_snapshot element */
> + ret = mi_lttng_writer_close_element(writer);
> +
> +end:
> + return ret;
> +}
> diff --git a/src/common/mi-lttng.h b/src/common/mi-lttng.h
> index 2dca80c..faa6d38 100644
> --- a/src/common/mi-lttng.h
> +++ b/src/common/mi-lttng.h
> @@ -26,6 +26,11 @@
> #include <common/config/config.h>
> #include <lttng/lttng.h>
>
> +#include <stdint.h>
> +
> +/* Don't want to reference snapshot-internal.h here */
> +struct lttng_snapshot_output;
> +
> /* Instance of a machine interface writer. */
> struct mi_writer {
> struct config_writer *writer;
> @@ -46,10 +51,16 @@ struct mi_lttng_version {
>
> /* Strings related to command */
> const char * const mi_lttng_element_command;
> +const char * const mi_lttng_element_command_action;
> const char * const mi_lttng_element_command_version;
> const char * const mi_lttng_element_command_list;
> const char * const mi_lttng_element_command_name;
> const char * const mi_lttng_element_command_output;
> +const char * const mi_lttng_element_command_snapshot;
> +const char * const mi_lttng_element_command_list_snapshot;
> +const char * const mi_lttng_element_command_del_snapshot;
> +const char * const mi_lttng_element_command_add_snapshot;
> +const char * const mi_lttng_element_command_record_snapshot;
>
> /* Strings related to command: version */
> const char * const mi_lttng_element_version;
> @@ -78,6 +89,14 @@ const char * const mi_lttng_element_type_float;
> const char * const mi_lttng_element_type_string;
> const char * const mi_lttng_element_nowrite;
>
> +/* String related to a lttng_snashot */
> +const char * const mi_lttng_element_snapshots;
> +const char * const mi_lttng_element_snapshot_session_name;
> +const char * const mi_lttng_element_snapshot_n_ptr;
> +const char * const mi_lttng_element_snapshot_data_url;
> +const char * const mi_lttng_element_snapshot_ctrl_url;
> +const char * const mi_lttng_element_snapshot_max_size;
> +
> /* Utility string function */
> const char *mi_lttng_loglevel_string(int value);
> const char *mi_lttng_logleveltype_string(enum lttng_loglevel_type value);
> @@ -507,4 +526,115 @@ int mi_lttng_pids_open(struct mi_writer *writer);
> int mi_lttng_pid(struct mi_writer *writer, pid_t pid , const char *cmdline,
> int is_open);
>
> +/*
> + * Machine interface of the snapshot list_output. It specify the session for which
> + * we are listing snapshots, and it open a snapshots element to list a sequence
> + * of snapshot.
> + *
> + * writer An instance of a machine interface writer.
> + *
> + * session_name: Snapshot output for session "session_name".
> + *
> + * Note: The client has to close the session and the snapshots elements after
> + * having list every lttng_snapshot_output.
> + *
> + * Returns zero if the element's value could be written.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_snapshot_output_session_name(struct mi_writer *writer,
> + const char *session_name);
> +
> +/*
> + * Machine interface of the snapshot output.
> + * The machine interface serialize the following attribute:
> + * - id: ID of the snapshot output.
> + * - name: Name of the output.
> + * - data_url : Destination of the output.
> + * - ctrl_url: Destination of the output.
> + * - max_size: total size of all stream combined.
> + *
> + * writer An instance of a machine interface writer.
> + *
> + * output: iterator over a lttng_snapshot_output_list.
> + *
> + * Returns zero if the element's value could be written.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_snapshot_list_output(struct mi_writer *writer,
> + struct lttng_snapshot_output *output);
> +
> +/*
> + * Machine interface of the output of the command snapshot del output
> + * when deleting a snapshot either by id or by name.
> + * If the snapshot was founded and successfully deleted using its id,
> + * we return the id of the snapshot and the current session name on which it
> + * was attached.
> + *
> + * Otherwise, We do the same process with the name of the snapshot, if the
> + * snapshot output id is undefined.
> + *
> + * writer An instance of a machine interface writer.
> + *
> + * id: ID of the snapshot output.
> + *
> + * name: Name of the snapshot.
> + *
> + * current_session_name: Session which the snapshot belong to.
> + *
> + * Returns zero if the element's value could be written.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_snapshot_del_output(struct mi_writer *writer, int id,
> + const char *name, const char *current_session_name);
> +
> +/*
> + * Machine interface of the output of the command snapshot add output
> + * when adding a snapshot from a user URL.
> + *
> + * If the snapshot was successfully added, the machine interface list
> + * these informations:
> + * - id: ID of the newly add snapshot output.
> + * - current_session_name: Name of the session to which the output was added.
> + * - ctrl_url: Destination of the output.
> + * - max_size: total size of all stream combined.
> + *
> + * writer An instance of a machine interface writer.
> + *
> + * current_session_name: Session which the snapshot belong to.
> + *
> + * n_ptr:
> + *
> + * output: iterator over a lttng_snapshot_output_list which contain the snapshot
> + * output informations.
> + *
> + * Returns zero if the element's value could be written.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_snapshot_add_output(struct mi_writer *writer,
> + const char *current_session_name, const char *n_ptr,
> + struct lttng_snapshot_output *output);
> +
> +/*
> + * Machine interface of the output of the command snapshot record from a URL (if given).
> + *
> + * If the snapshot is successfully record from a url, the machine interface
> + * output the following informations:
> + * - url: Destination of the output store in the snapshot.
> + *
> + * Otherwise, the machine interface output the data and ctrl url receive
> + * from the command-line.
> + *
> + * writer An instance of a machine interface writer.
> + *
> + * current_session_name: Snapshot record for session "current_session_name".
> + *
> + * ctrl_url, data_url: Destination of the output receive from the command-line.
> + *
> + * Returns zero if the element's value could be written.
> + * Negative values indicate an error.
> + */
> +int mi_lttng_snapshot_record(struct mi_writer *writer,
> + const char *current_session_name, const char *url,
> + const char *cmdline_ctrl_url, const char *cmdline_data_url);
> +
> #endif /* _MI_LTTNG_H */
> diff --git a/src/common/mi_lttng.xsd b/src/common/mi_lttng.xsd
> index 6fc25c6..e47f4d4 100644
> --- a/src/common/mi_lttng.xsd
> +++ b/src/common/mi_lttng.xsd
> @@ -248,6 +248,24 @@ THE SOFTWARE.
> </xs:all>
> </xs:complexType>
>
> + <!-- Maps to struct lttng_snapshot_output -->
> + <xs:complexType name="snapshot_type">
> + <xs:all>
> + <xs:element name="id" type="uint32_type" minOccurs="0" />
> + <xs:element name="max_size" type="uint64_type" minOccurs="0" />
> + <xs:element name="name" type="name_type" minOccurs="0" />
> + <xs:element name="session_name" type="name_type" minOccurs="0" />
> + <xs:element name="ctrl_url" type="name_type" minOccurs="0"/>
> + <xs:element name="data_url" type="name_type" minOccurs="0"/>
> + </xs:all>
> + </xs:complexType>
> +
> + <xs:complexType name="snapshots_type">
> + <xs:sequence>
> + <xs:element name="snapshot" type="snapshot_type" minOccurs="0" maxOccurs="unbounded" />
> + </xs:sequence>
> + </xs:complexType>
> +
> <xs:complexType name="channels_type">
> <xs:sequence>
> <xs:element name="channel" type="channel_type" minOccurs="0" maxOccurs="unbounded" />
> @@ -263,6 +281,7 @@ THE SOFTWARE.
> <xs:element name="live_timer_interval" type="uint32_type" />
> <xs:element name="channels" type="channels_type" minOccurs="0" />
> <xs:element name="domains" type="domains_type" minOccurs="0" />
> + <xs:element name="snapshots" type="snapshots_type" minOccurs="0" />
> </xs:all>
> </xs:complexType>
>
> @@ -293,10 +312,23 @@ THE SOFTWARE.
> </xs:sequence>
> </xs:complexType>
>
> +
> + <!-- Type of snapshot commands -->
> + <xs:simpleType name="snapshot_action_type">
> + <xs:restriction base="xs:string">
> + <xs:enumeration value="list-output"/>
> + <xs:enumeration value="del-output"/>
> + <xs:enumeration value="add-output"/>
> + <xs:enumeration value="record-output"/>
> + </xs:restriction>
> + </xs:simpleType>
> +
> <xs:complexType name="output_type">
> <xs:choice>
> <xs:element name="domains" type="domains_type" minOccurs="0" />
> + <xs:element name="session" type="session_type" minOccurs="0" />
> <xs:element name="sessions" type="sessions_type" minOccurs="0" />
> + <xs:element name="snapshot" type="snapshot_type" minOccurs="0" />
> <xs:element name="version" type="version_type" minOccurs="0" />
> </xs:choice>
> </xs:complexType>
> @@ -305,6 +337,7 @@ THE SOFTWARE.
> <xs:simpleType name="command_string_type">
> <xs:restriction base="xs:string">
> <xs:enumeration value="list" />
> + <xs:enumeration value="snapshot" />
> <xs:enumeration value="version" />
> </xs:restriction>
> </xs:simpleType>
> @@ -313,6 +346,7 @@ THE SOFTWARE.
> <xs:complexType>
> <xs:all>
> <xs:element name="name" type="command_string_type" maxOccurs="1" />
> + <xs:element name="action" type="snapshot_action_type" minOccurs="0" />
> <xs:element name="output" type="output_type" maxOccurs="1" />
> </xs:all>
> </xs:complexType>
> --
> 1.9.1
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 603 bytes
Desc: Digital signature
URL: <http://lists.lttng.org/pipermail/lttng-dev/attachments/20140513/eb0a5bff/attachment-0001.sig>
More information about the lttng-dev
mailing list