trimmer: infer end date from begin date
[babeltrace.git] / plugins / trimmer / trimmer.c
1 /*
2 * trimmer.c
3 *
4 * Babeltrace Trace Trimmer
5 *
6 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 *
8 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
29 #include <babeltrace/plugin/plugin-macros.h>
30 #include <babeltrace/plugin/component.h>
31 #include <babeltrace/plugin/filter.h>
32 #include <babeltrace/plugin/notification/notification.h>
33 #include <babeltrace/plugin/notification/iterator.h>
34 #include <babeltrace/plugin/notification/event.h>
35 #include "trimmer.h"
36 #include "iterator.h"
37 #include <assert.h>
38
39 static
40 void destroy_trimmer_data(struct trimmer *trimmer)
41 {
42 g_free(trimmer);
43 }
44
45 static
46 struct trimmer *create_trimmer_data(void)
47 {
48 struct trimmer *trimmer;
49
50 trimmer = g_new0(struct trimmer, 1);
51 if (!trimmer) {
52 goto end;
53 }
54 end:
55 return trimmer;
56 }
57
58 static
59 void destroy_trimmer(struct bt_component *component)
60 {
61 void *data = bt_component_get_private_data(component);
62
63 destroy_trimmer_data(data);
64 }
65
66 /*
67 * Parses a timestamp, figuring out its format.
68 *
69 * Returns a negative value if anything goes wrong.
70 *
71 * Expected formats:
72 *
73 * YYYY-MM-DD hh:mm:ss.ns
74 * hh:mm:ss.ns
75 * -ss.ns
76 * ss.ns
77 * YYYY-MM-DD hh:mm:ss
78 * hh:mm:ss
79 * -ss
80 * ss
81 */
82 static
83 int timestamp_from_arg(const char *arg, struct trimmer *trimmer,
84 struct trimmer_bound *result_bound, bool gmt)
85 {
86 int ret;
87 int64_t value;
88 unsigned int year, month, day, hh, mm, ss, ns;
89
90 /* YYYY-MM-DD hh:mm:ss.ns */
91 ret = sscanf(arg, "%u-%u-%u %u:%u:%u.%u",
92 &year, &month, &day, &hh, &mm, &ss, &ns);
93 if (ret == 7) {
94 struct tm tm = {
95 .tm_sec = ss,
96 .tm_min = mm,
97 .tm_hour = hh,
98 .tm_mday = day,
99 .tm_mon = month - 1,
100 .tm_year = year - 1900,
101 .tm_isdst = -1,
102 };
103 time_t result;
104
105 if (gmt) {
106 result = timegm(&tm);
107 if (result < 0) {
108 return -1;
109 }
110 } else {
111 result = mktime(&tm);
112 if (result < 0) {
113 return -1;
114 }
115 }
116 value = (int64_t) result;
117 value *= NSEC_PER_SEC;
118 value += ns;
119 if (!trimmer->date) {
120 trimmer->year = year;
121 trimmer->month = month;
122 trimmer->day = day;
123 trimmer->date = true;
124 }
125 goto set;
126 }
127 /* hh:mm:ss.ns */
128 ret = sscanf(arg, "%u:%u:%u.%u",
129 &hh, &mm, &ss, &ns);
130 if (ret == 4) {
131 if (!trimmer->date) {
132 /* We don't know which day until we get an event. */
133 result_bound->lazy_values.hh = hh;
134 result_bound->lazy_values.mm = mm;
135 result_bound->lazy_values.ss = ss;
136 result_bound->lazy_values.ns = ns;
137 result_bound->lazy_values.gmt = gmt;
138 goto lazy;
139 } else {
140 struct tm tm = {
141 .tm_sec = ss,
142 .tm_min = mm,
143 .tm_hour = hh,
144 .tm_mday = trimmer->day,
145 .tm_mon = trimmer->month - 1,
146 .tm_year = trimmer->year - 1900,
147 .tm_isdst = -1,
148 };
149 time_t result;
150
151 if (gmt) {
152 result = timegm(&tm);
153 if (result < 0) {
154 return -1;
155 }
156 } else {
157 result = mktime(&tm);
158 if (result < 0) {
159 return -1;
160 }
161 }
162 value = (int64_t) result;
163 value *= NSEC_PER_SEC;
164 value += ns;
165 goto set;
166 }
167 }
168 /* -ss.ns */
169 ret = sscanf(arg, "-%u.%u",
170 &ss, &ns);
171 if (ret == 2) {
172 value = -ss * NSEC_PER_SEC;
173 value -= ns;
174 goto set;
175 }
176 /* ss.ns */
177 ret = sscanf(arg, "%u.%u",
178 &ss, &ns);
179 if (ret == 2) {
180 value = ss * NSEC_PER_SEC;
181 value += ns;
182 goto set;
183 }
184
185 /* YYYY-MM-DD hh:mm:ss */
186 ret = sscanf(arg, "%u-%u-%u %u:%u:%u",
187 &year, &month, &day, &hh, &mm, &ss);
188 if (ret == 6) {
189 struct tm tm = {
190 .tm_sec = ss,
191 .tm_min = mm,
192 .tm_hour = hh,
193 .tm_mday = day,
194 .tm_mon = month - 1,
195 .tm_year = year - 1900,
196 .tm_isdst = -1,
197 };
198
199 if (gmt) {
200 value = timegm(&tm);
201 if (value < 0) {
202 return -1;
203 }
204 } else {
205 value = mktime(&tm);
206 if (value < 0) {
207 return -1;
208 }
209 }
210 value *= NSEC_PER_SEC;
211 if (!trimmer->date) {
212 trimmer->year = year;
213 trimmer->month = month;
214 trimmer->day = day;
215 trimmer->date = true;
216 }
217 goto set;
218 }
219 /* hh:mm:ss */
220 ret = sscanf(arg, "%u:%u:%u",
221 &hh, &mm, &ss);
222 if (ret == 3) {
223 if (!trimmer->date) {
224 /* We don't know which day until we get an event. */
225 result_bound->lazy_values.hh = hh;
226 result_bound->lazy_values.mm = mm;
227 result_bound->lazy_values.ss = ss;
228 result_bound->lazy_values.ns = 0;
229 result_bound->lazy_values.gmt = gmt;
230 goto lazy;
231 } else {
232 struct tm tm = {
233 .tm_sec = ss,
234 .tm_min = mm,
235 .tm_hour = hh,
236 .tm_mday = trimmer->day,
237 .tm_mon = trimmer->month - 1,
238 .tm_year = trimmer->year - 1900,
239 .tm_isdst = -1,
240 };
241 time_t result;
242
243 if (gmt) {
244 result = timegm(&tm);
245 if (result < 0) {
246 return -1;
247 }
248 } else {
249 result = mktime(&tm);
250 if (result < 0) {
251 return -1;
252 }
253 }
254 value = (int64_t) result;
255 value *= NSEC_PER_SEC;
256 goto set;
257 }
258 }
259 /* -ss */
260 ret = sscanf(arg, "-%u",
261 &ss);
262 if (ret == 1) {
263 value = -ss * NSEC_PER_SEC;
264 goto set;
265 }
266 /* ss */
267 ret = sscanf(arg, "%u",
268 &ss);
269 if (ret == 1) {
270 value = ss * NSEC_PER_SEC;
271 goto set;
272 }
273
274 /* Not found. */
275 return -1;
276
277 set:
278 result_bound->value = value;
279 result_bound->set = true;
280 return 0;
281
282 lazy:
283 result_bound->lazy = true;
284 return 0;
285 }
286
287 static
288 enum bt_component_status init_from_params(struct trimmer *trimmer, struct bt_value *params)
289 {
290 struct bt_value *value = NULL;
291 bool gmt = false;
292 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
293
294 assert(params);
295
296 value = bt_value_map_get(params, "clock-gmt");
297 if (value) {
298 enum bt_value_status value_ret;
299
300 value_ret = bt_value_bool_get(value, &gmt);
301 if (value_ret) {
302 ret = BT_COMPONENT_STATUS_INVALID;
303 printf_error("Failed to retrieve clock-gmt value. Expecting a boolean.\n");
304 }
305 }
306 bt_put(value);
307 if (ret != BT_COMPONENT_STATUS_OK) {
308 goto end;
309 }
310
311 value = bt_value_map_get(params, "begin");
312 if (value) {
313 enum bt_value_status value_ret;
314 const char *str;
315
316 value_ret = bt_value_string_get(value, &str);
317 if (value_ret || timestamp_from_arg(str,
318 trimmer, &trimmer->begin, gmt)) {
319 ret = BT_COMPONENT_STATUS_INVALID;
320 printf_error("Failed to retrieve begin value. Expecting a timestamp string.\n");
321 }
322 }
323 bt_put(value);
324 if (ret != BT_COMPONENT_STATUS_OK) {
325 goto end;
326 }
327
328 value = bt_value_map_get(params, "end");
329 if (value) {
330 enum bt_value_status value_ret;
331 const char *str;
332
333 value_ret = bt_value_string_get(value, &str);
334 if (value_ret || timestamp_from_arg(str,
335 trimmer, &trimmer->end, gmt)) {
336 ret = BT_COMPONENT_STATUS_INVALID;
337 printf_error("Failed to retrieve end value. Expecting a timestamp string.\n");
338 }
339 }
340 bt_put(value);
341 end:
342 return ret;
343 }
344
345 enum bt_component_status trimmer_component_init(
346 struct bt_component *component, struct bt_value *params)
347 {
348 enum bt_component_status ret;
349 struct trimmer *trimmer = create_trimmer_data();
350
351 if (!trimmer) {
352 ret = BT_COMPONENT_STATUS_NOMEM;
353 goto end;
354 }
355
356 ret = bt_component_set_destroy_cb(component,
357 destroy_trimmer);
358 if (ret != BT_COMPONENT_STATUS_OK) {
359 goto error;
360 }
361
362 ret = bt_component_set_private_data(component, trimmer);
363 if (ret != BT_COMPONENT_STATUS_OK) {
364 goto error;
365 }
366
367 ret = bt_component_filter_set_iterator_init_cb(component,
368 trimmer_iterator_init);
369 if (ret != BT_COMPONENT_STATUS_OK) {
370 goto error;
371 }
372
373 ret = init_from_params(trimmer, params);
374 end:
375 return ret;
376 error:
377 destroy_trimmer_data(trimmer);
378 return ret;
379 }
380
381 /* Initialize plug-in entry points. */
382 BT_PLUGIN_NAME("utils");
383 BT_PLUGIN_DESCRIPTION("Babeltrace Trace Trimmer Plug-In.");
384 BT_PLUGIN_AUTHOR("Jérémie Galarneau");
385 BT_PLUGIN_LICENSE("MIT");
386
387 BT_PLUGIN_COMPONENT_CLASSES_BEGIN
388 BT_PLUGIN_FILTER_COMPONENT_CLASS_ENTRY("trimmer",
389 "Ensure that trace notifications outside of a given range are filtered-out.",
390 trimmer_component_init)
391 BT_PLUGIN_COMPONENT_CLASSES_END
This page took 0.036627 seconds and 4 git commands to generate.