未验证 提交 c23fb247 编写于 作者: Y youyong205 提交者: GitHub

Merge pull request #1320 from stdrickforce/cppcat

Seperate cppcat from ccat.
# Cat Client
## Overview
The following programming languages are supported:
* C
* C++
* Python
* Go
* Node.js
And the following programming language is in our plan:
* PHP
* C# (.net)
## Word explanations
### Message types
* Transaction
* Event
* Heartbeat
* Metric
### Message properties
* type
Represents a category of message, like `SQL`, `RPC` or `HTTP`.
* name
Represents a specified action, for example
* If the **type** is `SQL`, the **name** may be `select <?> from user where id = <?>`, which is the base SQL.
* If the **type** is `RPC`, the **name** may be `QueryOrderByUserId(string, int)`, which is the signature of an api.
* If the **type** is `HTTP`, the **name** may be `/api/v8/{int}/orders`, which is the base uri.
> Detailed information should be recorded in the **data** field, like the parameters of an API.
* status
Represents the status of the message.
The message will be treated as a "problem" if the status of it is not equal to "0", and will be shown in the problem report. Once a message has been treated as a "problem", whatever what type it is, the current message tree will not be aggregated, that means you can always get the structure of a "problemed" logview.
* data
Record the detailed information about a message.
* If the **type** is `SQL`, the **data** may be `id=75442432`
* If the **type** is `RPC`, the **data** may be `userType=dianping&userId=9987`
* If the **type** is `HTTP`, the **data** may be `orderId=75442432`
`data` field may also contain `error stack trace` in some cases. (like represent an exception or an error)
* timestamp
Represents the created time of the message, will be displayed in `logview` or `message tree`.
The number of **milliseconds** that have elapsed since `1970-01-01 00:00:00`
#### Transaction-only properties
* duration
Represents the total time in **milliseconds** that a transaction has cost.
It is calculated while a transaction has been completed.
> duration = currentTimestamp() - durationStart
You can always specify the `duration` through related APIs before the transaction has been completed, and skip the calculating process.
* durationStart
Represents the start time of a transaction.
It can be different with `timestamp`, the `durationStart` is only used for calculating the `duration` of a transaction, overwrite `durationStart` won't influence `timestamp`.
# Preparations before initializing cat client.
1. Create `/data/appdatas/cat` directory.
Make sure that you have **read and write (>=0644)** permission of the created directory.
2. Create `/data/applogs/cat` directory. (optional)
This directory is used for preserving debug logs, which can be very useful while debugging, **read and write** permission is also required.
3. Create `/data/appdatas/cat/client.xml` with following contents.
```xml
<?xml version="1.0" encoding="utf-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema" xsi:noNamespaceSchemaLocation="config.xsd">
<servers>
<server ip="<cat server ip address>" port="2280" http-port="8080" />
</servers>
</config>
```
> Don't forget to change the **\<cat server IP address\>** to your server ip address.
# 启动 cat 客户端前的准备工作
1. 创建 `/data/appdatas/cat` 目录
确保你具有这个目录的读写权限。
2. 创建 `/data/applogs/cat` 目录 (可选)
这个目录是用于存放运行时日志的,这将会对调试提供很大帮助,同样需要读写权限。
3. 创建 `/data/appdatas/cat/client.xml`,内容如下
```xml
<?xml version="1.0" encoding="utf-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema" xsi:noNamespaceSchemaLocation="config.xsd">
<servers>
<server ip="<cat server ip address>" port="2280" http-port="8080" />
</servers>
</config>
```
> 不要忘记把 **\<cat server IP address\>** 替换成你自己的服务器地址哦!
# Cat Client
## Overview
我们目前支持以下编程语言:
* C
* C++
* Python
* Go
* Node.js
以下编程语言在我们的支持计划中:
* PHP
* C# (.net)
## 名词解释
### 消息类型
* Transaction
* Event
* Heartbeat
* Metric
### 消息属性
* type
表示一种类型的消息,比如 `SQL`,`RPC` 或 `HTTP`。
* name
表示一个特定的行为,举例来说:
* 如果 **type** 是 `SQL`, **name** 可以是 `select <?> from user where id = <?>`, 表示一个 SQL 模版。
* 如果 **type** 是 `RPC`, **name** 可以是 `QueryOrderByUserId(string, int)`, 表示一个 API 的函数签名。
* 如果 **type** 是 `HTTP`, **name** 可以是 `/api/v8/{int}/orders`, 表示基础 URI。
> 更详细的信息建议在 **data** 字段中记录,比如 api 的参数
* status
表示消息的状态。
当消息的状态不为 "0" 时,会被标记成一个 "problem"。无论消息类型是什么,只要被标记为 "problem",它所在的消息树就不会被聚合,这也意味着你随时可以获取它完整的日志信息。
* data
记录一个消息的详细信息
* 如果 **type** 是 `SQL`, **data** 可以是 `id=75442432`
* 如果 **type** 是 `RPC`, **data** 可以是 `userType=dianping&userId=9987`
* 如果 **type** 是 `HTTP`, **data** 可以是 `orderId=75442432`
在一些情况下,`data` 字段会包含错误堆栈信息(比如代表一个 exception 或者 error)
* timestamp
代表消息的创建时间,会在消息树中展示。
从 `1970-01-01 00:00:00` 开始到创建时经过的毫秒数。
#### Transaction 特有的参数
* duration
表示一个 transaction 花费的时间,以毫秒计算。
会在 transaction 被完成时计算。
> duration = currentTimestamp() - durationStart
你可以通过相关 API 在 transaction 被完成前指定 `duration` 的值,并且跳过计算过程。
* durationStart
表示 transaction 开始执行的时间。
区别于 `timestamp`,`durationStart` 只用来计算 transaction 的 `duration`,修改 `durationStart` 不会影响 `timestamp`。
cmake_minimum_required(VERSION 2.4)
cmake_minimum_required(VERSION 2.8)
project(ccat)
set(CCAT_VERSION 3.0.0)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/ccat/version.h)
message(STATUS "Current OS: " ${CMAKE_SYSTEM_NAME})
macro(use_c99)
......@@ -14,19 +18,6 @@ macro(use_c99)
endif ()
endmacro(use_c99)
macro(use_cxx11)
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()
endmacro(use_cxx11)
macro(add_definitions_c def)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${def}")
endmacro()
......@@ -36,10 +27,7 @@ macro(add_cxx_flags def)
endmacro()
use_c99()
use_cxx11()
# set(BUILD_TYPE CPP)
# set(BUILD_TEST 1)
# set(BUILD_SCRIPT 1)
add_definitions("-Wno-format-security")
......@@ -53,6 +41,7 @@ endif()
include_directories(include)
include_directories(src)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/include)
set(
HEADER_FILES
......@@ -63,7 +52,7 @@ set(
src/lib/cat_thread.h
src/lib/headers.h
src/lib/typedef.h
include/ccat/client.h
include/client.h
)
aux_source_directory(src/lib LIBRARY_FILES)
......@@ -82,37 +71,11 @@ elseif(UNIX)
link_libraries(pthread)
endif()
if (BUILD_TYPE STREQUAL CPP)
set(HEADER_FILES include/cppcat/client.h ${HEADER_FILES})
aux_source_directory(src/cppcat CPP_SOURCE_FILES)
set(SOURCE_FILES ${SOURCE_FILES} ${CPP_SOURCE_FILES})
add_library(catclient SHARED ${HEADER_FILES} ${SOURCE_FILES})
install(TARGETS catclient DESTINATION lib)
else()
set(HEADER_FILES include/ccat/client.h ${HEADER_FILES})
add_library(catclient SHARED ${HEADER_FILES} ${SOURCE_FILES})
install(TARGETS catclient DESTINATION lib)
endif()
if (BUILD_TEST)
link_libraries(gtest)
file(
COPY
tests/client.xml
tests/client.json
DESTINATION cat
)
aux_source_directory(tests/unit UNITTEST_FILES)
add_executable(unittest tests/unittest.cpp ${UNITTEST_FILES} ${SOURCE_FILES})
endif()
set(HEADER_FILES include/client.h ${HEADER_FILES})
add_library(catclient STATIC SHARED ${HEADER_FILES} ${SOURCE_FILES})
install(TARGETS catclient DESTINATION lib)
if (BUILD_SCRIPT)
if (BUILD_TYPE STREQUAL CPP)
add_executable(test_client ${HEADER_FILES} ${SOURCE_FILES} benchmark/cat_client_test.cpp)
add_executable(test_mpsc ${HEADER_FILES} ${SOURCE_FILES} benchmark/cat_mpsc_test.cpp)
else()
add_executable(test_client ${HEADER_FILES} ${SOURCE_FILES} benchmark/cat_client_test.c)
add_executable(test_mpsc ${HEADER_FILES} ${SOURCE_FILES} benchmark/cat_mpsc_test.c)
endif()
add_executable(test_client ${HEADER_FILES} ${SOURCE_FILES} scripts/cat_client_test.c)
add_executable(test_mpsc ${HEADER_FILES} ${SOURCE_FILES} scripts/cat_mpsc_test.c)
endif()
# Cat Client C & C++
# Cat Client for C
## Building & Installation
[中文文档](./docs/zh-CN.md)
The cat client can be compiled and used on Linux (both glibc and musl-libc) and OSX.
The cat client can be compiled and used on both Linux (both glibc and musl-libc) and OSX.
You need to have a C compiler (supporting C99) and a C++ compiler (supporting C++11) if you want to run test cases or build c++ version of cat client.
The following Operating Systems are tested:
You also need to have `cmake` and `make` installed, which we use for building static or dynamic libraries, and executable binary files (like test or benchmark script).
* OSX (>=10.13)
* Alpine linux
* CentOS 6
* CentOS 7
* Ubuntu 14.04 LTS
* Ubuntu 16.04 LTS
* Ubuntu 18.04 LTS
Upon you get your environment ready, it's easy to build and install ccat.
We also offered a cpp version, please refer to [cppcat](../cpp) for further information.
(In the project root dir, which contains CMakeLists.txt)
## Compilation
```
mkdir -p cmake
cd cmake
make -j 4
```
You need to have a C compiler (supporting C99) installed.
Build test cases if you want. ([googletest]() and a c++ compiler is required)
You also need to have `cmake` and `make` installed, which we use for building static or dynamic libraries and executable binary files.
```
make -j 4 -DBUILD_TEST=1
```
Once you have your environment ready, it's easy to build and install `ccat`.
Build c++ version of cat client.
(In the project root dir, which contains CMakeLists.txt)
```
make -j 4 -DBUILD_TYPE=CPP
mkdir -p cmake
cd cmake
make -j 4
```
### Installation
This command will install libcatclient.so (or .dylib in osx) to `LD_LIBRARY_PATH`, which in most cases is `/usr/local/lib`
The following command will install libcatclient.so (or .dylib in osx) to your `LD_LIBRARY_PATH`, which is `/usr/local/lib` in most cases.
```
make install
```
and it can be used as a built-in shared library
Now it can be used as a built-in shared library.
```
gcc -lcatclient x.c
```
## Initialization
First of all, you have to create `/data/appdatas/cat` directory, read and write permission is required (0644).`/data/applogs/cat` is also required if you'd like to preserve a debug log, it can be very useful while debugging.
And create a config file `/data/appdatas/cat/client.xml` with the following contents.
```xml
<?xml version="1.0" encoding="utf-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema" xsi:noNamespaceSchemaLocation="config.xsd">
<servers>
<server ip="<cat server ip address>" port="2280" http-port="8080" />
</servers>
</config>
```
Don't forget to change the `<cat server IP address>` to your own after you copy and paste the contents.
Some [preparations](../_/preparations.md) needs to be done before initialize `ccat`.
With all the preparations have done, It's easy to initialize it in your c codes.
With all the preparations have been done, it's easy to initialize `ccat` in your c codes.
```c
#include <ccat/client.h>
#include <client.h>
catClientInit("appkey");
```
> Only English characters, numbers, underscore and dash is allowed in appkey.
If you are using our cpp version, you can initialize it by following codes.
> Only English characters (a-z, A-Z), numbers (0-9), underscore (\_) and dash (-) is allowed in appkey.
```cpp
#include <cppcat/client.h>
cat::init("appkey");
```
We also have many initialize options, like enable text-encoder (adapt to lower server version), disable sampling or heartbeat which is enabled by default.
See [this link]()
Note that `sampling`, built-in `heartbeat` and `binary` encoder is enabled by default, which you may want to disable it. We also offered an API to customize your initialization, please refer to our [apidoc](./docs/api.md).
## Documentation
[ccat](./doc/api-c.md)
[cppcat](./doc/api-cpp.md)
[API doc](./docs/api.md)
//
// Created by Terence on 2018/8/27.
//
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <memory.h>
#include <net/if.h>
#include <netdb.h>
#include <stdio.h>
#define NULL 0
int ipAddressLevel(struct in_addr *addr, int offset) {
uint32_t a = addr->s_addr;
if ((a & 0xFF) == 10) {
return 1 + offset;
} else if (((a & 0xFF) == 172) && ((a >> 8 & 0xF0) == 16)) {
return 1 + offset;
} else if (((a & 0xFF) == 192) && ((a >> 8 & 0xFF) == 168)) {
return 1 + offset;
} else {
return 3 + offset;
}
}
int getLocalHostIp(char *ip) {
struct ifaddrs *interfaces = NULL;
if (getifaddrs(&interfaces)) {
return -1;
}
struct in_addr *res = NULL;
int res_level = 0, tmp_level = 0;
struct ifaddrs *tmp;
for (tmp = interfaces; NULL != tmp; tmp = tmp->ifa_next) {
char ipbuf[64];
char hostname[NI_MAXHOST];
if (tmp->ifa_addr->sa_family == AF_INET) {
// ignore not up interface.
if (!(tmp->ifa_flags & IFF_UP)) {
continue;
}
// ignore loopback interface.
if (tmp->ifa_flags & IFF_LOOPBACK) {
continue;
}
// get hostname and ip
getnameinfo(tmp->ifa_addr, sizeof(struct sockaddr_in), hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
struct in_addr *addr = &((struct sockaddr_in *) tmp->ifa_addr)->sin_addr;
if (NULL == inet_ntop(AF_INET, addr, ipbuf, 16)) {
continue;
}
// we put interface address with a hostname in a higher priority.
int offset = strcmp(ipbuf, hostname) == 0 ? 0 : 1;
if (NULL == res) {
res = addr;
res_level = ipAddressLevel(res, offset);
} else if (res_level < (tmp_level = ipAddressLevel(addr, offset))) {
res = addr;
res_level = tmp_level;
}
}
}
freeifaddrs(interfaces);
if (NULL == res) {
return -1;
} else {
return NULL == inet_ntop(AF_INET, res, ip, 16) ? -1 : 0;
}
}
int main() {
char ip[16];
getLocalHostIp(ip);
printf("%s", ip);
}
\ No newline at end of file
......@@ -3,7 +3,7 @@
## Quickstart
```c
#include "ccat/client.h"
#include "client.h"
void test() {
/**
......@@ -29,8 +29,8 @@ void test() {
CatTransaction *t3 = newTransaction("foo", "bar3");
t3->setStatus(t3, CAT_SUCCESS);
/**
* Upon you complete the transaction.
* The transaction will be popped from the stack and the duration will be set.
* Once you complete the transaction.
* The transaction will be popped from the stack and the duration will be calculated.
*/
t3->complete(t3);
......@@ -42,7 +42,7 @@ void test() {
CatTransaction *t4 = newTransactionWithDuration("foo", "bar4-with-duration", 1000);
snprintf(buf, 9, "bar%d", k);
/**
* Log a event, append the event to the children of current transaction.
* Log an event, it will be added to the children list of the current transaction.
*/
logEvent("foo", buf, CAT_SUCCESS, NULL);
t4->setStatus(t4, CAT_SUCCESS);
......@@ -51,8 +51,9 @@ void test() {
t1->setStatus(t1, CAT_SUCCESS);
/**
* When the last element of stack is popped.
* A message tree will be generated and sent to server.
* Complete the transaction and poped it from the stack.
* When the last element of the stack is popped.
* The message tree will be encoded and sent to server.
*/
t1->complete(t1);
}
......@@ -67,7 +68,6 @@ int main(int argc, char **argv) {
catClientDestroy();
return 0;
}
```
## API list
......@@ -76,7 +76,7 @@ int main(int argc, char **argv) {
#### catClientInit
initialize cat client by default configs.
initialize `ccat` by default configs.
```c
int catClientInit(const char *appkey);
......@@ -88,15 +88,17 @@ This is equivalent to the following codes.
return catClientInitWithConfig(appkey, &DEFAULT_CCAT_CONFIG);
```
* `binary` encoder
* built-in `heartbeat` enabled
* `sampling` enabled
* `multi process mode` disabled
* `debug log` disabled
With following configs:
* `encoderType` = CAT_ENCODER_BINARY.
* `enableHeartbeat` is true.
* `enableSampling` is true.
* `enableMultiprocessing` is false.
* `enableDebugLog` is false.
#### catClientInitWithConfig
You may want to customize the cat client in some cases.
You may want to customize the `ccat` in some cases.
```c
CatClientConfig config = DEFAULT_CCAT_CONFIG;
......@@ -107,7 +109,7 @@ catClientInitWithConfig("ccat", &config);
#### catClientDestroy
Disable the cat client, shutdown `sender`, `monitor` and `aggregator` threads.
Disable the `ccat`, shutdown `sender`, `monitor` and `aggregator` threads.
Also release all the resources that have been used.
......@@ -117,7 +119,7 @@ int catClientDestroy();
#### isCatEnabled
Represent if cat client is initialized.
Represent if `ccat` has been initialized.
```c
int isCatEnabled();
......@@ -125,27 +127,7 @@ int isCatEnabled();
### Transaction
A message has the following properties.
* `type` usually means a category of event, for example, `SQL`, `RPC`, `HTTP-GET` may be recommended types.
* `name` usually means a specified action.
* When the type is `SQL`, the name may be `select <?> from user where user_id = <?>`
* When the type is `RPC`, the name may be `queryOrderByUserId`
* when the type is `HTTP-GET`, the name may be `/api/v2/order/<int>`
* while `status` is not equal to `CAT_SUCCESS` (which is "0"), the message will be treated as a `problem`, and can be recorded in our problem report.
* `data` is used for storing some useful infomation.
* When the type is `SQL`, the data may like `user_id=194432&token=a94238`
* When the type is `RPC`, the data may like `order_id=11314152`
* `timestamp` represents the time when the message has been created, which will be shown on our log view page.
Though transaction is inherited from a message, it also has the foregoing properties.
And there are some transaction-only properties:
* `duration` means the time costs of a transaction.
* `durationStart` means the start time of a transaction.
> Note the `durationStart` may not as same as `timestamp`, they have different meanings.
You can find more information about the properties of a transaction in [Message properties](../../README.md#message-properties)
#### newTransaction
......@@ -155,7 +137,7 @@ Create a transaction.
CatTransaction *newTransaction(const char *type, const char *name);
```
We hid the properties of a transaction (due to safety reasons), but we offered a list of APIs to help you update them.
We hide the properties of a transaction (due to safety reasons), but we offered a list of APIs to help you to edit them.
* addData
* addKV
......@@ -166,7 +148,7 @@ We hid the properties of a transaction (due to safety reasons), but we offered a
* setDurationInMillis
* setDurationStart
They can be easily used, for example:
These can be easily used, for example:
```c
CatTransaction *t = newTransaction("Test1", "A");
......@@ -183,20 +165,16 @@ t->complete(t);
There is something you may want to know:
1. Duration of a transaction will be calculated while you complete the transaction. (currentTimestamp - durationStart)
1. Although `durationStart` is as same as `timestamp`, you can overwrite it.
2. `durationStart` and `timestamp` are different, the first one represents the start time of a transaction, and the second one only means created time of a message. (Transaction is one kind of message)
1. `durationStart` won't work when you specified the `duration`.
2. You can call `addData` and `addKV` several times, the added data will be connected by `&`.
> Don't forget to complete the transaction after you new it! Or you will get corrupted message trees and memory leaks!
2. It's meaningless to specify `duration` and `durationStart` in the same transaction, although we do it in the example :)
3. Never forget to complete the transaction! Or you will get corrupted message trees and memory leaks!
#### newTransactionWithDuration
Create a transaction with a specified duration in milliseconds.
Due to duration has been specified, it won't be overwritten after the transaction has been completed.
Due to `duration` has been specified, it won't be recalculated after the transaction has been completed.
> Note that the transaction has not been completed, so you have to complete it manually.
> Note that the transaction has not been completed! So it is necessary to complete it manually.
```c
CatTransaction *newTransactionWithDuration(const char *type, const char *name, unsigned long long duration);
......@@ -210,17 +188,17 @@ t->setDurationInMillis(t4, duration);
return t;
```
> Don't forget to complete the transaction.
> Once again, don't forget to complete the transaction!
#### newCompletedTransactionWithDuration
Log a transaction with a specified duration in milliseconds.
Log a transaction with a specified duration in milliseconds and complete it.
Due to the transaction has been auto-completed, the `durationStart` and the `timestamp` will be turned back.
Due to the transaction has been auto-completed, the `timestamp` will be turned back.
> Note that the specified duration should be less than 60,000 milliseconds.
>
> Or we won't turn back the start and created time.
> Or we won't turn back the timestamp.
```c
int duration = 1000;
......@@ -237,7 +215,6 @@ CatTransaction *t = newTransaction("type", "name");
t->setDurationInMillis(t, duration);
if (duration < 60000) {
t->setTimestamp(t, GetTime64() - duration);
t->setDurationStart(t, GetTime64() - duration);
}
t->complete(t);
return;
......@@ -285,8 +262,6 @@ CatEvent *newEvent(const char *type, const char *name);
#### logMetricForCount
log a count metric.
```c
void logMetricForCount(const char *name, int quantity);
```
......@@ -301,7 +276,7 @@ For example, if you called this API 3 times in one second (can be in different t
void logMetricForDuration(const char *name, unsigned long long duration);
```
Like `logMetricForCount`, the values reported in one second will be aggregated, the only difference is we reported `averaged` value instead of `summarized` value.
Like `logMetricForCount`, the metrics reported in the same second will be aggregated, the only difference is `averaged` value is used instead of `summarized` value.
### Heartbeat
......@@ -309,7 +284,7 @@ Like `logMetricForCount`, the values reported in one second will be aggregated,
Create a heartbeat.
> Heartbeat is reported by cat client automatically,
> Heartbeat is reported by ccat automatically,
> so you don't have to use this API in most cases,
> unless you want to overwrite our heartbeat message.
>
......
# cat c client
## 快速起步
```c
#include "client.h"
void test() {
/**
* 如果当前的栈为空,一个消息树会被创建
*/
CatTransaction *t1 = newTransaction("foo", "bar1");
/**
* Metric 可以在任何地方记录,并不会被加到消息树中
*/
logMetricForCount("metric-count", 1);
logMetricForDuration("metric-duration", 200);
/**
* 记录一个给定耗时的 transaction 并立刻完成它。
*/
newCompletedTransactionWithDuration("foo", "bar2-completed", 1000);
/**
* Transaction can be nested.
* Transaction 可以嵌套,最新的 transaction 会被推到栈顶
*/
CatTransaction *t3 = newTransaction("foo", "bar3");
t3->setStatus(t3, CAT_SUCCESS);
/**
* 当你完成一个 transaction 的时候,它会被从栈里面弹出,并且 duration 会被计算。
*/
t3->complete(t3);
char buf[10];
for (int k = 0; k < 3; k++) {
/**
* 创建一个给定耗时的 transaction
*/
CatTransaction *t4 = newTransactionWithDuration("foo", "bar4-with-duration", 1000);
snprintf(buf, 9, "bar%d", k);
/**
* 记录一个 event,会被添加到当前 transaction 的儿子列表中
*/
logEvent("foo", buf, CAT_SUCCESS, NULL);
t4->setStatus(t4, CAT_SUCCESS);
t4->complete(t4);
}
t1->setStatus(t1, CAT_SUCCESS);
/**
* 完成 transaction 并将它从栈里弹出
* 当最后一个元素被弹出时,消息树会被序列化并发送给服务端
*/
t1->complete(t1);
}
int main(int argc, char **argv) {
CatClientConfig config = DEFAULT_CCAT_CONFIG;
config.enableHeartbeat = 0;
config.enableDebugLog = 1;
catClientInitWithConfig("ccat", &config);
test();
Sleep(3000);
catClientDestroy();
return 0;
}
```
## API list
### Common apis
#### catClientInit
使用默认参数初始化 `ccat`
```c
int catClientInit(const char *appkey);
```
等价于下述代码。
```c
return catClientInitWithConfig(appkey, &DEFAULT_CCAT_CONFIG);
```
采用如下配置:
* `encoderType` = CAT_ENCODER_BINARY.
* `enableHeartbeat` is true.
* `enableSampling` is true.
* `enableMultiprocessing` is false.
* `enableDebugLog` is false.
#### catClientInitWithConfig
有时你会想要自定义 `ccat`
```c
CatClientConfig config = DEFAULT_CCAT_CONFIG;
config.enableHeartbeat = 0;
config.enableDebugLog = 1;
catClientInitWithConfig("ccat", &config);
```
#### catClientDestroy
禁用 `ccat`,退出**sender****monitor**,和**aggregator** 线程。
释放所有已申请的资源。
```c
int catClientDestroy();
```
#### isCatEnabled
表示 `ccat` 是否已经被初始化。
Represent if cat client is initialized.
```c
int isCatEnabled();
```
### Transaction
你可以在[消息属性](../../_/zh-CN.md#消息属性)中了解 transaction 的属性信息。
#### newTransaction
创建一个 Transaction
```c
CatTransaction *newTransaction(const char *type, const char *name);
```
由于安全原因,我们隐藏了 transaction 的属性,但我们提供了一系列 API 可供你修改它们。
* addData
* addKV
* setStatus
* setTimestamp
* complete
* addChild
* setDurationInMillis
* setDurationStart
他们用起来很简单,就像这样:
```c
CatTransaction *t = newTransaction("Test1", "A");
t->setStatus(t, CAT_SUCCESS);
t->setTimestamp(t, GetTime64() - 5000);
t->setDurationStart(t, GetTime64() - 5000);
t->setDurationInMillis(t, 4200);
t->addData(t, "data");
t->addKV(t, "k1", "v1");
t->addKV(t, "k2", "v2");
t->complete(t);
```
There is something you may want to know:
这里有一些你可能想要知道的:
1. 你可以调用 `addData``addKV` 多次,他们会被 `&` 连接起来。
2. 同时指定 `duration``durationStart` 是没有意义的,尽管我们在样例中这样做了。
3. 不要忘记完成 transaction!否则你会得到一个毁坏的消息树以及内存泄漏!
#### newTransactionWithDuration
创建一个给定耗时(毫秒)的 transaction
鉴于 `duration` 已经被指定了,它不会在 transaction 完成时被重算。
> 注意 transaction 并没有被完成!所以你还需要手动完成它。
```c
CatTransaction *newTransactionWithDuration(const char *type, const char *name, unsigned long long duration);
```
这和下面的代码是等价的:
```
CatTransaction *t = newTransaction("type", "name");
t->setDurationInMillis(t4, duration);
return t;
```
> 强调一遍,不要忘记完成 transaction!
#### newCompletedTransactionWithDuration
记录一个给定耗时(毫秒)的 transaction 并完成它。
鉴于 transaction 已经被自动完成了,`timestamp` 会被拨回。
> 注意我们只会在给定的耗时小于 60,000 毫秒时才会拨回 `timestamp`
```c
int duration = 1000;
newCompletedTransactionWithDuration("type", "name", duration);
```
这和下面的代码是等价的:
```c
// return current timestamp in milliseconds.
unsigned long GetTime64();
CatTransaction *t = newTransaction("type", "name");
t->setDurationInMillis(t, duration);
if (duration < 60000) {
t->setTimestamp(t, GetTime64() - duration);
}
t->complete(t);
return;
```
### Event
Event 是一个简化版的 Transaction,没有耗时。
#### logEvent
记录一个 Event。
```c
void logEvent(const char *type, const char *name, const char *status, const char *data);
```
#### logError
记录一个 Error。
```c
void logError(const char *msg, const char *errStr);
```
这和下面的代码是等价的:
```c
logEvent("Exception", msg, CAT_ERROR, errStr);
```
#### newEvent
创建一个 Event。
通常情况下你不需要用这个 API,除非你确实需要。
使用 logEvent / logError 是更好的选择。
```c
CatEvent *newEvent(const char *type, const char *name);
```
### Metric
#### logMetricForCount
```c
void logMetricForCount(const char *name, int quantity);
```
指标会每秒上报一次。
举例来说,如果你在同一秒内调用这个 API 三次(可以在不同的线程,我们使用线程安全的 map 来缓存指标的值),只有聚合后的值(求和)会被上报到服务端。
#### logMetricForDuration
```c
void logMetricForDuration(const char *name, unsigned long long duration);
```
就像 `logMetricForCount` 一样,同一秒上报的指标会被聚合,唯一的区别是这里使用平均值取代求和。
### Heartbeat
#### newHeartBeat
创建一个 Heartbeat。
> 心跳会被 ccat 自动上报,
> 因此大多数情况下你不需要使用这个 API,
> 除非你想覆盖我们的心跳信息。
>
> 当你这么做时,不要忘记禁用我们的内置心跳信息。
# Cat Client for C
`ccat` 同时支持 linux (glibc 和 musl-libc) 和 osx 两个平台。
下述列出的操作系统是经过测试可用的:
* OSX (>=10.13)
* Alpine linux
* CentOS 6
* CentOS 7
* Ubuntu 14.04 LTS
* Ubuntu 16.04 LTS
* Ubuntu 18.04 LTS
我们也提供了 c++ 版本的客户端,参考 [cppcat](../../cpp/docs/zh-CN.md)
## 编译
你需要安装一个支持 C99 的 C 编译器。
你同时还需要安装 `cmake``make`,这是我们用来构建动态或静态链接库以及可执行文件的工具。
当你准备好你的环境之后,编译安装 `ccat` 就很容易了。
(在项目根目录下,就包含 CMakeList.txt 的那个)
```
mkdir -p cmake
cd cmake
make -j 4
```
### 安装
下面的命令将会把 `libcatclient.so`(或者在 osx 下是 .dylib)安装到你的 `LD_LIBRARY_PATH` 目录下,大多数情况下是 `/usr/local/lib`
```
make install
```
然后你就可以像使用一个内置动态库一样使用 `ccat` 了。
```
gcc -lcatclient x.c
```
## 初始化
一些[准备工作](../_/preparations.zh-CN.md)需要在初始化 `ccat` 之前完成。
当你完成这些准备工作后,在你的 c 代码中初始化 `ccat` 就很简单了。
```c
#include <client.h>
catClientInit("appkey");
```
> appkey 只能包含英文字母 (a-z, A-Z)、数字 (0-9)、下划线 (\_) 和中划线 (-)
注意,**采样**,内置**心跳****二进制**序列化在默认情况下是开启的,你可能会想要禁用他们。我们同时提供了一个 API 可以使你自定义启动参数,请参考 [API 文档](./docs/api.zh-CN.md)
## Documentation
[API 文档](./api.zh-CN.md)
......@@ -140,6 +140,8 @@ CAT_CLIENT_EXPORT int catClientInitWithConfig(const char *appkey, CatClientConfi
CAT_CLIENT_EXPORT int catClientDestroy();
CAT_CLIENT_EXPORT const char* catVersion();
CAT_CLIENT_EXPORT int isCatEnabled();
/**
......
......@@ -2,6 +2,10 @@
// Created by Terence on 2018/8/23.
//
/**
* NOTE it is only a proposal, interfaces defined here has not been implemented.
*/
#ifndef CCAT_HELPER_H
#define CCAT_HELPER_H
......
#include <stdio.h>
#include "ccat/client.h"
#include "client.h"
#include "lib/cat_time_util.h"
......@@ -31,8 +31,8 @@ void test() {
CatTransaction *t3 = newTransaction("foo", "bar3");
t3->setStatus(t3, CAT_SUCCESS);
/**
* Upon you complete the transaction.
* The transaction will be popped from the stack and the duration will be set.
* Once you complete the transaction.
* The transaction will be popped from the stack and the duration will be calculated.
*/
t3->complete(t3);
......@@ -44,7 +44,7 @@ void test() {
CatTransaction *t4 = newTransactionWithDuration("foo", "bar4-with-duration", 1000);
snprintf(buf, 9, "bar%d", k);
/**
* Log a event, append the event to the children of current transaction.
* Log an event, it will be added to the children list of the current transaction.
*/
logEvent("foo", buf, CAT_SUCCESS, NULL);
t4->setStatus(t4, CAT_SUCCESS);
......@@ -53,8 +53,9 @@ void test() {
t1->setStatus(t1, CAT_SUCCESS);
/**
* When the last element of stack is popped.
* A message tree will be generated and sent to server.
* Complete the transaction and poped it from the stack.
* When the last element of the stack is popped.
* The message tree will be encoded and sent to server.
*/
t1->complete(t1);
}
......@@ -91,9 +92,9 @@ int main(int argc, char **argv) {
CatClientConfig config = DEFAULT_CCAT_CONFIG;
config.enableHeartbeat = 0;
config.enableDebugLog = 1;
catClientInitWithConfig("nodecat", &config);
test2();
Sleep(5000);
catClientInitWithConfig("ccat", &config);
test();
Sleep(3000);
catClientDestroy();
return 0;
}
#include "ccat/client.h"
#include "client.h"
#include <lib/cat_clog.h>
#include <lib/cat_time_util.h>
#include <ccat/version.h>
#include "client_config.h"
#include "context.h"
......@@ -95,6 +96,10 @@ int catClientDestroy() {
return 1;
}
const char* catVersion() {
return CCAT_VERSION;
}
void logError(const char *msg, const char *errStr) {
getContextMessageTree()->canDiscard = 0;
logEvent("Exception", msg, CAT_ERROR, errStr);
......
#ifndef CAT_CLIENT_C_CLIENT_CONFIG_H
#define CAT_CLIENT_C_CLIENT_CONFIG_H
#include "ccat/client.h"
#include "client.h"
#include "lib/cat_sds.h"
......
......@@ -8,7 +8,7 @@
#include <string.h>
#include <stdlib.h>
#include "ccat/client.h"
#include "client.h"
#include "ccat/message_helper.h"
#include "lib/cat_sds.h"
......
......@@ -5,7 +5,7 @@
#ifndef CCAT_MESSAGE_AGGREGATOR_EVENT_H
#define CCAT_MESSAGE_AGGREGATOR_EVENT_H
#include <ccat/client.h>
#include <client.h>
void addEventToAggregator(CatEvent * pEvent);
......
......@@ -5,7 +5,7 @@
#ifndef CCAT_MESSAGE_AGGREGATOR_TRANS_H
#define CCAT_MESSAGE_AGGREGATOR_TRANS_H
#include <ccat/client.h>
#include <client.h>
void addTransToAggregator(CatTransaction *pEvent);
......
#ifndef CAT_CLIENT_C_MESSAGE_TREE_H
#define CAT_CLIENT_C_MESSAGE_TREE_H
#include "ccat/client.h"
#include "client.h"
#include "lib/cat_sds.h"
......
......@@ -5,6 +5,7 @@
#include "ccat/message_manager.h"
#include "ccat/monitor_collector.h"
#include "ccat/server_connection_manager.h"
#include "ccat/version.h"
#include "lib/cat_thread.h"
#include "lib/cat_time_util.h"
......@@ -43,7 +44,7 @@ static PTHREAD catMonitorFun(PVOID para) {
if (runCount % 60 == 1 && g_config.enableHeartbeat) {
// Report ccat version.
logEvent("Cat_C_Client_Version", Cat_C_Client_Version, CAT_SUCCESS, NULL);
logEvent("Cat_C_Client_Version", CCAT_VERSION, CAT_SUCCESS, NULL);
// Report vm / runtime version. (For other programming language which using ccat mixin to report heartbeat)
if (strcmp(g_client_info.language, "C") != 0) {
......
#ifndef CAT_CLIENT_C_MONITOR_H
#define CAT_CLIENT_C_MONITOR_H
#define Cat_C_Client_Version "2.1.0"
#include "lib/cat_sds.h"
typedef struct {
......
......@@ -3,7 +3,7 @@
//
#include "monitor_collector.h"
#include "ccat/client.h"
#include "client.h"
void inline add_detail(ezxml_t ext, const char *key, const char *val, int *index) {
......
//
// Created by Terence on 2018/8/2.
//
......@@ -368,7 +368,7 @@ static int anetCreateSocket(char *err, int domain) {
return ANET_ERR;
}
/* Make sure connection-intensive things like the redis benchmark
/* Make sure connection-intensive things like the redis scripts
* will be able to close/open sockets a zillion of times */
if (anetSetReuseAddr(err, s) == ANET_ERR) {
close(s);
......
#ifndef _CCAT_VERSION_H_
#define _CCAT_VERSION_H_ 1
#define CCAT_VERSION "@CCAT_VERSION@"
#endif // _CCAT_VERSION_H_
\ No newline at end of file
cmake_minimum_required(VERSION 2.4)
project(cppcat)
set(CPPCAT_VERSION 3.0.0)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/ccat/version.h)
message(STATUS "Current OS: " ${CMAKE_SYSTEM_NAME})
macro(use_cxx11)
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()
endmacro(use_cxx11)
macro(add_definitions_c def)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${def}")
endmacro()
macro(add_cxx_flags def)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${def}")
endmacro()
use_cxx11()
# set(BUILD_TEST 1)
# set(BUILD_SCRIPT 1)
add_definitions("-Wno-format-security")
# add_definitions_c("-Wno-incompatible-pointer-types")
if (APPLE)
add_definitions_c("-Wno-ignored-qualifiers")
else()
add_definitions_c("-Wno-discarded-qualifiers")
endif()
include_directories(include)
include_directories(src)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/include)
include_directories(../c/include)
aux_source_directory(src/lib SOURCE_FILES)
aux_source_directory(src/ccat SOURCE_FILES)
aux_source_directory(src/cppcat SOURCE_FILES)
if (APPLE)
elseif(UNIX)
link_libraries(m)
link_libraries(rt)
link_libraries(pthread)
endif()
set(HEADER_FILES include/client.hpp)
add_library(catclient SHARED ${HEADER_FILES} ${SOURCE_FILES})
install(TARGETS catclient DESTINATION lib)
if (BUILD_TEST)
link_libraries(gtest)
file(
COPY
tests/client.xml
tests/client.json
DESTINATION cat
)
aux_source_directory(tests/unit UNITTEST_FILES)
add_executable(unittest tests/unittest.cpp ${UNITTEST_FILES} ${SOURCE_FILES})
endif()
if (BUILD_SCRIPT)
add_executable(test_client ${SOURCE_FILES} scripts/cat_client_test.cpp)
add_executable(test_mpsc ${SOURCE_FILES} scripts/cat_mpsc_test.cpp)
endif()
# Cat Client for C++
[中文文档](./docs/zh-CN.md)
The cat client can be compiled and used both on Linux (both glibc and musl-libc) and OSX.
The following Operating Systems are tested:
* OSX (>=10.13)
* Alpine linux
* CentOS 6
* CentOS 7
* Ubuntu 14.04 LTS
* Ubuntu 16.04 LTS
* Ubuntu 18.04 LTS
## Compilation
You need to have a C++ compiler (supporting C++11) installed.
You also need to have `cmake` and `make` installed, which we use for building static or dynamic libraries and executable binary files.
Once you have your environment ready, it's easy to build and install `cppcat`.
(In the project root dir, which contains CMakeLists.txt)
```
mkdir -p cmake
cd cmake
make -j 4
```
Build test cases if you want.
Since we using [googletest](https://github.com/google/googletest) as the test framework, it has to be installed first.
```
make -j 4 -DBUILD_TEST=1
```
### Installation
The following command will install libcatclient.so (or .dylib in osx) to your `LD_LIBRARY_PATH`, which is `/usr/local/lib` in most cases.
```
make install
```
Now it can be used as a built-in shared library.
```
g++ -lcatclient x.cpp
```
## Initialization
Some [preparations](../_/preparations.md) needs to be done before initialize `cppcat`.
With all the preparations have been done, it's easy to initialize `cppcat` in your c++ codes.
```cpp
#include <client.h>
cat::init("appkey");
```
> Only English characters (a-z, A-Z), numbers (0-9), underscore (\_) and dash (-) is allowed in appkey.
Note that `sampling`, built-in `heartbeat` and `binary` encoder is enabled by default, which you may want to disable it. We also offered an API to customize your initialization, please refer to our [apidoc](./docs/api.md).
## Documentation
[API doc](./docs/api.md)
......@@ -64,13 +64,13 @@ int main() {
## API list
All the cpp cat client apis are in the `cat` namespace.
All the `cppcat` apis are in the `cat` namespace.
### Common apis
#### cat::init
initialize cat client by default configs.
initialize `cppcat` by default configs.
```c
void init(const string& domain);
......@@ -78,11 +78,11 @@ void init(const string& domain);
Following config is used by default.
* `binary` encoder
* built-in `heartbeat` enabled
* `sampling` enabled
* `multi process mode` disabled
* `debug log` disabled
* `encoderType` = CAT_ENCODER_BINARY.
* `enableHeartbeat` is true.
* `enableSampling` is true.
* `enableMultiprocessing` is false.
* `enableDebugLog` is false.
You can also customize config. (Like to use text encoder instead of binary encoder)
......@@ -105,37 +105,17 @@ void destroy();
### Transaction
A message has the following properties.
* `type` usually means a category of event, for example, `SQL`, `RPC`, `HTTP-GET` may be recommended types.
* `name` usually means a specified action.
* When the type is `SQL`, the name may be `select <?> from user where user_id = <?>`
* When the type is `RPC`, the name may be `queryOrderByUserId`
* when the type is `HTTP-GET`, the name may be `/api/v2/order/<int>`
* while `status` is not equal to `CAT_SUCCESS` (which is "0"), the message will be treated as a `problem`, and can be recorded in our problem report.
* `data` is used for storing some useful infomation.
* When the type is `SQL`, the data may like `user_id=194432&token=a94238`
* When the type is `RPC`, the data may like `order_id=11314152`
* `timestamp` represents the time when the message has been created, which will be shown on our log view page.
Though transaction is inherited from a message, it also has the foregoing properties.
And there are some transaction-only properties:
* `duration` means the time costs of a transaction.
* `durationStart` means the start time of a transaction.
> Note the `durationStart` may not as same as `timestamp`, they have different meanings.
You can find more information about the properties of a transaction in [Message properties](../../README.md#message-properties)
#### cat::Transaction
Transaction can be easily created
Transaction can be easily created.
```cpp
cat::Transaction t("type", "name");
```
Due to the properties of a transaction were mostly private, we offered a list of APIs to help you update them.
Due to the properties of a transaction were mostly private, we offered a list of APIs to help you to edit them.
* AddData
* SetStatus
......@@ -161,12 +141,8 @@ t.Complete();
There is something you may want to know:
1. Duration of a transaction will be calculated while you complete the transaction. (currentTimestamp - durationStart)
1. Although `durationStart` is as same as `timestamp`, you can overwrite it.
2. `durationStart` and `timestamp` are different, the first one represents the start time of a transaction, and the second one only means created time of a message. (Transaction is one kind of message)
1. `durationStart` won't work when you specified the `duration`.
2. You can call `addData` several times, the added data will be connected by `&`.
> Don't forget to complete the transaction after you new it! Or you will get corrupted message trees and memory leaks!
2. It's meaningless to specify `duration` and `durationStart` in the same transaction, although we do it in the example :)
3. Never forget to complete the transaction! Or you will get corrupted message trees and memory leaks!
### Event
......@@ -200,4 +176,4 @@ For example, if you called this API 3 times in one second (can be in different t
void logMetricForDuration(const string& key, unsigned long ms);
```
Like `logMetricForCount`, the values reported in one second will be aggregated, the only difference is we reported `averaged` value instead of `summarized` value.
Like `logMetricForCount`, the metrics reported in the same second will be aggregated, the only difference is `averaged` value is used instead of `summarized` value.
# cat c++ client
## Quickstart
```cpp
#include <iostream>
#include <unistd.h>
#include "cppcat/client.h"
using namespace std;
unsigned long long GetTime64() {
return static_cast<unsigned long long int>(std::chrono::system_clock::now().time_since_epoch().count() / 1000);
}
void transaction() {
cat::Transaction t("foo", "bar");
t.AddData("foo", "1");
t.AddData("bar", "2");
t.AddData("foo is a bar");
t.SetDurationStart(GetTime64() - 1000);
t.SetTimestamp(GetTime64() - 1000);
t.SetDurationInMillis(150);
t.SetStatus(cat::FAIL);
t.Complete();
}
void event() {
cat::Event e("foo", "bar");
e.AddData("foo", "1");
e.AddData("bar", "2");
e.AddData("foo is a bar");
e.SetStatus(cat::SUCCESS);
e.Complete();
cat::logEvent("foo", "bar1");
cat::logEvent("foo", "bar2", "failed");
cat::logEvent("foo", "bar3", "failed", "k=v");
}
void metric() {
cat::logMetricForCount("count");
cat::logMetricForCount("count", 3);
cat::logMetricForDuration("duration", 100);
}
int main() {
cat::Config c = cat::Config();
c.enableDebugLog = true;
c.encoderType = cat::ENCODER_TEXT;
cat::init("cppcat", c);
for (int i = 0; i < 100; i++) {
transaction();
event();
metric();
usleep(10000);
}
usleep(1000000);
cat::destroy();
}
```
## API list
所有的 `cppcat` API 都在 `cat` 这个命名空间下。
### Common apis
#### cat::init
使用默认配置初始化 `cppcat`
```c
void init(const string& domain);
```
默认采用如下配置:
* `encoderType` = CAT_ENCODER_BINARY.
* `enableHeartbeat` is true.
* `enableSampling` is true.
* `enableMultiprocessing` is false.
* `enableDebugLog` is false.
你也可以自定义配置(比如使用文本序列化取代二进制序列化)
```cpp
cat::Config c = cat::Config();
c.enableDebugLog = true;
c.encoderType = cat::ENCODER_TEXT;
cat::init("cppcat", c);
```
#### cat::destory
禁用 `cppcat`,退出**sender****monitor**,和**aggregator** 线程。
释放所有已申请的资源。
```cpp
void destroy();
```
### Transaction
你可以在[消息属性](../../_/zh-CN.md#消息属性)中了解 transaction 的属性信息。
#### cat::Transaction
Transaction 可以很方便的被创建。
```cpp
cat::Transaction t("type", "name");
```
由于大多数的 transaction 属性都是私有的,我们提供了一系列 API 可供你修改它们。
* AddData
* SetStatus
* SetDurationStart
* SetDurationInMillis
* SetTimestamp
* Complete
他们用起来很简单,就像这样:
```cpp
cat::Transaction t("foo", "bar");
t.AddData("foo", "1");
t.AddData("bar", "2");
t.AddData("foo is a bar");
t.SetDurationStart(GetTime64() - 1000);
t.SetTimestamp(GetTime64() - 1000);
t.SetDurationInMillis(150);
t.SetStatus(cat::FAIL);
t.Complete();
```
这里有一些你可能想要知道的:
1. 你可以调用 `addData``addKV` 多次,他们会被 `&` 连接起来。
2. 同时指定 `duration``durationStart` 是没有意义的,尽管我们在样例中这样做了。
3. 不要忘记完成 transaction!否则你会得到一个毁坏的消息树以及内存泄漏!
### Event
Event 是一个简化版的 Transaction,没有耗时。
#### cat::logEvent
记录一个 Event。
```cpp
void logEvent(const string& type, const string& name, const string& status = SUCCESS, const string& data = "");
```
### Metric
#### logMetricForCount
```cpp
void logMetricForCount(const string& key, unsigned int count = 1);
```
指标会每秒上报一次。
举例来说,如果你在同一秒内调用这个 API 三次(可以在不同的线程,我们使用线程安全的 map 来缓存指标的值),只有聚合后的值(求和)会被上报到服务端。
#### logMetricForDuration
```cpp
void logMetricForDuration(const string& key, unsigned long ms);
```
就像 `logMetricForCount` 一样,同一秒上报的指标会被聚合,唯一的区别是这里使用平均值取代求和。
# Cat Client for C++
`cppcat` 同时支持 linux (glibc 和 musl-libc) 和 osx 两个平台。
下述列出的操作系统是经过测试可用的:
* OSX (>=10.13)
* Alpine linux
* CentOS 6
* CentOS 7
* Ubuntu 14.04 LTS
* Ubuntu 16.04 LTS
* Ubuntu 18.04 LTS
## 编译
你需要安装一个支持 C++11 的 C++ 编译器。
你同时还需要安装 `cmake``make`,这是我们用来构建动态或静态链接库以及可执行文件的工具。
当你准备好你的环境之后,编译安装 `cppcat` 就很容易了。
(在项目根目录下,就包含 CMakeList.txt 的那个)
```
mkdir -p cmake
cd cmake
make -j 4
```
你也可以尝试构建我们的测试用例。
由于我们使用了 [googletest](https://github.com/google/googletest) 作为我们的测试框架,你需要先安装它。
### 安装
下面的命令将会把 `libcatclient.so`(或者在 osx 下是 .dylib)安装到你的 `LD_LIBRARY_PATH` 目录下,大多数情况下是 `/usr/local/lib`
```
make install
```
然后你就可以像使用一个内置动态库一样使用 `cppcat` 了。
```
gcc -lcatclient x.cpp
```
## 初始化
一些[准备工作](../../_/preparations.zh-CN.md)需要在初始化 `cppcat` 之前完成。
当你完成这些准备工作后,在你的 c++ 代码中初始化 `cppcat` 就很简单了。
```c
#include <client.h>
cat::init("appkey");
```
> appkey 只能包含英文字母 (a-z, A-Z)、数字 (0-9)、下划线 (\_) 和中划线 (-)
注意,**采样**,内置**心跳****二进制**序列化在默认情况下是开启的,你可能会想要禁用他们。我们同时提供了一个 API 可以使你自定义启动参数,请参考 [API 文档](./api.zh-CN.md)
## Documentation
[API 文档](./api.zh-CN.md)
......@@ -2,8 +2,8 @@
// Created by Terence on 2018/8/2.
//
#ifndef CCAT_CLIENT_H
#define CCAT_CLIENT_H
#ifndef CPPCAT_CLIENT_H
#define CPPCAT_CLIENT_H
#include <string>
......@@ -83,6 +83,8 @@ namespace cat {
void init(const string& domain, const Config& config);
string version();
void destroy();
void logEvent(const string& type, const string& name, const string& status = SUCCESS, const string& data = "");
......@@ -92,4 +94,4 @@ namespace cat {
void logMetricForDuration(const string& key, unsigned long ms);
};
#endif //CCAT_CLIENT_H
#endif // CPPCAT_CLIENT_H
......@@ -5,7 +5,7 @@
#include <iostream>
#include <unistd.h>
#include "cppcat/client.h"
#include "client.hpp"
using namespace std;
......@@ -45,9 +45,10 @@ void metric() {
}
int main() {
cout << "cppcat version: " << cat::version() << endl;
cat::Config c = cat::Config();
c.enableDebugLog = true;
c.encoderType = cat::ENCODER_TEXT;
c.encoderType = cat::ENCODER_BINARY;
cat::init("cppcat", c);
for (int i = 0; i < 100; i++) {
......
../../c/src/ccat
\ No newline at end of file
......@@ -2,9 +2,10 @@
// Created by Terence on 2018/8/2.
//
#include "cppcat/client.h"
#include "client.hpp"
#include <ccat/client.h>
#include <client.h>
#include <ccat/version.h>
using namespace std;
......@@ -23,6 +24,10 @@ namespace cat {
catClientInitWithConfig(domain.c_str(), &conf);
}
string version() {
return string(CPPCAT_VERSION);
}
void destroy() {
catClientDestroy();
}
......
......@@ -2,11 +2,9 @@
// Created by Terence on 2018/8/2.
//
#include <string>
#include <ccat/client.h>
#include <ccat/message.h>
#include "client.hpp"
#include "cppcat/client.h"
#include <ccat/message.h>
#define E(e) ((CatEvent*)(e))
......
......@@ -2,10 +2,9 @@
// Created by Terence on 2018/8/2.
//
#include <string>
#include <ccat/client.h>
#include "client.hpp"
#include "cppcat/client.h"
#include <client.h>
using namespace std;
......
......@@ -2,11 +2,9 @@
// Created by Terence on 2018/8/2.
//
#include <string>
#include <ccat/client.h>
#include <ccat/message.h>
#include "client.hpp"
#include "cppcat/client.h"
#include <ccat/message.h>
using namespace std;
......
../../c/src/lib
\ No newline at end of file
#ifndef _CCAT_VERSION_H_
#define _CCAT_VERSION_H_ 1
#define CCAT_VERSION "@CPPCAT_VERSION@"
#endif // _CCAT_VERSION_H_
#ifndef _CPPCAT_VERSION_H_
#define _CPPCAT_VERSION_H_ 1
#define CPPCAT_VERSION "@CPPCAT_VERSION@"
#endif // _CPPCAT_VERSION_H_
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册