*
* The structures should be initialized to zero before use.
*/
-#define LTTNG_CHANNEL_ATTR_PADDING1 LTTNG_SYMBOL_NAME_LEN + 16
+#define LTTNG_CHANNEL_ATTR_PADDING1 LTTNG_SYMBOL_NAME_LEN + 12
struct lttng_channel_attr {
int overwrite; /* 1: overwrite, 0: discard */
uint64_t subbuf_size; /* bytes */
/* LTTng 2.1 padding limit */
uint64_t tracefile_size; /* bytes */
uint64_t tracefile_count; /* number of tracefiles */
+ /* LTTng 2.3 padding limit */
+ unsigned int live_timer_interval; /* usec */
char padding[LTTNG_CHANNEL_ATTR_PADDING1];
};
char path[PATH_MAX];
uint32_t enabled; /* enabled/started: 1, disabled/stopped: 0 */
uint32_t snapshot_mode;
+ unsigned int live_timer_interval; /* usec */
char padding[LTTNG_SESSION_PADDING1];
};
extern int lttng_create_session_snapshot(const char *name,
const char *snapshot_url);
+/*
+ * Create a session exclusively used for live reading.
+ *
+ * In this mode, the switch-timer parameter is forced for each UST channel, a
+ * live-switch-timer is enabled for kernel channels, manually setting
+ * switch-timer is forbidden. Synchronization beacons are sent to the relayd,
+ * indexes are sent and metadata is checked for each packet.
+ *
+ * Returns LTTNG_OK on success or a negative error code.
+ */
+extern int lttng_create_session_live(const char *name, const char *url,
+ unsigned int timer_interval);
+
/*
* Destroy a tracing session.
*
chan->attr.output = DEFAULT_KERNEL_CHANNEL_OUTPUT;
chan->attr.switch_timer_interval = DEFAULT_KERNEL_CHANNEL_SWITCH_TIMER;
chan->attr.read_timer_interval = DEFAULT_KERNEL_CHANNEL_READ_TIMER;
+ chan->attr.live_timer_interval = DEFAULT_KERNEL_CHANNEL_LIVE_TIMER;
break;
case LTTNG_DOMAIN_UST:
switch (type) {
DEFAULT_UST_UID_CHANNEL_SWITCH_TIMER;
chan->attr.read_timer_interval =
DEFAULT_UST_UID_CHANNEL_READ_TIMER;
+ chan->attr.live_timer_interval =
+ DEFAULT_UST_UID_CHANNEL_LIVE_TIMER;
break;
case LTTNG_BUFFER_PER_PID:
default:
DEFAULT_UST_PID_CHANNEL_SWITCH_TIMER;
chan->attr.read_timer_interval =
DEFAULT_UST_PID_CHANNEL_READ_TIMER;
+ chan->attr.live_timer_interval =
+ DEFAULT_UST_UID_CHANNEL_LIVE_TIMER;
break;
}
break;
rcu_read_lock();
+ /*
+ * Don't try to enable a channel if the session has been started at
+ * some point in time before. The tracer does not allow it.
+ */
+ if (session->started) {
+ ret = LTTNG_ERR_TRACE_ALREADY_STARTED;
+ goto error;
+ }
+
+ /*
+ * If the session is a live session, remove the switch timer, the
+ * live timer does the same thing but sends also synchronisation
+ * beacons for inactive streams.
+ */
+ if (session->live_timer > 0) {
+ attr->attr.live_timer_interval = session->live_timer;
+ attr->attr.switch_timer_interval = 0;
+ }
+
switch (domain->type) {
case LTTNG_DOMAIN_KERNEL:
{
* Command LTTNG_CREATE_SESSION processed by the client thread.
*/
int cmd_create_session_uri(char *name, struct lttng_uri *uris,
- size_t nb_uri, lttng_sock_cred *creds)
+ size_t nb_uri, lttng_sock_cred *creds, unsigned int live_timer)
{
int ret;
struct ltt_session *session;
session = session_find_by_name(name);
assert(session);
+ session->live_timer = live_timer;
/* Create default consumer output for the session not yet created. */
session->consumer = consumer_create_output(CONSUMER_DST_LOCAL);
if (session->consumer == NULL) {
* Create session in no output mode with URIs set to NULL. The uris we've
* received are for a default snapshot output if one.
*/
- ret = cmd_create_session_uri(name, NULL, 0, creds);
+ ret = cmd_create_session_uri(name, NULL, 0, creds, -1);
if (ret != LTTNG_OK) {
goto error;
}
/* Session commands */
int cmd_create_session_uri(char *name, struct lttng_uri *uris,
- size_t nb_uri, lttng_sock_cred *creds);
+ size_t nb_uri, lttng_sock_cred *creds, unsigned int live_timer);
int cmd_create_session_snapshot(char *name, struct lttng_uri *uris,
size_t nb_uri, lttng_sock_cred *creds);
int cmd_destroy_session(struct ltt_session *session, int wpipe);
int overwrite,
unsigned int switch_timer_interval,
unsigned int read_timer_interval,
+ unsigned int live_timer_interval,
int output,
int type,
uint64_t session_id,
msg->u.ask_channel.overwrite = overwrite;
msg->u.ask_channel.switch_timer_interval = switch_timer_interval;
msg->u.ask_channel.read_timer_interval = read_timer_interval;
+ msg->u.ask_channel.live_timer_interval = live_timer_interval;
msg->u.ask_channel.output = output;
msg->u.ask_channel.type = type;
msg->u.ask_channel.session_id = session_id;
int type,
uint64_t tracefile_size,
uint64_t tracefile_count,
- unsigned int monitor)
+ unsigned int monitor,
+ unsigned int live_timer_interval)
{
assert(msg);
msg->u.channel.tracefile_size = tracefile_size;
msg->u.channel.tracefile_count = tracefile_count;
msg->u.channel.monitor = monitor;
+ msg->u.channel.live_timer_interval = live_timer_interval;
strncpy(msg->u.channel.pathname, pathname,
sizeof(msg->u.channel.pathname));
int overwrite,
unsigned int switch_timer_interval,
unsigned int read_timer_interval,
+ unsigned int live_timer_interval,
int output,
int type,
uint64_t session_id,
int type,
uint64_t tracefile_size,
uint64_t tracefile_count,
- unsigned int monitor);
+ unsigned int monitor,
+ unsigned int live_timer_interval);
int consumer_is_data_pending(uint64_t session_id,
struct consumer_output *consumer);
int consumer_close_metadata(struct consumer_socket *socket,
CONSUMER_CHANNEL_TYPE_DATA,
channel->channel->attr.tracefile_size,
channel->channel->attr.tracefile_count,
- monitor);
+ monitor,
+ channel->channel->attr.live_timer_interval);
health_code_update();
DEFAULT_KERNEL_CHANNEL_OUTPUT,
CONSUMER_CHANNEL_TYPE_METADATA,
0, 0,
- monitor);
+ monitor, 0);
health_code_update();
goto error;
}
- DBG3("Kernel create channel %s with attr: %d, %" PRIu64 ", %" PRIu64 ", %u, %u, %d",
+ DBG3("Kernel create channel %s with attr: %d, %" PRIu64 ", %" PRIu64 ", %u, %u, %d, %d",
chan->name, lkc->channel->attr.overwrite,
lkc->channel->attr.subbuf_size, lkc->channel->attr.num_subbuf,
lkc->channel->attr.switch_timer_interval, lkc->channel->attr.read_timer_interval,
- lkc->channel->attr.output);
+ lkc->channel->attr.live_timer_interval, lkc->channel->attr.output);
/* Kernel tracer channel creation */
ret = kernctl_create_channel(session->fd, &lkc->channel->attr);
lus->gid = session->gid;
lus->output_traces = session->output_traces;
lus->snapshot_mode = session->snapshot_mode;
+ lus->live_timer_interval = session->live_timer;
session->ust_session = lus;
/* Copy session output to the newly created UST session */
switch (cmd_ctx->lsm->cmd_type) {
case LTTNG_CREATE_SESSION:
case LTTNG_CREATE_SESSION_SNAPSHOT:
+ case LTTNG_CREATE_SESSION_LIVE:
case LTTNG_DESTROY_SESSION:
case LTTNG_LIST_SESSIONS:
case LTTNG_LIST_DOMAINS:
switch (cmd_ctx->lsm->cmd_type) {
case LTTNG_CREATE_SESSION:
case LTTNG_CREATE_SESSION_SNAPSHOT:
+ case LTTNG_CREATE_SESSION_LIVE:
case LTTNG_CALIBRATE:
case LTTNG_LIST_SESSIONS:
case LTTNG_LIST_TRACEPOINTS:
}
ret = cmd_create_session_uri(cmd_ctx->lsm->session.name, uris, nb_uri,
- &cmd_ctx->creds);
+ &cmd_ctx->creds, 0);
free(uris);
free(uris);
break;
}
+ case LTTNG_CREATE_SESSION_LIVE:
+ {
+ size_t nb_uri, len;
+ struct lttng_uri *uris = NULL;
+
+ nb_uri = cmd_ctx->lsm->u.uri.size;
+ len = nb_uri * sizeof(struct lttng_uri);
+
+ if (nb_uri > 0) {
+ uris = zmalloc(len);
+ if (uris == NULL) {
+ ret = LTTNG_ERR_FATAL;
+ goto error;
+ }
+
+ /* Receive variable len data */
+ DBG("Waiting for %zu URIs from client ...", nb_uri);
+ ret = lttcomm_recv_unix_sock(sock, uris, len);
+ if (ret <= 0) {
+ DBG("No URIs received from client... continuing");
+ *sock_error = 1;
+ ret = LTTNG_ERR_SESSION_FAIL;
+ free(uris);
+ goto error;
+ }
+
+ if (nb_uri == 1 && uris[0].dtype != LTTNG_DST_PATH) {
+ DBG("Creating session with ONE network URI is a bad call");
+ ret = LTTNG_ERR_SESSION_FAIL;
+ free(uris);
+ goto error;
+ }
+ }
+
+ ret = cmd_create_session_uri(cmd_ctx->lsm->session.name, uris,
+ nb_uri, &cmd_ctx->creds, cmd_ctx->lsm->u.session_live.timer_interval);
+ free(uris);
+ break;
+ }
default:
ret = LTTNG_ERR_UND;
break;
* snapshot purposes.
*/
unsigned int snapshot_mode;
+ /*
+ * Timer set when the session is created for live reading.
+ */
+ int live_timer;
};
/* Prototypes */
unsigned int output_traces;
unsigned int snapshot_mode;
unsigned int has_non_default_channel;
+ unsigned int live_timer_interval; /* usec */
};
/*
/* There is only one consumer object per session possible. */
ua_sess->consumer = usess->consumer;
ua_sess->output_traces = usess->output_traces;
+ ua_sess->live_timer_interval = usess->live_timer_interval;
switch (ua_sess->buffer_type) {
case LTTNG_BUFFER_PER_PID:
struct rcu_head rcu_head;
/* If the channel's streams have to be outputed or not. */
unsigned int output_traces;
+ unsigned int live_timer_interval; /* usec */
};
/*
ua_chan->attr.overwrite,
ua_chan->attr.switch_timer_interval,
ua_chan->attr.read_timer_interval,
+ ua_sess->live_timer_interval,
(int) ua_chan->attr.output,
(int) ua_chan->attr.type,
ua_sess->tracing_id,
#define _GNU_SOURCE
#include <assert.h>
+#include <ctype.h>
#include <popt.h>
#include <stdio.h>
#include <stdlib.h>
static int opt_no_consumer;
static int opt_no_output;
static int opt_snapshot;
+static unsigned int opt_live_timer;
static int opt_disable_consumer;
enum {
OPT_HELP = 1,
OPT_LIST_OPTIONS,
+ OPT_LIVE_TIMER,
};
static struct poptOption long_options[] = {
{"no-consumer", 0, POPT_ARG_VAL, &opt_no_consumer, 1, 0, 0},
{"disable-consumer", 0, POPT_ARG_VAL, &opt_disable_consumer, 1, 0, 0},
{"snapshot", 0, POPT_ARG_VAL, &opt_snapshot, 1, 0, 0},
+ {"live", 0, POPT_ARG_INT, 0, OPT_LIVE_TIMER, 0, 0},
{0, 0, 0, 0, 0, 0, 0}
};
* why this declaration exists and used ONLY in for this command.
*/
extern int _lttng_create_session_ext(const char *name, const char *url,
- const char *datetime);
+ const char *datetime, int live_timer);
/*
* usage
fprintf(ofp, " if one, as the default snapshot output.\n");
fprintf(ofp, " Every channel will be set in overwrite mode\n");
fprintf(ofp, " and with mmap output (splice not supported).\n");
+ fprintf(ofp, " --live USEC Set the session in live-reading mode.\n");
+ fprintf(ofp, " The delay parameter in micro-seconds is the\n");
+ fprintf(ofp, " maximum time the user can wait for the data\n");
+ fprintf(ofp, " to be flushed. Requires a network URL (-U or -C/-D)\n");
+ fprintf(ofp, " and a lttng-relayd listening.\n");
fprintf(ofp, "\n");
fprintf(ofp, "Extended Options:\n");
fprintf(ofp, "\n");
goto error;
}
+ if ((opt_live_timer && !opt_url) && (opt_live_timer && !opt_data_url)) {
+ ERR("You need a network URL (-U or -C/-D) to use live tracing.");
+ ret = CMD_ERROR;
+ goto error;
+ }
+
+ if (opt_snapshot && opt_live_timer) {
+ ERR("Snapshot and live modes are mutually exclusive.");
+ ret = CMD_ERROR;
+ goto error;
+ }
+
if (opt_snapshot) {
/* No output by default. */
const char *snapshot_url = NULL;
snapshot_url = url;
}
ret = lttng_create_session_snapshot(session_name, snapshot_url);
+ } else if (opt_live_timer) {
+ ret = lttng_create_session_live(session_name, url, opt_live_timer);
} else {
- ret = _lttng_create_session_ext(session_name, url, datetime);
+ ret = _lttng_create_session_ext(session_name, url, datetime, -1);
}
if (ret < 0) {
/* Don't set ret so lttng can interpret the sessiond error. */
int cmd_create(int argc, const char **argv)
{
int opt, ret = CMD_SUCCESS;
+ char *opt_arg = NULL;
static poptContext pc;
pc = poptGetContext(NULL, argc, argv, long_options, 0);
case OPT_LIST_OPTIONS:
list_cmd_options(stdout, long_options);
goto end;
+ case OPT_LIVE_TIMER:
+ {
+ unsigned long v;
+
+ errno = 0;
+ opt_arg = poptGetOptArg(pc);
+ v = strtoul(opt_arg, NULL, 0);
+ if (errno != 0 || !isdigit(opt_arg[0])) {
+ ERR("Wrong value in --live parameter: %s", opt_arg);
+ ret = CMD_ERROR;
+ goto end;
+ }
+ if (v != (uint32_t) v) {
+ ERR("32-bit overflow in --live parameter: %s", opt_arg);
+ ret = CMD_ERROR;
+ goto end;
+ }
+ opt_live_timer = (uint32_t) v;
+ DBG("Session live timer interval set to %d", opt_live_timer);
+ break;
+ }
default:
usage(stderr);
ret = CMD_UNDEFINED;
uint64_t tracefile_size,
uint64_t tracefile_count,
uint64_t session_id_per_pid,
- unsigned int monitor)
+ unsigned int monitor,
+ unsigned int live_timer_interval)
{
struct lttng_consumer_channel *channel;
channel->tracefile_size = tracefile_size;
channel->tracefile_count = tracefile_count;
channel->monitor = monitor;
+ channel->live_timer_interval = live_timer_interval;
pthread_mutex_init(&channel->lock, NULL);
pthread_mutex_init(&channel->timer_lock, NULL);
* This is nested OUTSIDE consumer_relayd_sock_pair lock.
*/
pthread_mutex_t timer_lock;
+
+ /* Timer value in usec for live streaming. */
+ unsigned int live_timer_interval;
};
/*
uint64_t tracefile_size,
uint64_t tracefile_count,
uint64_t session_id_per_pid,
- unsigned int monitor);
+ unsigned int monitor,
+ unsigned int live_timer_interval);
void consumer_del_stream(struct lttng_consumer_stream *stream,
struct lttng_ht *ht);
void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
/* Must always be a power of 2 */
#define _DEFAULT_CHANNEL_SUBBUF_NUM 4
#define _DEFAULT_CHANNEL_SWITCH_TIMER 0 /* usec */
+#define _DEFAULT_CHANNEL_LIVE_TIMER 0 /* usec */
#define _DEFAULT_CHANNEL_READ_TIMER 200000 /* usec */
#define _DEFAULT_CHANNEL_OUTPUT LTTNG_EVENT_MMAP
#define DEFAULT_KERNEL_CHANNEL_OUTPUT LTTNG_EVENT_SPLICE
#define DEFAULT_KERNEL_CHANNEL_SWITCH_TIMER _DEFAULT_CHANNEL_SWITCH_TIMER
#define DEFAULT_KERNEL_CHANNEL_READ_TIMER _DEFAULT_CHANNEL_READ_TIMER
+#define DEFAULT_KERNEL_CHANNEL_LIVE_TIMER _DEFAULT_CHANNEL_LIVE_TIMER
/* User space defaults */
/* Timers in usec. */
#define DEFAULT_UST_PID_CHANNEL_SWITCH_TIMER _DEFAULT_CHANNEL_SWITCH_TIMER
#define DEFAULT_UST_UID_CHANNEL_SWITCH_TIMER _DEFAULT_CHANNEL_SWITCH_TIMER
+#define DEFAULT_UST_PID_CHANNEL_LIVE_TIMER _DEFAULT_CHANNEL_LIVE_TIMER
+#define DEFAULT_UST_UID_CHANNEL_LIVE_TIMER _DEFAULT_CHANNEL_LIVE_TIMER
#define DEFAULT_UST_PID_CHANNEL_READ_TIMER 0 /* usec */
#define DEFAULT_UST_UID_CHANNEL_READ_TIMER 0 /* usec */
msg.u.channel.relayd_id, msg.u.channel.output,
msg.u.channel.tracefile_size,
msg.u.channel.tracefile_count, 0,
- msg.u.channel.monitor);
+ msg.u.channel.monitor,
+ msg.u.channel.live_timer_interval);
if (new_channel == NULL) {
lttng_consumer_send_error(ctx, LTTCOMM_CONSUMERD_OUTFD_ERROR);
goto end_nosignal;
LTTNG_SNAPSHOT_LIST_OUTPUT = 27,
LTTNG_SNAPSHOT_RECORD = 28,
LTTNG_CREATE_SESSION_SNAPSHOT = 29,
+ LTTNG_CREATE_SESSION_LIVE = 30,
};
enum lttcomm_relayd_command {
uint32_t wait;
struct lttng_snapshot_output output;
} LTTNG_PACKED snapshot_record;
+ struct {
+ uint32_t nb_uri;
+ unsigned int timer_interval; /* usec */
+ } LTTNG_PACKED session_live;
} u;
} LTTNG_PACKED;
uint32_t tracefile_count; /* number of tracefiles */
/* If the channel's streams have to be monitored or not. */
uint32_t monitor;
+ /* timer to check the streams usage in live mode (usec). */
+ unsigned int live_timer_interval;
} LTTNG_PACKED channel; /* Only used by Kernel. */
struct {
uint64_t stream_key;
int32_t overwrite; /* 1: overwrite, 0: discard */
uint32_t switch_timer_interval; /* usec */
uint32_t read_timer_interval; /* usec */
+ unsigned int live_timer_interval; /* usec */
int32_t output; /* splice, mmap */
int32_t type; /* metadata or per_cpu */
uint64_t session_id; /* Tracing session id */
const char *pathname, const char *name, uid_t uid, gid_t gid,
uint64_t relayd_id, uint64_t key, enum lttng_event_output output,
uint64_t tracefile_size, uint64_t tracefile_count,
- uint64_t session_id_per_pid, unsigned int monitor)
+ uint64_t session_id_per_pid, unsigned int monitor,
+ unsigned int live_timer_interval)
{
assert(pathname);
assert(name);
return consumer_allocate_channel(key, session_id, pathname, name, uid,
gid, relayd_id, output, tracefile_size,
- tracefile_count, session_id_per_pid, monitor);
+ tracefile_count, session_id_per_pid, monitor, live_timer_interval);
}
/*
msg.u.ask_channel.tracefile_size,
msg.u.ask_channel.tracefile_count,
msg.u.ask_channel.session_id_per_pid,
- msg.u.ask_channel.monitor);
+ msg.u.ask_channel.monitor,
+ msg.u.ask_channel.live_timer_interval);
if (!channel) {
goto end_channel_error;
}
return ret;
}
+/*
+ * Create a session exclusively used for live.
+ *
+ * Returns LTTNG_OK on success or a negative error code.
+ */
+int lttng_create_session_live(const char *name, const char *url,
+ unsigned int timer_interval)
+{
+ int ret;
+ ssize_t size;
+ struct lttcomm_session_msg lsm;
+ struct lttng_uri *uris = NULL;
+
+ if (name == NULL) {
+ return -LTTNG_ERR_INVALID;
+ }
+
+ memset(&lsm, 0, sizeof(lsm));
+
+ lsm.cmd_type = LTTNG_CREATE_SESSION_LIVE;
+ lttng_ctl_copy_string(lsm.session.name, name, sizeof(lsm.session.name));
+
+ size = uri_parse_str_urls(url, NULL, &uris);
+ if (size < 0) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ /* file:// is not accepted for live session. */
+ if (uris[0].dtype == LTTNG_DST_PATH) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ lsm.u.session_live.nb_uri = size;
+ lsm.u.session_live.timer_interval = timer_interval;
+
+ ret = lttng_ctl_ask_sessiond_varlen(&lsm, uris,
+ sizeof(struct lttng_uri) * size, NULL);
+
+end:
+ free(uris);
+ return ret;
+}
+
/*
* lib constructor
*/