diff --git a/lib/README.md b/lib/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..8fbbd220e3ab95fe0330c98567f642bc51a8716e
--- /dev/null
+++ b/lib/README.md
@@ -0,0 +1,84 @@
+# 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`.
diff --git a/lib/_/preparations.md b/lib/_/preparations.md
new file mode 100644
index 0000000000000000000000000000000000000000..96ad5dd82a5a7db3b845179a2e644cef91c39230
--- /dev/null
+++ b/lib/_/preparations.md
@@ -0,0 +1,22 @@
+# 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
+
+
+
+
+
+
+ ```
+
+ > Don't forget to change the **\** to your server ip address.
diff --git a/lib/_/preparations.zh-CN.md b/lib/_/preparations.zh-CN.md
new file mode 100644
index 0000000000000000000000000000000000000000..d4094f5409e6c482605d6ef1c9f00e53e03daeea
--- /dev/null
+++ b/lib/_/preparations.zh-CN.md
@@ -0,0 +1,22 @@
+# 启动 cat 客户端前的准备工作
+
+1. 创建 `/data/appdatas/cat` 目录
+
+ 确保你具有这个目录的读写权限。
+
+2. 创建 `/data/applogs/cat` 目录 (可选)
+
+ 这个目录是用于存放运行时日志的,这将会对调试提供很大帮助,同样需要读写权限。
+
+3. 创建 `/data/appdatas/cat/client.xml`,内容如下
+
+ ```xml
+
+
+
+
+
+
+ ```
+
+ > 不要忘记把 **\** 替换成你自己的服务器地址哦!
diff --git a/lib/_/zh-CN.md b/lib/_/zh-CN.md
new file mode 100644
index 0000000000000000000000000000000000000000..015deaa8800f2f4e56d60edca06598be40c0d21c
--- /dev/null
+++ b/lib/_/zh-CN.md
@@ -0,0 +1,84 @@
+# 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`。
diff --git a/lib/c/CMakeLists.txt b/lib/c/CMakeLists.txt
index 6b2b15b3f09b1df8cc30a0f93b0e7cd8e3fb9e18..472d703e435aacc56710868e1b2df5e366b11ba5 100644
--- a/lib/c/CMakeLists.txt
+++ b/lib/c/CMakeLists.txt
@@ -1,7 +1,11 @@
-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()
diff --git a/lib/c/README.md b/lib/c/README.md
index 310c4dc54d1c891bcc699feccb42a151e2246f7e..147b83674a3ea8991ad7517f070e7a049c879cfb 100644
--- a/lib/c/README.md
+++ b/lib/c/README.md
@@ -1,89 +1,66 @@
-# 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
-
-
-
-
-
-
-```
-
-Don't forget to change the `` 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
+#include
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
-
-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)
diff --git a/lib/c/benchmark/cat_ip_test.c b/lib/c/benchmark/cat_ip_test.c
deleted file mode 100644
index 1581850deff551c0018c53c47f8eb15f949f37f7..0000000000000000000000000000000000000000
--- a/lib/c/benchmark/cat_ip_test.c
+++ /dev/null
@@ -1,84 +0,0 @@
-//
-// Created by Terence on 2018/8/27.
-//
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#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
diff --git a/lib/c/doc/api-c.md b/lib/c/docs/api.md
similarity index 60%
rename from lib/c/doc/api-c.md
rename to lib/c/docs/api.md
index 03ca80fb0b2d39d2f229351ae2c2dc362a917afa..01c1da3744adabd1450f1050738d7bf087f93811 100644
--- a/lib/c/doc/api-c.md
+++ b/lib/c/docs/api.md
@@ -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/`
-* 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.
>
diff --git a/lib/c/docs/api.zh-CN.md b/lib/c/docs/api.zh-CN.md
new file mode 100644
index 0000000000000000000000000000000000000000..28de0a20c1061f77640ce863b431b8fb4e86baf2
--- /dev/null
+++ b/lib/c/docs/api.zh-CN.md
@@ -0,0 +1,291 @@
+# 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,
+> 除非你想覆盖我们的心跳信息。
+>
+> 当你这么做时,不要忘记禁用我们的内置心跳信息。
diff --git a/lib/c/docs/zh-CN.md b/lib/c/docs/zh-CN.md
new file mode 100644
index 0000000000000000000000000000000000000000..c4a7d10a72ac77a5807610bc4e6049f109641f89
--- /dev/null
+++ b/lib/c/docs/zh-CN.md
@@ -0,0 +1,65 @@
+# 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
+
+catClientInit("appkey");
+```
+
+> appkey 只能包含英文字母 (a-z, A-Z)、数字 (0-9)、下划线 (\_) 和中划线 (-)
+
+注意,**采样**,内置**心跳**,**二进制**序列化在默认情况下是开启的,你可能会想要禁用他们。我们同时提供了一个 API 可以使你自定义启动参数,请参考 [API 文档](./docs/api.zh-CN.md)
+
+## Documentation
+
+[API 文档](./api.zh-CN.md)
diff --git a/lib/c/include/ccat/client.h b/lib/c/include/client.h
similarity index 99%
rename from lib/c/include/ccat/client.h
rename to lib/c/include/client.h
index 948df0100936c3e7a6c186a8ba410bb713bf0694..5cae6d6afd32e1cf51cadfa697ad1cdc8d175cae 100644
--- a/lib/c/include/ccat/client.h
+++ b/lib/c/include/client.h
@@ -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();
/**
diff --git a/lib/c/include/ccat/helper.h b/lib/c/include/helper.h
similarity index 90%
rename from lib/c/include/ccat/helper.h
rename to lib/c/include/helper.h
index e92f7e978f445ca5fc6d246f25c18aa6f6bf5e56..39ee3760545b75c8e965d82eb9ddae1df03ef80f 100644
--- a/lib/c/include/ccat/helper.h
+++ b/lib/c/include/helper.h
@@ -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
diff --git a/lib/c/benchmark/cat_client_test.c b/lib/c/scripts/cat_client_test.c
similarity index 84%
rename from lib/c/benchmark/cat_client_test.c
rename to lib/c/scripts/cat_client_test.c
index 342b04373896ecf2aee77a1558976b855e812700..7c3962f2d50bde9a9fc54ee4f9adc4f53fe714d6 100644
--- a/lib/c/benchmark/cat_client_test.c
+++ b/lib/c/scripts/cat_client_test.c
@@ -1,6 +1,6 @@
#include
-#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;
}
diff --git a/lib/c/benchmark/cat_mpsc_test.c b/lib/c/scripts/cat_mpsc_test.c
similarity index 100%
rename from lib/c/benchmark/cat_mpsc_test.c
rename to lib/c/scripts/cat_mpsc_test.c
diff --git a/lib/c/src/ccat/client.c b/lib/c/src/ccat/client.c
index 4b619186b30a85879308355d5663485ef5479064..4385b68f08d289b6b8cca9761961e10dda26bec4 100644
--- a/lib/c/src/ccat/client.c
+++ b/lib/c/src/ccat/client.c
@@ -1,7 +1,8 @@
-#include "ccat/client.h"
+#include "client.h"
#include
#include
+#include
#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);
diff --git a/lib/c/src/ccat/client_config.h b/lib/c/src/ccat/client_config.h
index 9279de2ce59f89e834729ca1f2d2c02ffeb3ae95..92d66f3ad3f3a6dcb271a10b20b805d5ca92142b 100644
--- a/lib/c/src/ccat/client_config.h
+++ b/lib/c/src/ccat/client_config.h
@@ -1,7 +1,7 @@
#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"
diff --git a/lib/c/src/ccat/message.h b/lib/c/src/ccat/message.h
index d760364e2f951ab957b9a988bdcad0e918743d7c..9c7d17cc9bc41a386ac4339f633d57194e6af177 100644
--- a/lib/c/src/ccat/message.h
+++ b/lib/c/src/ccat/message.h
@@ -8,7 +8,7 @@
#include
#include
-#include "ccat/client.h"
+#include "client.h"
#include "ccat/message_helper.h"
#include "lib/cat_sds.h"
diff --git a/lib/c/src/ccat/message_aggregator_event.h b/lib/c/src/ccat/message_aggregator_event.h
index 489b0a83879637fdeb72b44b58239ba99ba58ab2..e52296c1c0c2722f76077cd70b33132098c37161 100644
--- a/lib/c/src/ccat/message_aggregator_event.h
+++ b/lib/c/src/ccat/message_aggregator_event.h
@@ -5,7 +5,7 @@
#ifndef CCAT_MESSAGE_AGGREGATOR_EVENT_H
#define CCAT_MESSAGE_AGGREGATOR_EVENT_H
-#include
+#include
void addEventToAggregator(CatEvent * pEvent);
diff --git a/lib/c/src/ccat/message_aggregator_trans.h b/lib/c/src/ccat/message_aggregator_trans.h
index 5a8593c2df44b34881498d58a336613b8fd4888d..8199b6e32c2c3a02c9baf7bc54dea125aec78e86 100644
--- a/lib/c/src/ccat/message_aggregator_trans.h
+++ b/lib/c/src/ccat/message_aggregator_trans.h
@@ -5,7 +5,7 @@
#ifndef CCAT_MESSAGE_AGGREGATOR_TRANS_H
#define CCAT_MESSAGE_AGGREGATOR_TRANS_H
-#include
+#include
void addTransToAggregator(CatTransaction *pEvent);
diff --git a/lib/c/src/ccat/message_tree.h b/lib/c/src/ccat/message_tree.h
index 9c99dcbc5012f022e4fe3572087c7342759d32ea..cf448a37e1d46974904ad0379622f4d9c1f4e365 100644
--- a/lib/c/src/ccat/message_tree.h
+++ b/lib/c/src/ccat/message_tree.h
@@ -1,7 +1,7 @@
#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"
diff --git a/lib/c/src/ccat/monitor.c b/lib/c/src/ccat/monitor.c
index be6277b20c9de793aeb1459e85667066ab5354f0..c3aca8e4481c75bf5e8bd1ac8ce70931c52f9749 100644
--- a/lib/c/src/ccat/monitor.c
+++ b/lib/c/src/ccat/monitor.c
@@ -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) {
diff --git a/lib/c/src/ccat/monitor.h b/lib/c/src/ccat/monitor.h
index bd76ce71101231793ed77ab13d8f9db6e4b1a730..1016b20ea1787574a2b32428f5d194e7633fcbd3 100644
--- a/lib/c/src/ccat/monitor.h
+++ b/lib/c/src/ccat/monitor.h
@@ -1,8 +1,6 @@
#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 {
diff --git a/lib/c/src/ccat/monitor_collector.c b/lib/c/src/ccat/monitor_collector.c
index 8db4d6b1e88a778f77eea25b48d2399cc56ad59d..6bd64c693abeecf30a46b21d217c4a977fb1cfdf 100644
--- a/lib/c/src/ccat/monitor_collector.c
+++ b/lib/c/src/ccat/monitor_collector.c
@@ -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) {
diff --git a/lib/c/src/cppcat/heartbeat.cpp b/lib/c/src/cppcat/heartbeat.cpp
deleted file mode 100644
index 9a9d62c7b16c061eb32c8612c14108263ddaf77c..0000000000000000000000000000000000000000
--- a/lib/c/src/cppcat/heartbeat.cpp
+++ /dev/null
@@ -1,4 +0,0 @@
-//
-// Created by Terence on 2018/8/2.
-//
-
diff --git a/lib/c/src/lib/cat_anet.c b/lib/c/src/lib/cat_anet.c
index 652013a44663a32cb97e012ae465efe35c33bca3..fb0704116d67b13b0134d2b893b163d5164908b2 100644
--- a/lib/c/src/lib/cat_anet.c
+++ b/lib/c/src/lib/cat_anet.c
@@ -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);
diff --git a/lib/c/src/version.h.in b/lib/c/src/version.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..d9b834b40730ce6248a18acdfe8cfa6bd412ef49
--- /dev/null
+++ b/lib/c/src/version.h.in
@@ -0,0 +1,6 @@
+#ifndef _CCAT_VERSION_H_
+#define _CCAT_VERSION_H_ 1
+
+#define CCAT_VERSION "@CCAT_VERSION@"
+
+#endif // _CCAT_VERSION_H_
\ No newline at end of file
diff --git a/lib/cpp/CMakeLists.txt b/lib/cpp/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..785ac996976006343825517627b6adde32375c07
--- /dev/null
+++ b/lib/cpp/CMakeLists.txt
@@ -0,0 +1,82 @@
+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()
diff --git a/lib/cpp/README.md b/lib/cpp/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..fd78478b73e342b0db118585af76070af001458f
--- /dev/null
+++ b/lib/cpp/README.md
@@ -0,0 +1,72 @@
+# 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
+
+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)
diff --git a/lib/c/doc/api-cpp.md b/lib/cpp/docs/api.md
similarity index 59%
rename from lib/c/doc/api-cpp.md
rename to lib/cpp/docs/api.md
index 9caaeda329fbd9129cf130aa1e8ebcce462964d3..47faf50a4a015c46ac1f881743a3652a43c5cee1 100644
--- a/lib/c/doc/api-cpp.md
+++ b/lib/cpp/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/`
-* 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.
diff --git a/lib/cpp/docs/api.zh-CN.md b/lib/cpp/docs/api.zh-CN.md
new file mode 100644
index 0000000000000000000000000000000000000000..39d551812991b493f154601d104a1a67a40d5a62
--- /dev/null
+++ b/lib/cpp/docs/api.zh-CN.md
@@ -0,0 +1,178 @@
+# cat c++ client
+
+## Quickstart
+
+```cpp
+#include
+#include
+
+#include "cppcat/client.h"
+
+using namespace std;
+
+unsigned long long GetTime64() {
+ return static_cast(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` 一样,同一秒上报的指标会被聚合,唯一的区别是这里使用平均值取代求和。
diff --git a/lib/cpp/docs/zh-CN.md b/lib/cpp/docs/zh-CN.md
new file mode 100644
index 0000000000000000000000000000000000000000..5b1d504cb8c0df9882e309bf446b9642d9ac5e33
--- /dev/null
+++ b/lib/cpp/docs/zh-CN.md
@@ -0,0 +1,67 @@
+# 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
+
+cat::init("appkey");
+```
+
+> appkey 只能包含英文字母 (a-z, A-Z)、数字 (0-9)、下划线 (\_) 和中划线 (-)
+
+注意,**采样**,内置**心跳**,**二进制**序列化在默认情况下是开启的,你可能会想要禁用他们。我们同时提供了一个 API 可以使你自定义启动参数,请参考 [API 文档](./api.zh-CN.md)
+
+## Documentation
+
+[API 文档](./api.zh-CN.md)
diff --git a/lib/c/include/cppcat/client.h b/lib/cpp/include/client.hpp
similarity index 95%
rename from lib/c/include/cppcat/client.h
rename to lib/cpp/include/client.hpp
index fe8bba694cdecd35b40dd6c386d6f37f8c601b2a..c3f1784bba74e94da7db7a97e81a47444dab5da9 100644
--- a/lib/c/include/cppcat/client.h
+++ b/lib/cpp/include/client.hpp
@@ -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
@@ -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
diff --git a/lib/c/benchmark/cat_client_test.cpp b/lib/cpp/scripts/cat_client_test.cpp
similarity index 91%
rename from lib/c/benchmark/cat_client_test.cpp
rename to lib/cpp/scripts/cat_client_test.cpp
index b9dc698bb4bc0efcb0f902f9b34af5a989d020df..02e5842fb809ba29182f1c83fbcbe1fd8a608f79 100644
--- a/lib/c/benchmark/cat_client_test.cpp
+++ b/lib/cpp/scripts/cat_client_test.cpp
@@ -5,7 +5,7 @@
#include
#include
-#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++) {
diff --git a/lib/c/benchmark/cat_mpsc_test.cpp b/lib/cpp/scripts/cat_mpsc_test.cpp
similarity index 100%
rename from lib/c/benchmark/cat_mpsc_test.cpp
rename to lib/cpp/scripts/cat_mpsc_test.cpp
diff --git a/lib/cpp/src/ccat b/lib/cpp/src/ccat
new file mode 120000
index 0000000000000000000000000000000000000000..750a184a10b330f162be866dad54f0d6db8499c8
--- /dev/null
+++ b/lib/cpp/src/ccat
@@ -0,0 +1 @@
+../../c/src/ccat
\ No newline at end of file
diff --git a/lib/c/src/cppcat/client.cpp b/lib/cpp/src/cppcat/client.cpp
similarity index 83%
rename from lib/c/src/cppcat/client.cpp
rename to lib/cpp/src/cppcat/client.cpp
index 003fc3a989e3099736ef983ea6c61f22786ef2cb..766a7c275519ad5a47cec10506026be8fa747f99 100644
--- a/lib/c/src/cppcat/client.cpp
+++ b/lib/cpp/src/cppcat/client.cpp
@@ -2,9 +2,10 @@
// Created by Terence on 2018/8/2.
//
-#include "cppcat/client.h"
+#include "client.hpp"
-#include
+#include
+#include
using namespace std;
@@ -23,6 +24,10 @@ namespace cat {
catClientInitWithConfig(domain.c_str(), &conf);
}
+ string version() {
+ return string(CPPCAT_VERSION);
+ }
+
void destroy() {
catClientDestroy();
}
diff --git a/lib/c/src/cppcat/event.cpp b/lib/cpp/src/cppcat/event.cpp
similarity index 95%
rename from lib/c/src/cppcat/event.cpp
rename to lib/cpp/src/cppcat/event.cpp
index df0e50fbae07658cfc0946948396366e80fcbf29..54252fb5501e61d6b08f56f3ecca75110ff35338 100644
--- a/lib/c/src/cppcat/event.cpp
+++ b/lib/cpp/src/cppcat/event.cpp
@@ -2,11 +2,9 @@
// Created by Terence on 2018/8/2.
//
-#include
-#include
-#include
+#include "client.hpp"
-#include "cppcat/client.h"
+#include
#define E(e) ((CatEvent*)(e))
diff --git a/lib/c/src/cppcat/metric.cpp b/lib/cpp/src/cppcat/metric.cpp
similarity index 82%
rename from lib/c/src/cppcat/metric.cpp
rename to lib/cpp/src/cppcat/metric.cpp
index e79bd7211371b83461e2f44da110c4a54db20600..753b2e1e7ba9ce7acc9ed96982704258f04e5ee8 100644
--- a/lib/c/src/cppcat/metric.cpp
+++ b/lib/cpp/src/cppcat/metric.cpp
@@ -2,10 +2,9 @@
// Created by Terence on 2018/8/2.
//
-#include
-#include
+#include "client.hpp"
-#include "cppcat/client.h"
+#include
using namespace std;
diff --git a/lib/c/src/cppcat/transaction.cpp b/lib/cpp/src/cppcat/transaction.cpp
similarity index 95%
rename from lib/c/src/cppcat/transaction.cpp
rename to lib/cpp/src/cppcat/transaction.cpp
index 957eca305f936b11b466cc1f2b7c7e2f94ad11d6..974ee457d82a87fa3b8498feb3a0994de8b30b11 100644
--- a/lib/c/src/cppcat/transaction.cpp
+++ b/lib/cpp/src/cppcat/transaction.cpp
@@ -2,11 +2,9 @@
// Created by Terence on 2018/8/2.
//
-#include
-#include
-#include
+#include "client.hpp"
-#include "cppcat/client.h"
+#include
using namespace std;
diff --git a/lib/cpp/src/lib b/lib/cpp/src/lib
new file mode 120000
index 0000000000000000000000000000000000000000..818089e5b9a59e63dbfa26b33d9f7f8949d67d36
--- /dev/null
+++ b/lib/cpp/src/lib
@@ -0,0 +1 @@
+../../c/src/lib
\ No newline at end of file
diff --git a/lib/cpp/src/version.h.in b/lib/cpp/src/version.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..046dd453f7abecd50879bb5a27b7cec5938ad0e4
--- /dev/null
+++ b/lib/cpp/src/version.h.in
@@ -0,0 +1,13 @@
+#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_
diff --git a/lib/c/tests/client.json b/lib/cpp/tests/client.json
similarity index 100%
rename from lib/c/tests/client.json
rename to lib/cpp/tests/client.json
diff --git a/lib/c/tests/client.xml b/lib/cpp/tests/client.xml
similarity index 100%
rename from lib/c/tests/client.xml
rename to lib/cpp/tests/client.xml
diff --git a/lib/c/tests/unit/test_client.cpp b/lib/cpp/tests/unit/test_client.cpp
similarity index 100%
rename from lib/c/tests/unit/test_client.cpp
rename to lib/cpp/tests/unit/test_client.cpp
diff --git a/lib/c/tests/unit/test_concurrent.cpp b/lib/cpp/tests/unit/test_concurrent.cpp
similarity index 100%
rename from lib/c/tests/unit/test_concurrent.cpp
rename to lib/cpp/tests/unit/test_concurrent.cpp
diff --git a/lib/c/tests/unit/test_json.cpp b/lib/cpp/tests/unit/test_json.cpp
similarity index 100%
rename from lib/c/tests/unit/test_json.cpp
rename to lib/cpp/tests/unit/test_json.cpp
diff --git a/lib/c/tests/unit/test_mpsc.cpp b/lib/cpp/tests/unit/test_mpsc.cpp
similarity index 100%
rename from lib/c/tests/unit/test_mpsc.cpp
rename to lib/cpp/tests/unit/test_mpsc.cpp
diff --git a/lib/c/tests/unit/test_sds.cpp b/lib/cpp/tests/unit/test_sds.cpp
similarity index 100%
rename from lib/c/tests/unit/test_sds.cpp
rename to lib/cpp/tests/unit/test_sds.cpp
diff --git a/lib/c/tests/unit/test_xml.cpp b/lib/cpp/tests/unit/test_xml.cpp
similarity index 100%
rename from lib/c/tests/unit/test_xml.cpp
rename to lib/cpp/tests/unit/test_xml.cpp
diff --git a/lib/c/tests/unittest.cpp b/lib/cpp/tests/unittest.cpp
similarity index 100%
rename from lib/c/tests/unittest.cpp
rename to lib/cpp/tests/unittest.cpp