Fix: rotation client example: leak of handle on error
[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 = NULL;
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 (ret = %i)\n", ret);
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 ret = 0;
102
103 end:
104 lttng_destroy_handle(chan_handle);
105 return ret;
106 }
107
108 static
109 int cleanup_session(const char *session_name)
110 {
111 int ret;
112
113 printf("Stopping session %s", session_name);
114 ret = lttng_stop_tracing_no_wait(session_name);
115 if (ret) {
116 fprintf(stderr, "Failed to stop tracing\n");
117 goto end;
118 }
119
120 fflush(stdout);
121 do {
122 ret = lttng_data_pending(session_name);
123 if (ret < 0) {
124 /* Return the data available call error. */
125 goto end;
126 }
127
128 /*
129 * Data sleep time before retrying (in usec). Don't sleep if the call
130 * returned value indicates availability.
131 */
132 if (ret) {
133 usleep(DEFAULT_DATA_AVAILABILITY_WAIT_TIME);
134 printf(".");
135 fflush(stdout);
136 }
137 } while (ret != 0);
138 printf("\n");
139
140 printf("Destroying session %s\n", session_name);
141 ret = lttng_destroy_session(session_name);
142 if (ret) {
143 fprintf(stderr, "Failed to destroy the session\n");
144 goto end;
145 }
146
147 ret = 0;
148
149 end:
150 return ret;
151 }
152
153 static
154 int rotate_session(const char *session_name, const char *ext_program)
155 {
156 int ret;
157 struct lttng_rotation_handle *handle = NULL;
158 enum lttng_rotation_status rotation_status;
159 enum lttng_rotation_state rotation_state = LTTNG_ROTATION_STATE_ONGOING;
160 char cmd[PATH_MAX];
161
162 printf("Rotating the output files of session %s", session_name);
163
164 ret = lttng_rotate_session(session_name, NULL, &handle);
165 if (ret < 0) {
166 fprintf(stderr, "Failed to rotate session, %s\n", lttng_strerror(ret));
167 goto end;
168 }
169
170 fflush(stdout);
171
172 do {
173 rotation_status = lttng_rotation_handle_get_state(handle,
174 &rotation_state);
175 if (rotation_status != LTTNG_ROTATION_STATUS_OK) {
176 ret = -1;
177 fprintf(stderr, "Failed to get the current rotation's state\n");
178 goto end;
179 }
180
181 /*
182 * Data sleep time before retrying (in usec). Don't
183 * sleep if the call returned value indicates
184 * availability.
185 */
186 if (rotation_state == LTTNG_ROTATION_STATE_ONGOING) {
187 usleep(DEFAULT_DATA_AVAILABILITY_WAIT_TIME);
188 printf(".");
189 fflush(stdout);
190 }
191 } while (rotation_state == LTTNG_ROTATION_STATE_ONGOING);
192 printf("\n");
193
194 switch (rotation_state) {
195 case LTTNG_ROTATION_STATE_COMPLETED:
196 {
197 const struct lttng_trace_archive_location *location;
198 const char *absolute_path;
199 enum lttng_trace_archive_location_status location_status;
200
201 rotation_status = lttng_rotation_handle_get_archive_location(
202 handle, &location);
203 if (rotation_status != LTTNG_ROTATION_STATUS_OK) {
204 fprintf(stderr, "Failed to retrieve the rotation's completed chunk archive location\n");
205 ret = -1;
206 goto end;
207 }
208
209 location_status = lttng_trace_archive_location_local_get_absolute_path(
210 location, &absolute_path);
211 if (location_status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
212 fprintf(stderr, "Failed to get absolute path of completed chunk archive");
213 ret = -1;
214 goto end;
215 }
216
217 printf("Output files of session %s rotated to %s\n",
218 session_name, absolute_path);
219 ret = snprintf(cmd, PATH_MAX, "%s %s", ext_program, absolute_path);
220 if (ret < 0) {
221 fprintf(stderr, "Failed to prepare command string\n");
222 goto end;
223 }
224 ret = system(cmd);
225 goto end;
226 }
227 case LTTNG_ROTATION_STATE_EXPIRED:
228 printf("Output files of session %s rotated, but the handle expired\n", session_name);
229 ret = 0;
230 goto end;
231 case LTTNG_ROTATION_STATE_ERROR:
232 fprintf(stderr, "An error occurred with the rotation of session %s\n", session_name);
233 ret = -1;
234 goto end;
235 }
236
237 end:
238 lttng_rotation_handle_destroy(handle);
239 return ret;
240 }
241
242 static
243 int cleanup_dir(const char *path)
244 {
245 char cmd[PATH_MAX];
246 int ret;
247
248 ret = snprintf(cmd, PATH_MAX, "rm -rf %s", path);
249 if (ret < 0) {
250 fprintf(stderr, "Failed to prepare rm -rf command string\n");
251 goto end;
252 }
253 ret = system(cmd);
254
255 end:
256 return ret;
257 }
258
259 void usage(const char *prog_name)
260 {
261 fprintf(stderr, "Usage: %s <session-name> <delay-sec> <nr-rotate> <program>\n",
262 prog_name);
263 fprintf(stderr, " <session-name>: the name of the session you want to create\n");
264 fprintf(stderr, " <delay-sec>: the delay in seconds between each rotation\n");
265 fprintf(stderr, " <nr-rotate>: the number of rotation you want to perform, "
266 "-1 for infinite until ctrl-c\n");
267 fprintf(stderr, " <program>: program to run on each chunk, it must be "
268 "executable, and expect a trace folder as only argument\n");
269 fprintf(stderr, "\nThe trace folder is deleted when this program completes.\n");
270 }
271
272 int main(int argc, char **argv)
273 {
274 int ret;
275 char tmppath[] = "/tmp/lttng-rotate-XXXXXX";
276 char *session_name, *path, *ext_program;
277 int delay, nr;
278
279 if (argc != 5) {
280 usage(argv[0]);
281 ret = -1;
282 goto end;
283 }
284
285 session_name = argv[1];
286 delay = atoi(argv[2]);
287 nr = atoi(argv[3]);
288 ext_program = argv[4];
289
290 if (delay < 0) {
291 fprintf(stderr, "delay-sec must be a positive values\n");
292 ret = -1;
293 goto end;
294 }
295
296 if (signal(SIGINT, sighandler) == SIG_ERR) {
297 perror("signal handler");
298 goto end;
299 }
300
301 path = mkdtemp(tmppath);
302 if (!path) {
303 fprintf(stderr, "Failed to create temporary path\n");
304 }
305
306 printf("Output directory: %s\n", path);
307
308 ret = setup_session(session_name, path);
309 if (ret) {
310 goto end_cleanup_dir;
311 }
312
313 if (nr > 0) {
314 unsigned int sleep_time;
315 int i;
316
317 for (i = 0; i < nr; i++) {
318 ret = rotate_session(session_name, ext_program);
319 if (ret) {
320 goto end_cleanup;
321 }
322 sleep_time = delay;
323 while (sleep_time > 0) {
324 sleep_time = sleep(sleep_time);
325 }
326 }
327 } else {
328 for(;;) {
329 if (quit) {
330 break;
331 }
332 ret = rotate_session(session_name, ext_program);
333 if (ret) {
334 goto end_cleanup;
335 }
336 sleep(delay);
337 }
338 }
339
340 end_cleanup:
341 ret = cleanup_session(session_name);
342 if (ret) {
343 goto end;
344 }
345 end_cleanup_dir:
346 ret = cleanup_dir(path);
347 end:
348 return ret;
349 }
This page took 0.036876 seconds and 5 git commands to generate.