Support standard timestamp formats for begin/end
[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,
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 goto set;
120 }
121 /* hh:mm:ss.ns */
122 ret = sscanf(arg, "%u:%u:%u.%u",
123 &hh, &mm, &ss, &ns);
124 if (ret == 4) {
125 /* We don't know which day until we get an event. */
126 result_bound->lazy_values.hh = hh;
127 result_bound->lazy_values.mm = mm;
128 result_bound->lazy_values.ss = ss;
129 result_bound->lazy_values.ns = ns;
130 result_bound->lazy_values.gmt = gmt;
131 goto lazy;
132 }
133 /* -ss.ns */
134 ret = sscanf(arg, "-%u.%u",
135 &ss, &ns);
136 if (ret == 2) {
137 value = -ss * NSEC_PER_SEC;
138 value -= ns;
139 goto set;
140 }
141 /* ss.ns */
142 ret = sscanf(arg, "%u.%u",
143 &ss, &ns);
144 if (ret == 2) {
145 value = ss * NSEC_PER_SEC;
146 value += ns;
147 goto set;
148 }
149
150 /* YYYY-MM-DD hh:mm:ss */
151 ret = sscanf(arg, "%u-%u-%u %u:%u:%u",
152 &year, &month, &day, &hh, &mm, &ss);
153 if (ret == 6) {
154 struct tm tm = {
155 .tm_sec = ss,
156 .tm_min = mm,
157 .tm_hour = hh,
158 .tm_mday = day,
159 .tm_mon = month - 1,
160 .tm_year = year - 1900,
161 .tm_isdst = -1,
162 };
163
164 if (gmt) {
165 value = timegm(&tm);
166 if (value < 0) {
167 return -1;
168 }
169 } else {
170 value = mktime(&tm);
171 if (value < 0) {
172 return -1;
173 }
174 }
175 value *= NSEC_PER_SEC;
176 goto set;
177 }
178 /* hh:mm:ss */
179 ret = sscanf(arg, "%u:%u:%u",
180 &hh, &mm, &ss);
181 if (ret == 3) {
182 /* We don't know which day until we get an event. */
183 result_bound->lazy_values.hh = hh;
184 result_bound->lazy_values.mm = mm;
185 result_bound->lazy_values.ss = ss;
186 result_bound->lazy_values.ns = 0;
187 result_bound->lazy_values.gmt = gmt;
188 goto lazy;
189 }
190 /* -ss */
191 ret = sscanf(arg, "-%u",
192 &ss);
193 if (ret == 1) {
194 value = -ss * NSEC_PER_SEC;
195 goto set;
196 }
197 /* ss */
198 ret = sscanf(arg, "%u",
199 &ss);
200 if (ret == 1) {
201 value = ss * NSEC_PER_SEC;
202 goto set;
203 }
204
205 /* Not found. */
206 return -1;
207
208 set:
209 result_bound->value = value;
210 result_bound->set = true;
211 return 0;
212
213 lazy:
214 result_bound->lazy = true;
215 return 0;
216 }
217
218 static
219 enum bt_component_status init_from_params(struct trimmer *trimmer, struct bt_value *params)
220 {
221 struct bt_value *value = NULL;
222 bool gmt = false;
223 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
224
225 assert(params);
226
227 value = bt_value_map_get(params, "clock-gmt");
228 if (value) {
229 enum bt_value_status value_ret;
230
231 value_ret = bt_value_bool_get(value, &gmt);
232 if (value_ret) {
233 ret = BT_COMPONENT_STATUS_INVALID;
234 printf_error("Failed to retrieve clock-gmt value. Expecting a boolean.\n");
235 }
236 }
237 bt_put(value);
238 if (ret != BT_COMPONENT_STATUS_OK) {
239 goto end;
240 }
241
242 value = bt_value_map_get(params, "begin");
243 if (value) {
244 enum bt_value_status value_ret;
245 const char *str;
246
247 value_ret = bt_value_string_get(value, &str);
248 if (value_ret || timestamp_from_arg(str,
249 &trimmer->begin, gmt)) {
250 ret = BT_COMPONENT_STATUS_INVALID;
251 printf_error("Failed to retrieve begin value. Expecting a timestamp string.\n");
252 }
253 }
254 bt_put(value);
255 if (ret != BT_COMPONENT_STATUS_OK) {
256 goto end;
257 }
258
259 value = bt_value_map_get(params, "end");
260 if (value) {
261 enum bt_value_status value_ret;
262 const char *str;
263
264 value_ret = bt_value_string_get(value, &str);
265 if (value_ret || timestamp_from_arg(str,
266 &trimmer->end, gmt)) {
267 ret = BT_COMPONENT_STATUS_INVALID;
268 printf_error("Failed to retrieve end value. Expecting a timestamp string.\n");
269 }
270 }
271 bt_put(value);
272 end:
273 return ret;
274 }
275
276 enum bt_component_status trimmer_component_init(
277 struct bt_component *component, struct bt_value *params)
278 {
279 enum bt_component_status ret;
280 struct trimmer *trimmer = create_trimmer_data();
281
282 if (!trimmer) {
283 ret = BT_COMPONENT_STATUS_NOMEM;
284 goto end;
285 }
286
287 ret = bt_component_set_destroy_cb(component,
288 destroy_trimmer);
289 if (ret != BT_COMPONENT_STATUS_OK) {
290 goto error;
291 }
292
293 ret = bt_component_set_private_data(component, trimmer);
294 if (ret != BT_COMPONENT_STATUS_OK) {
295 goto error;
296 }
297
298 ret = bt_component_filter_set_iterator_init_cb(component,
299 trimmer_iterator_init);
300 if (ret != BT_COMPONENT_STATUS_OK) {
301 goto error;
302 }
303
304 ret = init_from_params(trimmer, params);
305 end:
306 return ret;
307 error:
308 destroy_trimmer_data(trimmer);
309 return ret;
310 }
311
312 /* Initialize plug-in entry points. */
313 BT_PLUGIN_NAME("utils");
314 BT_PLUGIN_DESCRIPTION("Babeltrace Trace Trimmer Plug-In.");
315 BT_PLUGIN_AUTHOR("Jérémie Galarneau");
316 BT_PLUGIN_LICENSE("MIT");
317
318 BT_PLUGIN_COMPONENT_CLASSES_BEGIN
319 BT_PLUGIN_FILTER_COMPONENT_CLASS_ENTRY("trimmer",
320 "Ensure that trace notifications outside of a given range are filtered-out.",
321 trimmer_component_init)
322 BT_PLUGIN_COMPONENT_CLASSES_END
This page took 0.034689 seconds and 4 git commands to generate.