From 7779bc96ee56bdcb10bc91ee0631114a57229049 Mon Sep 17 00:00:00 2001 From: Julien Desfossez Date: Thu, 21 Dec 2017 14:57:49 -0500 Subject: [PATCH] Example client to use the session rotation API MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This client creates a session with all system calls enabled, offers the option to rotate periodically the session (unlimited or only a number of times), and call a script on each rotated chunk. The script provided compresses the chunk and deletes the original. Signed-off-by: Julien Desfossez Signed-off-by: Jérémie Galarneau --- .../rotation/rotate-client-compress.sh | 14 + doc/examples/rotation/rotate-client-example.c | 345 ++++++++++++++++++ 2 files changed, 359 insertions(+) create mode 100755 doc/examples/rotation/rotate-client-compress.sh create mode 100644 doc/examples/rotation/rotate-client-example.c diff --git a/doc/examples/rotation/rotate-client-compress.sh b/doc/examples/rotation/rotate-client-compress.sh new file mode 100755 index 000000000..b7e508b0d --- /dev/null +++ b/doc/examples/rotation/rotate-client-compress.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# Receive the path of a chunk of trace, compress it to a temporary directory +# and delete the chunk. + +TRACE_PATH="$1" +TRACE_NAME="$(basename "$TRACE_PATH")" +OUT_PATH="$(mktemp -d)" + +cd "$TRACE_PATH/.." + +tar czf ${OUT_PATH}/${TRACE_NAME}.tar.gz $TRACE_NAME +echo "New trace chunk archive compressed to ${OUT_PATH}/${TRACE_NAME}.tar.gz" +rm -rf "$TRACE_PATH" diff --git a/doc/examples/rotation/rotate-client-example.c b/doc/examples/rotation/rotate-client-example.c new file mode 100644 index 000000000..9dcbdfbac --- /dev/null +++ b/doc/examples/rotation/rotate-client-example.c @@ -0,0 +1,345 @@ +/* + * Session rotation example control application + * + * Copyright 2017, Julien Desfossez + * + * 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. + */ + +/* + * Compile with: + * gcc -o rotate-client rotate-client-example.c -llttng-ctl + * + * Run with the following command to rotate the session every second and + * compress the chunk, until ctrl-c: + * ./rotate-client mysession 1 -1 ./rotate-client-compress.sh + */ + +#include +#include +#include +#include +#include +#include + +#define DEFAULT_DATA_AVAILABILITY_WAIT_TIME 200000 /* usec */ + +/* Uncomment to enable debug output. */ +//#define DEBUG +#ifndef DEBUG +#define printf(fmt, ...) (0) +#endif + +static volatile int quit = 0; + +static +void sighandler(int signal) +{ + printf("Signal caught, exiting\n"); + quit = 1; +} + +static +int setup_session(const char *session_name, const char *path) +{ + int ret; + struct lttng_domain dom; + struct lttng_event ev; + struct lttng_handle *chan_handle; + + printf("Creating session %s\n", session_name); + ret = lttng_create_session(session_name, path); + if (ret) { + fprintf(stderr, "Failed to create session, ret = %d\n", ret); + goto end; + } + + dom.type = LTTNG_DOMAIN_KERNEL; + dom.buf_type = LTTNG_BUFFER_GLOBAL; + + chan_handle = lttng_create_handle(session_name, &dom); + if (chan_handle == NULL) { + ret = -1; + goto end; + } + + memset(&ev, 0, sizeof(ev)); + ev.type = LTTNG_EVENT_SYSCALL; + strcpy(ev.name, "*"); + ev.loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL; + + ret = lttng_enable_event_with_exclusions(chan_handle, &ev, "mychan", NULL, + 0, NULL); + if (ret < 0) { + fprintf(stderr, "Failed to enable events\n"); + goto end; + } + printf("Enabled all system call kernel events\n"); + + ret = lttng_start_tracing(session_name); + if (ret < 0) { + fprintf(stderr, "Failed to start tracing\n"); + goto end; + } + + lttng_destroy_handle(chan_handle); + + ret = 0; + +end: + return ret; +} + +static +int cleanup_session(const char *session_name) +{ + int ret; + + printf("Stopping session %s", session_name); + ret = lttng_stop_tracing_no_wait(session_name); + if (ret) { + fprintf(stderr, "Failed to stop tracing\n"); + goto end; + } + + fflush(stdout); + do { + ret = lttng_data_pending(session_name); + if (ret < 0) { + /* Return the data available call error. */ + goto end; + } + + /* + * Data sleep time before retrying (in usec). Don't sleep if the call + * returned value indicates availability. + */ + if (ret) { + usleep(DEFAULT_DATA_AVAILABILITY_WAIT_TIME); + printf("."); + fflush(stdout); + } + } while (ret != 0); + printf("\n"); + + printf("Destroying session %s\n", session_name); + ret = lttng_destroy_session(session_name); + if (ret) { + fprintf(stderr, "Failed to destroy the session\n"); + goto end; + } + + ret = 0; + +end: + return ret; +} + +static +int rotate_session(const char *session_name, const char *ext_program) +{ + int ret; + char *path = NULL; + struct lttng_rotation_manual_attr *attr = NULL; + struct lttng_rotation_handle *handle = NULL; + enum lttng_rotation_status rotation_status; + char cmd[PATH_MAX]; + + attr = lttng_rotation_manual_attr_create(); + if (!attr) { + fprintf(stderr, "Failed to create rotate attr\n"); + ret = -1; + goto end; + } + + ret = lttng_rotation_manual_attr_set_session_name(attr, session_name); + if (ret < 0) { + fprintf(stderr, "Failed to set rotate attr session name\n"); + goto end; + } + + printf("Rotating the output files of session %s", session_name); + + ret = lttng_rotate_session(attr, &handle); + if (ret < 0) { + fprintf(stderr, "Failed to rotate session, %s\n", lttng_strerror(ret)); + goto end; + } + + fflush(stdout); + do { + ret = lttng_rotation_is_pending(handle); + if (ret < 0) { + fprintf(stderr, "Rotate pending failed\n"); + goto end; + } + + /* + * Data sleep time before retrying (in usec). Don't sleep if the call + * returned value indicates availability. + */ + if (ret) { + usleep(DEFAULT_DATA_AVAILABILITY_WAIT_TIME); + printf("."); + fflush(stdout); + } + } while (ret == 1); + printf("\n"); + + rotation_status = lttng_rotation_handle_get_status(handle); + switch(rotation_status) { + case LTTNG_ROTATION_STATUS_COMPLETED: + lttng_rotation_handle_get_output_path(handle, &path); + printf("Output files of session %s rotated to %s\n", session_name, path); + ret = snprintf(cmd, PATH_MAX, "%s %s", ext_program, path); + if (ret < 0) { + fprintf(stderr, "Failed to prepare command string\n"); + goto end; + } + ret = system(cmd); + goto end; + case LTTNG_ROTATION_STATUS_STARTED: + /* Should not happen after a rotate_pending. */ + printf("Rotation started for session %s\n", session_name); + ret = 0; + goto end; + case LTTNG_ROTATION_STATUS_EXPIRED: + printf("Output files of session %s rotated, but handle expired", session_name); + ret = 0; + goto end; + case LTTNG_ROTATION_STATUS_ERROR: + fprintf(stderr, "An error occurred with the rotation of session %s", session_name); + ret = -1; + goto end; + } + +end: + lttng_rotation_handle_destroy(handle); + lttng_rotation_manual_attr_destroy(attr); + return ret; +} + +static +int cleanup_dir(const char *path) +{ + char cmd[PATH_MAX]; + int ret; + + ret = snprintf(cmd, PATH_MAX, "rm -rf %s", path); + if (ret < 0) { + fprintf(stderr, "Failed to prepare rm -rf command string\n"); + goto end; + } + ret = system(cmd); + +end: + return ret; +} + +void usage(const char *prog_name) +{ + fprintf(stderr, "Usage: %s \n", + prog_name); + fprintf(stderr, " : the name of the session you want to create\n"); + fprintf(stderr, " : the delay in seconds between each rotation\n"); + fprintf(stderr, " : the number of rotation you want to perform, " + "-1 for infinite until ctrl-c\n"); + fprintf(stderr, " : program to run on each chunk, it must be " + "executable, and expect a trace folder as only argument\n"); + fprintf(stderr, "\nThe trace folder is deleted when this program completes.\n"); +} + +int main(int argc, char **argv) +{ + int ret; + char tmppath[] = "/tmp/lttng-rotate-XXXXXX"; + char *session_name, *path, *ext_program; + int delay, nr; + + if (argc != 5) { + usage(argv[0]); + ret = -1; + goto end; + } + + session_name = argv[1]; + delay = atoi(argv[2]); + nr = atoi(argv[3]); + ext_program = argv[4]; + + if (delay < 0) { + fprintf(stderr, "delay-sec must be a positive values\n"); + ret = -1; + goto end; + } + + if (signal(SIGINT, sighandler) == SIG_ERR) { + perror("signal handler"); + goto end; + } + + path = mkdtemp(tmppath); + if (!path) { + fprintf(stderr, "Failed to create temporary path\n"); + } + + printf("Output directory: %s\n", path); + + ret = setup_session(session_name, path); + if (ret) { + goto end_cleanup_dir; + } + + if (nr > 0) { + unsigned int sleep_time; + int i; + + for (i = 0; i < nr; i++) { + ret = rotate_session(session_name, ext_program); + if (ret) { + goto end_cleanup; + } + sleep_time = delay; + while (sleep_time > 0) { + sleep_time = sleep(sleep_time); + } + } + } else { + for(;;) { + if (quit) { + break; + } + ret = rotate_session(session_name, ext_program); + if (ret) { + goto end_cleanup; + } + sleep(delay); + } + } + +end_cleanup: + ret = cleanup_session(session_name); + if (ret) { + goto end; + } +end_cleanup_dir: + ret = cleanup_dir(path); +end: + return ret; +} -- 2.34.1