C++探针无需安装,但是需要在编译时包含tingyun.h,Linux版本链接时需要libtingyun.so文件,Windows版本链接时需要tingyun.lib文件。
#cp tingyun.h /usr/include/
#cp libtingyun.so /usr/lib/
#include <tingyun.h>
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定义一个完整事务,通常它对应的是一个完整的HTTP请求过程。 代码
//功能: 定义一个事务过程
//调用时机: 客户端请求处理过程开始时
//
//参数:
// appid : 是CreateApplication调用返回的应用ID
// uri : 是Action对应的事务名,若此参数为空串则使用所在函数的类名::函数名
//返回值 : 事务Id
TActionId CreateAction(TAppId appid, const char *uri);
Action说明 应用性能分解过程中,我们使用Action定义一个完整事务,通常它对应的是一个完整的HTTP请求过程。 代码
//功能: 结束事务过程
//调用时机: 客户端请求处理过程结束时
//说明: ActionDestroy调用之后,即表示事物的数据采集过程完成,此后action和由action创建的所有component将失效
// 对应从Action获取的数据缓冲区也将失效。
//
//参数:
// action : 事务id
void ActionDestroy(TActionId action);
一个事务通常会包含多个子过程,子过程还可能由其他子过程组成。我们将这样的子过程定义为Component,通过对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);
//方法1:
//不指定函数名过程名,自动获取当前方法名作为组件名称
//功能: 开始一个组件的数据采集
//调用时机: 当一个耗时的计算过程被分解为几个子过程时,我们需要采集每个子过程的耗时情况,来详细分析性能瓶颈。
// 此时通过这个API可以构建一个调用树,通过分析每个过程的耗时情况,解决性能问题。
//参数 parent: 父级组件Id
//返回值: 组件Id
TComponentId CCreateComponent(TComponentId parent);
//方法2:
//自定义组件名称
//功能: 同上, 差别是用此API自定义过程名
//调用时机: 同上
//参数:
//参数 parent: 父级组件Id
// ComponentName: 自定义组件名
//返回值: 组件Id
TComponentId ComponentCreateComponent(TComponentId parent, const char *ComponentName);
//参数 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的查找路径。