[lttng-dev] Patch mi lttng
Jonathan Rajotte-Julien
jonathan.rajotte-julien at ericsson.com
Tue May 13 14:00:11 EDT 2014
On 05/13/2014 01:32 PM, David Goulet wrote:
> 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.
Absolutely. And with a full set of tests with 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
>>
>
>
>
> _______________________________________________
> lttng-dev mailing list
> lttng-dev at lists.lttng.org
> http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
>
More information about the lttng-dev
mailing list