[LTTng学习之旅]------Trace 数据提取和格式转换---Babeltrace 2 C 应用程序开发

25 篇文章 6 订阅

一、目录

二、目标

分为两个方面,

  1. 提取Trace 数据中我需要的指标。用于 开发自己设计的监控程序。(本机目标 优先)
  2. LTTng Live下进行数据分析和提取。(远端目标 其次)

三、工具 概述

需要学习研究下面两个方面:

babeltrace2

CTF “Common Trace Format”

研究发现 CTF也是他们自己搞出来的格式。而且是二进制的数据格式。学习意义不大 感觉、、、

babeltrace2

babeltrace2是LTTng项目独立出来的一套Trace log 文件处理工具。

我研究了一下感觉像是要翻车啊。这一套东西感觉人气不旺啊。在网上连问问题的人都很少。更别说有例子可以参考了。

唯一找到一篇中文博客还是骂他API设计的烂的。。。如果想要完成任务可能只有靠自己了。

工具切入点

babeltrace2 也是很努力的提供了三套工具来给人用。:

1、CLI 也就是命令行。可以直接通过终端来构建一个所谓的trace processing graph。然后来处理数据。这个先不管。

2、C API。这个是我关注的重点。因为我的目标是 在嵌入式设备中把Trace数据转换格式。虽然有Live模式可以配置,但是嵌入式设备的网络环境相比堪忧。那么还是在本地简单的处理一下,把东西走大家都用的通道传出来吧。不要让我单独再给LTTng live 配置个TCP的通道了。

3、Python API。这个备选吧。据他自己的说法是,操作起来比C简单。但是运行慢。

babeltrace2 工具的架构

在这里插入图片描述
babeltrace2 可以这样看:
plugins 插件:由一组class 构成。可以分成三类:source filter sink。

source: 负责读取数据 针对不同的格式和数据源进行定制
filter: 负责对数据进行处理
sink: 导出数据,针对不同的格式需求和输出目标进行定制。

graph: 由各种class 的实例构成
connections: class 之间的链接线

目前有一些提供的class, 也可以使用API自己开发class 和 plugins。

四、使用Babeltrace 2 C API

1、Graph

Graph 的概念相当于是顶层的架构设计。我的计划是先使用提供的现有库做一个简单的demo。然后再根据我的任务去开发自己的component。那么先从graph入手。理想的话可以先run起来。
在这里插入图片描述
图中的.so 文件我没有找到,可能在编译库的时候需要特殊的configure。不过如果不需要动态链接可能也不需要。

后面我找到了 在/usr/local/lib/babeltrace2/plugins下面 名字和图中不一样 babeltrace后面不带2

Graph 的生命周期和API

在这里插入图片描述
graph 的类型是 bt_graph.

Create a default trace processing graph with bt_graph_create(). You need to pass a Message Interchange Protocol (MIP) version number when you call this function. 这个函数要传MIP version 这个参数。这个参数类似VLAN号,只有参数一样构建的模块才能通messages。

创建Graph

创建Graph


bt_graph* bt_graph_create	(	uint64_t 	mip_version	)	

As of Babeltrace 2.0, the only available MIP version is 0.现在是已经舍弃了MIP机制了? 只能传值0?

在建立Graph之后,可以使用 add component系列function添加component。

Add components

在Graph上实例化 component class。

必须通过下列六个API添加:

//	Alias of bt_graph_add_XXXX_component_with_initialize_method_data() with the initialize_method_data parameter set to NULL.

//	Creates a XXXX component from the class component_class with the initialization parameters params, the initialization user data initialize_method_data, and the initial logging level logging_level, adds it to the trace processing graph graph with the name name, and sets *component to the resulting component.

bt_graph_add_component_status 	bt_graph_add_source_component (bt_graph *graph, const bt_component_class_source *component_class, const char *name, const bt_value *params, bt_logging_level logging_level, const bt_component_source **component)

bt_graph_add_component_status 	bt_graph_add_source_component_with_initialize_method_data (bt_graph *graph, const bt_component_class_source *component_class, const char *name, const bt_value *params, void *initialize_method_data, bt_logging_level logging_level, const bt_component_source **component)

bt_graph_add_component_status 	bt_graph_add_filter_component (bt_graph *graph, const bt_component_class_filter *component_class, const char *name, const bt_value *params, bt_logging_level logging_level, const bt_component_filter **component)

bt_graph_add_component_status 	bt_graph_add_filter_component_with_initialize_method_data (bt_graph *graph, const bt_component_class_filter *component_class, const char *name, const bt_value *params, void *initialize_method_data, bt_logging_level logging_level, const bt_component_filter **component)

