From b4d507caca4c97965357fb3d02e60265c12c1a4e Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Mon, 18 Jun 2018 22:46:25 -0400 Subject: [PATCH] Backport: Relayd: introduce --group-output-by-session LTTng-relayd now support the grouping of trace data per session name. This mode can be used via the "--group-output-per-session" The default, and current way, of grouping is done around the hostname of the traced system. When grouped by host the following folder hierarchy is mostly found on the filesystem: /[-]/ When using "--group-output-per-session", the following hierarchy is found on the filesystem: /[-]/ The datetime is not always present given how it is generated in certain situations either on the client (cli) or in lttng-sessiond and specified output type. This commit ensure maximum compatibility with all lttng-relayd client (lttng-consumerd) version. Further work can be accomplished on the client (cli), lttng-sessiond, lttng-consumerd to pass individual path information: session name, datetime and hostname. Note that the automatic naming can be problematic since the datetime is used inside the session name while when using a defined session name it is not part of the session name. Still, this would leave older lttng-relayd client version in the dark given that such modification would require communication API changes. The current solution ensure that even when dealing with older client the grouping option is respected. The received paths are tokenized in 3 tokens. The first one is the hostname. This is respected across all communications. Note that, the hostname is already known since the create session command (version >= 2.4). The second one can either be a session name, with or without a datetime, or extra path information. The extra path information come from the URIs set at the client level: lttng create --set-url=net://localhost/extra/path/information When the second token is extra path information the session name is never present in the path. We reuse the name passed on the create session command (version >= 2.4). The datetime, if present, is extracted from the session name passed by the client or if not present from the session name passed by the create session command. This enable the support of automatic session name. The third one is the rest of the path. No information extraction is done on this token. Signed-off-by: Jonathan Rajotte --- src/bin/lttng-relayd/cmd-2-1.c | 5 +- src/bin/lttng-relayd/cmd-2-1.h | 4 +- src/bin/lttng-relayd/cmd-2-2.c | 5 +- src/bin/lttng-relayd/cmd-2-2.h | 3 +- src/bin/lttng-relayd/lttng-relayd.h | 2 + src/bin/lttng-relayd/main.c | 28 ++++- src/bin/lttng-relayd/utils.c | 164 +++++++++++++++++++++++++++- src/bin/lttng-relayd/utils.h | 2 +- 8 files changed, 200 insertions(+), 13 deletions(-) diff --git a/src/bin/lttng-relayd/cmd-2-1.c b/src/bin/lttng-relayd/cmd-2-1.c index 99aa86668..291e1e380 100644 --- a/src/bin/lttng-relayd/cmd-2-1.c +++ b/src/bin/lttng-relayd/cmd-2-1.c @@ -32,7 +32,8 @@ * cmd_recv_stream_2_1 allocates path_name and channel_name. */ int cmd_recv_stream_2_1(const struct lttng_buffer_view *payload, - char **ret_path_name, char **ret_channel_name) + char **ret_path_name, char **ret_channel_name, + struct relay_session *session) { int ret; struct lttcomm_relayd_add_stream stream_info; @@ -55,7 +56,7 @@ int cmd_recv_stream_2_1(const struct lttng_buffer_view *payload, ERR("Path name too long"); goto error; } - path_name = create_output_path(stream_info.pathname); + path_name = create_output_path(stream_info.pathname, session->session_name); if (!path_name) { PERROR("Path name allocation"); ret = -ENOMEM; diff --git a/src/bin/lttng-relayd/cmd-2-1.h b/src/bin/lttng-relayd/cmd-2-1.h index c1eb6b327..47b8f3d14 100644 --- a/src/bin/lttng-relayd/cmd-2-1.h +++ b/src/bin/lttng-relayd/cmd-2-1.h @@ -21,9 +21,11 @@ */ #include "lttng-relayd.h" +#include "session.h" #include int cmd_recv_stream_2_1(const struct lttng_buffer_view *payload, - char **path_name, char **channel_name); + char **path_name, char **channel_name, + struct relay_session *session); #endif /* RELAYD_CMD_2_1_H */ diff --git a/src/bin/lttng-relayd/cmd-2-2.c b/src/bin/lttng-relayd/cmd-2-2.c index 5ff628050..70415d7bb 100644 --- a/src/bin/lttng-relayd/cmd-2-2.c +++ b/src/bin/lttng-relayd/cmd-2-2.c @@ -35,7 +35,8 @@ */ int cmd_recv_stream_2_2(const struct lttng_buffer_view *payload, char **ret_path_name, char **ret_channel_name, - uint64_t *tracefile_size, uint64_t *tracefile_count) + uint64_t *tracefile_size, uint64_t *tracefile_count, + struct relay_session *session) { int ret; struct lttcomm_relayd_add_stream_2_2 stream_info; @@ -58,7 +59,7 @@ int cmd_recv_stream_2_2(const struct lttng_buffer_view *payload, ERR("Path name too long"); goto error; } - path_name = create_output_path(stream_info.pathname); + path_name = create_output_path(stream_info.pathname, session->session_name); if (!path_name) { PERROR("Path name allocation"); ret = -ENOMEM; diff --git a/src/bin/lttng-relayd/cmd-2-2.h b/src/bin/lttng-relayd/cmd-2-2.h index 822f627b1..864995aa6 100644 --- a/src/bin/lttng-relayd/cmd-2-2.h +++ b/src/bin/lttng-relayd/cmd-2-2.h @@ -25,6 +25,7 @@ int cmd_recv_stream_2_2(const struct lttng_buffer_view *payload, char **path_name, char **channel_name, - uint64_t *tracefile_size, uint64_t *tracefile_count); + uint64_t *tracefile_size, uint64_t *tracefile_count, + struct relay_session *session); #endif /* RELAYD_CMD_2_2_H */ diff --git a/src/bin/lttng-relayd/lttng-relayd.h b/src/bin/lttng-relayd/lttng-relayd.h index e4e29e781..a3976852d 100644 --- a/src/bin/lttng-relayd/lttng-relayd.h +++ b/src/bin/lttng-relayd/lttng-relayd.h @@ -47,6 +47,8 @@ extern struct lttng_ht *viewer_streams_ht; extern char *opt_output_path; extern const char *tracing_group_name; extern const char * const config_section_name; +extern int opt_group_output_by_session; +extern int opt_group_output_by_host; extern int thread_quit_pipe[2]; diff --git a/src/bin/lttng-relayd/main.c b/src/bin/lttng-relayd/main.c index c171dfdfe..c3c9a4fa6 100644 --- a/src/bin/lttng-relayd/main.c +++ b/src/bin/lttng-relayd/main.c @@ -85,6 +85,8 @@ enum relay_connection_status { /* command line options */ char *opt_output_path, *opt_working_directory; static int opt_daemon, opt_background; +int opt_group_output_by_session; +int opt_group_output_by_host; /* * We need to wait for listener and live listener threads, as well as @@ -170,6 +172,8 @@ static struct option long_options[] = { { "config", 1, 0, 'f' }, { "version", 0, 0, 'V' }, { "working-directory", 1, 0, 'w', }, + { "group-output-by-session", 0, 0, 's', }, + { "group-output-by-host", 0, 0, 'p', }, { NULL, 0, 0, 0, }, }; @@ -305,6 +309,20 @@ static int set_option(int opt, const char *arg, const char *optname) } } break; + case 's': + if (opt_group_output_by_host) { + ERR("Cannot set --group-output-by-session, --group-output-by-host already defined"); + exit(EXIT_FAILURE); + } + opt_group_output_by_session = 1; + break; + case 'p': + if (opt_group_output_by_session) { + ERR("Cannot set --group-output-by-host, --group-output-by-session already defined"); + exit(EXIT_FAILURE); + } + opt_group_output_by_host = 1; + break; default: /* Unknown option or other error. * Error is printed by getopt, just return */ @@ -502,6 +520,11 @@ static int set_options(int argc, char **argv) } } + if (!opt_group_output_by_session && !opt_group_output_by_host) { + /* Group by host by default */ + opt_group_output_by_host = 1; + } + exit: free(optstring); return retval; @@ -1219,12 +1242,13 @@ static int relay_add_stream(const struct lttcomm_relayd_hdr *recv_hdr, switch (session->minor) { case 1: /* LTTng sessiond 2.1. Allocates path_name and channel_name. */ ret = cmd_recv_stream_2_1(payload, &path_name, - &channel_name); + &channel_name, session); break; case 2: /* LTTng sessiond 2.2. Allocates path_name and channel_name. */ default: ret = cmd_recv_stream_2_2(payload, &path_name, - &channel_name, &tracefile_size, &tracefile_count); + &channel_name, &tracefile_size, &tracefile_count, + session); break; } if (ret < 0) { diff --git a/src/bin/lttng-relayd/utils.c b/src/bin/lttng-relayd/utils.c index 51fe19348..682c5dd59 100644 --- a/src/bin/lttng-relayd/utils.c +++ b/src/bin/lttng-relayd/utils.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -29,7 +30,143 @@ #include "lttng-relayd.h" #include "utils.h" -static char *create_output_path_auto(char *path_name) +#define DATETIME_STRING_SIZE 16 + +#define DATETIME_REGEX ".*-[0-9][0-9][0-9][0-9][0-1][0-9][0-3][0-9]-[0-2][0-9][0-5][0-9][0-5][0-9]$" + +static char *get_filesystem_per_session(const char *path, const char *local_session_name) { + int ret; + char *local_copy = NULL; + char *session_name = NULL; + char *datetime = NULL; + char *extra_path = NULL; + char *hostname_ptr; + const char *second_token_ptr; + char *leftover_ptr; + char *filepath_per_session = NULL; + regex_t regex; + + /* Get a local copy for strtok */ + local_copy = strdup(path); + if (!local_copy) { + ERR("strdup of local copy failed"); + goto error; + } + + /* + * The use of strtok with '/' as delimiter is valid since we refuse '/' + * in session name and '/' is not a valid hostname character based on + * RFC-952 [1], RFC-921 [2] and refined in RFC-1123 [2]. + * [1] https://tools.ietf.org/html/rfc952 + * [2] https://tools.ietf.org/html/rfc921 + * [3] https://tools.ietf.org/html/rfc1123#page-13 + */ + + /* + * Get the hostname and possible session_name. + * Note that we can get the hostname and session name from the + * relay_session object we already have. Still, it is easier to + * tokenized the passed path to obtain the start of the path leftover. + */ + hostname_ptr = strtok_r(local_copy, "/", &leftover_ptr); + if (!hostname_ptr) { + ERR("hostname token not found"); + goto error; + } + + second_token_ptr = strtok_r(NULL, "/", &leftover_ptr); + if (!second_token_ptr) { + ERR("Session name token not found"); + goto error; + } + + /* + * Check if the second token is a extra path set at url level. This is + * legal in streaming, live and snapshot [1]. Otherwise it is the + * session name with possibly a datetime attached [2]. Note that when + * "adding" snapshot output (lttng snapshot add-output), no session name + * is present in the path by default. The handling for "extra path" take + * care of this case as well. + * [1] e.g --set-url net://localhost/my_marvellous_path + * [2] Can be: + * + * When using --snapshot on session create. + * --