首页 帮助中心 基调听云Server 安装和使用
基调听云Server

安装和使用

安装探针

C++探针无需安装,但是需要在编译时包含tingyun.h,Linux版本链接时需要libtingyun.so文件,Windows版本链接时需要tingyun.lib文件。

#cp tingyun.h /usr/include/
#cp libtingyun.so /usr/lib/

使用探针

引用模块

#include <tingyun.h>

Agent SDK 初始化和终止

Agent初始化:

	//功能: Agent初始化过程中,将读取配置文件,创建一个后台线程。
	//  在这个后台线程中处理日志,驱动应用数据的处理过程。
	//调用时机: main函数开始时即调用。
	//注意事项: 在使用其他接口前,调用初始化接口。

	//
	//参数:   json格式的配置文件路径
	//返回值: 0或者1。返回0,表示初始化失败;返回1,表示初始化成功。
	int AgentInit(const char *jsonFile);

Agent终止:

	//功能: 终止所有应用的处理过程,结束线程,结束日志写入过程。
	//调用时机: 进程退出最后一步。或者不调用

	//
	//参数: Agent终止原因,将会被写入日志
	void AgentStop(const char *reason);

创建应用

代码:

	//功能: 创建一个应用并开始应用的数据采集,初始化应用数据和本地配置项,开始跟DC服务器通信,向服务器注册应用
	//服务器登录成功后开始处理Action数据并汇总发送到DC服务器
	//调用时机: 在AgentInit之后
	//说明: 此API只调用一次

	//
	//参数:   应用名称
	//返回值: 应用ID. 创建事务时会用到应用ID
	TAppId CreateApplication(const char *AppName);

创建Action

Action说明 应用性能分解过程中,我们使用Action定义一个完整事务,通常它对应的是一个完整的HTTP请求过程。 代码

	//功能:  定义一个事务过程
	//调用时机: 客户端请求处理过程开始时
	
	//
	//参数:
	//	appid :  是CreateApplication调用返回的应用ID
	//	uri :    是Action对应的事务名,若此参数为空串则使用所在函数的类名::函数名
	//返回值 :    事务Id
	TActionId CreateAction(TAppId appid, const char *uri);

结束Action

Action说明 应用性能分解过程中,我们使用Action定义一个完整事务,通常它对应的是一个完整的HTTP请求过程。 代码

	//功能: 结束事务过程
	//调用时机: 客户端请求处理过程结束时
	//说明:  ActionDestroy调用之后,即表示事物的数据采集过程完成,此后action和由action创建的所有component将失效
	//  对应从Action获取的数据缓冲区也将失效。
	
	//
	//参数:
	//	action :  事务id
	void ActionDestroy(TActionId action);

创建Component

一个事务通常会包含多个子过程,子过程还可能由其他子过程组成。我们将这样的子过程定义为Component,通过对Component树的耗时分析来定位事务执行过程中的性能瓶颈。

从Action创建Component

一般组件

	//方法1:
	//不指定函数名过程名,自动获取当前方法名作为组件名称
	//功能: 开始一个组件的数据采集,这个API获取当前所处的函数名字作为组件名
	//调用时机: 一个可能耗时的计算类型的子过程开始的时候
	//
	//参数 action: 事务Id
	//返回值:      组件Id
	TComponentId ACreateComponent(TActionId action);
	
	
	
	//方法2:
	//自定义组件名称
	//功能: 同上,这个API使用自定义的名字作为组件名
	//调用时机: 同上
	//
	//参数:
	//	action:                   事务Id
	//	ComponentName: 自定义组件名
	//返回值:           组件Id
	TComponentId ActionCreateComponent(TActionId action, const char *ComponentName);

