Set notification iterator methods to the component class
[babeltrace.git] / plugins / trimmer / trimmer.c
CommitLineData
cab3f160
JG
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
33b34c43
PP
29#include <babeltrace/plugin/plugin-dev.h>
30#include <babeltrace/component/component.h>
d71dcf2c 31#include <babeltrace/component/component-filter.h>
33b34c43
PP
32#include <babeltrace/component/notification/notification.h>
33#include <babeltrace/component/notification/iterator.h>
34#include <babeltrace/component/notification/event.h>
7d61fa8e 35#include <plugins-common.h>
cab3f160
JG
36#include "trimmer.h"
37#include "iterator.h"
44d3cbf0 38#include <assert.h>
cab3f160
JG
39
40static
41void destroy_trimmer_data(struct trimmer *trimmer)
42{
43 g_free(trimmer);
44}
45
46static
47struct trimmer *create_trimmer_data(void)
48{
49 struct trimmer *trimmer;
50
51 trimmer = g_new0(struct trimmer, 1);
52 if (!trimmer) {
53 goto end;
54 }
55end:
56 return trimmer;
57}
58
59static
60void destroy_trimmer(struct bt_component *component)
61{
62 void *data = bt_component_get_private_data(component);
63
64 destroy_trimmer_data(data);
65}
66
528debdf
MD
67/*
68 * Parses a timestamp, figuring out its format.
69 *
70 * Returns a negative value if anything goes wrong.
71 *
72 * Expected formats:
73 *
74 * YYYY-MM-DD hh:mm:ss.ns
75 * hh:mm:ss.ns
76 * -ss.ns
77 * ss.ns
78 * YYYY-MM-DD hh:mm:ss
79 * hh:mm:ss
80 * -ss
81 * ss
82 */
44d3cbf0 83static
c6dedfd4 84int timestamp_from_arg(const char *arg, struct trimmer *trimmer,
528debdf
MD
85 struct trimmer_bound *result_bound, bool gmt)
86{
87 int ret;
88 int64_t value;
89 unsigned int year, month, day, hh, mm, ss, ns;
90
91 /* YYYY-MM-DD hh:mm:ss.ns */
92 ret = sscanf(arg, "%u-%u-%u %u:%u:%u.%u",
93 &year, &month, &day, &hh, &mm, &ss, &ns);
94 if (ret == 7) {
95 struct tm tm = {
96 .tm_sec = ss,
97 .tm_min = mm,
98 .tm_hour = hh,
99 .tm_mday = day,
100 .tm_mon = month - 1,
101 .tm_year = year - 1900,
102 .tm_isdst = -1,
103 };
104 time_t result;
105
106 if (gmt) {
107 result = timegm(&tm);
108 if (result < 0) {
109 return -1;
110 }
111 } else {
112 result = mktime(&tm);
113 if (result < 0) {
114 return -1;
115 }
116 }
117 value = (int64_t) result;
118 value *= NSEC_PER_SEC;
119 value += ns;
c6dedfd4
MD
120 if (!trimmer->date) {
121 trimmer->year = year;
122 trimmer->month = month;
123 trimmer->day = day;
124 trimmer->date = true;
125 }
528debdf
MD
126 goto set;
127 }
128 /* hh:mm:ss.ns */
129 ret = sscanf(arg, "%u:%u:%u.%u",
130 &hh, &mm, &ss, &ns);
131 if (ret == 4) {
c6dedfd4
MD
132 if (!trimmer->date) {
133 /* We don't know which day until we get an event. */
134 result_bound->lazy_values.hh = hh;
135 result_bound->lazy_values.mm = mm;
136 result_bound->lazy_values.ss = ss;
137 result_bound->lazy_values.ns = ns;
138 result_bound->lazy_values.gmt = gmt;
139 goto lazy;
140 } else {
141 struct tm tm = {
142 .tm_sec = ss,
143 .tm_min = mm,
144 .tm_hour = hh,
145 .tm_mday = trimmer->day,
146 .tm_mon = trimmer->month - 1,
147 .tm_year = trimmer->year - 1900,
148 .tm_isdst = -1,
149 };
150 time_t result;
151
152 if (gmt) {
153 result = timegm(&tm);
154 if (result < 0) {
155 return -1;
156 }
157 } else {
158 result = mktime(&tm);
159 if (result < 0) {
160 return -1;
161 }
162 }
163 value = (int64_t) result;
164 value *= NSEC_PER_SEC;
165 value += ns;
166 goto set;
167 }
528debdf
MD
168 }
169 /* -ss.ns */
170 ret = sscanf(arg, "-%u.%u",
171 &ss, &ns);
172 if (ret == 2) {
173 value = -ss * NSEC_PER_SEC;
174 value -= ns;
175 goto set;
176 }
177 /* ss.ns */
178 ret = sscanf(arg, "%u.%u",
179 &ss, &ns);
180 if (ret == 2) {
181 value = ss * NSEC_PER_SEC;
182 value += ns;
183 goto set;
184 }
185
186 /* YYYY-MM-DD hh:mm:ss */
187 ret = sscanf(arg, "%u-%u-%u %u:%u:%u",
188 &year, &month, &day, &hh, &mm, &ss);
189 if (ret == 6) {
190 struct tm tm = {
191 .tm_sec = ss,
192 .tm_min = mm,
193 .tm_hour = hh,
194 .tm_mday = day,
195 .tm_mon = month - 1,
196 .tm_year = year - 1900,
197 .tm_isdst = -1,
198 };
199
200 if (gmt) {
201 value = timegm(&tm);
202 if (value < 0) {
203 return -1;
204 }
205 } else {
206 value = mktime(&tm);
207 if (value < 0) {
208 return -1;
209 }
210 }
211 value *= NSEC_PER_SEC;
c6dedfd4
MD
212 if (!trimmer->date) {
213 trimmer->year = year;
214 trimmer->month = month;
215 trimmer->day = day;
216 trimmer->date = true;
217 }
528debdf
MD
218 goto set;
219 }
220 /* hh:mm:ss */
221 ret = sscanf(arg, "%u:%u:%u",
222 &hh, &mm, &ss);
223 if (ret == 3) {
c6dedfd4
MD
224 if (!trimmer->date) {
225 /* We don't know which day until we get an event. */
226 result_bound->lazy_values.hh = hh;
227 result_bound->lazy_values.mm = mm;
228 result_bound->lazy_values.ss = ss;
229 result_bound->lazy_values.ns = 0;
230 result_bound->lazy_values.gmt = gmt;
231 goto lazy;
232 } else {
233 struct tm tm = {
234 .tm_sec = ss,
235 .tm_min = mm,
236 .tm_hour = hh,
237 .tm_mday = trimmer->day,
238 .tm_mon = trimmer->month - 1,
239 .tm_year = trimmer->year - 1900,
240 .tm_isdst = -1,
241 };
242 time_t result;
243
244 if (gmt) {
245 result = timegm(&tm);
246 if (result < 0) {
247 return -1;
248 }
249 } else {
250 result = mktime(&tm);
251 if (result < 0) {
252 return -1;
253 }
254 }
255 value = (int64_t) result;
256 value *= NSEC_PER_SEC;
257 goto set;
258 }
528debdf
MD
259 }
260 /* -ss */
261 ret = sscanf(arg, "-%u",
262 &ss);
263 if (ret == 1) {
264 value = -ss * NSEC_PER_SEC;
265 goto set;
266 }
267 /* ss */
268 ret = sscanf(arg, "%u",
269 &ss);
270 if (ret == 1) {
271 value = ss * NSEC_PER_SEC;
272 goto set;
273 }
274
275 /* Not found. */
276 return -1;
277
278set:
279 result_bound->value = value;
280 result_bound->set = true;
281 return 0;
282
283lazy:
284 result_bound->lazy = true;
285 return 0;
286}
287
288static
289enum bt_component_status init_from_params(struct trimmer *trimmer, struct bt_value *params)
44d3cbf0
JG
290{
291 struct bt_value *value = NULL;
528debdf
MD
292 bool gmt = false;
293 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
44d3cbf0
JG
294
295 assert(params);
296
528debdf
MD
297 value = bt_value_map_get(params, "clock-gmt");
298 if (value) {
44d3cbf0
JG
299 enum bt_value_status value_ret;
300
528debdf
MD
301 value_ret = bt_value_bool_get(value, &gmt);
302 if (value_ret) {
303 ret = BT_COMPONENT_STATUS_INVALID;
55595636 304 printf_error("Failed to retrieve clock-gmt value. Expecting a boolean");
44d3cbf0
JG
305 }
306 }
307 bt_put(value);
528debdf
MD
308 if (ret != BT_COMPONENT_STATUS_OK) {
309 goto end;
310 }
311
312 value = bt_value_map_get(params, "begin");
313 if (value) {
44d3cbf0 314 enum bt_value_status value_ret;
528debdf 315 const char *str;
44d3cbf0 316
528debdf
MD
317 value_ret = bt_value_string_get(value, &str);
318 if (value_ret || timestamp_from_arg(str,
c6dedfd4 319 trimmer, &trimmer->begin, gmt)) {
528debdf 320 ret = BT_COMPONENT_STATUS_INVALID;
55595636 321 printf_error("Failed to retrieve begin value. Expecting a timestamp string");
44d3cbf0
JG
322 }
323 }
324 bt_put(value);
528debdf
MD
325 if (ret != BT_COMPONENT_STATUS_OK) {
326 goto end;
327 }
328
329 value = bt_value_map_get(params, "end");
330 if (value) {
331 enum bt_value_status value_ret;
332 const char *str;
333
334 value_ret = bt_value_string_get(value, &str);
335 if (value_ret || timestamp_from_arg(str,
c6dedfd4 336 trimmer, &trimmer->end, gmt)) {
528debdf 337 ret = BT_COMPONENT_STATUS_INVALID;
55595636 338 printf_error("Failed to retrieve end value. Expecting a timestamp string");
528debdf
MD
339 }
340 }
341 bt_put(value);
342end:
55595636
MD
343 if (trimmer->begin.set && trimmer->end.set) {
344 if (trimmer->begin.value > trimmer->end.value) {
345 printf_error("Unexpected: time range begin value is above end value");
346 ret = BT_COMPONENT_STATUS_INVALID;
347 }
348 }
528debdf 349 return ret;
44d3cbf0
JG
350}
351
cab3f160 352enum bt_component_status trimmer_component_init(
6358c163 353 struct bt_component *component, struct bt_value *params,
7d61fa8e 354 UNUSED_VAR void *init_method_data)
cab3f160
JG
355{
356 enum bt_component_status ret;
357 struct trimmer *trimmer = create_trimmer_data();
358
359 if (!trimmer) {
360 ret = BT_COMPONENT_STATUS_NOMEM;
361 goto end;
362 }
363
cab3f160
JG
364 ret = bt_component_set_private_data(component, trimmer);
365 if (ret != BT_COMPONENT_STATUS_OK) {
366 goto error;
367 }
368
528debdf 369 ret = init_from_params(trimmer, params);
cab3f160
JG
370end:
371 return ret;
372error:
373 destroy_trimmer_data(trimmer);
374 return ret;
375}
376
377/* Initialize plug-in entry points. */
6ba0b073 378BT_PLUGIN(utils);
cab3f160
JG
379BT_PLUGIN_DESCRIPTION("Babeltrace Trace Trimmer Plug-In.");
380BT_PLUGIN_AUTHOR("Jérémie Galarneau");
381BT_PLUGIN_LICENSE("MIT");
d3eb6e8f
PP
382BT_PLUGIN_FILTER_COMPONENT_CLASS(trimmer, trimmer_iterator_get,
383 trimmer_iterator_next);
d3e4dcd8 384BT_PLUGIN_FILTER_COMPONENT_CLASS_DESCRIPTION(trimmer,
6ba0b073 385 "Ensure that trace notifications outside of a given range are filtered-out.");
d3e4dcd8
PP
386BT_PLUGIN_FILTER_COMPONENT_CLASS_INIT_METHOD(trimmer, trimmer_component_init);
387BT_PLUGIN_FILTER_COMPONENT_CLASS_DESTROY_METHOD(trimmer, destroy_trimmer);
d3eb6e8f
PP
388BT_PLUGIN_FILTER_COMPONENT_CLASS_NOTIFICATION_ITERATOR_INIT_METHOD(trimmer,
389 trimmer_iterator_init);
390BT_PLUGIN_FILTER_COMPONENT_CLASS_NOTIFICATION_ITERATOR_DESTROY_METHOD(trimmer,
391 trimmer_iterator_destroy);
392BT_PLUGIN_FILTER_COMPONENT_CLASS_NOTIFICATION_ITERATOR_SEEK_TIME_METHOD(trimmer,
393 trimmer_iterator_seek_time);
This page took 0.039096 seconds and 4 git commands to generate.