bt_graph_add_component_status 	bt_graph_add_sink_component (bt_graph *graph, const bt_component_class_sink *component_class, const char *name, const bt_value *params, bt_logging_level logging_level, const bt_component_sink **component)

bt_graph_add_component_status 	bt_graph_add_sink_component_with_initialize_method_data (bt_graph *graph, const bt_component_class_sink *component_class, const char *name, const bt_value *params, void *initialize_method_data, bt_logging_level logging_level, const bt_component_sink **component)

Parameters
[in] graph Trace processing graph to which to add the created source component.
[in] component_class Class to instantiate within graph.
[in] name Unique name, within graph, of the component to create.
[in] params Initialization parameters to use when creating the source component. Can be NULL, in which case the created source component’s initialization method receives an empty map value as its params parameter.

[in] initialize_method_data User data passed as is to the created source component’s initialization method.
[in] logging_level Initial logging level of the source component to create.
[out] component On success, if not NULL, *component is a borrowed reference of the created source component.

Connect component ports
bt_graph_connect_ports_status bt_graph_connect_ports (	
bt_graph *          	graph,
const bt_port_output * 	upstream_port,
const bt_port_input * 	downstream_port,
const bt_connection ** 	connection 
)

Parameters
[in] graph Trace processing graph containing the components to which belong upstream_port and downstream_port.
[in] upstream_port Output port to connect to downstream_port.
[in] downstream_port Input port to connect to upstream_port.
[in] connection On success, if not NULL, *connection is a borrowed reference of the resulting connection.

Run之前 ,添加component和连线可以反复进行,没说要先添加所有的再连线。
但是一旦Run了,就不要再改设计了。

Run
//Runs the trace processing graph graph, calling each sink component's consuming method in a round robin fashion until they are all done consuming or an exception occurs.
bt_graph_run_status bt_graph_run	(	bt_graph * 	graph	)	

//Calls the consuming method of the next non-ended sink component to make consume within the trace processing graph graph.
bt_graph_run_once_status bt_graph_run_once	(	bt_graph * 	graph	)	

once是只处理一个message吗?

另一个是会RR形式将所有喂给sink的message做完?

使用API构建的简单Demo

真正上手写一写代码,我理解了两件事
1、为什么LTTng这个项目没人用,还专门被人写博客骂
C API里关于使用API的代码例子实在是太少了,或者说根本就没有使用示例。接口根本不知道怎么用。
而且LTTng也好,Babeltrace也好,感觉生怕别人理解不了,拼命想把理念说明白,自己整了很多新概念出来。更是让人云里雾里。
2、为什么很多程序员离开了github就写不了代码
我在github上找到了一个老哥基于(可能是全世界唯一一个)babeltrace的库写的小项目。在里面找到了接口调用。虽然他觉得很难用,又用C++封了一层,但是我还是看懂了。想必很多程序员拿到库和需求,可以直接上github去抄(如果东西比较热门的话)。那真是省事多了。//stack overflow都搜不到。。

下面是成果:读取LTTng生成的默认trace 数据,然后打印到文件里:

#include <babeltrace2/babeltrace.h>

