Example client to use the session rotation API
[lttng-tools.git] / doc / examples / rotation / rotate-client-example.c
1 /*
2 * Session rotation example control application
3 *
4 * Copyright 2017, Julien Desfossez <jdesfossez@efficios.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25 /*
26 * Compile with:
27 * gcc -o rotate-client rotate-client-example.c -llttng-ctl
28 *
29 * Run with the following command to rotate the session every second and
30 * compress the chunk, until ctrl-c:
31 * ./rotate-client mysession 1 -1 ./rotate-client-compress.sh
32 */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <signal.h>
39 #include <lttng/lttng.h>
40
41 #define DEFAULT_DATA_AVAILABILITY_WAIT_TIME 200000 /* usec */
42
43 /* Uncomment to enable debug output. */
44 //#define DEBUG
45 #ifndef DEBUG
46 #define printf(fmt, ...) (0)
47 #endif
48
49 static volatile int quit = 0;
50
51 static
52 void sighandler(int signal)
53 {
54 printf("Signal caught, exiting\n");
55 quit = 1;
56 }
57
58 static
59 int setup_session(const char *session_name, const char *path)
60 {
61 int ret;
62 struct lttng_domain dom;
63 struct lttng_event ev;
64 struct lttng_handle *chan_handle;
65
66 printf("Creating session %s\n", session_name);
67 ret = lttng_create_session(session_name, path);
68 if (ret) {
69 fprintf(stderr, "Failed to create session, ret = %d\n", ret);
70 goto end;
71 }
72
73 dom.type = LTTNG_DOMAIN_KERNEL;
74 dom.buf_type = LTTNG_BUFFER_GLOBAL;
75
76 chan_handle = lttng_create_handle(session_name, &dom);
77 if (chan_handle == NULL) {
78 ret = -1;
79 goto end;
80 }
81
82 memset(&ev, 0, sizeof(ev));
83 ev.type = LTTNG_EVENT_SYSCALL;
84 strcpy(ev.name, "*");
85 ev.loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL;
86
87 ret = lttng_enable_event_with_exclusions(chan_handle, &ev, "mychan", NULL,
88 0, NULL);
89 if (ret < 0) {
90 fprintf(stderr, "Failed to enable events\n");
91 goto end;
92 }
93 printf("Enabled all system call kernel events\n");
94
95 ret = lttng_start_tracing(session_name);
96 if (ret < 0) {
97 fprintf(stderr, "Failed to start tracing\n");
98 goto end;
99 }
100
101 lttng_destroy_handle(chan_handle);
102
103 ret = 0;
104
105 end:
106 return ret;
107 }
108
109 static
110 int cleanup_session(const char *session_name)
111 {
112 int ret;
113
114 printf("Stopping session %s", session_name);
115 ret = lttng_stop_tracing_no_wait(session_name);
116 if (ret) {
117 fprintf(stderr, "Failed to stop tracing\n");
118 goto end;
119 }
120
121 fflush(stdout);
122 do {
123 ret = lttng_data_pending(session_name);
124 if (ret < 0) {
125 /* Return the data available call error. */
126 goto end;
127 }
128
129 /*
130 * Data sleep time before retrying (in usec). Don't sleep if the call
131 * returned value indicates availability.
132 */
133 if (ret) {
134 usleep(DEFAULT_DATA_AVAILABILITY_WAIT_TIME);
135 printf(".");
136 fflush(stdout);
137 }
138 } while (ret != 0);
139 printf("\n");
140
141 printf("Destroying session %s\n", session_name);
142 ret = lttng_destroy_session(session_name);
143 if (ret) {
144 fprintf(stderr, "Failed to destroy the session\n");
145 goto end;
146 }
147
148 ret = 0;
149
150 end:
151 return ret;
152 }
153
154 static
155 int rotate_session(const char *session_name, const char *ext_program)
156 {
157 int ret;
158 char *path = NULL;
159 struct lttng_rotation_manual_attr *attr = NULL;
160 struct lttng_rotation_handle *handle = NULL;
161 enum lttng_rotation_status rotation_status;
162 char cmd[PATH_MAX];
163
164 attr = lttng_rotation_manual_attr_create();
165 if (!attr) {
166 fprintf(stderr, "Failed to create rotate attr\n");
167 ret = -1;
168 goto end;
169 }
170
171 ret = lttng_rotation_manual_attr_set_session_name(attr, session_name);
172 if (ret < 0) {
173 fprintf(stderr, "Failed to set rotate attr session name\n");
174 goto end;
175 }
176
177 printf("Rotating the output files of session %s", session_name);
178
179 ret = lttng_rotate_session(attr, &handle);
180 if (ret < 0) {
181 fprintf(stderr, "Failed to rotate session, %s\n", lttng_strerror(ret));
182 goto end;
183 }
184
185 fflush(stdout);
186 do {
187 ret = lttng_rotation_is_pending(handle);
188 if (ret < 0) {
189 fprintf(stderr, "Rotate pending failed\n");
190 goto end;
191 }
192
193 /*
194 * Data sleep time before retrying (in usec). Don't sleep if the call
195 * returned value indicates availability.
196 */
197 if (ret) {
198 usleep(DEFAULT_DATA_AVAILABILITY_WAIT_TIME);
199 printf(".");
200 fflush(stdout);
201 }
202 } while (ret == 1);
203 printf("\n");
204
205 rotation_status = lttng_rotation_handle_get_status(handle);
206 switch(rotation_status) {
207 case LTTNG_ROTATION_STATUS_COMPLETED:
208 lttng_rotation_handle_get_output_path(handle, &path);
209 printf("Output files of session %s rotated to %s\n", session_name, path);
210 ret = snprintf(cmd, PATH_MAX, "%s %s", ext_program, path);
211 if (ret < 0) {
212 fprintf(stderr, "Failed to prepare command string\n");
213 goto end;
214 }
215 ret = system(cmd);
216 goto end;
217 case LTTNG_ROTATION_STATUS_STARTED:
218 /* Should not happen after a rotate_pending. */
219 printf("Rotation started for session %s\n", session_name);
220 ret = 0;
221 goto end;
222 case LTTNG_ROTATION_STATUS_EXPIRED:
223 printf("Output files of session %s rotated, but handle expired", session_name);
224 ret = 0;
225 goto end;
226 case LTTNG_ROTATION_STATUS_ERROR:
227 fprintf(stderr, "An error occurred with the rotation of session %s", session_name);
228 ret = -1;
229 goto end;
230 }
231
232 end:
233 lttng_rotation_handle_destroy(handle);
234 lttng_rotation_manual_attr_destroy(attr);
235 return ret;
236 }
237
238 static
239 int cleanup_dir(const char *path)
240 {
241 char cmd[PATH_MAX];
242 int ret;
243
244 ret = snprintf(cmd, PATH_MAX, "rm -rf %s", path);
245 if (ret < 0) {
246 fprintf(stderr, "Failed to prepare rm -rf command string\n");
247 goto end;
248 }
249 ret = system(cmd);
250
251 end:
252 return ret;
253 }
254
255 void usage(const char *prog_name)
256 {
257 fprintf(stderr, "Usage: %s <session-name> <delay-sec> <nr-rotate> <program>\n",
258 prog_name);
259 fprintf(stderr, " <session-name>: the name of the session you want to create\n");
260 fprintf(stderr, " <delay-sec>: the delay in seconds between each rotation\n");
261 fprintf(stderr, " <nr-rotate>: the number of rotation you want to perform, "
262 "-1 for infinite until ctrl-c\n");
263 fprintf(stderr, " <program>: program to run on each chunk, it must be "
264 "executable, and expect a trace folder as only argument\n");
265 fprintf(stderr, "\nThe trace folder is deleted when this program completes.\n");
266 }
267
268 int main(int argc, char **argv)
269 {
270 int ret;
271 char tmppath[] = "/tmp/lttng-rotate-XXXXXX";
272 char *session_name, *path, *ext_program;
273 int delay, nr;
274
275 if (argc != 5) {
276 usage(argv[0]);
277 ret = -1;
278 goto end;
279 }
280
281 session_name = argv[1];
282 delay = atoi(argv[2]);
283 nr = atoi(argv[3]);
284 ext_program = argv[4];
285
286 if (delay < 0) {
287 fprintf(stderr, "delay-sec must be a positive values\n");
288 ret = -1;
289 goto end;
290 }
291
292 if (signal(SIGINT, sighandler) == SIG_ERR) {
293 perror("signal handler");
294 goto end;
295 }
296
297 path = mkdtemp(tmppath);
298 if (!path) {
299 fprintf(stderr, "Failed to create temporary path\n");
300 }
301
302 printf("Output directory: %s\n", path);
303
304 ret = setup_session(session_name, path);
305 if (ret) {
306 goto end_cleanup_dir;
307 }
308
309 if (nr > 0) {
310 unsigned int sleep_time;
311 int i;
312
313 for (i = 0; i < nr; i++) {
314 ret = rotate_session(session_name, ext_program);
315 if (ret) {
316 goto end_cleanup;
317 }
318 sleep_time = delay;
319 while (sleep_time > 0) {
320 sleep_time = sleep(sleep_time);
321 }
322 }
323 } else {
324 for(;;) {
325 if (quit) {
326 break;
327 }
328 ret = rotate_session(session_name, ext_program);
329 if (ret) {
330 goto end_cleanup;
331 }
332 sleep(delay);
333 }
334 }
335
336 end_cleanup:
337 ret = cleanup_session(session_name);
338 if (ret) {
339 goto end;
340 }
341 end_cleanup_dir:
342 ret = cleanup_dir(path);
343 end:
344 return ret;
345 }
This page took 0.038169 seconds and 5 git commands to generate.