Use per PID buffer (\-u only). Each application has its own buffers.
\-\-buffers-global
Use shared buffer for the whole system (\-k only)
+\-C, \-\-tracefile-size SIZE
+ Maximum size of of each tracefile within a stream (in bytes).
+\-W, \-\-tracefile-count COUNT
+ Used in conjunction with \-C option, this will limit the number
+ of files created to the specified count.
+
+.B EXAMPLES:
+
+$ lttng enable-channel -C 4096 -W 32 chan1
+For each stream, the maximum size of a trace file will be 4096 bytes divided
+over a \fBmaximum\fP of 32 different files. The file count is appended after
+the stream number as seen in the following example. The last trace file is
+smaller than 4096 since it was not completely filled.
+
+ ~/lttng-traces/[...]/chan1_0_0 (4096)
+ ~/lttng-traces/[...]/chan1_0_1 (4096)
+ ~/lttng-traces/[...]/chan1_0_2 (3245)
+ ~/lttng-traces/[...]/chan1_1_0 (4096)
+ ...
+
+$ lttng enable-channel -C 4096
+This will create trace files of 4096 bytes and will create new ones as long as
+there is data available.
.fi
.IP
*
* The structures should be initialized to zero before use.
*/
-#define LTTNG_CHANNEL_ATTR_PADDING1 LTTNG_SYMBOL_NAME_LEN + 32
+#define LTTNG_CHANNEL_ATTR_PADDING1 LTTNG_SYMBOL_NAME_LEN + 16
struct lttng_channel_attr {
int overwrite; /* 1: overwrite, 0: discard */
uint64_t subbuf_size; /* bytes */
unsigned int switch_timer_interval; /* usec */
unsigned int read_timer_interval; /* usec */
enum lttng_event_output output; /* splice, mmap */
+ /* LTTng 2.1 padding limit */
+ uint64_t tracefile_size; /* bytes */
+ uint64_t tracefile_count; /* number of tracefiles */
char padding[LTTNG_CHANNEL_ATTR_PADDING1];
};
goto error;
}
+ /*
+ * The tracefile_size should not be < to the subbuf_size, otherwise
+ * we won't be able to write the packets on disk
+ */
+ if ((attr->attr.tracefile_size > 0) &&
+ (attr->attr.tracefile_size < attr->attr.subbuf_size)) {
+ ret = LTTNG_ERR_INVALID;
+ goto error;
+ }
+
/* Create UST channel */
uchan = trace_ust_create_channel(attr, usess->pathname);
if (uchan == NULL) {
uint64_t relayd_id,
uint64_t key,
unsigned char *uuid,
- uint32_t chan_id)
+ uint32_t chan_id,
+ uint64_t tracefile_size,
+ uint64_t tracefile_count)
{
assert(msg);
msg->u.ask_channel.relayd_id = relayd_id;
msg->u.ask_channel.key = key;
msg->u.ask_channel.chan_id = chan_id;
+ msg->u.ask_channel.tracefile_size = tracefile_size;
+ msg->u.ask_channel.tracefile_count = tracefile_count;
memcpy(msg->u.ask_channel.uuid, uuid, sizeof(msg->u.ask_channel.uuid));
const char *name,
unsigned int nb_init_streams,
enum lttng_event_output output,
- int type)
+ int type,
+ uint64_t tracefile_size,
+ uint64_t tracefile_count)
{
assert(msg);
msg->u.channel.nb_init_streams = nb_init_streams;
msg->u.channel.output = output;
msg->u.channel.type = type;
+ msg->u.channel.tracefile_size = tracefile_size;
+ msg->u.channel.tracefile_count = tracefile_count;
strncpy(msg->u.channel.pathname, pathname,
sizeof(msg->u.channel.pathname));
uint64_t relayd_id,
uint64_t key,
unsigned char *uuid,
- uint32_t chan_id);
+ uint32_t chan_id,
+ uint64_t tracefile_size,
+ uint64_t tracefile_count);
void consumer_init_stream_comm_msg(struct lttcomm_consumer_msg *msg,
enum lttng_consumer_command cmd,
uint64_t channel_key,
const char *name,
unsigned int nb_init_streams,
enum lttng_event_output output,
- int type);
+ int type,
+ uint64_t tracefile_size,
+ uint64_t tracefile_count);
int consumer_is_data_pending(uint64_t session_id,
struct consumer_output *consumer);
int consumer_close_metadata(struct consumer_socket *socket,
channel->channel->name,
channel->stream_count,
channel->channel->attr.output,
- CONSUMER_CHANNEL_TYPE_DATA);
+ CONSUMER_CHANNEL_TYPE_DATA,
+ channel->channel->attr.tracefile_size,
+ channel->channel->attr.tracefile_count);
health_code_update();
DEFAULT_METADATA_NAME,
1,
DEFAULT_KERNEL_CHANNEL_OUTPUT,
- CONSUMER_CHANNEL_TYPE_METADATA);
+ CONSUMER_CHANNEL_TYPE_METADATA,
+ 0, 0);
health_code_update();
LTTNG_CONSUMER_ADD_STREAM,
session->metadata->fd,
session->metadata_stream_fd,
- 0); /* CPU: 0 for metadata. */
+ 0); /* CPU: 0 for metadata. */
health_code_update();
PERROR("fcntl session fd");
}
+ lks->tracefile_size = channel->channel->attr.tracefile_size;
+ lks->tracefile_count = channel->channel->attr.tracefile_count;
+
/* Add stream to channe stream list */
cds_list_add(&lks->list, &channel->stream_list.head);
channel->stream_count++;
int cpu;
/* Format is %s_%d respectively channel name and CPU number. */
char name[DEFAULT_STREAM_NAME_LEN];
+ uint64_t tracefile_size;
+ uint64_t tracefile_count;
struct cds_list_head list;
};
luc->events = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
luc->ctx = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
+ /* On-disk circular buffer parameters */
+ luc->tracefile_size = chan->attr.tracefile_size;
+ luc->tracefile_count = chan->attr.tracefile_count;
+
DBG2("Trace UST channel %s created", luc->name);
error:
struct lttng_ht *ctx;
struct lttng_ht *events;
struct lttng_ht_node_str node;
+ uint64_t tracefile_size;
+ uint64_t tracefile_count;
};
/* UST Metadata */
strncpy(ua_chan->name, uchan->name, sizeof(ua_chan->name));
ua_chan->name[sizeof(ua_chan->name) - 1] = '\0';
+ ua_chan->tracefile_size = uchan->tracefile_size;
+ ua_chan->tracefile_count = uchan->tracefile_count;
+
/* Copy event attributes since the layout is different. */
ua_chan->attr.subbuf_size = uchan->attr.subbuf_size;
ua_chan->attr.num_subbuf = uchan->attr.num_subbuf;
struct ust_app_session *session;
struct lttng_ht *ctx;
struct lttng_ht *events;
+ uint64_t tracefile_size;
+ uint64_t tracefile_count;
/*
* Node indexed by channel name in the channels' hash table of a session.
*/
consumer->net_seq_index,
ua_chan->key,
registry->uuid,
- chan_id);
+ chan_id,
+ ua_chan->tracefile_size,
+ ua_chan->tracefile_count);
health_code_update();
OPT_READ_TIMER,
OPT_USERSPACE,
OPT_LIST_OPTIONS,
+ OPT_TRACEFILE_SIZE,
+ OPT_TRACEFILE_COUNT,
};
static struct lttng_handle *handle;
{"buffers-uid", 0, POPT_ARG_VAL, &opt_buffer_uid, 1, 0, 0},
{"buffers-pid", 0, POPT_ARG_VAL, &opt_buffer_pid, 1, 0, 0},
{"buffers-global", 0, POPT_ARG_VAL, &opt_buffer_global, 1, 0, 0},
+ {"tracefile-size", 'C', POPT_ARG_INT, 0, OPT_TRACEFILE_SIZE, 0, 0},
+ {"tracefile-count", 'W', POPT_ARG_INT, 0, OPT_TRACEFILE_COUNT, 0, 0},
{0, 0, 0, 0, 0, 0, 0}
};
fprintf(ofp, " --buffers-uid Use per UID buffer (-u only)\n");
fprintf(ofp, " --buffers-pid Use per PID buffer (-u only)\n");
fprintf(ofp, " --buffers-global Use shared buffer for the whole system (-k only)\n");
+ fprintf(ofp, " -C, --tracefile-size SIZE\n");
+ fprintf(ofp, " Maximum size of of each tracefile within a stream (in bytes).\n");
+ fprintf(ofp, " -W, --tracefile-count COUNT\n");
+ fprintf(ofp, " Used in conjunction with -C option, this will limit the number\n");
+ fprintf(ofp, " of files created to the specified count.\n");
fprintf(ofp, "\n");
}
if (chan.attr.output == -1) {
chan.attr.output = default_attr.output;
}
+ if (chan.attr.tracefile_count == -1) {
+ chan.attr.tracefile_count = default_attr.tracefile_count;
+ }
+ if (chan.attr.tracefile_size == -1) {
+ chan.attr.tracefile_size = default_attr.tracefile_size;
+ }
}
/*
set_default_attr(&dom);
+ if ((chan.attr.tracefile_size > 0) &&
+ (chan.attr.tracefile_size < chan.attr.subbuf_size)) {
+ ERR("Tracefile_size must be greater than or equal to subbuf_size "
+ "(%" PRIu64 " < %" PRIu64 ")",
+ chan.attr.tracefile_size, chan.attr.subbuf_size);
+ ret = CMD_ERROR;
+ goto error;
+ }
+
/* Setting channel output */
if (opt_output) {
if (!strncmp(output_mmap, opt_output, strlen(output_mmap))) {
case OPT_USERSPACE:
opt_userspace = 1;
break;
+ case OPT_TRACEFILE_SIZE:
+ chan.attr.tracefile_size = atoll(poptGetOptArg(pc));
+ DBG("Maximum tracefile size set to %" PRIu64,
+ chan.attr.tracefile_size);
+ break;
+ case OPT_TRACEFILE_COUNT:
+ chan.attr.tracefile_count = atoll(poptGetOptArg(pc));
+ DBG("Maximum tracefile count set to %" PRIu64,
+ chan.attr.tracefile_count);
+ break;
case OPT_LIST_OPTIONS:
list_cmd_options(stdout, long_options);
goto end;
uid_t uid,
gid_t gid,
int relayd_id,
- enum lttng_event_output output)
+ enum lttng_event_output output,
+ uint64_t tracefile_size,
+ uint64_t tracefile_count)
{
struct lttng_consumer_channel *channel;
channel->gid = gid;
channel->relayd_id = relayd_id;
channel->output = output;
+ channel->tracefile_size = tracefile_size;
+ channel->tracefile_count = tracefile_count;
strncpy(channel->pathname, pathname, sizeof(channel->pathname));
channel->pathname[sizeof(channel->pathname) - 1] = '\0';
return ret;
}
+/*
+ * Create the tracefile on disk.
+ *
+ * Return 0 on success or else a negative value.
+ */
+int lttng_create_output_file(struct lttng_consumer_stream *stream)
+{
+ int ret;
+ char full_path[PATH_MAX];
+ char *path_name_id = NULL;
+ char *path;
+
+ assert(stream);
+ assert(stream->net_seq_idx == (uint64_t) -1ULL);
+
+ ret = snprintf(full_path, sizeof(full_path), "%s/%s",
+ stream->chan->pathname, stream->name);
+ if (ret < 0) {
+ PERROR("snprintf create output file");
+ goto error;
+ }
+
+ /*
+ * If we split the trace in multiple files, we have to add the tracefile
+ * current count at the end of the tracefile name
+ */
+ if (stream->chan->tracefile_size > 0) {
+ ret = asprintf(&path_name_id, "%s_%" PRIu64, full_path,
+ stream->tracefile_count_current);
+ if (ret < 0) {
+ PERROR("Allocating path name ID");
+ goto error;
+ }
+ path = path_name_id;
+ } else {
+ path = full_path;
+ }
+
+ ret = run_as_open(path, O_WRONLY | O_CREAT | O_TRUNC,
+ S_IRWXU | S_IRWXG | S_IRWXO, stream->uid, stream->gid);
+ if (ret < 0) {
+ PERROR("open stream path %s", path);
+ goto error_open;
+ }
+ stream->out_fd = ret;
+ stream->tracefile_size_current = 0;
+
+error_open:
+ free(path_name_id);
+error:
+ return ret;
+}
+
+/*
+ * Change the output tracefile according to the tracefile_size and
+ * tracefile_count parameters. The stream lock MUST be held before calling this
+ * function because we are modifying the stream status.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int rotate_output_file(struct lttng_consumer_stream *stream)
+{
+ int ret;
+
+ assert(stream);
+ assert(stream->tracefile_size_current);
+
+ ret = close(stream->out_fd);
+ if (ret < 0) {
+ PERROR("Closing tracefile");
+ goto end;
+ }
+
+ if (stream->chan->tracefile_count > 0) {
+ stream->tracefile_count_current =
+ (stream->tracefile_count_current + 1) %
+ stream->chan->tracefile_count;
+ } else {
+ stream->tracefile_count_current++;
+ }
+
+ return lttng_create_output_file(stream);
+
+end:
+ return ret;
+}
+
/*
* Mmap the ring buffer, read it and write the data to the tracefile. This is a
* core function for writing trace buffers to either the local filesystem or
} else {
/* No streaming, we have to set the len with the full padding */
len += padding;
+
+ /*
+ * Check if we need to change the tracefile before writing the packet.
+ */
+ if (stream->chan->tracefile_size > 0 &&
+ (stream->tracefile_size_current + len) >
+ stream->chan->tracefile_size) {
+ ret = rotate_output_file(stream);
+ if (ret < 0) {
+ ERR("Rotating output file");
+ goto end;
+ }
+ outfd = stream->out_fd;
+ }
+ stream->tracefile_size_current += len;
}
while (len > 0) {
} else {
/* No streaming, we have to set the len with the full padding */
len += padding;
+
+ /*
+ * Check if we need to change the tracefile before writing the packet.
+ */
+ if (stream->chan->tracefile_size > 0 &&
+ (stream->tracefile_size_current + len) >
+ stream->chan->tracefile_size) {
+ ret = rotate_output_file(stream);
+ if (ret < 0) {
+ ERR("Rotating output file");
+ goto end;
+ }
+ outfd = stream->out_fd;
+ }
+ stream->tracefile_size_current += len;
}
while (len > 0) {
/* For metadata periodical flush */
int switch_timer_enabled;
timer_t switch_timer;
+ /* On-disk circular buffer */
+ uint64_t tracefile_size;
+ uint64_t tracefile_count;
};
/*
/* Internal state of libustctl. */
struct ustctl_consumer_stream *ustream;
struct cds_list_head send_node;
+ /* On-disk circular buffer */
+ uint64_t tracefile_size_current;
+ uint64_t tracefile_count_current;
};
/*
uid_t uid,
gid_t gid,
int relayd_id,
- enum lttng_event_output output);
+ enum lttng_event_output output,
+ uint64_t tracefile_size,
+ uint64_t tracefile_count);
void consumer_del_stream(struct lttng_consumer_stream *stream,
struct lttng_ht *ht);
void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
int (*recv_stream)(struct lttng_consumer_stream *stream),
int (*update_stream)(int sessiond_key, uint32_t state));
void lttng_consumer_destroy(struct lttng_consumer_local_data *ctx);
+int lttng_create_output_file(struct lttng_consumer_stream *stream);
ssize_t lttng_consumer_on_read_subbuffer_mmap(
struct lttng_consumer_local_data *ctx,
struct lttng_consumer_stream *stream, unsigned long len,
#define DEFAULT_KERNEL_CHANNEL_SUBBUF_NUM DEFAULT_CHANNEL_SUBBUF_NUM
/* See lttng-kernel.h enum lttng_kernel_output for channel output */
#define DEFAULT_KERNEL_CHANNEL_OUTPUT LTTNG_EVENT_SPLICE
+/* By default, unlimited tracefile size */
+#define DEFAULT_KERNEL_CHANNEL_TRACEFILE_SIZE 0
+/* By default, unlimited tracefile count */
+#define DEFAULT_KERNEL_CHANNEL_TRACEFILE_COUNT 0
#define DEFAULT_KERNEL_CHANNEL_SWITCH_TIMER \
DEFAULT_CHANNEL_SWITCH_TIMER
#define DEFAULT_UST_CHANNEL_SUBBUF_NUM DEFAULT_CHANNEL_SUBBUF_NUM
/* See lttng-ust.h enum lttng_ust_output */
#define DEFAULT_UST_CHANNEL_OUTPUT LTTNG_EVENT_MMAP
+/* By default, unlimited tracefile size */
+#define DEFAULT_UST_CHANNEL_TRACEFILE_SIZE 0
+/* By default, unlimited tracefile count */
+#define DEFAULT_UST_CHANNEL_TRACEFILE_COUNT 0
#define DEFAULT_UST_CHANNEL_SWITCH_TIMER \
DEFAULT_CHANNEL_SWITCH_TIMER
new_channel = consumer_allocate_channel(msg.u.channel.channel_key,
msg.u.channel.session_id, msg.u.channel.pathname,
msg.u.channel.name, msg.u.channel.uid, msg.u.channel.gid,
- msg.u.channel.relayd_id, msg.u.channel.output);
+ msg.u.channel.relayd_id, msg.u.channel.output,
+ msg.u.channel.tracefile_size,
+ msg.u.channel.tracefile_count);
if (new_channel == NULL) {
lttng_consumer_send_error(ctx, LTTCOMM_CONSUMERD_OUTFD_ERROR);
goto end_nosignal;
int lttng_kconsumer_on_recv_stream(struct lttng_consumer_stream *stream)
{
int ret;
- char full_path[PATH_MAX];
assert(stream);
- ret = snprintf(full_path, sizeof(full_path), "%s/%s",
- stream->chan->pathname, stream->name);
+ ret = lttng_create_output_file(stream);
if (ret < 0) {
- PERROR("snprintf on_recv_stream");
+ ERR("Creating output file");
goto error;
}
- /* Opening the tracefile in write mode */
- if (stream->net_seq_idx == (uint64_t) -1ULL) {
- ret = run_as_open(full_path, O_WRONLY | O_CREAT | O_TRUNC,
- S_IRWXU|S_IRWXG|S_IRWXO, stream->uid, stream->gid);
- if (ret < 0) {
- PERROR("open kernel stream path %s", full_path);
- goto error;
- }
- stream->out_fd = ret;
- }
-
if (stream->output == LTTNG_EVENT_MMAP) {
/* get the len of the mmap region */
unsigned long mmap_len;
/* Use splice or mmap to consume this fd */
enum lttng_event_output output;
int type; /* Per cpu or metadata. */
+ uint64_t tracefile_size; /* bytes */
+ uint32_t tracefile_count; /* number of tracefiles */
} LTTNG_PACKED channel; /* Only used by Kernel. */
struct {
uint64_t stream_key;
uint64_t key; /* Unique channel key. */
unsigned char uuid[UUID_STR_LEN]; /* uuid for ust tracer. */
uint32_t chan_id; /* Channel ID on the tracer side. */
+ uint64_t tracefile_size; /* bytes */
+ uint32_t tracefile_count; /* number of tracefiles */
} LTTNG_PACKED ask_channel;
struct {
uint64_t key;
*/
static struct lttng_consumer_channel *allocate_channel(uint64_t session_id,
const char *pathname, const char *name, uid_t uid, gid_t gid,
- int relayd_id, uint64_t key, enum lttng_event_output output)
+ int relayd_id, uint64_t key, enum lttng_event_output output,
+ uint64_t tracefile_size, uint64_t tracefile_count)
{
assert(pathname);
assert(name);
return consumer_allocate_channel(key, session_id, pathname, name, uid, gid,
- relayd_id, output);
+ relayd_id, output, tracefile_size, tracefile_count);
}
/*
msg.u.ask_channel.pathname, msg.u.ask_channel.name,
msg.u.ask_channel.uid, msg.u.ask_channel.gid,
msg.u.ask_channel.relayd_id, msg.u.ask_channel.key,
- (enum lttng_event_output) msg.u.ask_channel.output);
+ (enum lttng_event_output) msg.u.ask_channel.output,
+ msg.u.ask_channel.tracefile_size,
+ msg.u.ask_channel.tracefile_count);
if (!channel) {
goto end_channel_error;
}
*/
int lttng_ustconsumer_on_recv_stream(struct lttng_consumer_stream *stream)
{
- int ret;
- char full_path[PATH_MAX];
-
- /* Opening the tracefile in write mode */
- if (stream->net_seq_idx != (uint64_t) -1ULL) {
- goto end;
- }
-
- ret = snprintf(full_path, sizeof(full_path), "%s/%s",
- stream->chan->pathname, stream->name);
- if (ret < 0) {
- PERROR("snprintf on_recv_stream");
- goto error;
- }
-
- ret = run_as_open(full_path, O_WRONLY | O_CREAT | O_TRUNC,
- S_IRWXU | S_IRWXG | S_IRWXO, stream->uid, stream->gid);
- if (ret < 0) {
- PERROR("open stream path %s", full_path);
- goto error;
- }
- stream->out_fd = ret;
-
-end:
- /* we return 0 to let the library handle the FD internally */
- return 0;
-
-error:
- return ret;
+ return lttng_create_output_file(stream);
}
/*
attr->subbuf_size = default_get_kernel_channel_subbuf_size();
attr->num_subbuf = DEFAULT_KERNEL_CHANNEL_SUBBUF_NUM;
attr->output = DEFAULT_KERNEL_CHANNEL_OUTPUT;
+ attr->tracefile_size = DEFAULT_KERNEL_CHANNEL_TRACEFILE_SIZE;
+ attr->tracefile_count = DEFAULT_KERNEL_CHANNEL_TRACEFILE_COUNT;
break;
case LTTNG_DOMAIN_UST:
#if 0
attr->subbuf_size = default_get_ust_channel_subbuf_size();
attr->num_subbuf = DEFAULT_UST_CHANNEL_SUBBUF_NUM;
attr->output = DEFAULT_UST_CHANNEL_OUTPUT;
+ attr->tracefile_size = DEFAULT_UST_CHANNEL_TRACEFILE_SIZE;
+ attr->tracefile_count = DEFAULT_UST_CHANNEL_TRACEFILE_COUNT;
break;
default:
/* Default behavior: leave set to 0. */