* SOFTWARE.
*/
-#include <babeltrace/plugin/plugin-macros.h>
-#include <babeltrace/plugin/component.h>
-#include <babeltrace/plugin/filter.h>
-#include <babeltrace/plugin/notification/notification.h>
-#include <babeltrace/plugin/notification/iterator.h>
-#include <babeltrace/plugin/notification/event.h>
+#include <babeltrace/plugin/plugin-dev.h>
+#include <babeltrace/component/component.h>
+#include <babeltrace/component/filter.h>
+#include <babeltrace/component/notification/notification.h>
+#include <babeltrace/component/notification/iterator.h>
+#include <babeltrace/component/notification/event.h>
#include "trimmer.h"
#include "iterator.h"
#include <assert.h>
destroy_trimmer_data(data);
}
+/*
+ * Parses a timestamp, figuring out its format.
+ *
+ * Returns a negative value if anything goes wrong.
+ *
+ * Expected formats:
+ *
+ * YYYY-MM-DD hh:mm:ss.ns
+ * hh:mm:ss.ns
+ * -ss.ns
+ * ss.ns
+ * YYYY-MM-DD hh:mm:ss
+ * hh:mm:ss
+ * -ss
+ * ss
+ */
+static
+int timestamp_from_arg(const char *arg, struct trimmer *trimmer,
+ struct trimmer_bound *result_bound, bool gmt)
+{
+ int ret;
+ int64_t value;
+ unsigned int year, month, day, hh, mm, ss, ns;
+
+ /* YYYY-MM-DD hh:mm:ss.ns */
+ ret = sscanf(arg, "%u-%u-%u %u:%u:%u.%u",
+ &year, &month, &day, &hh, &mm, &ss, &ns);
+ if (ret == 7) {
+ struct tm tm = {
+ .tm_sec = ss,
+ .tm_min = mm,
+ .tm_hour = hh,
+ .tm_mday = day,
+ .tm_mon = month - 1,
+ .tm_year = year - 1900,
+ .tm_isdst = -1,
+ };
+ time_t result;
+
+ if (gmt) {
+ result = timegm(&tm);
+ if (result < 0) {
+ return -1;
+ }
+ } else {
+ result = mktime(&tm);
+ if (result < 0) {
+ return -1;
+ }
+ }
+ value = (int64_t) result;
+ value *= NSEC_PER_SEC;
+ value += ns;
+ if (!trimmer->date) {
+ trimmer->year = year;
+ trimmer->month = month;
+ trimmer->day = day;
+ trimmer->date = true;
+ }
+ goto set;
+ }
+ /* hh:mm:ss.ns */
+ ret = sscanf(arg, "%u:%u:%u.%u",
+ &hh, &mm, &ss, &ns);
+ if (ret == 4) {
+ if (!trimmer->date) {
+ /* We don't know which day until we get an event. */
+ result_bound->lazy_values.hh = hh;
+ result_bound->lazy_values.mm = mm;
+ result_bound->lazy_values.ss = ss;
+ result_bound->lazy_values.ns = ns;
+ result_bound->lazy_values.gmt = gmt;
+ goto lazy;
+ } else {
+ struct tm tm = {
+ .tm_sec = ss,
+ .tm_min = mm,
+ .tm_hour = hh,
+ .tm_mday = trimmer->day,
+ .tm_mon = trimmer->month - 1,
+ .tm_year = trimmer->year - 1900,
+ .tm_isdst = -1,
+ };
+ time_t result;
+
+ if (gmt) {
+ result = timegm(&tm);
+ if (result < 0) {
+ return -1;
+ }
+ } else {
+ result = mktime(&tm);
+ if (result < 0) {
+ return -1;
+ }
+ }
+ value = (int64_t) result;
+ value *= NSEC_PER_SEC;
+ value += ns;
+ goto set;
+ }
+ }
+ /* -ss.ns */
+ ret = sscanf(arg, "-%u.%u",
+ &ss, &ns);
+ if (ret == 2) {
+ value = -ss * NSEC_PER_SEC;
+ value -= ns;
+ goto set;
+ }
+ /* ss.ns */
+ ret = sscanf(arg, "%u.%u",
+ &ss, &ns);
+ if (ret == 2) {
+ value = ss * NSEC_PER_SEC;
+ value += ns;
+ goto set;
+ }
+
+ /* YYYY-MM-DD hh:mm:ss */
+ ret = sscanf(arg, "%u-%u-%u %u:%u:%u",
+ &year, &month, &day, &hh, &mm, &ss);
+ if (ret == 6) {
+ struct tm tm = {
+ .tm_sec = ss,
+ .tm_min = mm,
+ .tm_hour = hh,
+ .tm_mday = day,
+ .tm_mon = month - 1,
+ .tm_year = year - 1900,
+ .tm_isdst = -1,
+ };
+
+ if (gmt) {
+ value = timegm(&tm);
+ if (value < 0) {
+ return -1;
+ }
+ } else {
+ value = mktime(&tm);
+ if (value < 0) {
+ return -1;
+ }
+ }
+ value *= NSEC_PER_SEC;
+ if (!trimmer->date) {
+ trimmer->year = year;
+ trimmer->month = month;
+ trimmer->day = day;
+ trimmer->date = true;
+ }
+ goto set;
+ }
+ /* hh:mm:ss */
+ ret = sscanf(arg, "%u:%u:%u",
+ &hh, &mm, &ss);
+ if (ret == 3) {
+ if (!trimmer->date) {
+ /* We don't know which day until we get an event. */
+ result_bound->lazy_values.hh = hh;
+ result_bound->lazy_values.mm = mm;
+ result_bound->lazy_values.ss = ss;
+ result_bound->lazy_values.ns = 0;
+ result_bound->lazy_values.gmt = gmt;
+ goto lazy;
+ } else {
+ struct tm tm = {
+ .tm_sec = ss,
+ .tm_min = mm,
+ .tm_hour = hh,
+ .tm_mday = trimmer->day,
+ .tm_mon = trimmer->month - 1,
+ .tm_year = trimmer->year - 1900,
+ .tm_isdst = -1,
+ };
+ time_t result;
+
+ if (gmt) {
+ result = timegm(&tm);
+ if (result < 0) {
+ return -1;
+ }
+ } else {
+ result = mktime(&tm);
+ if (result < 0) {
+ return -1;
+ }
+ }
+ value = (int64_t) result;
+ value *= NSEC_PER_SEC;
+ goto set;
+ }
+ }
+ /* -ss */
+ ret = sscanf(arg, "-%u",
+ &ss);
+ if (ret == 1) {
+ value = -ss * NSEC_PER_SEC;
+ goto set;
+ }
+ /* ss */
+ ret = sscanf(arg, "%u",
+ &ss);
+ if (ret == 1) {
+ value = ss * NSEC_PER_SEC;
+ goto set;
+ }
+
+ /* Not found. */
+ return -1;
+
+set:
+ result_bound->value = value;
+ result_bound->set = true;
+ return 0;
+
+lazy:
+ result_bound->lazy = true;
+ return 0;
+}
+
static
-void init_from_params(struct trimmer *trimmer, struct bt_value *params)
+enum bt_component_status init_from_params(struct trimmer *trimmer, struct bt_value *params)
{
struct bt_value *value = NULL;
+ bool gmt = false;
+ enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
assert(params);
- value = bt_value_map_get(params, "begin_ns_epoch");
- if (value && bt_value_is_integer(value)) {
+ value = bt_value_map_get(params, "clock-gmt");
+ if (value) {
enum bt_value_status value_ret;
- value_ret = bt_value_integer_get(value, &trimmer->begin.value);
- if (!value_ret) {
- trimmer->begin.set = true;
- } else {
- printf_error("Failed to retrieve begin_ns_epoch value\n");
+ value_ret = bt_value_bool_get(value, &gmt);
+ if (value_ret) {
+ ret = BT_COMPONENT_STATUS_INVALID;
+ printf_error("Failed to retrieve clock-gmt value. Expecting a boolean");
}
}
bt_put(value);
- value = bt_value_map_get(params, "end_ns_epoch");
- if (value && bt_value_is_integer(value)) {
+ if (ret != BT_COMPONENT_STATUS_OK) {
+ goto end;
+ }
+
+ value = bt_value_map_get(params, "begin");
+ if (value) {
enum bt_value_status value_ret;
+ const char *str;
- value_ret = bt_value_integer_get(value, &trimmer->end.value);
- if (!value_ret) {
- trimmer->end.set = true;
- } else {
- printf_error("Failed to retrieve end_ns_epoch value\n");
+ value_ret = bt_value_string_get(value, &str);
+ if (value_ret || timestamp_from_arg(str,
+ trimmer, &trimmer->begin, gmt)) {
+ ret = BT_COMPONENT_STATUS_INVALID;
+ printf_error("Failed to retrieve begin value. Expecting a timestamp string");
}
}
bt_put(value);
+ if (ret != BT_COMPONENT_STATUS_OK) {
+ goto end;
+ }
+
+ value = bt_value_map_get(params, "end");
+ if (value) {
+ enum bt_value_status value_ret;
+ const char *str;
+
+ value_ret = bt_value_string_get(value, &str);
+ if (value_ret || timestamp_from_arg(str,
+ trimmer, &trimmer->end, gmt)) {
+ ret = BT_COMPONENT_STATUS_INVALID;
+ printf_error("Failed to retrieve end value. Expecting a timestamp string");
+ }
+ }
+ bt_put(value);
+end:
+ if (trimmer->begin.set && trimmer->end.set) {
+ if (trimmer->begin.value > trimmer->end.value) {
+ printf_error("Unexpected: time range begin value is above end value");
+ ret = BT_COMPONENT_STATUS_INVALID;
+ }
+ }
+ return ret;
}
enum bt_component_status trimmer_component_init(
goto error;
}
- init_from_params(trimmer, params);
+ ret = init_from_params(trimmer, params);
end:
return ret;
error:
}
/* Initialize plug-in entry points. */
-BT_PLUGIN_NAME("utils");
+BT_PLUGIN(utils);
BT_PLUGIN_DESCRIPTION("Babeltrace Trace Trimmer Plug-In.");
BT_PLUGIN_AUTHOR("Jérémie Galarneau");
BT_PLUGIN_LICENSE("MIT");
-
-BT_PLUGIN_COMPONENT_CLASSES_BEGIN
-BT_PLUGIN_FILTER_COMPONENT_CLASS_ENTRY("trimmer",
- "Ensure that trace notifications outside of a given range are filtered-out.",
- trimmer_component_init)
-BT_PLUGIN_COMPONENT_CLASSES_END
+BT_PLUGIN_COMPONENT_CLASS(BT_COMPONENT_TYPE_FILTER, trimmer,
+ trimmer_component_init);
+BT_PLUGIN_COMPONENT_CLASS_DESCRIPTION(BT_COMPONENT_TYPE_FILTER, trimmer,
+ "Ensure that trace notifications outside of a given range are filtered-out.");