int main(int argc, char const *argv[])
{
    //create graph
    bt_graph * my_graph = bt_graph_create(0);//看手册似乎必须通过0构造。

    /**
     *Add source component to read ctf files
     *  
     */

    //find plugin, and borrow component class from plugin
    const bt_plugin * my_source_ctf_fs_plugin;
    bt_plugin_find("ctf",BT_FALSE,BT_FALSE,BT_TRUE,BT_FALSE,BT_TRUE,&my_source_ctf_fs_plugin);//先是通过查找插件的名字来找到插件
    //我觉得可能在这里链接了.so库
    const bt_component_class_source *my_source_ctf_fs_class = 
                            bt_plugin_borrow_source_component_class_by_name_const(my_source_ctf_fs_plugin,"fs");
                            //然后因为插件、类是所谓的共享对象,必须“借”一个来使用。根据名字从插件里借出类

    //add components from class
    bt_value * my_ctf_path=bt_value_array_create();
    bt_value_array_append_string_element(my_ctf_path,"/home/userhome/lttng-traces/my_session/kernel");//存放trace数据的目录地址,能看到metadata index 之类的地方。
    bt_value * my_source_ctf_fs_parameter=bt_value_map_create();
    bt_value_map_insert_entry(my_source_ctf_fs_parameter,"inputs",my_ctf_path);
    //这里是构造模块的初始化参数。定义的是参数是map形式的bt_value这是一种类似json的格式。
    const bt_component_source* my_ctf_reader;
    bt_graph_add_source_component(my_graph,
                                  my_source_ctf_fs_class,
                                  "my_reader",
                                  my_source_ctf_fs_parameter,                            
                                  BT_LOGGING_LEVEL_ERROR,//这里根据选择的不同在运行时候会在终端打印不同等级的信息。改成debug真的有助于开发的时候查错。
                                  &my_ctf_reader
                                  );

    /**
     * Add sink component to write trace log in file
     */


    //find plugin, and borrow component class from plugin
    const bt_plugin * my_sink_text_pretty_plugin;
    bt_plugin_find("text",BT_FALSE,BT_FALSE,BT_TRUE,BT_FALSE,BT_TRUE,&my_sink_text_pretty_plugin);
    const bt_component_class_sink *my_sink_text_pretty_class = 
                            bt_plugin_borrow_sink_component_class_by_name_const(my_sink_text_pretty_plugin,"pretty");    

    //add components from class  
    bt_value * my_writer_parameter=bt_value_map_create();
    bt_value_map_insert_string_entry(my_writer_parameter,"path","my_log");
    const bt_component_sink* my_pretty_writer;
    bt_graph_add_sink_component  (my_graph,
                                  my_sink_text_pretty_class,
                                  "my_writer",
                                  my_writer_parameter,                            
                                  BT_LOGGING_LEVEL_DEBUG,
                                  &my_pretty_writer
                                  );

    /**
     * I find that the source conponent has 4 output ports.
     * so maybe, I need a muxer component.
     */
    const bt_plugin * my_filter_utils_muxer_plugin;
    bt_plugin_find("utils",BT_FALSE,BT_FALSE,BT_TRUE,BT_FALSE,BT_TRUE,&my_filter_utils_muxer_plugin);
    const bt_component_class_filter *my_filter_utils_muxer_class =
                            bt_plugin_borrow_filter_component_class_by_name_const(my_filter_utils_muxer_plugin,"muxer");

    const bt_component_filter * my_muxer;
    bt_graph_add_filter_component(my_graph,
                                  my_filter_utils_muxer_class,
                                  "my_muxer",
                                  NULL,                            
                                  BT_LOGGING_LEVEL_ERROR,
                                  &my_muxer
                                  );



    /**
     * Now, let`s connect all the port.
    */

//source
   const  bt_port_output * ctf_fs_0 = 
            bt_component_source_borrow_output_port_by_index_const(my_ctf_reader,0);

   const  bt_port_output * ctf_fs_1 = 
            bt_component_source_borrow_output_port_by_index_const(my_ctf_reader,1);

   const  bt_port_output * ctf_fs_2 = 
            bt_component_source_borrow_output_port_by_index_const(my_ctf_reader,2);

   const  bt_port_output * ctf_fs_3 = 
            bt_component_source_borrow_output_port_by_index_const(my_ctf_reader,3);

//filter
//NOTE: After you connecting one port, the component will create the next one. So,you should borrow and connect one by one.
    const bt_port_input * muxer_in_0 =
            bt_component_filter_borrow_input_port_by_name_const(my_muxer,"in0");

    bt_graph_connect_ports(my_graph,ctf_fs_0,muxer_in_0,NULL);

    const bt_port_input * muxer_in_1 =
            bt_component_filter_borrow_input_port_by_name_const(my_muxer,"in1");

    bt_graph_connect_ports(my_graph,ctf_fs_1,muxer_in_1,NULL); 
    
    const bt_port_input * muxer_in_2 =
            bt_component_filter_borrow_input_port_by_name_const(my_muxer,"in2");

    bt_graph_connect_ports(my_graph,ctf_fs_2,muxer_in_2,NULL);

    const bt_port_input * muxer_in_3 =
            bt_component_filter_borrow_input_port_by_name_const(my_muxer,"in3");

    bt_graph_connect_ports(my_graph,ctf_fs_3,muxer_in_3,NULL);

    const bt_port_output * muxer_out =
            bt_component_filter_borrow_output_port_by_name_const(my_muxer,"out");

//sink
    const bt_port_input * pretty_in =
            bt_component_sink_borrow_input_port_by_name_const(my_pretty_writer,"in");

//connections

    bt_graph_connect_ports(my_graph,muxer_out,pretty_in,NULL);


//run
    bt_graph_run(my_graph);

    return 0;
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小羊苏C

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值