This example shows a basic filter component class packaged as a shared object plugin.
The name of the plugin is distill and the name of the filter component class is theone. Therefore the component class is identified in the babeltrace2 command-line tool as filter.distill.theone.
A filter.distill.theone component removes specific event messages from a stream based on their event class's name.
A filter.distill.theone component accepts a single initialization parameter, names, which is an array value of string values. The array value contains the names of the classes of the events to discard.
A filter.distill.theone component creates a single input port named in and a single output port named out.
To simplify this example, a filter.distill.theone component is not resilient and needs a valid input and valid initialization parameters. The code also doesn't check the return status codes of API functions for simplicity, but you must check them in production code.
The filter component class implementation and the shared object plugin macros are in the same file, distill.c:
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <stdbool.h>
#include <babeltrace2/babeltrace.h>
struct distill {
};
static
const bt_value *params,
void *initialize_method_data)
{
struct distill *distill = malloc(sizeof(*distill));
distill->names_value =
distill);
"in", NULL, &distill->in_port);
"out", NULL, NULL);
}
static
{
free(distill);
}
struct distill_message_iterator {
struct distill *distill;
};
static
distill_message_iterator_initialize(
{
struct distill_message_iterator *distill_iter =
malloc(sizeof(*distill_iter));
distill_iter->distill = distill;
distill->in_port, &distill_iter->message_iterator);
}
static
void distill_message_iterator_finalize(
{
struct distill_message_iterator *distill_iter =
free(distill_iter);
}
static
bool message_passes(struct distill_message_iterator *distill_iter,
{
bool passes = true;
passes = false;
goto end;
}
distill_iter->distill->names_value); i++) {
distill_iter->distill->names_value, i));
if (strcmp(name, discard_name) == 0) {
passes = false;
goto end;
}
}
end:
return passes;
}
static
uint64_t *count)
{
struct distill_message_iterator *distill_iter =
uint64_t upstream_message_count;
consume_upstream_messages:
&upstream_messages, &upstream_message_count);
switch (next_status) {
goto end;
goto end;
goto end;
goto end;
default:
break;
}
uint64_t i = 0;
for (uint64_t upstream_i = 0; upstream_i < upstream_message_count;
upstream_i++) {
const bt_message *upstream_message = upstream_messages[upstream_i];
if (message_passes(distill_iter, upstream_message)) {
messages[i] = upstream_message;
i++;
continue;
}
}
if (i == 0) {
goto consume_upstream_messages;
}
*count = i;
end:
return status;
}
theone, distill_message_iterator_initialize);
distill_message_iterator_finalize);
As per the Compile and link a Babeltrace 2 shared object plugin guide, you can build the shared object plugin as such:
1 $ cc distill.c -fPIC -c $(pkg-config --cflags babeltrace2)
2 $ ld distill.o -o distill.so -shared $(pkg-config --libs babeltrace2)
With the babeltrace2 tool, you can use a filter.distill.theone component, reading a CTF trace (see babeltrace2-source.ctf.fs(7)) for example:
1 $ babeltrace2 --plugin-path=. /path/to/ctf/trace \
2 --component=filter.distill.theone \
3 --params='names=["sched_switch", "rcu_utilization", "kmem_kfree"]'