数据库组件

	//方法1: 有SQL语句的情况下,使用SQL语句自动解析
	//功能: 开始一个数据库调用过程的数据采集,需要传递sql语句.内部将解析出数据库操作类型和表名,作为组件名的一部分
	//调用时机: 数据库过程开始时
	//
	//参数:
	//	action: 事务Id
	//	type:   数据库类型: "Mysql"/"Postgresql"
	//	host:   数据库主机地址
	//	dbname: 数据库名
	//	sql:    执行的SQL语句
	//返回值:    组件Id
	TComponentId CreateSQLComponent(TActionId action, const char *type, const char *host, const char *dbname, const char *sql);
	
	
	//方法2: 无SQL语句的情况下,传递表名和操作名(select/update/insert/delete)
	//功能: 同上,差别是明确指定表明和操作方法(select/update/insert/delete)
	//调用时机: 同上
	//
	//参数:
	//	action: 事务Id
	//	type:   数据库类型: "Mysql"/"Postgresql"
	//	host:   数据库主机地址
	//	dbname: 数据库名
	//	table:  表名
	//	op:     表上的操作名
	//返回值:    组件Id
	TComponentId CreateDBComponent(TActionId action, const char *type, const char *host, const char *dbname, const char *table, const char *op);

NoSQL组件

	//功能: 开始一个NoSQL数据库调用过程的数据采集
	//调用时机: 数据库过程开始时
	//
	//参数:
	//	action:      事务Id
	//	type:        数据库类型: "Mysql"/"Postgresql"
	//	host:        数据库主机地址
	//	dbname:      数据库名
	//	object_name: 对象名
	//	op:          对象上的操作名
	//返回值:         组件Id
	TComponentId CreateNoSQLComponent(TActionId action, const char *type, const char *host, const char *dbname, const char *object_name, const char *op);

外部调用组件(RPC、HTTP等)

	//自定义组件名称
	//功能: 开始一个外部调用的数据采集,外部调用可以是向其他服务器发起的http请求,或者rpc调用
	//调用时机: 外部调用开始时
	//
	//参数:
	//	action: 事务Id
	//	url:    外部调用的url
	//返回值:    组件Id
	TComponentId CreateExternalComponent(TActionId action, const char *url);

从Component创建Component

	//方法1:
	//不指定函数名过程名,自动获取当前方法名作为组件名称
	//功能: 开始一个组件的数据采集
	//调用时机: 当一个耗时的计算过程被分解为几个子过程时,我们需要采集每个子过程的耗时情况,来详细分析性能瓶颈。
	//  此时通过这个API可以构建一个调用树,通过分析每个过程的耗时情况,解决性能问题。
	
	//参数 parent: 父级组件Id
	//返回值:      组件Id
	TComponentId CCreateComponent(TComponentId parent);
	
	//方法2:
	//自定义组件名称
	//功能: 同上, 差别是用此API自定义过程名
	//调用时机: 同上
	
	//参数:
	//参数 parent:      父级组件Id
	//	ComponentName: 自定义组件名
	//返回值:           组件Id
	TComponentId ComponentCreateComponent(TComponentId parent, const char *ComponentName);

结束Component

	//参数 component: 组件id
	void ComponentFinish(TComponentId component);
	//功能: 结束一个组件的数据采集
	//调用时机: 对应该组件的过程执行完毕时。比如数据库过程执行完时,或者一个外部调用执行完成时

子过程结束时,需要调用对应的Component.Finish(),才能达到采集数据的目的。

示例代码

//应用ID定义为全局变量,以便其他地方使用
TAppId app_id;
int main(int argc, char *argv[])
{
    if (argc < 2) { printf("use :\n%s port\n", argv[0]); return 0; }
	//SDK初始化
    AgentInit("tingyun.json");
	//创建应用,参数是应用名
    app_id = CreateApplication("MyFirstTestAppName");
    unsigned short port = atoi(argv[1]);
    HEAD::Driver<> runner;
    HEAD::NET::Net net(runner);
    HEAD::NET::http http(net);
    HEAD::NET::NameAgent name_agent(net, dns_ip);
    HEAD::NET::HttpClient http_client(net, name_agent);
    auto httpsvr = http.listen(port, [&](HEAD::NET::http::IncomingMessage * req) {
		//创建事务以URI命名Action名字
        auto action = CreateAction(app_id, req->uri.c_str());
        auto close = [req]() { req->destroy(); };

		//如果调用方有跨应用追踪请求,将追踪ID添加到追踪事务
        if ( auto cross_id = req->header("X-Tingyun-Id"); cross_id ) ActionSetTrackId(action, cross_id->c_str());

        req->on_break(close);
        req->on_end(close);
        req->res.http_code = 200;

		if (req->uri == "/pf" || req->uri == "/xhr" || req->uri == "/err") {
			//创建一般过程组件
            auto component = ACreateComponent(action);
			char time_buf[128];gmt_string(time_buf, 128);
            req->res.params["Content-Type"] = "text/plain; charset=utf-8";
            req->res.params["Access-Control-Allow-Origin"] = "*";
            req->res.params["Cache-Control"] = "no-cache";
			req->res.params["Date"] = time_buf;
            req->res.params["Connection"] = "keep-alive";
            if (req->ver == "HTTP/1.0") req->res.ver = "HTTP/1.0";
			//组件结束
            ComponentFinish(component);
            const char *url = "http://172.16.101.1/x.php";
            auto request = http_client.NewRequest(url);
			//创建外部调用组件
            auto rpccomponent = CreateExternalComponent(action, url);
			//从外部调用组件获取跨应用追踪ID,并添加到HTTP头
            if (char track_id[256] = { 0 }; ComponentCreateTrackId(rpccomponent, track_id, 255) ) request->Header("X-Tingyun-Id") = track_id;

            request->OnProgress([&, req, action, request, rpccomponent](HEAD::NET::HttpClient::State state_now, HEAD::NET::HttpClient::State state_before) {
                if (state_now == HEAD::NET::HttpClient::State::InData) {
                    HEAD::smart_buffer<char, 1024> buffer;
                    while ( auto size = request->Res()->Read(&buffer, 1024)) printf("%.*s", size, &buffer);
                }
                if (state_now >= HEAD::NET::HttpClient::State::RecvedFinished) {
					//如果外部HTTP调用返回头中有"X-Tingyun-Tx-Data",则表示对端支持跨应用追踪
                    if ( auto it = request->Res()->Headers().find(HEAD::string("X-Tingyun-Tx-Data")); it != request->Res()->Headers().end()) {
						//将跨应用追踪数据记录到外部调用组件,完成上一级的追踪
                        ComponentSetTxData(rpccomponent, it->second.c_str());
                    }
                    request->Destroy();
					//跨应用追踪完毕
                    ComponentFinish(rpccomponent);
					const char *host = "10.221.150.179:5444";
					const char *dbname = "edb";
					const char *sql = "SELECT id, name FROM test";
					//创建数据库事务
					auto dbcomponent = CreateSQLComponent(tingyun_action, "PostgreSql", host, dbname, sql);
					//异步数据库调用
                    db_call(host, dbname, sql, runner, [req, dbcomponent] {
						//数据库事务结束
						ComponentFinish(dbcomponent);
                        HEAD::refstring helloworld = "HelloWorld.";
                        char len_buffer[10]; sprintf(len_buffer, "%d", helloword.size());
                        req->res.params["Content-Length"] = len_buffer;

						//从事务对象取跨应用追踪数据(如果能取到),通过HTTP头发送给调用方
                        if (const char *tx_data = ActionGetTxData(action); *tx_data) req->res.params["X-Tingyun-Tx-Data"] = tx_data;

                        HEAD::string err;
                        req->res.write(helloworld.c_str(), helloworld.size(), err);

						//将http状态码写入事务
                        ActionSetStatus(action, req->res.http_code);
						//事务结束
                        ActionDestroy(action);
                        req->res.end();
                    });
                }
            });
            request->Get();
            return;
        }
        else req->res.http_code = 404;
		//设置HTTP状态码
        ActionSetStatus(action, req->res.http_code);
		//事务结束
        ActionDestroy(action);
        req->res.end();
    });
    if (httpsvr) printf("http listen @%d\n", (int)port);
    return runner.play();
}

编译配置

编译

编译选项需要添加tingyun.h的路径 
例如: tingyun.h 位于 /opt/tingyun/cpp 下 则添加 编译选项 -I/opt/tingyun/cpp

链接

链接选项需要添加libtingyun.so的路径
例如: libtingyun.so 位于 /opt/tingyun/cpp下 则添加编译选项 -L/opt/tingyun/cpp -ltingyun

运行配置

调用SDK的应用程序编译完成后,运行时需要指定libtingyun.so的路径,或者将libtingyun.so放入系统的so查找路径,如/usr/lib。 指定so查找路径方法: 例如: 运行环境中, libtingyun.so 位于/opt/tingyun/cpp下,则在运行应用程序前需要设置环境变量: export LD_LIBRARY_PATH=/opt/tingyun/cpp:$LD_LIBRARY_PATH 指定so的查找路径。