diff --git a/source/tools/monitor/unity/Dockerfile b/source/tools/monitor/unity/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..301e0625119398a7c9b069cdbcf345cda0fdf76b --- /dev/null +++ b/source/tools/monitor/unity/Dockerfile @@ -0,0 +1,34 @@ +FROM centos:7 +MAINTAINER "liaozhaoyan " +WORKDIR /root/ +RUN yum install -y http://mirrors.tuna.tsinghua.edu.cn/centos/7/extras/x86_64/Packages/centos-release-scl-rh-2-3.el7.centos.noarch.rpm && \ + yum install -y devtoolset-9-gcc-c++ && \ + source /opt/rh/devtoolset-9/enable && \ + yum install -y make wget readline-devel lua-devel unzip git && \ + mkdir /root/build && \ + cd /root/build && \ + git clone https://gitee.com/chuyansz/sysak.git && \ + cd sysak/source/tools/monitor/unity/third/ && \ + unzip v2.0.5.zip && \ + cd LuaJIT-2.0.5 && \ + make && make install && \ + cd ../ && \ + tar zxvf luarocks-3.9.1.tar.gz && \ + cd luarocks-3.9.1 && \ + ./configure && make && make install && \ + cd ../ && \ + tar zxvf yaml-0.2.5.tar.gz && \ + cd yaml-0.2.5 && \ + ./configure && make && make install && \ + cd ../ && \ + luarocks install luasec && \ + luarocks install lua-cjson && \ + luarocks install luasocket && \ + luarocks install lyaml && \ + luarocks install lbase64 && \ + luarocks install lua-csnappy && \ + luarocks install lua-protobuf && \ + luarocks install luaposix && \ + export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/ && \ + cd ../beeQ/ && \ + make \ No newline at end of file diff --git a/source/tools/monitor/unity/ReadMe.md b/source/tools/monitor/unity/ReadMe.md new file mode 100644 index 0000000000000000000000000000000000000000..05a4137090d1cba82915b468369018ccecedc06e --- /dev/null +++ b/source/tools/monitor/unity/ReadMe.md @@ -0,0 +1,44 @@ +# 构建编译镜像 + +从Dockerfile 构建镜像,最新git路径 `https://gitee.com/chuyansz/sysak/blob/opensource_branch/source/tools/monitor/unity/Dockerfile` + +构建环境需要以下准备: + +1. 安装了docker +2. 可以访问gitee和github + +执行以下命令构建 +``` +docker build -c 2 -t sysak-unity-devel:v1.0 . +``` + +大约10+分钟后即可构建完毕 + +# 使用编译镜像 + +如果在本地构建完毕,可以采用以下命令拉起刚才构建好的镜像 + +```bash +docker run -itd --net=host --name unity-devel :v1.0 +docker exec -it unity-devel bash +``` + +如果采用已经好的镜像 + +```bash +docker run -itd --net=host --name unity-devel registry.cn-hangzhou.aliyuncs.com/sysom/unity:v1.0 +docker exec -it unity-devel bash +``` + +进入到容器后,进入到代码路径,执行启动脚本即可拉起监控服务 + +```bash +cd build/sysak/source/tools/monitor/unity/test/bees/ +./run.sh +``` + +通过访问8400 端口即可获取到数据,也可以用浏览器浏览页面 + +```bash +curl 127.0.0.1:8400 +``` \ No newline at end of file diff --git a/source/tools/monitor/unity/beaver/Makefile b/source/tools/monitor/unity/beaver/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4968b522f36f375ee9c2644dd92ed663d0173746 --- /dev/null +++ b/source/tools/monitor/unity/beaver/Makefile @@ -0,0 +1,19 @@ +CC := gcc +AR := ar +CFLAG := -g +OBJS := beaver.o echos.o +LIB := libbeaver.a + +all: $(LIB) + +echos.o: echos.c beaver.h echos.h + $(CC) -c $< -o $@ $(CFLAG) + +beaver.o: beaver.c beaver.h echos.h + $(CC) -c $< -o $@ $(CFLAG) + +$(LIB): $(OBJS) + $(AR) cr $@ $(OBJS) + +clean: + rm -f $(EXEC) $(OBJS) diff --git a/source/tools/monitor/unity/beaver/beaver.c b/source/tools/monitor/unity/beaver/beaver.c new file mode 100644 index 0000000000000000000000000000000000000000..53c4b068b6e125be07bdbcf9917cfc79ce9d1ec3 --- /dev/null +++ b/source/tools/monitor/unity/beaver/beaver.c @@ -0,0 +1,403 @@ +// +// Created by 廖肇燕 on 2022/12/20. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "beaver.h" +#include "echos.h" + +extern volatile int sighup_counter; + +#define FD_RATIO 2 // fd_num vs thread +#define gettidv1() syscall(__NR_gettid) + +#define unlikely(x) __builtin_expect((x),0) +#define ASSERT_LOCKS(X) do{ \ +if (unlikely(X < 0)) \ +{ \ + perror("hold lock failed."); \ + exit(1); \ +}\ +}while(0) + +struct beaver_message { + pthread_mutex_t pc_mutex; + pthread_cond_t pc_condp, pc_condc; + int sk_accept; + int status; // working is 0, bad is -1; + int thread; // thread num + int fd_num; // fd pool number max value. + int fd_count; // fd pool realtime count + int* fds; // fd pool +}; + +static int beaver_broad_stop(struct beaver_message* pmsg) { + int ret = 0; + pmsg->status = -1; + + ret = pthread_cond_broadcast(&pmsg->pc_condc); + ASSERT_LOCKS(ret); + ret = pthread_cond_broadcast(&pmsg->pc_condp); + ASSERT_LOCKS(ret); + + return ret; +} + +static int fd_in_beaver(int fd, struct beaver_message* pmsg){ + if (pmsg->status) { // bad status should exit. + return 0; + } + + if (pmsg->fd_count == pmsg->fd_num) { //fd poll may large + return 1; + } + + for (int i = 0; i < pmsg->fd_num; ++i) { + if (pmsg->fds[i] == fd) { + return 1; + } + } + + return 0; +} + +static int add_in_beaver(int fd, struct beaver_message* pmsg){ + for (int i = 0; i < pmsg->fd_num; i ++) { +#ifdef BEAVER_DEBUG + if (pmsg->fds[i] == fd) { + fprintf(stderr, "bug: fd %d is already in fds.\n", fd); + exit(0); + } +#endif + if (pmsg->fds[i] == -1) { + pmsg->fds[i] = fd; + pmsg->fd_count ++; + return 0; + } + } +#ifdef BEAVER_DEBUG + fprintf(stderr, "bug: add %d to fds failed..\n\t", fd); + for (int i = 0; i < pmsg->fd_num; i ++) { + fprintf(stderr, "%d ", pmsg->fds[i]); + } + fprintf(stderr, "\n"); + exit(0); +#endif + return 1; +} + +static int del_in_beaver(int fd, struct beaver_message* pmsg){ + int ret; + ret = pthread_mutex_lock(&pmsg->pc_mutex); + ASSERT_LOCKS(ret); + for (int i = 0; i < pmsg->fd_num; ++i) { + if (pmsg->fds[i] == fd) { + pmsg->fds[i] = -1; + pmsg->fd_count --; + ret = pthread_cond_signal(&pmsg->pc_condp); + ASSERT_LOCKS(ret); + ret = pthread_mutex_unlock(&pmsg->pc_mutex); + ASSERT_LOCKS(ret); + return 0; + } + } +#ifdef BEAVER_DEBUG + fprintf(stderr, "bug: fd %d is not in fds.\n", fd); + exit(0); +#endif + ret = pthread_mutex_unlock(&pmsg->pc_mutex); + ASSERT_LOCKS(ret); + return 1; +} + +static void * beaver_threads(void * arg) { + int ret; + int fd; + int tid = (int)gettidv1(); + struct beaver_message * pmsg = (struct beaver_message *)arg; + lua_State *L; + int count = sighup_counter; + + // init is here. + L = echos_init(tid); + if (L == NULL) { + exit(1); + } + + while (1) { + ret = pthread_mutex_lock(&pmsg->pc_mutex); + ASSERT_LOCKS(ret); + + while (pmsg->sk_accept == 0 || pmsg->status != 0){ + ret = pthread_cond_wait(&pmsg->pc_condc, &pmsg->pc_mutex); + ASSERT_LOCKS(ret); + } + if (pmsg->status != 0) { + goto endStatus; + } + fd = pmsg->sk_accept; + pmsg->sk_accept = 0; + ret = pthread_mutex_unlock(&pmsg->pc_mutex); + ASSERT_LOCKS(ret); + + if (count != sighup_counter) { // need to reload ? + lua_close(L); + L = NULL; + + L = echos_init(tid); + if (L == NULL) { + exit(1); + } + count = sighup_counter; + } + + //work here + ret = echos(L, fd); + close(fd); + del_in_beaver(fd, pmsg); + + if (ret) { + goto endThread; + } + } + endStatus: + ret = pthread_mutex_unlock(&pmsg->pc_mutex); + ASSERT_LOCKS(ret); + endThread: + lua_close(L); + beaver_broad_stop(pmsg); + pthread_exit(NULL); +} + +static int beaver_setup_message(struct beaver_message* pmsg) { + int ret; + int fret; + + pmsg->sk_accept = 0; + pmsg->status = 0; + + ret = pthread_mutex_init(&pmsg->pc_mutex, NULL); + if (ret < 0) { + perror("pc_mutex create failed."); + goto endMutex; + } + ret = pthread_cond_init(&pmsg->pc_condp, NULL); + if (ret < 0) { + perror("pc_condp create failed."); + goto endCondp; + } + ret = pthread_cond_init(&pmsg->pc_condc, NULL); + if (ret < 0) { + perror("pc_condc create failed."); + goto endCondc; + } + + return ret; + endCondc: + fret = pthread_cond_destroy(&pmsg->pc_condp); + if (fret < 0){ + perror("destroy condp faild."); + exit(1); + } + endCondp: + fret = pthread_mutex_destroy(&pmsg->pc_mutex); + if (fret < 0){ + perror("destroy pc_mutex faild."); + exit(1); + } + endMutex: + return ret; +} + +static void beaver_destroy_message(struct beaver_message* pmsg) { + int ret; + + ret = pthread_cond_destroy(&pmsg->pc_condc); + if (ret < 0){ + perror("destroy condc faild."); + exit(1); + } + ret = pthread_cond_destroy(&pmsg->pc_condp); + if (ret < 0){ + perror("destroy condp faild."); + exit(1); + } + ret = pthread_mutex_destroy(&pmsg->pc_mutex); + if (ret < 0){ + perror("destroy pc_mutex faild."); + exit(1); + } +} + +static int beaver_threads_start(int thread, pthread_t ** tid_arr, struct beaver_message* pmsg) { + int ret = 0; + pthread_t *tids; + + tids = (pthread_t *) malloc(thread * sizeof (pthread_t)); + if (tids == NULL) { + perror("beaver thread malloc."); + ret = -ENOMEM; + goto endMalloc; + } + for (int i = 0; i < thread; i ++) { + tids[i] = 0; + } + *tid_arr = tids; + + ret = beaver_setup_message(pmsg); + if (ret < 0) { + goto endMessage; + } + + for (int i = 0; i < thread; i ++) { + ret = pthread_create(&tids[i], NULL, beaver_threads, pmsg); + ASSERT_LOCKS(ret); + } + + return ret; + endMessage: + free(tids); + endMalloc: + return ret; +} + +static int beaver_thread_stop(int thread, pthread_t ** tid_arr, struct beaver_message* pmsg) { + int ret = 0; + pthread_t * tids = *tid_arr; + + beaver_broad_stop(pmsg); + for (int i = 0; i < thread; i ++) { + if (tids[i] > 0) { + ret = pthread_join(tids[i], NULL); + ASSERT_LOCKS(ret); + } + } + free(tids); + *tid_arr = NULL; + return 0; +} + +static int beaver_accept(int sk_listen, struct beaver_message* pmsg) { + struct sockaddr_in cli_addr; + socklen_t len = sizeof(cli_addr); + int sk_accept; + int ret; + + ret = pthread_mutex_lock(&pmsg->pc_mutex); + ASSERT_LOCKS(ret); + pmsg->fds = malloc(sizeof (int) * pmsg->fd_num); + if (pmsg->fds == NULL) { + ret = -ENOMEM; + goto endMem; + } + for (int i = 0; i < pmsg->fd_num; i ++) { + pmsg->fds[i] = -1; + } + ret = pthread_mutex_unlock(&pmsg->pc_mutex); + ASSERT_LOCKS(ret); + + while (1) { + sk_accept = accept(sk_listen, (struct sockaddr *)&cli_addr, &len); + if (sk_accept < 0) { + perror("accept failed."); + ret = sk_accept; + goto endAccept; + } + + ret = pthread_mutex_lock(&pmsg->pc_mutex); + ASSERT_LOCKS(ret); + while (fd_in_beaver(sk_accept, pmsg)){ // new fd may re + ret = pthread_cond_wait(&pmsg->pc_condp, &pmsg->pc_mutex); + ASSERT_LOCKS(ret); + } + if (pmsg->status) { + ret = pthread_mutex_unlock(&pmsg->pc_mutex); + ASSERT_LOCKS(ret); + goto endStatus; + } + add_in_beaver(sk_accept, pmsg); + + pmsg->sk_accept = sk_accept; + ret = pthread_cond_signal(&pmsg->pc_condc); + ASSERT_LOCKS(ret); + + ret = pthread_mutex_unlock(&pmsg->pc_mutex); + ASSERT_LOCKS(ret); + } + endStatus: + endAccept: + free(pmsg->fds); + endMem: + return ret; +} + +int beaver_init(int port, int thread) { + int ret; + int sk_listen; + int sockopt = 1; + struct sockaddr_in srvaddr; + pthread_t * tids; + struct beaver_message msg; + + msg.thread = thread; + msg.fd_num = thread * FD_RATIO; + msg.fd_count = 0; + + sk_listen = socket(AF_INET, SOCK_STREAM, 0); + if (sk_listen < 0) { + perror("create socket failed."); + ret = -ENOENT; + goto endSocket; + } + + srvaddr.sin_family = AF_INET; + srvaddr.sin_port = htons(port); + srvaddr.sin_addr.s_addr = htonl(INADDR_ANY); + + ret = setsockopt(sk_listen, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)); + if (ret < 0) { + perror("setsockopt socket failed."); + goto endSetoption; + } + + ret = bind(sk_listen, (struct sockaddr *)&srvaddr, sizeof(srvaddr)); + if (ret < 0) { + perror("bind socket failed."); + goto endBind; + } + + ret = listen(sk_listen, thread); + if (ret < 0) { + perror("listen socket failed."); + goto endListen; + } + + ret = beaver_threads_start(thread, &tids, &msg); + if (ret < 0) { + goto endThread; + } + + printf("listen %d for %d threads.\n", port, thread); + beaver_accept(sk_listen, &msg); + beaver_thread_stop(thread, &tids, &msg); + return ret; + endThread: + endListen: + endBind: + endSetoption: + close(sk_listen); + endSocket: + return ret; +} diff --git a/source/tools/monitor/unity/beaver/beaver.h b/source/tools/monitor/unity/beaver/beaver.h new file mode 100644 index 0000000000000000000000000000000000000000..878bd54885d8212499f40787d1a9ef8910b286ff --- /dev/null +++ b/source/tools/monitor/unity/beaver/beaver.h @@ -0,0 +1,10 @@ +// +// Created by 廖肇燕 on 2022/12/20. +// + +#ifndef UNITY_BEAVER_H +#define UNITY_BEAVER_H + +int beaver_init(int port, int thread); + +#endif //UNITY_BEAVER_H diff --git a/source/tools/monitor/unity/beaver/beaver.lua b/source/tools/monitor/unity/beaver/beaver.lua new file mode 100644 index 0000000000000000000000000000000000000000..2567102d978de4ce2b56ea2c01407f11361a4f58 --- /dev/null +++ b/source/tools/monitor/unity/beaver/beaver.lua @@ -0,0 +1,39 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/21 11:44 AM +--- + +package.path = package.path .. ";../common/?.lua;" +package.path = package.path .. ";../httplib/?.lua;" +package.path = package.path .. ";../tsdb/?.lua;" +package.path = package.path .. ";../tsdb/native/?.lua;" + +local Cframe = require("frame") +local CurlApi = require("url_api") +local CurlRpc = require("url_rpc") +local CurlIndex = require("index") +local Cexport = require("export") +local CurlGuide = require("url_guide") +local CurlExportHtml = require("url_export_html") +local CurlExportRaw = require("url_export_raw") + +local web = Cframe.new() + +function init(tid) + print("hello beaver " .. tid) + CurlIndex.new(web) + CurlApi.new(web) + CurlRpc.new(web) + CurlGuide.new(web) + + local export = Cexport.new("12345abdc") + CurlExportHtml.new(web, export) + CurlExportRaw.new(web, export) + return 0 +end + +function echo(fd) + web:proc(fd) + return 0 +end diff --git a/source/tools/monitor/unity/beaver/echos.c b/source/tools/monitor/unity/beaver/echos.c new file mode 100644 index 0000000000000000000000000000000000000000..7938c83eff8f3a554438f6edb6fdf024ede5554d --- /dev/null +++ b/source/tools/monitor/unity/beaver/echos.c @@ -0,0 +1,141 @@ +// +// Created by 廖肇燕 on 2022/12/20. +// + +#include "echos.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, int level); + +static void report_lua_failed(lua_State *L) { + fprintf(stderr, "\nFATAL ERROR:%s\n\n", lua_tostring(L, -1)); +} + +static int call_init(lua_State *L, int tid) { + int ret; + lua_Number lret; + + lua_getglobal(L, "init"); + lua_pushinteger(L, tid); + ret = lua_pcall(L, 1, 1, 0); + if (ret) { + perror("luaL_call init func error"); + report_lua_failed(L); + goto endCall; + } + + if (!lua_isnumber(L, -1)) { // check + errno = -EINVAL; + perror("function beaver.lua init must return a number."); + goto endReturn; + } + lret = lua_tonumber(L, -1); + lua_pop(L, 1); + if (lret < 0) { + errno = -EINVAL; + ret = -1; + perror("beaver.lua init failed."); + goto endReturn; + } + + return ret; + endReturn: + endCall: + return ret; +} + +void LuaAddPath(lua_State *L, char *name, char *value) { + char s[256]; + + lua_getglobal(L, "package"); + lua_getfield(L, -1, name); + strcpy(s, lua_tostring(L, -1)); + strcat(s, ";"); + strcat(s, value); + strcat(s, ";"); + lua_pushstring(L, s); + lua_setfield(L, -3, name); + lua_pop(L, 2); +} + +lua_State * echos_init(int tid) { + int ret; + + /* create a state and load standard library. */ + lua_State *L = luaL_newstate(); + if (L == NULL) { + perror("new lua failed."); + goto endNew; + } + + /* opens all standard Lua libraries into the given state. */ + luaL_openlibs(L); + + LuaAddPath(L, "path", "../beaver/?.lua"); + + ret = luaL_loadfile(L, "../beaver/beaver.lua"); + printf("ret: %d\n", ret); + ret = lua_pcall(L, 0, LUA_MULTRET, 0); + if (ret) { + const char *msg = lua_tostring(L, -1); + perror("luaL_dofile error"); + if (msg) { + luaL_traceback(L, L, msg, 0); + fprintf(stderr, "FATAL ERROR:%s\n\n", msg); + } + goto endLoad; + } + + ret = call_init(L, tid); + if (ret < 0) { + goto endCall; + } + + return L; + endCall: + endLoad: + lua_close(L); + endNew: + return NULL; +} + +int echos(lua_State *L, int fd) { + int ret; + lua_Number lret; + + lua_getglobal(L, "echo"); + lua_pushinteger(L, fd); + ret = lua_pcall(L, 1, 1, 0); + if (ret) { + perror("lua call error"); + report_lua_failed(L); + goto endCall; + } + + if (!lua_isnumber(L, -1)) { // check + errno = -EINVAL; + perror("function beaver.lua init must return a number."); + goto endReturn; + } + lret = lua_tonumber(L, -1); + lua_pop(L, 1); + if (lret < 0) { + errno = -EINVAL; + ret = -1; + perror("beaver.lua init failed."); + goto endReturn; + } + + return ret; + endReturn: + endCall: + return ret; +} \ No newline at end of file diff --git a/source/tools/monitor/unity/beaver/echos.h b/source/tools/monitor/unity/beaver/echos.h new file mode 100644 index 0000000000000000000000000000000000000000..a91dded3ff10e733cb5758bfef8c68b47296939f --- /dev/null +++ b/source/tools/monitor/unity/beaver/echos.h @@ -0,0 +1,13 @@ +// +// Created by 廖肇燕 on 2022/12/20. +// + +#ifndef UNITY_ECHOS_H +#define UNITY_ECHOS_H +#include + +#define BEAVER_DEBUG +lua_State * echos_init(int tid); +int echos(lua_State *L, int fd); + +#endif //UNITY_ECHOS_H diff --git a/source/tools/monitor/unity/beaver/export.lua b/source/tools/monitor/unity/beaver/export.lua new file mode 100644 index 0000000000000000000000000000000000000000..3edc64ccf30fd9ff2200de8eadf0eb157e94c72e --- /dev/null +++ b/source/tools/monitor/unity/beaver/export.lua @@ -0,0 +1,88 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/25 11:20 AM +--- + +local system = require("system") +local pystring = require("pystring") +local CfoxTSDB = require("foxTSDB") +require("class") + +local Cexport = class("Cexport") + +function Cexport:_init_(instance, fYaml) + self._instance = instance + fYaml = fYaml or "../beaver/export.yaml" + local ms = self:_load(fYaml) + self._tDescr = ms.metrics + self._fox = CfoxTSDB.new() + self._fox:_setupRead() +end + +function Cexport:_load(fYaml) + local lyaml = require("lyaml") + local f = io.open(fYaml,"r") + local s = f:read("*all") + f:close() + + return lyaml.load(s) +end + +local function qFormData(from, tData) + local res = {} + + for _, line in ipairs(tData) do + if from == line.title then + table.insert(res, line) + end + end + return res +end + +local function packLine(title, ls, v) + local tLs = {} + for k, v in pairs(ls) do + table.insert(tLs, string.format("%s=\"%s\"", k , v)) + end + local lable = "" + if #tLs then + lable = pystring:join(",", tLs) + lable = "{" .. lable .. "}" + end + return string.format("%s%s %.1f", title, lable, v) +end + +function Cexport:export() + local qs = {} + self._fox:resize() + self._fox:qlast(15, qs) + local res = {} + for _, line in ipairs(self._tDescr) do + local from = line.from + local tFroms = qFormData(from, qs) + if #tFroms then + local title = line.title + local help = string.format("# HELP %s %s", title, line.help) + table.insert(res, help) + local sType = string.format("# TYPE %s %s", title, line.type) + table.insert(res, sType) + + for _, tFrom in ipairs(tFroms) do + local labels = system:deepcopy(tFrom.labels) + if not labels then + labels = {} + end + labels.instance = self._instance + for k, v in pairs(tFrom.values) do + labels[line.head] = k + table.insert(res, packLine(title, labels, v)) + end + end + end + end + local lines = pystring:join("\n", res) + return lines +end + +return Cexport diff --git a/source/tools/monitor/unity/beaver/export.yaml b/source/tools/monitor/unity/beaver/export.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c93efb4ae44516d24d6c1a36ec8cd5477dd4bec6 --- /dev/null +++ b/source/tools/monitor/unity/beaver/export.yaml @@ -0,0 +1,52 @@ +metrics: + - + title: sysak_proc_cpu_total + from: cpu_total + head: mode + help: "cpu usage info for total." + type: "gauge" + - title: sysak_proc_cpus + from: cpus + head: mode + help: "cpu usage info for per-cpu." + type: "gauge" + - title: sysak_proc_sirq + from: sirq + head: type + help: "system soft irq times." + type: "gauge" + - title: sysak_proc_stat_counters + from: stat_counters + head: counter + help: "system state counter." + type: "gauge" + - title: sysak_proc_meminfo + from: meminfo + head: value + help: "meminfo from /proc/meminfo." + type: "gauge" + - title: sysak_proc_vmstat + from: vmstat + head: value + help: "vmstat info from /proc/vmstat." + type: "gauge" + - title: sysak_proc_networks + from: networks + head: counter + help: "networks info from /proc/net/dev." + type: "gauge" + - title: sysak_proc_disks + from: disks + head: counter + help: "disk info from /proc/diskstats." + type: "gauge" + - title: sysak_sample_tbl1 + from: sample_tbl1 + head: value + help: "example1 for develop." + type: "gauge" + - title: sysak_sample_tbl2 + from: sample_tbl2 + head: value + help: "example2 for develop." + type: "gauge" \ No newline at end of file diff --git a/source/tools/monitor/unity/beaver/frame.lua b/source/tools/monitor/unity/beaver/frame.lua new file mode 100644 index 0000000000000000000000000000000000000000..7de16848fa8d275de25de4f09bab85c8dabe323b --- /dev/null +++ b/source/tools/monitor/unity/beaver/frame.lua @@ -0,0 +1,169 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/21 2:39 PM +--- + +-- refer to https://blog.csdn.net/zx_emily/article/details/83024065 + +local unistd = require("posix.unistd") +local poll = require("posix.poll") + +require("class") +local ChttpComm = require("httpComm") +local pystring = require("pystring") +local serpent = require("serpent") +local Cframe = class("frame", ChttpComm) + +function Cframe:_init_() + ChttpComm._init_(self) + self._objs = {} +end + +local function waitDataRest(fd, rest, tReq, tmo) + tmo = tmo or 100 -- max wait 100ms, other wise + local len = 0 + local tStream = {} + while len < rest do + local r = poll.rpoll(fd, tmo) + if r == 0 then -- wait time out + return -1 + elseif r == 1 then + local s = unistd.read(fd, 4096) + table.insert(tStream, s) + len = len + #s + else -- bad socket + return -2 + end + end + tReq.data = tReq.data .. pystring:join("", tStream) + return 0 +end + +local function waitHttpRest(fd, tReq) + if tReq.header["content-length"] then + local lenData = #tReq.data + local lenInfo = tonumber(tReq.header["content-length"]) + + local rest = lenInfo - lenData + if rest > 10 * 1024 * 1024 then -- limit max data len + return -1 + end + + if waitDataRest(fd, rest, tReq) < 0 then + return -2 + end + end + return 0 +end + +local function waitHttpHead(fd, tmo, maxLen) + tmo = tmo or 100 -- max wait 100ms, + maxLen = maxLen or 8192 + local use = 0 + local stream = "" + while tmo > 0 do + local r = poll.rpoll(fd, tmo) + if r == 0 then + return nil + elseif r == 1 then + local s = unistd.read(fd, maxLen - use) + if type(s) == "string" then + stream = stream .. s + use = use + #stream + if string.find(stream, "\r\n\r\n") then -- http head end with \r\n\r\n + return stream + end + end + tmo = tmo - 1 -- time quota weill + else -- bad socket + return nil + end + end +end + +function Cframe:parse(fd, stream) + local tStatus = pystring:split(stream, "\r\n", 1) + if #tStatus < 2 then + print("bad stream format.") + return nil + end + + local stat, heads = unpack(tStatus) + local tStat = pystring:split(stat, " ") + if #tStat < 3 then + print("bad stat: "..stat) + return nil + end + + local method, path, vers = unpack(tStat) + local tReq = self:parsePath(path) + tReq.method = method + tReq.vers = vers + + local tHead = pystring:split(heads, "\r\n\r\n", 1) + if #tHead < 2 then + print("bad head: " .. heads) + return nil + end + local headers, data = unpack(tHead) + local tHeader = pystring:split(headers, "\r\n") + local header = {} + for _, s in ipairs(tHeader) do + local tKv = pystring:split(s, ":", 1) + if #tKv < 2 then + print("bad head kv value: " .. s) + return nil + end + local k, v = unpack(tKv) + k = string.lower(k) + header[k] = pystring:lstrip(v) + end + tReq.header = header + tReq.data = data + if waitHttpRest(fd, tReq) < 0 then + return nil + end + return tReq +end + +function Cframe:echo404() + local stat = self:packStat(404) + local tHead = { + ["Content-Type"] = "text/plain", + } + local body = "Oops! The page may have flown to Mars!!!\n" + local headers = self:packHeaders(tHead, #body) + local tHttp = {stat, headers, body} + return pystring:join("\r\n", tHttp) +end + +function Cframe:proc(fd) + local stream = waitHttpHead(fd) + if type(stream) ~= "string" then -- read return stream or error code or nil + return stream + end + + local tReq = self:parse(fd, stream) + if tReq then + if self._objs[tReq.path] then + local obj = self._objs[tReq.path] + local res = obj:call(tReq) + unistd.write(fd, res) + else + print("show all path.") + for k, _ in pairs(self._objs) do + print("path:", k) + end + unistd.write(fd, self:echo404()) + end + end + collectgarbage("collect") +end + +function Cframe:register(path, obj) + assert(self._objs[path] == nil, "the " .. path .. " is already registered.") + self._objs[path] = obj +end + +return Cframe diff --git a/source/tools/monitor/unity/beaver/guide/guide.md b/source/tools/monitor/unity/beaver/guide/guide.md new file mode 100644 index 0000000000000000000000000000000000000000..2726b2ce58f4613f5ebe7dd803a5f84a1825c830 --- /dev/null +++ b/source/tools/monitor/unity/beaver/guide/guide.md @@ -0,0 +1,6 @@ +# 目录 + +1. [插件化与热更新](/guide/hotplugin) +2. [面向对象设计](/guide/oop) +3. [字符串处理](/guide/pystring) +4. [页面开发](/guide/webdevel) diff --git a/source/tools/monitor/unity/beaver/guide/hotplugin.md b/source/tools/monitor/unity/beaver/guide/hotplugin.md new file mode 100644 index 0000000000000000000000000000000000000000..5eb67541b94d1cc9e7bed100142e18127f55adb6 --- /dev/null +++ b/source/tools/monitor/unity/beaver/guide/hotplugin.md @@ -0,0 +1,114 @@ +# 插件化 + +unity监控采用[yaml](http://yaml.org/)对插件进行管理,当前插件分为采集和输出两个部分进行管理: + +## 采集侧(collector) + +在collector/plugin.yaml 文件中,示例文件: + + plugins: + - # 数组成员标志 + so: sample # so名,对应 collector/native 目录下应当存在 libsample.so + description: "just a example." # 插件描述,当前监控系统未使用 + +## 采集侧示例代码 + +在collector/plugin/sample 目录下有一个示例工程,它的本质其实就是一个so文件的编译项目。首先要看下sample 同级目录下的公共头文件 plugin_head.h,该头文件提供了数据生成的API,降低开发者实现难度。 + + + /// \brief 申请数据行数量,在填入数据前统一申请,根据实际情况填入 + /// \param lines 数据结构体 + /// \param num 申请行号数量 + /// \return 成功返回 0 + inline int unity_alloc_lines(struct unity_lines * lines, unsigned int num) __attribute__((always_inline)); + /// \brief 获取对应行数据,用于填入数据 + /// \param lines 数据结构体 + /// \param i 对应行下标 + /// \return 返回对应的数据行 + inline struct unity_line * unity_get_line(struct unity_lines * lines, unsigned int i) __attribute__((always_inline)); + /// \brief 设置数据行 表名 + /// \param line 行指针 + /// \param table 表名 + /// \return 成功返回 0 + inline int unity_set_table(struct unity_line * line, const char * table) __attribute__((always_inline)); + /// \brief 设置数据行 索引信息 + /// \param line 行指针 + /// \param i 索引下标 + /// \param name 索引名 + /// \param index 索引内容 + /// \return 成功返回 0 + inline int unity_set_index(struct unity_line * line, unsigned int i, const char * name, const char * index) __attribute__((always_inline)); + /// \brief 设置数据行 指标信息 + /// \param line 行指针 + /// \param i 指标下标 + /// \param name 指标名 + /// \param value 指标内容 + /// \return 成功返回 0 + inline int unity_set_value(struct unity_line * line, unsigned int i, const char * name, double value) __attribute__((always_inline)); + + +### 数据行规格限制 + +1. unity\_set\_table 中 table 参数长度应该小于32(不含) +2. unity\_set\_index 中 name、index和unity\_set\_value 中 name 参数长度应该要小于16(不含) +3. unity\_set\_index 下标从0开始,并小于 4,即最多4个索引。而且下标数值应该连续,否则数据会从留白处截断 +4. unity\_set\_index 下标从0开始,并小于 32,即最多32个数值。而且下标数值应该连续,否则数据会从留白处截断 + + +### sample 用例代码 + +参考 sample.c + + /// \brief 插件构造函数,在加载so的时候,会调用一次init + /// \param arg 当前未使用,为NULL + /// \return 成功返回 0 + int init(void * arg) { + printf("sample plugin install.\n"); + return 0; + } + + /// \brief 插件调用函数,通过调用在函数来收集要采集的指标 + /// \param t,间隔周期,如15s的采样周期,则该值为15 + /// \param lines 数值指针,用于填充采集到的数据。 + /// \return 成功返回 0 + int call(int t, struct unity_lines* lines) { + static double value = 0.0; + struct unity_line* line; + + unity_alloc_lines(lines, 2); + line = unity_get_line(lines, 0); + unity_set_table(line, "sample_tbl1"); + unity_set_index(line, 0, "mode", "sample1"); + unity_set_value(line, 0, "value1", 1.0 + value); + unity_set_value(line, 1, "value2", 2.0 + value); + + line = unity_get_line(lines, 1); + unity_set_table(line, "sample_tbl2"); + unity_set_value(line, 0, "value1", 3.0 + value); + unity_set_value(line, 1, "value2", 4.0 + value); + unity_set_value(line, 2, "value3", 3.1 + value); + unity_set_value(line, 3, "value4", 4.1 + value); + + value += 0.1; + return 0; + } + + /// \brief 插件析构函数,调用完该函数时,必须要确保该插件已申请的资源已经全部释放完毕。 + /// \return 成功返回 0 + void deinit(void) { + printf("sample plugin uninstall\n"); + } + +### 工程编译和安装 + +执行make完成编译,编译成功后,**执行make install** 将so复制到 collector/plugin/native目录下。 + +# 热更新 + +往unity 监控主进程发送一个1号(SIGHUP)信号,即可完成热更新。 + +# 输出侧更新 + +此时数据只是已经更新入库了,但是要在nodexport上面显示,需要配置beaver/export.yaml 文件,才能将查询从数据表中更新。 + +[返回目录](/guide) \ No newline at end of file diff --git a/source/tools/monitor/unity/beaver/guide/oop.md b/source/tools/monitor/unity/beaver/guide/oop.md new file mode 100644 index 0000000000000000000000000000000000000000..90c265bc6927e9b562df770a247f56fceb3498c3 --- /dev/null +++ b/source/tools/monitor/unity/beaver/guide/oop.md @@ -0,0 +1,116 @@ +# 面向对象(OOP)概述 + +面向对象设计具有易维护、易扩展、质量高、效率高等优势,参考[这里的总结和设计原则](https://www.cnblogs.com/sun_moon_earth/archive/2008/07/21/1247512.html),适合中大型项目使用。当然,软件质量是由开发者最终决定的,而不是采用什么开发方法。 + +当前unity监控大部分应用开发采用OOP模式设计。**OOP 并不是Lua自带的特性**,故需要在Lua table 基础上,进行面向对象扩展支持。代码实现参考 /common/class.lua。 + +当前lua 面向对象支持特性梳理: + +1. 支持单继承; +2. 类建议采用单独lua文件进行分装; +3. 只支持私有(local成员和方法)和公开(self)两种成员访问模式; +4. 通过 \_init\_ 实现构造 +5. 通过 \_del\_ 实现析构 + +# show code + +在guide/oop 目录下有 面向对象的功能代码, 继承关系:Cbase->Cone->Ctwo, Cone->Cthree。 + +## Cbase + +顾名思义,这是一个基础类 + + require("class") -- 包含头文件 + + local Cbase = class("base") -- 声明为类,第一个传参是类名字,可以自己取,第二入参为要继承的基类 + + function Cbase:_init_(name) --类构造函数 + self.name = name + end + + function Cbase:hello() --类成员方法 + return self.name + end + + function Cbase:_del_() --类析构函数,按照 _del_方法命名 + print("base del..." .. self.name) + end + + return Cbase -- 返回类声明,这里不要忘记 + + +## Cone + +这是一个继承类的实现。**注意构造函数里面中的调用父类函数的方法**, 不能采用 self:_init_的方法来调用。 + + require("class") + local Cbase = require("base") --引用base类 + + Cone = class("one", Cbase) --从Cbase类继承 + + function Cone:_init_(name) + Cbase._init_(self, name) --调用父类函数。 + end + + function Cone:say() + print("one say " .. self.name) + end + + return Cone + + +## Ctwo + +Ctwo 继承于Cone,这里重新实现并复用了父类的say方法。 + + require("class") + local Cone = require("one") + + CTwo = class("two", Cone) + + function CTwo:_init_(name) + Cone._init_(self, name) + end + + function CTwo:say() + print("two say " .. self.name) + print("super") + Cone.say(self) + end + + return CTwo + +## 类实例化 tobj + +采用new函数来实例化类,注意, new 并不是类的方法,故不能用 Cone:new 的方法来做初始化。 + + package.path = package.path .. ";../../common/?.lua;" + + local Cone = require("one") + local Ctwo = require("two") + local CThree = require("three") + + local one = Cone.new("1one") + local two = Ctwo.new("2two") + local three = CThree.new("3three") + + assert(one:hello() == "1one") + assert(two:hello() == "2two") + assert(three:hello() == "3three") + + one:say() + two:say() + three:say() + + one = nil --销毁基础类,不会对子类带来任何影响。 + two:say() + +## 关于:和.的区别 + +.是访问表成员的方法,和C语言中访问结构体成员的方法一致。 +:是一种[语法糖](https://baike.baidu.com/item/%E8%AF%AD%E6%B3%95%E7%B3%96/5247005),它会将self(类似C++中的this指针,或者python的中self)作为一个隐藏参数参数进行传递,以下两个操作是等价的。 + + function Cone:say() + function Cone.say(self) + +[返回目录](/guide) diff --git a/source/tools/monitor/unity/beaver/guide/pystring.md b/source/tools/monitor/unity/beaver/guide/pystring.md new file mode 100644 index 0000000000000000000000000000000000000000..5e795f4bcb036c979bf099737770d1ce889ffa77 --- /dev/null +++ b/source/tools/monitor/unity/beaver/guide/pystring.md @@ -0,0 +1,101 @@ +# 字符串处理 + +同为脚本语言,lua 默认的字符串处理并不像python 那么完善。但只要通过拓展,也可以像python 一样对字符串进行处理。当前已经实现了split/strip 等高频使用函数。参考[Python字符串处理](https://www.jianshu.com/p/b758332c44bb) + +头文件 `local pystring = require("pystring")` + +## split + +split 是 python 常用的字符串分割函数,它还有rsplit一个变体,用于字符串分割,提升字符串处理效率 + +*** + +``` +-- 字符串分割,默认按照空格分割 +local ret = pystring:split("hello lua language") +assert(#ret == 3) +assert(ret[1] == "hello") +assert(ret[2] == "lua") +assert(ret[3] == "language") + +-- 自定符号分割 +ret = pystring:split("hello*lua *language", "*") +assert(#ret == 3) +assert(ret[1] == "hello") +assert(ret[2] == "lua ") +assert(ret[3] == "language") + +-- 从右边开始规定次数分割 +ret = pystring:rsplit("hello*lua *language", "*", 1) +assert(#ret == 2) +assert(ret[1] == "hello*lua ") + +-- 多字符串分割 +ret = pystring:split("hello*lua *language", "*l") +assert(#ret == 3) +assert(ret[1] == "hello") +assert(ret[2] == "ua ") +assert(ret[3] == "anguage") +``` + + +## strip + +strip 用于剔除字符串两边不需要的字符,还有rstrip/lstrip两个实现,只删除左右两边不需要的字符数据。 + +*** +``` +-- strip掉左右空格 +assert(pystring:strip("\t hello world. \t\n") == "hello world.") + +-- strip掉左右指定符号 +assert(pystring:strip("**hello world**", "*") == "hello world") + +-- strip复合符号 +assert(pystring:strip("*?hello world*?", "*?") == "hello world") + +-- strip字符串 +assert(pystring:strip("abcdefhello worldabcdef", "abcdef") == "hello world") + +-- lstrip字符串 +assert(pystring:lstrip("abcdefhello worldabcdef", "abcdef") == "hello worldabcdef") + +-- rstrip字符串 +assert(pystring:rstrip("abcdefhello worldabcdef", "abcdef") == "abcdefhello world") +``` + +## join + +join 是 split的逆运算,将字符串数组按照delim连接起来,形成一个新的字符串。 +不论是脚本还是编译语言,都应避免频繁申请新内存。针对需要组大字符串的场景,应该尽可能采用[join方式](https://blog.csdn.net/weixin_46491071/article/details/109786998)来组合大长字符串。 + +*** +``` +-- join 连接 +local s = "abc d ef g" +local ret = pystring:split(s) +assert(pystring:join(" ", ret) == s) +``` + +## startswith/endswith + +startswith 用于判断字符串是否以指定字符串开头,endswith用于判断结尾 + +*** +``` +-- startswith/endswith +assert(pystring:startswith("hello world", "hello")) +assert(pystring:endswith("hello world", "world")) +``` + +## find + +find 用于子串查找,成功返回首次开始的位置,如果不包含,返回nil + +*** +``` +-- find +assert(pystring:find("hello world.", "hello") == 1) +``` + +[返回目录](/guide) \ No newline at end of file diff --git a/source/tools/monitor/unity/beaver/index.lua b/source/tools/monitor/unity/beaver/index.lua new file mode 100644 index 0000000000000000000000000000000000000000..1ac711309a0dc8b0cc44f7706296c861f200f6d0 --- /dev/null +++ b/source/tools/monitor/unity/beaver/index.lua @@ -0,0 +1,62 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/24 9:06 PM +--- + +require("class") +local unistd = require("posix.unistd") +local ChttpHtml = require("httpHtml") + +local CurlIndex = class("CurlIndex", ChttpHtml) + +function CurlIndex:_init_(frame) + ChttpHtml._init_(self) + self._urlCb["/"] = function(tReq) return self:show(tReq) end + self._urlCb["/index"] = function(tReq) return self:show(tReq) end + self._urlCb["/index.html"] = function(tReq) return self:show(tReq) end + self:_install(frame) +end + +function CurlIndex:show(tReq) + local content1 = [[ +## welcome to visit SysAk Agent + + this Agent provides web services for [SysAk](https://gitee.com/anolis/sysak). + +## About this agent. + +### SysAk + + [SysAk](https://gitee.com/anolis/sysak) (System Analyse Kit) is a system operation and maintenance SIG in the Anolis community, which provides a comprehensive system operation and maintenance tool set by abstracting the experience of millions of servers in the past, which can cover common operation and maintenance scenarios such as daily monitoring of the system, online problem diagnosis and system fault repair. In terms of the overall design of the tool, it strives to make the operation and maintenance work simple, so that system operation and maintenance personnel do not need to understand the kernel to find out the problem. Problem Discussion: 31987277(DingDing) + +### Coolbpf + + [Coolbpf](https://gitee.com/anolis/coolbpf) is implemented based on CORE (Compile Once--Run Everywhere), which retains the advantages of low resource occupation and strong portability, and also integrates the characteristics of BCC dynamic compilation. Coolbpf uses the idea of remote compilation to push the user's BPF program to a remote server and return .o or .so, providing python/rust/c high-level language loading. Users only focus on their own function development, and do not care about the installation of underlying libraries and environment construction. + +### export + +  for [web browser](/export) + +  for [promethues](/export/metrics) + +### code test + + #include + int main() + { + // printf() 中字符串需要引号 + printf("Hello, World!"); + return 0; + } + +### Tips + + This page is rendered directly via markdown, for [guide](/guide) +]] + local content2 = string.format("\n thread id is:%d\n", unistd.getpid()) + local title = "welcome to visit SysAk Agent server." + return {title=title, content=self:markdown(content1 .. content2)} +end + +return CurlIndex diff --git a/source/tools/monitor/unity/beaver/main.c b/source/tools/monitor/unity/beaver/main.c new file mode 100644 index 0000000000000000000000000000000000000000..42dd21ade1014aca577f55abfd7f164ee3363d32 --- /dev/null +++ b/source/tools/monitor/unity/beaver/main.c @@ -0,0 +1,19 @@ +// +// Created by 廖肇燕 on 2022/12/20. +// + +#include +#include +#include "beaver.h" + +int main(int argc, char** argv) { + int port = 8400; + int thread = 3; + if (argc >= 3) { + char *ptr; + port = strtol(argv[1], &ptr, 10); + thread = strtol(argv[2], &ptr, 10); + } + beaver_init(port, thread); +} + diff --git a/source/tools/monitor/unity/beaver/make.bak b/source/tools/monitor/unity/beaver/make.bak new file mode 100644 index 0000000000000000000000000000000000000000..edee774c86013f8e5e7abcc285794e8b4ea383c4 --- /dev/null +++ b/source/tools/monitor/unity/beaver/make.bak @@ -0,0 +1,22 @@ +CC := gcc +CFLAG := -g +LDFLAG := -g -lm -ldl -lpthread -lluajit-5.1 +OBJS := beaver.o main.o echos.o +EXEC := beaver + +all: $(EXEC) + +echos.o: echos.c beaver.h echos.h + $(CC) -c $< -o $@ $(CFLAG) + +beaver.o: beaver.c beaver.h echos.h + $(CC) -c $< -o $@ $(CFLAG) + +main.o: main.c beaver.h + $(CC) -c $< -o $@ $(CFLAG) + +$(EXEC): $(OBJS) + $(CC) -o $@ $(OBJS) $(LDFLAG) + +clean: + rm -f $(EXEC) $(OBJS) diff --git a/source/tools/monitor/unity/beaver/url_api.lua b/source/tools/monitor/unity/beaver/url_api.lua new file mode 100644 index 0000000000000000000000000000000000000000..cc9eb0c97fbf00d7a0b3ad3c7e215fb49691acbb --- /dev/null +++ b/source/tools/monitor/unity/beaver/url_api.lua @@ -0,0 +1,37 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/22 12:08 PM +--- + +require("class") +local ChttpApp = require("httpApp") + +local CurlApi = class("urlApi", ChttpApp) + +function CurlApi:_init_(frame) + ChttpApp._init_(self) + self._urlCb["/api/sum"] = function(tReq) return self:sum(tReq) end + self._urlCb["/api/sub"] = function(tReq) return self:sub(tReq) end + self:_install(frame) +end + +function CurlApi:sum(tReq) + local stat, tJson = pcall(self.getJson, self, tReq) + if stat then + return {sum=tJson.num1 + tJson.num2} + else + return {} + end +end + +function CurlApi:sub(tReq) + local stat, tJson = pcall(self.getJson, self, tReq) + if stat then + return {sum=tJson.num1 - tJson.num2} + else + return {} + end +end + +return CurlApi diff --git a/source/tools/monitor/unity/beaver/url_export_html.lua b/source/tools/monitor/unity/beaver/url_export_html.lua new file mode 100644 index 0000000000000000000000000000000000000000..5b46b0bdcc49460808d9f54f08ff1e773e90cf7e --- /dev/null +++ b/source/tools/monitor/unity/beaver/url_export_html.lua @@ -0,0 +1,33 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/25 11:19 AM +--- + +local pystring = require("pystring") +require("class") +local ChttpHtml = require("httpHtml") + +local CurlExportHtml = class("CurlExportHtml", ChttpHtml) + +function CurlExportHtml:_init_(frame, export) + ChttpHtml._init_(self) + self._export = export + + self._urlCb["/export"] = function(tReq) return self:show(tReq) end + self:_install(frame) +end + +function CurlExportHtml:show(tReq) + local res = {title="Beaver Exporter"} + local content = self._export:export() + local contents = { + "
",
+        content,
+        '
' + } + res.content = pystring:join("\n", contents) + return res +end + +return CurlExportHtml \ No newline at end of file diff --git a/source/tools/monitor/unity/beaver/url_export_raw.lua b/source/tools/monitor/unity/beaver/url_export_raw.lua new file mode 100644 index 0000000000000000000000000000000000000000..d8147be280f5ace3ec85871c17b96a115722e6a3 --- /dev/null +++ b/source/tools/monitor/unity/beaver/url_export_raw.lua @@ -0,0 +1,24 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/25 11:20 AM +--- + +require("class") +local ChttpPlain = require("httpPlain") + +local CurlExportRaw = class("CurlExportRaw", ChttpPlain) + +function CurlExportRaw:_init_(frame, export) + ChttpPlain._init_(self) + self._export = export + + self._urlCb["/export/metrics"] = function(tReq) return self:show(tReq) end + self:_install(frame) +end + +function CurlExportRaw:show(tReq) + return {text = self._export:export()} +end + +return CurlExportRaw diff --git a/source/tools/monitor/unity/beaver/url_guide.lua b/source/tools/monitor/unity/beaver/url_guide.lua new file mode 100644 index 0000000000000000000000000000000000000000..bc995d1cad8ee729fc92adfc0642f6558fb8b58f --- /dev/null +++ b/source/tools/monitor/unity/beaver/url_guide.lua @@ -0,0 +1,50 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2023/1/2 12:05 PM +--- + +require("class") +local ChttpHtml = require("httpHtml") + +local CurlGuide = class("CurlIndex", ChttpHtml) + +function CurlGuide:_init_(frame) + ChttpHtml._init_(self) + self._urlCb["/guide"] = function(tReq) return self:guide(tReq) end + self._urlCb["/guide/hotplugin"] = function(tReq) return self:hotplugin(tReq) end + self._urlCb["/guide/oop"] = function(tReq) return self:oop(tReq) end + self._urlCb["/guide/pystring"] = function(tReq) return self:pystring(tReq) end + self._urlCb["/guide/webdevel"] = function(tReq) return self:webdevel(tReq) end + self:_install(frame) +end + +local function loadFile(fPpath) + local path = "../beaver/guide/" .. fPpath + local f = io.open(path,"r") + local s = f:read("*all") + f:close() + return s +end + +function CurlGuide:guide(tReq) + return {title="guide", content=self:markdown(loadFile("guide.md"))} +end + +function CurlGuide:hotplugin(tReq) + return {title="hotplugin", content=self:markdown(loadFile("hotplugin.md"))} +end + +function CurlGuide:oop(tReq) + return {title="oop", content=self:markdown(loadFile("oop.md"))} +end + +function CurlGuide:pystring(tReq) + return {title="pystring", content=self:markdown(loadFile("pystring.md"))} +end + +function CurlGuide:webdevel(tReq) + return {title="webdevel", content=self:markdown(loadFile("webdevel.md"))} +end + +return CurlGuide diff --git a/source/tools/monitor/unity/beaver/url_rpc.lua b/source/tools/monitor/unity/beaver/url_rpc.lua new file mode 100644 index 0000000000000000000000000000000000000000..403e1bfdac35b07349791dc6f80c2360275d7fd7 --- /dev/null +++ b/source/tools/monitor/unity/beaver/url_rpc.lua @@ -0,0 +1,115 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/29 10:17 PM +--- +-- refer to https://www.cnblogs.com/cielosun/p/6762550.html +require("class") +local ChttpApp = require("httpApp") +local system = require("system") + +local CurlRpc = class("urlRpc", ChttpApp) + +function CurlRpc:_init_(frame) + ChttpApp._init_(self) + self:addMethods() + self._urlCb["/rpc"] = function(tReq) return self:rpc(tReq) end + self:_install(frame) +end + +function CurlRpc:addMethods() + self._method = { + sum = function(tJson) return self:sum(tJson) end + } +end + +function CurlRpc:sum(tJson) + local sum = 0 + for _, v in ipairs(tJson.params) do + if type(v) == "number" then + sum = sum + v + end + end + return { + id = tJson.id, + jsonrpc = "2.0", + result = sum, + error = nil, + } +end + +local function parseError() + return { + id = 0, + jsonrpc = "2.0", + error = {code = -32700, message = "parse error", data="null"}, + } +end + +local function jsonError(id, msg) + msg = msg or "json error" + return { + id = id, + jsonrpc = "2.0", + error = {code = -32600, message = msg, data="null"}, + } +end + +local function methodError(id) + return { + id = id, + jsonrpc = "2.0", + error = {code = -32601, message = "not this method.", data="null"}, + } +end + +local function checkMember(tJson) + local heads = {"jsonrpc", "method", "params", "id"} + + for _, v in ipairs(heads) do + if not system:tableIsIn(tJson, v) then + return false + end + end + return true +end + +function CurlRpc:methodProc(tJson) + local method = tJson.method + if system:tableIsIn(self._method, method) then + return self._method[method](tJson) + else + return methodError(tJson.id) + end +end + +function CurlRpc:check(tJson) + if tJson then + if system:tableIsIn(tJson, "id") then -- check id is in. + if checkMember(tJson) then + if type(tJson.params) == "table" then + return self:methodProc(tJson) + else + return jsonError(tJson.id, "bad param type.") + end + else + return jsonError(tJson.id) + end + else + return parseError() + end + else -- 服务端接收到无效的 JSON。该错误发送于服务器尝试解析 JSON 文本 32700 + return parseError() + end +end + +function CurlRpc:rpc(tReq) + local stat, tJson = pcall(self.getJson, self, tReq) + if stat then + return self:check(tJson) + else + return parseError() + end +end + +return CurlRpc diff --git a/source/tools/monitor/unity/beeQ/Makefile b/source/tools/monitor/unity/beeQ/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b4ce7679a672ba193ee60bfdd9c3f5eb191285e6 --- /dev/null +++ b/source/tools/monitor/unity/beeQ/Makefile @@ -0,0 +1,26 @@ +LIB= -lpthread -ldl + +CC=gcc +CFLAG := -g -I../beaver +LDFLAG := -g -lm -ldl -lrt -lpthread -lluajit-5.1 -L../beaver -lbeaver + +PRG=unity-mon +OBJ=apps.o bees.o beeQ.o +DEPMOD=../beaver ../collector/native ../collector/plugin ../tsdb/native + +$(PRG): $(DEPMOD) $(OBJ) + $(CC) $(LIB) -o $@ $(OBJ) $(LDFLAG) + +%.o: %.c + $(CC) -O $(CFLAG) -c $< -o $@ + +$(DEPMOD):ECHO + make -C $@ + +ECHO: + @echo $(SUBDIRS) + +.PRONY:clean +clean: + @echo "Removing linked and compiled files......" + rm -f $(OBJ) $(PRG) diff --git a/source/tools/monitor/unity/beeQ/apps.c b/source/tools/monitor/unity/beeQ/apps.c new file mode 100644 index 0000000000000000000000000000000000000000..a159a1bf0bcc6b0de472a6a7a189513ef80c4c0a --- /dev/null +++ b/source/tools/monitor/unity/beeQ/apps.c @@ -0,0 +1,332 @@ +// +// Created by 廖肇燕 on 2022/12/26. +// + +#include +#include +#include +#include +#include +#include "beeQ.h" +#include "apps.h" +#include + +#define gettidv1() syscall(__NR_gettid) + +LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, int level); + +static void report_lua_failed(lua_State *L) { + fprintf(stderr, "\nFATAL ERROR:%s\n\n", lua_tostring(L, -1)); +} + +static int call_init(lua_State *L) { + int ret; + lua_Number lret; + + lua_getglobal(L, "init"); + lua_pushinteger(L, (int)gettidv1()); + ret = lua_pcall(L, 1, 1, 0); + if (ret) { + perror("luaL_call init func error"); + report_lua_failed(L); + goto endCall; + } + + if (!lua_isnumber(L, -1)) { // check + errno = -EINVAL; + perror("function bees.lua init must return a number."); + goto endReturn; + } + lret = lua_tonumber(L, -1); + lua_pop(L, 1); + if (lret < 0) { + errno = -EINVAL; + ret = -1; + perror("bees.lua init failed."); + goto endReturn; + } + + return ret; + endReturn: + endCall: + return ret; +} + +lua_State * app_recv_init(void) { + int ret; + + /* create a state and load standard library. */ + lua_State *L = luaL_newstate(); + if (L == NULL) { + perror("new lua failed."); + goto endNew; + } + /* opens all standard Lua libraries into the given state. */ + luaL_openlibs(L); + + ret = luaL_dofile(L, "bees.lua"); + if (ret) { + const char *msg = lua_tostring(L, -1); + perror("luaL_dofile error"); + if (msg) { + luaL_traceback(L, L, msg, 0); + fprintf(stderr, "FATAL ERROR:%s\n\n", msg); + } + goto endLoad; + } + + ret = call_init(L); + if (ret < 0) { + goto endCall; + } + + return L; + endCall: + endLoad: + lua_close(L); + endNew: + return NULL; +} + +extern volatile int sighup_counter; +int app_recv_proc(void* msg, void * arg) { + int ret = 0; + struct beeMsg *pMsg = (struct beeMsg *)msg; + int len = pMsg->size; + static int counter = 0; + + if (len > 0) { + int lret; + lua_State **pL = (lua_State **)arg; + lua_State *L = *pL; + char *body; + + if (counter != sighup_counter) { // check counter for signal. + lua_close(L); + + L = app_recv_init(); + if (L == NULL) { + exit(1); + } + *pL = L; + counter = sighup_counter; + } + + body = malloc(len); // http://www.lua.org/manual/5.1/manual.html#lua_pushlstring + //Pushes the string pointed to by s with size len onto the stack. + // Lua makes (or reuses) an internal copy of the given string, + // so the memory at s can be freed or reused immediately after the function returns. + // The string can contain embedded zeros. + if (body == NULL) { + ret = -ENOMEM; + goto endMem; + } + memcpy(body, &pMsg->body[0], len); + lua_getglobal(L, "proc"); + lua_pushlstring(L, body, len); + ret = lua_pcall(L, 1, 1, 0); + if (ret) { + perror("lua call error"); + report_lua_failed(L); + goto endCall; + } + + if (!lua_isnumber(L, -1)) { // check + errno = -EINVAL; + perror("function bees.lua proc must return a number."); + goto endReturn; + } + lret = lua_tonumber(L, -1); + lua_pop(L, 1); + if (lret < 0) { + errno = -EINVAL; + ret = -1; + perror("bees.lua proc failed."); + goto endReturn; + } + } + return ret; + endMem: + endReturn: + endCall: + return ret; +} + +static int collector_qout(lua_State *L) { + int ret; + struct beeQ* q = (struct beeQ*) lua_topointer(L, 1); + const char *body = lua_tostring(L, 2); + int len = lua_tonumber(L, 3); + + struct beeMsg* pMsg = malloc(sizeof (int) + len); + if (pMsg == NULL) { + lua_pushnumber(L, -ENOMEM); + return 1; + } + + pMsg->size = len; + memcpy(&pMsg->body[0], body, len); + + ret = beeQ_send(q, pMsg); + lua_pushnumber(L, ret); + return 1; +} + +static lua_State * app_collector_init(void* q, int delta) { + int ret; + lua_Number lret; + + /* create a state and load standard library. */ + lua_State *L = luaL_newstate(); + if (L == NULL) { + perror("new lua failed."); + goto endNew; + } + luaL_openlibs(L); + + ret = luaL_dofile(L, "collectors.lua"); + if (ret) { + const char *msg = lua_tostring(L, -1); + perror("luaL_dofile error"); + if (msg) { + luaL_traceback(L, L, msg, 0); + fprintf(stderr, "FATAL ERROR:%s\n\n", msg); + } + goto endLoad; + } + + lua_register(L, "collector_qout", collector_qout); + + // call init. + lua_getglobal(L, "init"); + lua_pushlightuserdata(L, q); + lua_pushinteger(L, delta); + ret = lua_pcall(L, 2, 1, 0); + if (ret) { + perror("luaL_call init func error"); + report_lua_failed(L); + goto endCall; + } + + if (!lua_isnumber(L, -1)) { // check + errno = -EINVAL; + perror("function collectors.lua init must return a number."); + goto endReturn; + } + lret = lua_tonumber(L, -1); + lua_pop(L, 1); + if (lret < 0) { + errno = -EINVAL; + ret = -1; + perror("collectors.lua init failed."); + goto endReturn; + } + return L; + + endReturn: + endCall: + endLoad: + lua_close(L); + endNew: + return NULL; +} + +static int app_collector_work(lua_State **pL, void* q, int delta) { + int ret; + lua_Number lret; + static int counter = 0; + + lua_State *L = *pL; + + if (counter != sighup_counter) { // check counter for signal. + lua_close(L); + + L = app_collector_init(q, delta); + if (L == NULL) { + exit(1); + } + *pL = L; + counter = sighup_counter; + } + + lua_getglobal(L, "work"); + lua_pushinteger(L, 15); + ret = lua_pcall(L, 1, 1, 0); + if (ret) { + perror("luaL_call init func error"); + report_lua_failed(L); + goto endCall; + } + + if (!lua_isnumber(L, -1)) { // check + errno = -EINVAL; + perror("function collectors.lua work must return a number."); + goto endReturn; + } + lret = lua_tonumber(L, -1); + lua_pop(L, 1); + if (lret < 0) { + errno = -EINVAL; + ret = -1; + perror("collectors.lua work failed."); + goto endReturn; + } + + return ret; + endReturn: + endCall: + return ret; +} + +#include +#include +typedef long bee_time_t; +#define APP_LOOP_PERIOD 15 +static bee_time_t local_time(void) { + int ret; + struct timespec tp; + + ret = clock_gettime(CLOCK_MONOTONIC, &tp); + if (ret == 0) { + return tp.tv_sec * 1000000 + tp.tv_nsec / 1000; + } else { + perror("get clock failed."); + exit(1); + return 0; + } +} + +int app_collector_run(struct beeQ* q, void* arg) { + int ret = 0; + lua_State *L; + lua_State **pL; + + L = app_collector_init(q, APP_LOOP_PERIOD); + if (L == NULL) { + ret = -1; + goto endInit; + } + pL = &L; + + while (1) { + bee_time_t t1, t2, delta; + t1 = local_time(); + ret = app_collector_work(pL, q, APP_LOOP_PERIOD); + if (ret < 0) { + goto endLoop; + } + t2 = local_time(); + + delta = t1 + APP_LOOP_PERIOD * 1000000 - t2; + + if (delta > 0) { + usleep(delta); + } + } + + lua_close(L); + return 0; + endLoop: + endInit: + return ret; +} diff --git a/source/tools/monitor/unity/beeQ/apps.h b/source/tools/monitor/unity/beeQ/apps.h new file mode 100644 index 0000000000000000000000000000000000000000..734689ffddff71d1486dbb13f7c2eb945c817c37 --- /dev/null +++ b/source/tools/monitor/unity/beeQ/apps.h @@ -0,0 +1,20 @@ +// +// Created by 廖肇燕 on 2022/12/26. +// + +#ifndef UNITY_APPS_H +#define UNITY_APPS_H + +#include +#include + +struct beeMsg { + int size; + char body[]; +}; + +lua_State * app_recv_init(void); +int app_recv_proc(void* msg, void * arg); +int app_collector_run(struct beeQ* q, void* arg); + +#endif //UNITY_APPS_H diff --git a/source/tools/monitor/unity/beeQ/beeQ.c b/source/tools/monitor/unity/beeQ/beeQ.c new file mode 100644 index 0000000000000000000000000000000000000000..38e46fcc587dd636da4b30d07743de2f406e4bb4 --- /dev/null +++ b/source/tools/monitor/unity/beeQ/beeQ.c @@ -0,0 +1,292 @@ +// +// Created by 廖肇燕 on 2022/12/7. +// + +#include "beeQ.h" +#include +#include + +#define USE_BEEQ_DEBUG +#ifdef USE_BEEQ_DEBUG +#define BEEQ_DEBUG(...)\ + do{\ + fprintf(stderr,"-----BEEQ DEBUG-----\n");\ + fprintf(stderr,"%s %s\n",__TIME__,__DATE__);\ + fprintf(stderr,"%s:%d:%s():",__FILE__,__LINE__,__func__);\ + fprintf(stderr,__VA_ARGS__);\ + }while(0) +#else +#define BEEQ_DEBUG(...)\ +do{}while(0) +#endif + +#define LOOP_QUEUE_MAX 32 + +struct beeMsg { + struct beeQ *q; + void *arg; + int (*cb)(struct beeQ *q, void* arg); +}; + +inline int isfull(struct beeQ* q) { + return (q->send + 1) % q->size == q->recv; +} + +inline int isempty(struct beeQ* q) { + return q->send == q->recv; +} + +static int beeQ_register(struct beeQ *q) { + int i; + pthread_t tid = pthread_self(); + + pthread_mutex_lock(&q->mtx); + if (q->stop || q->tid_count >= BEEQ_TIDS) { + pthread_mutex_unlock(&q->mtx); + return -ENOENT; + } + + for (i = 0; i < BEEQ_TIDS; i ++) { + if (q->tids[i] == 0) { + q->tids[i] = tid; + break; + } + } + + q->tid_count ++; + pthread_mutex_unlock(&q->mtx); + return 0; +} + +static int beeQ_thread_exit(struct beeQ *q) { + int i; + pthread_t tid = pthread_self(); + + pthread_mutex_lock(&q->mtx); + if (q->tid_count == 0) { + pthread_mutex_unlock(&q->mtx); + return 0; + } + for (i = 0; i < BEEQ_TIDS; i ++) { + if (q->tids[i] == tid) { + q->tids[i] = 0; + break; + } + } + pthread_mutex_unlock(&q->mtx); + return 0; +} + +static int beeQ_join(struct beeQ *q) { + int i; + + pthread_mutex_lock(&q->mtx); + for (i = 0; i < BEEQ_TIDS; i ++) { + if (q->tids[i] != 0) { + pthread_mutex_unlock(&q->mtx); + pthread_join(q->tids[i], NULL); + pthread_mutex_lock(&q->mtx); + } + } + pthread_mutex_unlock(&q->mtx); + return 0; +} + +static void * beeQ_proc(void * arg) { + struct beeQ* q = (struct beeQ*)arg; + + if (beeQ_register(q)) { + return NULL; + } + + BEEQ_DEBUG("start proc thread.\n"); + pthread_mutex_lock(&q->mtx); + pthread_cond_signal(&q->cond); + while (q->stop == 0) { + pthread_cond_wait(&q->cond, &q->mtx); + while (!isempty(q)) { + void* msg; + + q->recv = (q->recv + 1) % q->size; + msg = q->msgs[q->recv]; + q->msgs[q->recv] = NULL; + + pthread_mutex_unlock(&q->mtx); // Processing messages can be very time consuming + q->cb(msg, q->arg); // the call back function should + pthread_mutex_lock(&q->mtx); + } + } + pthread_mutex_unlock(&q->mtx); + + beeQ_thread_exit(q); + return NULL; +} + +struct beeQ* beeQ_init(int size, int (*cb)(void *msg, void* arg), void *arg) { + int res; + struct beeQ* q; + pthread_t tid; + int i; + + q = (struct beeQ*) malloc(sizeof(struct beeQ)); + if (q == NULL) { + errno = ENOMEM; + goto failStruct; + } + + pthread_mutex_init(&q->mtx, NULL); + pthread_cond_init(&q->cond, NULL); + q->stop = 0; + + q->recv = 0; + q->send = 0; + q->size = size; + + q->msgs = (void **) malloc(size * sizeof(void *)); + if (q->msgs == NULL) { + errno = ENOMEM; + goto failMsg; + } + for (i = 0; i < size; i ++) { + q->msgs[i] = NULL; + } + q->cb = cb; + q->arg = arg; + + q->tid_count = 0; + for (i = 0; i < BEEQ_TIDS; i ++) { + q->tids[i] = 0; + } + + res = pthread_create(&tid, NULL, beeQ_proc, (void *)q); + if (res == -1) { + errno = ENOENT; + goto failThread; + } + + // confirm receiver thread is wait for queue. + pthread_mutex_lock(&q->mtx); + pthread_cond_wait(&q->cond, &q->mtx); + pthread_mutex_unlock(&q->mtx); + return q; + + failThread: + free(q->msgs); + failMsg: + free(q); + failStruct: + return NULL; +} + +int beeQ_stop(struct beeQ *q) { + + pthread_mutex_lock(&q->mtx); + q->stop = 1; + if (isempty(q)) { + pthread_cond_signal(&q->cond); + } + pthread_mutex_unlock(&q->mtx); + + beeQ_join(q); + + pthread_mutex_destroy(&q->mtx); + pthread_cond_destroy(&q->cond); + + while (!isempty(q)) { // clear msg queue; + void* msg; + + q->recv = (q->recv + 1) % q->size; + msg = q->msgs[q->recv]; + q->msgs[q->recv] = NULL; + + free(msg); + } + + free(q->msgs); + q->msgs = NULL; + free(q); + return 0; +} + +int beeQ_send(struct beeQ *q, void *msg) { + int loop = 0; + + pthread_mutex_lock(&q->mtx); + if (q->stop) { + pthread_mutex_unlock(&q->mtx); + free(msg); + return -1; + } + + while (isfull(q)) { // full + pthread_mutex_unlock(&q->mtx); + usleep(30000); + loop ++; + if (loop < LOOP_QUEUE_MAX) { + pthread_mutex_lock(&q->mtx); //continue. + } else { + fprintf(stderr, "message que is full now.\n"); + free(msg); + return 0; + } + } + + if (isempty(q)) { + pthread_cond_signal(&q->cond); // need to wakeup. + } + q->send = (q->send + 1) % q->size; + q->msgs[q->send] = msg; + pthread_mutex_unlock(&q->mtx); + return 0; +} + +static void * beeQ_send_run(void * args) { + struct beeMsg* msg = (struct beeMsg*)args; + struct beeQ *q = msg->q; + void *arg = msg->arg; + int (*cb)(struct beeQ *q, void* arg) = msg->cb; + + free(args); + + if (beeQ_register(q)) { + return NULL; + } + + BEEQ_DEBUG("SEND QUEUE IS WORKING.\n"); + cb(q, arg); + beeQ_thread_exit(q); + return NULL; +} + +int beeQ_send_thread(struct beeQ *q, void *arg, int (*cb)(struct beeQ *q, void* arg)) { + pthread_t tid; + int res; + struct beeMsg* msg; + + if (q->stop) { + return -ENOENT; + } + + msg = malloc(sizeof(struct beeMsg)); + if (msg == NULL) { + res = -ENOMEM; + goto failMalloc; + } + + msg->q = q; + msg->arg = arg; + msg->cb = cb; + + res = pthread_create(&tid, NULL, beeQ_send_run, (void *)msg); + if (res == -1) { + res = -ENOENT; + goto failThread; + } + res = 0; + return res; + + failThread: + free(msg); + failMalloc: + return res; +} diff --git a/source/tools/monitor/unity/beeQ/beeQ.h b/source/tools/monitor/unity/beeQ/beeQ.h new file mode 100644 index 0000000000000000000000000000000000000000..e04be1d74370cf45220b3a678972f111f401c93d --- /dev/null +++ b/source/tools/monitor/unity/beeQ/beeQ.h @@ -0,0 +1,36 @@ +// +// Created by 廖肇燕 on 2022/12/7. +// + +#ifndef TINYINFO_BEEQ_H +#define TINYINFO_BEEQ_H +#define _GNU_SOURCE +#include +#include +#include + +#define BEEQ_TIDS 32 + +struct beeQ { + pthread_mutex_t mtx; + pthread_cond_t cond; + int stop; + + int send; + int recv; + int size; + + void **msgs; + void *arg; + int (*cb)(void *msg, void *arg); // callback for message. + + int tid_count; + pthread_t tids[BEEQ_TIDS]; +}; + +int beeQ_send(struct beeQ *q, void *msg); +int beeQ_send_thread(struct beeQ *q, void *arg, int (*cb)(struct beeQ *q, void* arg)); +struct beeQ* beeQ_init(int size, int (*cb)(void *msg, void* arg), void *arg); +int beeQ_stop(struct beeQ *q); + +#endif //TINYINFO_BEEQ_H diff --git a/source/tools/monitor/unity/beeQ/bees.c b/source/tools/monitor/unity/beeQ/bees.c new file mode 100644 index 0000000000000000000000000000000000000000..361b7f943e80c03868761662c654d5398f7b4492 --- /dev/null +++ b/source/tools/monitor/unity/beeQ/bees.c @@ -0,0 +1,56 @@ +// +// Created by 廖肇燕 on 2022/12/26. +// + +#include "beeQ.h" +#include "apps.h" +#include "beaver.h" +#include +#include +#include + +#define RUN_THREAD_MAX 8 +#define RUN_QUEUE_SIZE 32 + +volatile int sighup_counter = 0; + +void sig_handler(int num) +{ + printf("receive the signal %d.\n", num); + if (num == SIGHUP) { + sighup_counter ++; + } else { + exit(1); + } +} + +static int beeQ_collectors(struct beeQ* q) { + beeQ_send_thread(q, NULL, app_collector_run); +} + +int main(int argc, char *argv[]) { + lua_State *L; + lua_State **pL; + struct beeQ* q; + + signal(SIGHUP, sig_handler); + signal(SIGINT, sig_handler); + + L = app_recv_init(); + if (L == NULL) { + exit(1); + } + + pL = &L; + q = beeQ_init(RUN_QUEUE_SIZE, app_recv_proc, (void *)pL); + if (q == NULL) { + exit(1); + } + beeQ_send_thread(q, NULL, app_collector_run); + + beaver_init(8400, 3); + pause(); + fprintf(stderr, "test exit."); + beeQ_stop(q); + return 0; +} diff --git a/source/tools/monitor/unity/beeQ/bees.lua b/source/tools/monitor/unity/beeQ/bees.lua new file mode 100644 index 0000000000000000000000000000000000000000..91c1c4e30a5d9fe3cf61b0698a0c99e90d45297d --- /dev/null +++ b/source/tools/monitor/unity/beeQ/bees.lua @@ -0,0 +1,27 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/26 4:02 PM +--- + +package.path = package.path .. ";../common/?.lua;" +package.path = package.path .. ";../tsdb/?.lua;" +package.path = package.path .. ";../tsdb/native/?.lua;" + +local CfoxRecv = require("foxRecv") +local unistd = require("posix.unistd") +--local proto = require("protoData") +--local system = require("system") + + +local fox = CfoxRecv.new() + +function init(tid) + print(string.format("hello beeQ, pid: %d, tid: %d", unistd.getpid(), tid)) + return 0 +end + +function proc(stream) + fox:write(stream) + return 0 +end diff --git a/source/tools/monitor/unity/beeQ/collectors.lua b/source/tools/monitor/unity/beeQ/collectors.lua new file mode 100644 index 0000000000000000000000000000000000000000..66aef5205dca4de0a2f2343e0ee74908124940b8 --- /dev/null +++ b/source/tools/monitor/unity/beeQ/collectors.lua @@ -0,0 +1,24 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/26 11:26 PM +--- +package.path = package.path .. ";../common/?.lua;" +package.path = package.path .. ";../collector/?.lua;" +package.path = package.path .. ";../collector/native/?.lua;" + +local Cloop = require("loop") +local system = require("system") + +workLoop = nil + +function init(que, t) + local work = Cloop.new(que) + workLoop = work + return 0 +end + +function work(t) + workLoop:work(t) + return 0 +end diff --git a/source/tools/monitor/unity/beeQ/foxRecv.lua b/source/tools/monitor/unity/beeQ/foxRecv.lua new file mode 100644 index 0000000000000000000000000000000000000000..a77b9dcd3f671536bd07a5e42c736944176a919a --- /dev/null +++ b/source/tools/monitor/unity/beeQ/foxRecv.lua @@ -0,0 +1,22 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/26 3:57 PM +--- + +require("class") + +local CfoxTSDB = require("foxTSDB") + +local CfoxRecv = class("CfoxRecv") + +function CfoxRecv:_init_() + self._fox = CfoxTSDB.new() + self._fox:setupWrite() +end + +function CfoxRecv:write(stream) + self._fox:write(stream) +end + +return CfoxRecv diff --git a/source/tools/monitor/unity/collector/kvProc.lua b/source/tools/monitor/unity/collector/kvProc.lua new file mode 100644 index 0000000000000000000000000000000000000000..e60d8e31c1cd437a271ffc0b540c94641ebe9f9f --- /dev/null +++ b/source/tools/monitor/unity/collector/kvProc.lua @@ -0,0 +1,52 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/16 11:30 PM +--- + +local system = require("system") +require("class") +local CvProc = require("vproc") + +local CkvProc = class("kvProc", CvProc) + +function CkvProc:_init_(proto, pffi, pFile, tName) + CvProc._init_(self, proto, pffi, pFile) + self._protoTable = { + line = tName, + ls = nil, + vs = {} + } +end + +function CkvProc:checkTitle(title) + local res = string.gsub(title, ":", "") + res = string.gsub(res, "%)", "") + res = string.gsub(res, "%(", "_") + return res +end + +function CkvProc:readKV(line) + local data = self._ffi.new("var_kvs_t") + assert(self._cffi.var_input_kvs(self._ffi.string(line), data) == 0) + assert(data.no >= 1) + + local name = self._ffi.string(data.s) + name = self:checkTitle(name) + local value = tonumber(data.value[0]) + + local cell = {name=name, value=value} + table.insert(self._protoTable["vs"], cell) +end + +function CkvProc:proc(elapsed, lines) + self._protoTable.vs = {} + CvProc.proc(self) + for line in io.lines(self.pFile) do + self:readKV(line) + end + self:appendLine(self._protoTable) + return self:push(lines) +end + +return CkvProc \ No newline at end of file diff --git a/source/tools/monitor/unity/collector/loop.lua b/source/tools/monitor/unity/collector/loop.lua new file mode 100644 index 0000000000000000000000000000000000000000..2fdbda64f7fa97ef7b7116b26e684c526e292267 --- /dev/null +++ b/source/tools/monitor/unity/collector/loop.lua @@ -0,0 +1,44 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/16 10:39 PM +--- + +require("class") +local CprotoData = require("protoData") +local procffi = require("procffi") + +local CprocStat = require("proc_stat") +local CprocMeminfo = require("proc_meminfo") +local CprocVmstat = require("proc_vmstat") +local CprocNetdev = require("proc_netdev") +local CprocDiskstats = require("proc_diskstats") + +local Cplugin = require("plugin") + +local Cloop = class("loop") + +function Cloop:_init_(que) + self._proto = CprotoData.new(que) + self._procs = { + CprocStat.new(self._proto, procffi), + CprocMeminfo.new(self._proto, procffi), + CprocVmstat.new(self._proto, procffi), + CprocNetdev.new(self._proto, procffi), + CprocDiskstats.new(self._proto, procffi), + } + self._plugin = Cplugin.new(self._proto) +end + +function Cloop:work(t) + local lines = self._proto:protoTable() + for k, obj in pairs(self._procs) do + lines = obj:proc(t, lines) + end + lines = self._plugin:proc(t, lines) + print(#lines.lines) + local bytes = self._proto:encode(lines) + self._proto:que(bytes) +end + +return Cloop diff --git a/source/tools/monitor/unity/collector/native/Makefile b/source/tools/monitor/unity/collector/native/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..988c905c09adf4b4ca2610a8f3660dd835f0cd4f --- /dev/null +++ b/source/tools/monitor/unity/collector/native/Makefile @@ -0,0 +1,16 @@ +CC := gcc +CFLAG := -g -fpic +LDFLAG := -g -fpic -shared +OBJS := procffi.o +SO := libprocffi.so + +all: $(SO) + +procffi.o: procffi.c + $(CC) -c $< -o $@ $(CFLAG) + +$(SO): $(OBJS) + $(CC) -o $@ $(OBJS) $(LDFLAG) + +clean: + rm -f $(SO) $(OBJS) \ No newline at end of file diff --git a/source/tools/monitor/unity/collector/native/plugincffi.lua b/source/tools/monitor/unity/collector/native/plugincffi.lua new file mode 100644 index 0000000000000000000000000000000000000000..f566dd826fe8a30287bc30b959443811af329270 --- /dev/null +++ b/source/tools/monitor/unity/collector/native/plugincffi.lua @@ -0,0 +1,43 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/30 3:40 PM +--- + +local ffi = require("ffi") +ffi.cdef [[ +struct unity_index { + char name[16]; + char index[16]; +}; + +struct unity_value { + char name[16]; + double value; +}; + +struct unity_log { + char name[16]; + char* log; +}; + +struct unity_line { + char table[32]; + struct unity_index indexs[4]; + struct unity_value values[32]; + struct unity_log log; +}; + +struct unity_lines { + int num; + struct unity_line *line; +}; + +int init(void * arg); +int call(int t, struct unity_lines* lines); +void deinit(void); + +void free(void *p); +]] + +return ffi diff --git a/source/tools/monitor/unity/collector/native/procffi.c b/source/tools/monitor/unity/collector/native/procffi.c new file mode 100644 index 0000000000000000000000000000000000000000..4f15238fc0489626202e74d88f98b8b7742ad005 --- /dev/null +++ b/source/tools/monitor/unity/collector/native/procffi.c @@ -0,0 +1,119 @@ +// +// Created by 廖肇燕 on 2022/12/16. +// + +#include "procffi.h" + +#include +#include + +static inline int var_next(char ** ppv) { + char *pv = *ppv; + + if (pv == NULL) { + return -1; + } + while (*pv == ' ') { + pv ++; + } + if (*pv == '\0') { + return -1; + } + + *ppv = pv; + return 0; +} + +int var_input_long(const char * line, struct var_long *p) { + char *pv = (char *)line; + int res; + int i; + + p->no = 0; + if (var_next(&pv)) { + return 0; + } + + for (i = 0; i < VAR_INDEX_MAX; i ++) { + res = sscanf(pv, "%lld", &p->value[i]); + if (!res) { + goto breakLoop; + } + + pv = strchr(pv, ' '); + if (var_next(&pv)) { + goto breakLoop; + } + } + p->no = i; + return 0; + breakLoop: + p->no = i + 1; + return 0; +} + +int var_input_string(const char * line, struct var_string *p) { + char *pv = (char *)line; + int res; + int i; + + p->no = 0; + if (var_next(&pv)) { + return 0; + } + + for (i = 0; i < VAR_INDEX_MAX; i ++) { + res = sscanf(pv, "%31s", &p->s[i][0]); + if (!res) { + goto breakLoop;; + } + + pv = strchr(pv, ' '); + if (var_next(&pv)) { + goto breakLoop; + } + } + p->no = i; + return 0; + breakLoop: + p->no = i + 1; + return 0; +} + +int var_input_kvs(const char * line, struct var_kvs *p) { + char *pv = (char *)line; + int res; + int i; + + p->no = 0; + if (var_next(&pv)) { + return 0; + } + + res = sscanf(pv, "%31s", &p->s[0]); + if (!res) { + return -1; + } + + pv = strchr(pv, ' '); + if (var_next(&pv)) { + return 0; + } + + for (i = 0; i < VAR_INDEX_MAX; i ++) { + res = sscanf(pv, "%lld", &p->value[i]); + if (!res) { + goto breakLoop; + } + + pv = strchr(pv, ' '); + if (var_next(&pv)) { + goto breakLoop; + } + } + p->no = i; + return 0; + breakLoop: + p->no = i + 1; + return 0; +} diff --git a/source/tools/monitor/unity/collector/native/procffi.h b/source/tools/monitor/unity/collector/native/procffi.h new file mode 100644 index 0000000000000000000000000000000000000000..70a2d02a33f5c7086d374740cc8c17a3547197b3 --- /dev/null +++ b/source/tools/monitor/unity/collector/native/procffi.h @@ -0,0 +1,30 @@ +// +// Created by 廖肇燕 on 2022/12/16. +// + +#ifndef UNITY_PROCFFI_H +#define UNITY_PROCFFI_H + +#define VAR_INDEX_MAX 64 + +typedef struct var_long { + int no; + long long value[VAR_INDEX_MAX]; +}var_long_t; + +typedef struct var_string { + int no; + char s[VAR_INDEX_MAX][32]; +}var_string_t; + +typedef struct var_kvs { + int no; + char s[32]; + long long value[VAR_INDEX_MAX]; +}var_kvs_t; + +int var_input_long(const char * line, struct var_long *p); +int var_input_string(const char * line, struct var_string *p); +int var_input_kvs(const char * line, struct var_kvs *p); + +#endif //UNITY_PROCFFI_H diff --git a/source/tools/monitor/unity/collector/native/procffi.lua b/source/tools/monitor/unity/collector/native/procffi.lua new file mode 100644 index 0000000000000000000000000000000000000000..efe6eab89ad89af93072458a7e3fb48cfeebb86d --- /dev/null +++ b/source/tools/monitor/unity/collector/native/procffi.lua @@ -0,0 +1,31 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/16 9:38 PM +--- + +local ffi = require("ffi") +local cffi = ffi.load('procffi') + +ffi.cdef [[ +typedef struct var_long { + int no; + long long value[64]; +}var_long_t; + +typedef struct var_string { + int no; + char s[64][32]; +}var_string_t; + +typedef struct var_kvs { + int no; + char s[32]; + long long value[64]; +}var_kvs_t; +int var_input_long(const char * line, struct var_long *p); +int var_input_string(const char * line, struct var_string *p); +int var_input_kvs(const char * line, struct var_kvs *p); +]] + +return {ffi = ffi, cffi=cffi} diff --git a/source/tools/monitor/unity/collector/plugin.lua b/source/tools/monitor/unity/collector/plugin.lua new file mode 100644 index 0000000000000000000000000000000000000000..bfa2704b0ba087a987350f177082df6fe2ee7095 --- /dev/null +++ b/source/tools/monitor/unity/collector/plugin.lua @@ -0,0 +1,105 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/30 10:20 AM +--- + +require("class") + +local Cplugin = class("plugin") + +function Cplugin:_init_(proto, fYaml) + self._proto = proto + fYaml = fYaml or "../collector/plugin.yaml" + self._ffi = require("plugincffi") + + local res = self:loadYaml(fYaml) + self:setup(res.plugins) +end + +function Cplugin:_del_() + for _, plugin in ipairs(self._plugins) do + local cffi = plugin.cffi + cffi.deinit() + end +end + +function Cplugin:loadYaml(fYaml) + local lyaml = require("lyaml") + local f = io.open(fYaml,"r") + local s = f:read("*all") + f:close() + + return lyaml.load(s) +end + +function Cplugin:setup(plugins) + self._plugins = {} + for _, plugin in ipairs(plugins) do + local so = plugin.so + if so then + local cffi = self._ffi.load(so) + local plugin = { + so = plugin.so, + cffi = cffi + } + cffi.init(nil); + table.insert(self._plugins, plugin) + end + end +end + +function Cplugin:load_label(unity_line, line) + for i=0, 4 - 1 do + local name = self._ffi.string(unity_line.indexs[i].name) + local index = self._ffi.string(unity_line.indexs[i].index) + + if #name > 0 then + table.insert(line.ls, {name = name, index = index}) + else + return + end + end +end + +function Cplugin:load_value(unity_line, line) + for i=0, 32 - 1 do + local name = self._ffi.string(unity_line.values[i].name) + local value = unity_line.values[i].value + + if #name > 0 then + table.insert(line.vs, {name = name, value = value}) + else + return + end + end +end + +function Cplugin:_proc(unity_lines, lines) + for i=0, unity_lines.num - 1 do + local unity_line = unity_lines.line[i] + local line = {line = self._ffi.string(unity_line.table), + ls = {}, + vs = {}, + log = {}} + + self:load_label(unity_line, line) + self:load_value(unity_line, line) + table.insert(lines["lines"], line) + end +end + +function Cplugin:proc(t, lines) + for _, plugin in ipairs(self._plugins) do + local cffi = plugin.cffi + local unity_lines = self._ffi.new("struct unity_lines") + local res = cffi.call(t, unity_lines) + if res == 0 then + self:_proc(unity_lines, lines) + end + self._ffi.C.free(unity_lines.line) -- should free memory. + end + return lines +end + +return Cplugin diff --git a/source/tools/monitor/unity/collector/plugin.yaml b/source/tools/monitor/unity/collector/plugin.yaml new file mode 100644 index 0000000000000000000000000000000000000000..25c841875c2652d40e7eaea395098133306c8e7b --- /dev/null +++ b/source/tools/monitor/unity/collector/plugin.yaml @@ -0,0 +1,4 @@ +plugins: + - + so: sample + description: "just a example." \ No newline at end of file diff --git a/source/tools/monitor/unity/collector/plugin/Makefile b/source/tools/monitor/unity/collector/plugin/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f33bf6081cd3d272ffb8e56ba658a05d2a06b44a --- /dev/null +++ b/source/tools/monitor/unity/collector/plugin/Makefile @@ -0,0 +1,7 @@ +DEPMOD=sample + +$(DEPMOD):ECHO + make -C $@ + +ECHO: + @echo $(SUBDIRS) diff --git a/source/tools/monitor/unity/collector/plugin/plugin_head.h b/source/tools/monitor/unity/collector/plugin/plugin_head.h new file mode 100644 index 0000000000000000000000000000000000000000..12edc015c1809f8c213cc51d9c60461df5d68769 --- /dev/null +++ b/source/tools/monitor/unity/collector/plugin/plugin_head.h @@ -0,0 +1,90 @@ +// +// Created by 廖肇燕 on 2022/12/30. +// + +#ifndef UNITY_PLUGIN_HEAD_H +#define UNITY_PLUGIN_HEAD_H + +struct unity_index { + char name[16]; + char index[16]; +}; + +struct unity_value { + char name[16]; + double value; +}; + +struct unity_log { + char name[16]; + char* log; +}; + +struct unity_line { + char table[32]; + struct unity_index indexs[4]; + struct unity_value values[32]; + struct unity_log log; +}; + +struct unity_lines { + int num; + struct unity_line *line; +}; + +#include // for malloc exit +#include // for memset +#include +#include +inline int unity_alloc_lines(struct unity_lines * lines, unsigned int num) __attribute__((always_inline)); +inline struct unity_line * unity_get_line(struct unity_lines * lines, unsigned int i) __attribute__((always_inline)); +inline int unity_set_table(struct unity_line * line, const char * table) __attribute__((always_inline)); +inline int unity_set_index(struct unity_line * line, unsigned int i, const char * name, const char * index) __attribute__((always_inline)); +inline int unity_set_value(struct unity_line * line, unsigned int i, const char * name, double value) __attribute__((always_inline)); + +inline int unity_alloc_lines(struct unity_lines * lines, unsigned int num) { + size_t size = num * sizeof (struct unity_line); + lines->line = (struct unity_line *)(malloc(size)); + + if (lines->line == NULL) { + perror("alloc memory for unity line failed."); + exit(1); + } + memset(lines->line, 0, size); + lines->num = num; + return num; +} + +inline struct unity_line * unity_get_line(struct unity_lines * lines, unsigned int i) { + if (i >= 4) { + return NULL; + } + return &(lines->line[i]); +} + +inline int unity_set_table(struct unity_line * line, const char * table) { + strncpy(line->table, table, 32); + return 0; +} + +inline int unity_set_index(struct unity_line * line, + unsigned int i, const char * name, const char * index) { + if (i >= 4) { + return -ERANGE; + } + strncpy(line->indexs[i].name, name, 16); + strncpy(line->indexs[i].index, index, 16); + return 0; +} + +inline int unity_set_value(struct unity_line * line, + unsigned int i, const char * name, double value) { + if (i >= 32) { + return -ERANGE; + } + strncpy(line->values[i].name, name, 16); + line->values[i].value = value; + return 0; +} + +#endif //UNITY_PLUGIN_HEAD_H diff --git a/source/tools/monitor/unity/collector/plugin/sample/Makefile b/source/tools/monitor/unity/collector/plugin/sample/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..97fceee561bf0218368e29dbe600b723bc9f9b98 --- /dev/null +++ b/source/tools/monitor/unity/collector/plugin/sample/Makefile @@ -0,0 +1,19 @@ +CC := gcc +CFLAG := -g -fpic +LDFLAG := -g -fpic -shared +OBJS := sample.o +SO := libsample.so + +all: $(SO) install + +%.o: %.c + $(CC) -c $< -o $@ $(CFLAG) + +$(SO): $(OBJS) + $(CC) -o $@ $(OBJS) $(LDFLAG) + +install: $(SO) + cp $(SO) ../../native/ + +clean: + rm -f $(SO) $(OBJS) \ No newline at end of file diff --git a/source/tools/monitor/unity/collector/plugin/sample/sample.c b/source/tools/monitor/unity/collector/plugin/sample/sample.c new file mode 100644 index 0000000000000000000000000000000000000000..69200b68aa757795eacacc15715f251501e2477d --- /dev/null +++ b/source/tools/monitor/unity/collector/plugin/sample/sample.c @@ -0,0 +1,36 @@ +// +// Created by 廖肇燕 on 2022/12/30. +// + +#include "sample.h" + +int init(void * arg) { + printf("sample plugin install.\n"); + return 0; +} + +int call(int t, struct unity_lines* lines) { + static double value = 0.0; + struct unity_line* line; + + unity_alloc_lines(lines, 2); + line = unity_get_line(lines, 0); + unity_set_table(line, "sample_tbl1"); + unity_set_index(line, 0, "mode", "sample1"); + unity_set_value(line, 0, "value1", 1.0 + value); + unity_set_value(line, 1, "value2", 2.0 + value); + + line = unity_get_line(lines, 1); + unity_set_table(line, "sample_tbl2"); + unity_set_value(line, 0, "value1", 3.0 + value); + unity_set_value(line, 1, "value2", 4.0 + value); + unity_set_value(line, 2, "value3", 3.1 + value); + unity_set_value(line, 3, "value4", 4.1 + value); + + value += 0.1; + return 0; +} + +void deinit(void) { + printf("sample plugin uninstall\n"); +} diff --git a/source/tools/monitor/unity/collector/plugin/sample/sample.h b/source/tools/monitor/unity/collector/plugin/sample/sample.h new file mode 100644 index 0000000000000000000000000000000000000000..7b9e7c28e9deee4f673a78522713cb1f4e7cb6e5 --- /dev/null +++ b/source/tools/monitor/unity/collector/plugin/sample/sample.h @@ -0,0 +1,14 @@ +// +// Created by 廖肇燕 on 2022/12/30. +// + +#ifndef UNITY_SAMPLE_H +#define UNITY_SAMPLE_H + +#include "../plugin_head.h" + +int init(void * arg); +int call(int t, struct unity_lines* lines); +void deinit(void); + +#endif //UNITY_SAMPLE_H diff --git a/source/tools/monitor/unity/collector/proc_diskstats.lua b/source/tools/monitor/unity/collector/proc_diskstats.lua new file mode 100644 index 0000000000000000000000000000000000000000..9465231ca801fc3b19d28dc0dedc46b700c59062 --- /dev/null +++ b/source/tools/monitor/unity/collector/proc_diskstats.lua @@ -0,0 +1,133 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/16 11:49 PM +--- + +require("class") +local system = require("system") +local CvProc = require("vproc") + +local CprocDiskstats = class("proc_diskstats", CvProc) + +function CprocDiskstats:_init_(proto, pffi, pFile) + CvProc._init_(self, proto, pffi, pFile or "/proc/diskstats") + self._lastData = {} + self._lastDisk = {} + self._diskVNum = 11 +end + +function CprocDiskstats:_diskIndex() + return { + "reads", "rmerge", "rkb", "rmsec", + "writes", "wmerge", "wkb", "wmsec", + "inflight", "time", "backlog" + } +end + +function CprocDiskstats:_diffIndex() + return { + "reads", "rmerge", "rkb", "rmsec", + "writes", "wmerge", "wkb", "wmsec", + "backlog", "xfers" + } +end + +-- "reads", "rmerge", "rkb", "rmsec", "writes", "wmerge", "wkb", "wmsec", "inflight", "time", "backlog" +function CprocDiskstats:_getNewValue(data) + local now = {} + local index = self:_diskIndex() + for i = 1, self._diskVNum do + local head = index[i] + now[head] = tonumber(self._ffi.string(data.s[i + 2])) + end + + now["rkb"] = now["rkb"] / 2 -- sectors = 512 bytes + now['wkb'] = now['wkb'] / 2 + now['xfers'] = now['reads'] + now['writes'] + if now['xfers'] == 0 then + now['bsize'] = 0 + else + now['bsize'] = (now['rkb'] + now['wkb']) * 1024 / now['xfers'] + end + + now['time'] = now['time'] / 10.0 + return now +end + +function CprocDiskstats:_calcDiff(disk_name, now, last, elapsed) + local protoTable = { + line = "disks", + ls = {{name = "disk_name", index = disk_name}}, + vs = {} + } + local index = self:_diffIndex() + + for i = 1, #index do + local value = (now[index[i]] - last[index[i]]) / elapsed + local cell = { + name = index[i], + value = value + } + table.insert(protoTable.vs, cell) + end + + local cell = { + name = "inflight", + value = now["inflight"] + } + table.insert(protoTable.vs, cell) + + cell = { + name = "bsize", + value = now["bsize"] + } + table.insert(protoTable.vs, cell) + + cell = { + name = "busy", + value = (now["time"] - now["time"]) / elapsed + } + table.insert(protoTable.vs, cell) + self:appendLine(protoTable) +end + +function CprocDiskstats:_calcDisk(disk_name, data, elapsed) + local now = self:_getNewValue(data) + local last = self._lastData[disk_name] + + if last then + self:_calcDiff(disk_name, now, last, elapsed) + end + self._lastData[disk_name] = now + self._lastDisk[disk_name] = 1 +end + +function CprocDiskstats:checkLastDisks() + for k, _ in pairs(self._lastData) do + if not self._lastDisk[k] then + self._lastData[k] = nil + end + end + self._lastDisk = {} +end + +function CprocDiskstats:_proc(line, elapsed) + local data = self._ffi.new("var_string_t") + assert(self._cffi.var_input_string(self._ffi.string(line), data) == 0) + assert(data.no >= 14) + + local disk_name = self._ffi.string(data.s[2]) + self:_calcDisk(disk_name, data, elapsed) +end + +function CprocDiskstats:proc(elapsed, lines) + CvProc.proc(self) + for line in io.lines(self.pFile) do + self:_proc(line, elapsed) + end + self:checkLastDisks() + return self:push(lines) +end + +return CprocDiskstats diff --git a/source/tools/monitor/unity/collector/proc_meminfo.lua b/source/tools/monitor/unity/collector/proc_meminfo.lua new file mode 100644 index 0000000000000000000000000000000000000000..51d34785efe99bfda799e867e60817f135e8161a --- /dev/null +++ b/source/tools/monitor/unity/collector/proc_meminfo.lua @@ -0,0 +1,16 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/16 11:36 PM +--- + +require("class") +local CkvProc = require("kvProc") + +local CprocMeminfo = class("proc_meminfo", CkvProc) + +function CprocMeminfo:_init_(proto, pffi, pFile) + CkvProc._init_(self, proto, pffi, pFile or "/proc/meminfo", "meminfo") +end + +return CprocMeminfo \ No newline at end of file diff --git a/source/tools/monitor/unity/collector/proc_netdev.lua b/source/tools/monitor/unity/collector/proc_netdev.lua new file mode 100644 index 0000000000000000000000000000000000000000..d0fe256df265e1c3cc423d96820a9937d8e6bf20 --- /dev/null +++ b/source/tools/monitor/unity/collector/proc_netdev.lua @@ -0,0 +1,97 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/16 11:57 PM +--- + +require("class") +local CvProc = require("vproc") +local system = require("system") + +local CprocNetdev = class("proc_netdev", CvProc) + +function CprocNetdev:_init_(proto, pffi, pFile) + CvProc._init_(self, proto, pffi, pFile or "/proc/net/dev") + self._lastData = {} + self._lastIfNames = {} +end + +function CprocNetdev:_netdevIndex() + return { + "if_ibytes", "if_ipackets", "if_ierrs", "if_idrop", "if_ififo", "if_iframe", "if_icompressed", "if_imulticast", + "if_obytes", "if_opackets", "if_oerrs", "if_odrop", "if_ofifo", "if_ocolls", "if_ocarrier", "if_ocompressed" + } +end + +function CprocNetdev:_getNewValue(ifName, data) + local now = {} + local index = self:_netdevIndex() + for i = 1, #index do + table.insert(now, tonumber(data.value[i - 1])) + end + self._lastData[ifName] = now + self._lastIfNames[ifName] = 1 +end + +function CprocNetdev:_calcIf(ifName, data, res, elapsed) + local now = {} + local index = self:_netdevIndex() + local protoTable = { + line = "networks", + ls = {{name = "network_name", index = ifName}}, + vs = {} + } + for i, index in ipairs(index) do + local nowValue = tonumber(data.value[i -1]) + table.insert(now, nowValue) + local value = (nowValue - res[i]) / elapsed + local cell = { + name = index, + value = value + } + table.insert(protoTable.vs, cell) + end + + self:appendLine(protoTable) + self._lastData[ifName] = now + self._lastIfNames[ifName] = 1 +end + +function CprocNetdev:_proc(line, elapsed) + local data = self._ffi.new("var_kvs_t") + assert(self._cffi.var_input_kvs(self._ffi.string(line), data) == 0) + assert(data.no == 16) + + local ifName = string.gsub(self._ffi.string(data.s), ":", "") + local last = self._lastData[ifName] + + if last then + self:_calcIf(ifName, data, last, elapsed) + else + self:_getNewValue(ifName, data) + end +end + +function CprocNetdev:checkLastIfNames() + for k, _ in pairs(self._lastData) do + if not self._lastIfNames[k] then + self._lastData[k] = nil + end + end + self._lastIfNames = {} +end + +function CprocNetdev:proc(elapsed, lines) + CvProc.proc(self) + local i = 1 + for line in io.lines(self.pFile) do + if i > 2 then + self:_proc(line, elapsed) + end + i = i + 1 + end + self:checkLastIfNames() + return self:push(lines) +end + +return CprocNetdev diff --git a/source/tools/monitor/unity/collector/proc_stat.lua b/source/tools/monitor/unity/collector/proc_stat.lua new file mode 100644 index 0000000000000000000000000000000000000000..966e7e5718ec5fb92fdac30ae638d26d13c84367 --- /dev/null +++ b/source/tools/monitor/unity/collector/proc_stat.lua @@ -0,0 +1,191 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/16 10:27 PM +--- + +require("class") +local pystring = require("pystring") +local CvProc = require("vproc") + +local CprocStat = class("procstat", CvProc) + +function CprocStat:_init_(proto, pffi, pFile) + CvProc._init_(self, proto, pffi, pFile or "/proc/stat") + self._funs = self:setupTable() + self._cpuArr = {} +end + +function CprocStat:_cpuHead() + return {"user", "nice", "sys", "idle", "iowait", + "hardirq", "softirq", "steal", "guest", "guestnice"} +end + +function CprocStat:_procCpu(now, last) + if last then + local vs = {} + local sum = 0 + local index = self:_cpuHead() + for i = 1, #index do + local delta = now.value[i - 1] - last.value[i - 1] + table.insert(vs, delta) + sum = sum + delta + end + + if sum > 0 then + local res = {} + local total = tonumber(sum) + for i = 1, #vs do + local v = tonumber(vs[i]) + local cell = {name=index[i], value=tonumber(v * 100.0 / total)} + table.insert(res, cell) + end + return res + end + end +end + +function CprocStat:_pCpuTotal(data) + local res = self:_procCpu(data, self._lastCpuTotal) + self._lastCpuTotal = data + + if res then + self:appendLine(self:_packProto("cpu_total", nil, res)) + end +end + +function CprocStat:_pperCpu(data, vcpu) + local res = self:_procCpu(data, self._cpuArr[vcpu]) + self._cpuArr[vcpu] = data + + if res then + local label = {{name = "cpu_name", index = "cpu" .. vcpu}} + self:appendLine( self:_packProto("cpus", label, res)) + end +end + +function CprocStat:_fcpu(line) + local s = string.sub(line, 4) + local ch = string.byte(s, 1) + + if ch == 32 then -- blank is 32 + local data = self._ffi.new("var_long_t") + assert(self._cffi.var_input_long(self._ffi.string(s), data) == 0) + assert(data.no == 10) + self:_pCpuTotal(data) + else + local data = self._ffi.new("var_kvs_t") + assert(self._cffi.var_input_kvs(self._ffi.string(s), data) == 0) + assert(data.no == 10) + local sNcpu = self._ffi.string(data.s) + local Ncpu = tonumber(sNcpu) + self:_pperCpu(data, Ncpu) + end +end + +function CprocStat:_sirqHead() + return {"hi", "timer", "nettx", "netrx", "bsirq", "iopoll", + "tasklet", "sched", "hrtimer", "rcu", "nr"} +end + +function CprocStat:_procSirq(now, last) + if last then + local res = {} + local index = self:_sirqHead() + for i = 1, #index do + local delta = now.value[i - 1] - last.value[i - 1] + local cell = {name=index[i], value=tonumber(delta)} + table.insert(res, cell) + end + return res + end +end + +function CprocStat:_fsirq(line) + local s = string.sub(line, 8) + + local data = self._ffi.new("var_long_t") + assert(self._cffi.var_input_long(self._ffi.string(s), data) == 0) + assert(data.no == 11) + + local res = self:_procSirq(data, self._lastSirq) + self._lastSirq = data + + if res then + self:appendLine(self:_packProto("sirq", nil, res)) + end +end + +function CprocStat:setupTable() + return { + ctxt = function(s) return self:ctxt(s) end, + btime = function(s) return self:btime(s) end, + processes = function(s) return self:processes(s) end, + procs_running = function(s) return self:procs_running(s) end, + procs_blocked = function(s) return self:procs_blocked(s) end, + } +end + +function CprocStat:ctxt(s) + local v = tonumber(s) + local tValue + if self._lastCtxt then + local res = v - self._lastCtxt + tValue = {name="ctxt", value=res} + end + self._lastCtxt = v + return tValue +end + +function CprocStat:btime(s) + local res = tonumber(s) + local tValue = {name="btime", value=res} + return tValue +end + +function CprocStat:processes(s) + local now = tonumber(s) + local tValue + if self._lastProcesses then + local res = now - self._lastProcesses + tValue = {name="processes_forks", value=res} + end + self._lastProcesses = now + return tValue +end + +function CprocStat:procs_running(s) + local res = tonumber(s) + local tValue = {name="procs_running", value=res} + return tValue +end + +function CprocStat:procs_blocked(s) + local res = tonumber(s) + local tValue = {name="procs_blocked", value=res} + return tValue +end + +function CprocStat:proc(elapsed, lines) + CvProc.proc(self) + local counter = {} + for line in io.lines(self.pFile) do + if pystring:startswith(line, "cpu") then + self:_fcpu(line) + elseif pystring:startswith(line, "softirq") then + self:_fsirq(line) + else + local res = pystring:split(line, ' ', 1) + if self._funs[res[1]] then + local tValue = self._funs[res[1]](res[2]) + if tValue then + table.insert(counter, tValue) + end + end + end + end + self:appendLine(self:_packProto("stat_counters", nil, counter, nil)) + return self:push(lines) +end + +return CprocStat diff --git a/source/tools/monitor/unity/collector/proc_vmstat.lua b/source/tools/monitor/unity/collector/proc_vmstat.lua new file mode 100644 index 0000000000000000000000000000000000000000..594ec2a4c9531c623bec10e719b59318f088a875 --- /dev/null +++ b/source/tools/monitor/unity/collector/proc_vmstat.lua @@ -0,0 +1,16 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/16 11:40 PM +--- + +require("class") +local CkvProc = require("kvProc") + +local CprocVmstat = class("proc_vmstat", CkvProc) + +function CprocVmstat:_init_(proto, pffi, pFile) + CkvProc._init_(self, proto, pffi, pFile or "/proc/vmstat", "vmstat") +end + +return CprocVmstat \ No newline at end of file diff --git a/source/tools/monitor/unity/collector/vproc.lua b/source/tools/monitor/unity/collector/vproc.lua new file mode 100644 index 0000000000000000000000000000000000000000..264ab70e4a85d507ed19e4f4f34418b065059b8a --- /dev/null +++ b/source/tools/monitor/unity/collector/vproc.lua @@ -0,0 +1,44 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/16 10:12 PM +--- + +require("class") +local system = require("system") + +local CvProc = class("vproc") + +function CvProc:_init_(proto, pffi, pFile) + self._proto = proto + self._cffi = pffi["cffi"] + self._ffi = pffi["ffi"] + self.pFile = pFile + print(pFile) +end + +function CvProc:proc(elapsed) + self._lines = self._proto:protoTable() +end + +function CvProc:appendLine(line) + table.insert(self._lines["lines"], line) +end + +function CvProc:copyLine(line) + self:appendLine(system:deepcopy(line)) +end + +function CvProc:push(lines) + for _, v in ipairs(self._lines["lines"]) do + table.insert(lines["lines"], v) + end + self._lines = nil + return lines +end + +function CvProc:_packProto(head, labels, vs, log) + return {line = head, ls = labels, vs = vs, log = log} +end + +return CvProc \ No newline at end of file diff --git a/source/tools/monitor/unity/common/class.lua b/source/tools/monitor/unity/common/class.lua new file mode 100644 index 0000000000000000000000000000000000000000..8e239435a382744093bd537b1b186adbb6dccdc8 --- /dev/null +++ b/source/tools/monitor/unity/common/class.lua @@ -0,0 +1,38 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/16 10:16 AM +--- + +function class(name, super) + local cls = { + __super = super, + __cname = name, + } + + + setmetatable(cls, {__index = super, }) + + if not cls._init_ then + cls._init_ = function(self, ...) end + end + + if not cls._del_ then + cls._del_ = function(self) end + end + + cls.__meta = {__index = cls} + cls.new = function(...) + local obj = setmetatable({}, cls.__meta) + obj:_init_(...) + + local proxy = newproxy(true) -- create dummy userdata + obj.__proxy = proxy -- bind dummy userdata to object + getmetatable(proxy).__gc = function() + obj:_del_() + end + + return obj + end + return cls +end diff --git a/source/tools/monitor/unity/common/lmd.lua b/source/tools/monitor/unity/common/lmd.lua new file mode 100644 index 0000000000000000000000000000000000000000..e7ba7e4ea3a08d423b4200eeab79a2ad21c4638e --- /dev/null +++ b/source/tools/monitor/unity/common/lmd.lua @@ -0,0 +1,458 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2023/1/2 10:45 PM +--- + +-- for markdown trans + +require("class") +local pystring = require("pystring") + +local Clmd = class("lmd") + +function Clmd:_init_() + self._escs = '\\`*_{}[]()>#+-.!' + self._cStr = "#+->_`|" + self._cbs = { + ["#"] = function(s) return self:pTitle(s) end, + } +end + +function Clmd:pTitle(s) + local res = pystring:split(s, " ", 1) + if #res < 2 then + error("bad markdown: "..s) + end + local head, value = unpack(res) + local level = #head + local tag = string.format("", level) + local etag = string.format("", level) + return pystring:join("", {tag, value, etag}) +end + +local function boldItalic(s) + if string.sub(s, -4, -4) == "\\" then + return s + end + return pystring:join("", {"", string.sub(s, 4, -4), ""}) +end + +local function bold(s) + if string.sub(s, -3, -3) == "\\" then + return s + end + return pystring:join("", {"", string.sub(s, 3, -3), ""}) +end + +local function italic(s) + if string.sub(s, -2, -2) == "\\" then + return s + end + return pystring:join("", {"", string.sub(s, 2, -2), ""}) +end + +local function delete(s) + if string.sub(s, -3, -3) == "\\" then + return s + end + return pystring:join("", {"", string.sub(s, 3, -3), ""}) +end + +local function code1(s) + return pystring:join("", {"", string.sub(s, 2, -2), ""}) +end + +local function code2(s) + return pystring:join("", {"", string.sub(s, 3, -3), ""}) +end + +local function pBI(s) + return string.gsub(s, "[%*_][%*_][%*_]%S.-%S-[%*_][%*_][%*_]", function(s) return boldItalic(s) end) +end + +local function pBold(s) + return string.gsub(s, "[%*_][%*_]%S.-%S-[%*_][%*_]", function(s) return bold(s) end) +end + +local function pItalic(s) + return string.gsub(s, "[%*_]%S.-%S-[%*_]", function(s) return italic(s) end) +end + +local function pDelete(s) + return string.gsub(s, "~~%S.-%S~~", function(s) return delete(s) end) +end + +local function pEnter(s) + return string.gsub(s, "%s%s+$", "
") +end + +local function pCode(s) + if string.find(s, "``") then + return string.gsub(s, "``.-``", function(s) return code2(s) end) + else + if string.sub(s, -2, -2) == "\\" then + return s + end + return string.gsub(s, "`.-`", function(s) return code1(s) end) + end +end + +local function links(s) + local name, link = unpack(pystring:split(s, "](", 1)) + name = string.sub(name, 2) + link = string.sub(link, 1, -2) + if string.sub(name, -1, -1) == "\\" then + return s + end + if string.sub(link, -1, -1) == "\\" then + return s + end + return string.format('%s', link, name) +end + +local function pLink(s) + return string.gsub(s, "%[.-%]%(.-%)", function(s) return links(s) end) +end + +local function Quotes(quotes, res) + local len = #quotes + local start = 1 + local level = 1 + for i = start, len do + local levels, body = unpack(pystring:split(quotes[i], " ", 1)) + local v = string.len(levels) + if v > level then + while v > level do + table.insert(res, "
") + level = level + 1 + end + elseif v < level then + while v < level do + table.insert(res, "
") + level = level - 1 + end + end + local line = pystring:join("", {"

", body, "

"}) + table.insert(res, line) + end + while level > 1 do + table.insert(res, "") + level = level - 1 + end +end + +local function pQuote(quotes, res) + table.insert(res, "
") + Quotes(quotes, res) + table.insert(res, "
") +end + +local function countBlankTab(s) + local blank = 0 + local tab = 0 + for i = 1, #s do + local ch = string.byte(s, i) + if ch == 0x20 then -- for blank + blank = blank + 1 + elseif ch == 0x09 then -- for tab + tab = tab + 1 + end + end + return blank, tab +end + +local function level4BT(s) + local blank, tab =countBlankTab(s) + return tab + blank / 4 +end + +function Clmd:ol(ols, res) + local len = #ols + local start = 1 + local level = 0 + + for i = start, len do + local levels, body = unpack(pystring:split(ols[i], ".", 1)) + local v = level4BT(levels) + if v > level then + while v > level do + table.insert(res, "
    ") + level = level + 1 + end + elseif v < level then + while v < level do + table.insert(res, "
") + level = level - 1 + end + end + local line = pystring:join("", {"
  • ", self:seg(string.sub(body, 2)), "
  • "}) + table.insert(res, line) + end + + while level > 0 do + table.insert(res, "") + level = level - 1 + end +end + +function Clmd:pOl(ols, res) + table.insert(res, "
      ") + self:ol(ols, res) + table.insert(res, "
    ") +end + +local function splitUl(s) + if pystring:startswith(s, " ") then + local pos = string.find(s, "%S", 1) + return string.sub(s, 1, pos + 1), string.sub(s, pos + 2) + else + return unpack(pystring:split(s, " ", 1)) + end +end + +function Clmd:ul(uls, res) + local len = #uls + local start = 1 + local level = 0 + + for i = start, len do + local levels, body = splitUl(uls[i]) + local v = level4BT(levels) + if v > level then + while v > level do + table.insert(res, "
      ") + level = level + 1 + end + elseif v < level then + while v < level do + table.insert(res, "
    ") + level = level - 1 + end + end + local line = pystring:join("", {"
  • ", self:seg(body), "
  • "}) + table.insert(res, line) + end + + while level > 0 do + table.insert(res, "") + level = level - 1 + end +end + +function Clmd:pUl(uls, res) + table.insert(res, "
      ") + self:ul(uls, res) + table.insert(res, "
    ") +end + +local function pCodeTab(codes, res) + table.insert(res, "
    ")
    +    for _, line in ipairs(codes) do
    +        table.insert(res, string.sub(line, 2))
    +    end
    +    table.insert(res, "
    ") +end + +local function pCodeBlank(codes, res) + table.insert(res, "
    ")
    +    for _, line in ipairs(codes) do
    +        table.insert(res, string.sub(line, 5))
    +    end
    +    table.insert(res, "
    ") +end + +local function pCodeFence(codes, res) + table.insert(res, "
    ")
    +    for _, line in ipairs(codes) do
    +        table.insert(res, line)
    +    end
    +    table.insert(res, "
    ") +end + +local function tableAligns(line) + local aligns = pystring:split(line, "|") + local res = {} + for i=2, #aligns - 1 do + local cell = pystring:strip(aligns[i]) + if pystring:startswith(cell, ":") then + if pystring:endswith(cell, ":") then + table.insert(res, "center") + else + table.insert(res, "left") + end + else + if pystring:endswith(cell, ":") then + table.insert(res, "right") + else + table.insert(res, "nil") + end + end + end + return res +end + +function Clmd:pTable(codes, res) + local len = #codes + local start = 3 + + if len < 3 then + return + end + + local aligns = tableAligns(codes[2]) + table.insert(res, "") + + local heads = pystring:split(codes[1], "|") + table.insert(res, "") + for j=2, #heads - 1 do + local cell = pystring:strip(heads[j]) + cell = self:seg(cell) + local line + if aligns[j - 1] == nil or aligns[j - 1] == "nil" then + line = pystring:join("", {""}) + else + line = pystring:join("", {string.format('"}) + end + table.insert(res, line) + end + table.insert(res, "") + + for i = start, len do + local cells = pystring:split(codes[i], "|") + table.insert(res, "") + for j=2, #heads - 1 do + local cell = pystring:strip(cells[j]) + cell = self:seg(cell) + local line + if aligns[j - 1] == nil or aligns[j - 1] == "nil" then + line = pystring:join("", {""}) + else + line = pystring:join("", {string.format('"}) + end + table.insert(res, line) + end + table.insert(res, "") + end + table.insert(res, "
    ", cell, "', aligns[j - 1]), + cell, "
    ", cell, "', aligns[j - 1]), + cell, "
    ") +end + +local function escape(s) + return string.sub(s, 2) +end + +local function pEscape(s) + return string.gsub(s, "\\.", function(s) return escape(s) end) +end + +function Clmd:seg(s) + s = pBI(s) + s = pBold(s) + s = pItalic(s) + s = pDelete(s) + s = pCode(s) + s = pLink(s) + return pEscape(s) +end + +function Clmd:pSeg(s) + s = self:seg(s) + return pystring:join("", {"

    ", pEnter(s), "

    "}) +end + +function Clmd:toHtml(md) + local mds = pystring:split(md, '\n') + local res = {} + local len = #mds + local stop = 0 + + for i = 1, len do + local line = mds[i] + + if i < stop then -- no continue in lua + goto continue + end + + if string.find(line, "#+%s") then + table.insert(res, self:pTitle(line)) + elseif string.find(line, ">%s") then -- for block quote + local j = i + 1 + local quotes = {line} + while j <= len and string.find(mds[j], ">+%s") do + table.insert(quotes, mds[j]) + j = j + 1 + end + pQuote(quotes, res) + stop = j + elseif string.find(line, "^%d%.%s") then + local j = i + 1 + local ols = {line} + while j <= len and string.find(mds[j], "[\t%s]*%d%.%s") do + table.insert(ols, mds[j]) + j = j + 1 + end + self:pOl(ols, res) + stop = j + elseif string.find(line, "^[%-%*%+]%s") then + local j = i + 1 + local uls = {line} + while j <= len and string.find(mds[j], "[\t%s]*[%-%*%+]%s") do + table.insert(uls, mds[j]) + j = j + 1 + end + self:pUl(uls, res) + stop = j + elseif string.find(line, "^\t") then + local j = i + 1 + local codes = {line} + while j <= len and string.find(mds[j], "^\t") do + table.insert(codes, mds[j]) + j = j + 1 + end + pCodeTab(codes, res) + stop = j + elseif string.find(line, "^%s%s%s%s") then + local j = i + 1 + local codes = {line} + while j <= len and string.find(mds[j], "^%s%s%s%s") do + table.insert(codes, mds[j]) + j = j + 1 + end + pCodeBlank(codes, res) + stop = j + elseif string.find(line, "^```") then + local j = i + 1 + local codes = {} + while j <= len and not string.find(mds[j], "^```") do + table.insert(codes, mds[j]) + j = j + 1 + end + pCodeFence(codes, res) + stop = j + 1 + elseif string.find(line, "^|") then + local j = i + 1 + local codes = {line} + while j <= len and string.find(mds[j], "^|") do + table.insert(codes, mds[j]) + j = j + 1 + end + self:pTable(codes, res) + stop = j + elseif string.find(line, "^[%*%-_][%*%-_][%*%-_]") then + table.insert(res, "
    ") + else + if #line > 0 then + table.insert(res, self:pSeg(line)) + else + table.insert(res, line) + end + end + + ::continue:: + end + return pystring:join("\n", res) +end + +return Clmd diff --git a/source/tools/monitor/unity/common/protoData.lua b/source/tools/monitor/unity/common/protoData.lua new file mode 100644 index 0000000000000000000000000000000000000000..82bdaadf625a13d2e5159235a6c8ebb0b3e8516d --- /dev/null +++ b/source/tools/monitor/unity/common/protoData.lua @@ -0,0 +1,64 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/16 6:05 PM +--- + +require("class") +local pb = require("pb") +local protoc = require("protoc") +local serpent = require("serpent") + +local CprotoData = class("CprotoData") + +function CprotoData:_init_(que) + self._pc = protoc:new() + self._que = que + assert(self._pc:load[[ + message labels { + required string name = 1; + required string index = 2; + } + message values { + required string name = 1; + required double value = 2; + } + message logs { + required string name = 1; + required string log = 2; + } + message dataLine{ + required string line = 1; + repeated labels ls = 2; + repeated values vs = 3; + repeated logs log = 4; + } + message dataLines{ + repeated dataLine lines = 1; + } + ]]) +end + +function CprotoData:encode(lines) + --print(serpent.block(data)) + return assert(pb.encode("dataLines", lines)) +end + +function CprotoData:decode(bytes) + return assert(pb.decode("dataLines", bytes)) +end + +function CprotoData:showProto(bytes) + local data = assert(pb.decode("dataLines", bytes)) + return serpent.block(data) +end + +function CprotoData:protoTable() + return {lines = {}} +end + +function CprotoData:que(bytes) + collector_qout(self._que, bytes, #bytes) +end + +return CprotoData diff --git a/source/tools/monitor/unity/common/pystring.lua b/source/tools/monitor/unity/common/pystring.lua new file mode 100644 index 0000000000000000000000000000000000000000..25278335fd9d1003e143608efe260766908b6e2b --- /dev/null +++ b/source/tools/monitor/unity/common/pystring.lua @@ -0,0 +1,177 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/8 10:37 AM +--- + +local pystring = {} + +local function formatKey(key) + local t = type(key) + if t == "number" then + return "["..key.."]" + elseif t == "string" then + local n = tonumber(key) + if n then + return "["..key.."]" + end + end + return key +end + +local function newStack() + local stack = { + tableList = {} + } + function stack:push(t) + table.insert(self.tableList, t) + end + function stack:pop() + return table.remove(self.tableList) + end + function stack:contains(t) + for _, v in ipairs(self.tableList) do + if v == t then + return true + end + end + return false + end + return stack +end + +local function checkDelimiter(ch) + local s = "().%+-*?[]^$" + if ch == " " then + return "%s" + end + for c in string.gmatch(s, ".") do + if c == ch then + return "%" .. ch + end + end + return ch +end + +local function setupDelimiter(delimiter) + local rt = {} + for c in string.gmatch(delimiter, ".") do + table.insert(rt, checkDelimiter(c)) + end + return table.concat(rt) +end + +local function setupPatten(s) + local patten + if s == nil then + patten = "[%s\t\n]" + else + patten = setupDelimiter(s) + end + return patten +end + +function pystring:split(s, delimiter, n) + local result = {} + local delimiter = setupDelimiter(delimiter or " ") + local n = n or 2 ^ 63 - 1 + + local nums = 0 + local beg = 1 + while (true) do + local iBeg, iEnd = string.find(s, delimiter, beg) + if (iBeg) then + table.insert(result, string.sub(s, beg, iBeg - 1)) + beg = iEnd + 1 + nums = nums + 1 + if nums >= n then + table.insert(result, string.sub(s, beg, string.len(s))) + break + end + else + table.insert(result, string.sub(s, beg, string.len(s))) + break + end + end + return result +end + +function pystring:reverseTable(t) + local n = #t + for i = 1, n / 2 do + t[i], t[n + 1 - i] = t[n + 1 - i], t[i] + end +end + +function pystring:rsplit(s, delimiter, n) + local result = {} + local n = n or 2 ^ 63 - 1 + local len = string.len(s) + 1 + local rs = string.reverse(s) + local rDel = string.reverse(delimiter or " ") + rDel = setupDelimiter(rDel) + local nums = 0 + local beg = 1 + + while (true) do + local iBeg, iEnd = string.find(rs, rDel, beg) + if (iBeg) then + table.insert(result, string.sub(s, len - (iBeg - 1),len - beg)) + beg = iEnd + 1 + nums = nums + 1 + if nums >= n then + table.insert(result, string.sub(s, 1, len - beg)) + break + end + else + table.insert(result, string.sub(s, 1, len - beg)) + break + end + end + --return result + pystring:reverseTable(result) + return result +end + +function pystring:lstrip(s, chars) + local patten = "^" .. setupPatten(chars) .. "+" + local _, ends = string.find(s, patten) + if ends then + return string.sub(s, ends + 1, -1) + else + return s + end +end + +function pystring:rstrip(s, chars) + local patten = setupPatten(chars) .. "+$" + local last = string.find(s, patten) + if last then + return string.sub(s, 1, last - 1) + else + return s + end +end + +function pystring:strip(s, chars) + local res = pystring:lstrip(s, chars) + return pystring:rstrip(res, chars) +end + +function pystring:join(delim, strings) + return table.concat(strings, delim) +end + +function pystring:startswith(s1, s2) + return string.sub(s1,1,string.len(s2)) == s2 +end + +function pystring:endswith(s1, s2) + return s2=='' or string.sub(s1,-string.len(s2)) == s2 +end + +function pystring:find(s1, s2) + return string.find(s1, s2, 1, false) +end + +return pystring diff --git a/source/tools/monitor/unity/common/serpent.lua b/source/tools/monitor/unity/common/serpent.lua new file mode 100644 index 0000000000000000000000000000000000000000..9a66ffd2fae2f937760ab51950debdea1a38938e --- /dev/null +++ b/source/tools/monitor/unity/common/serpent.lua @@ -0,0 +1,158 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2023/1/4 3:43 PM +--- + +local n, v = "serpent", "0.303" -- (C) 2012-18 Paul Kulchenko; MIT License +local c, d = "Paul Kulchenko", "Lua serializer and pretty printer" +local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'} +local badtype = {thread = true, userdata = true, cdata = true} +local getmetatable = debug and debug.getmetatable or getmetatable +local pairs = function(t) return next, t end -- avoid using __pairs in Lua 5.2+ +local keyword, globals, G = {}, {}, (_G or _ENV) +for _,k in ipairs({'and', 'break', 'do', 'else', 'elseif', 'end', 'false', + 'for', 'function', 'goto', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat', + 'return', 'then', 'true', 'until', 'while'}) do keyword[k] = true end +for k,v in pairs(G) do globals[v] = k end -- build func to name mapping +for _,g in ipairs({'coroutine', 'debug', 'io', 'math', 'string', 'table', 'os'}) do + for k,v in pairs(type(G[g]) == 'table' and G[g] or {}) do globals[v] = g..'.'..k end end + +local function s(t, opts) + local name, indent, fatal, maxnum = opts.name, opts.indent, opts.fatal, opts.maxnum + local sparse, custom, huge = opts.sparse, opts.custom, not opts.nohuge + local space, maxl = (opts.compact and '' or ' '), (opts.maxlevel or math.huge) + local maxlen, metatostring = tonumber(opts.maxlength), opts.metatostring + local iname, comm = '_'..(name or ''), opts.comment and (tonumber(opts.comment) or math.huge) + local numformat = opts.numformat or "%.17g" + local seen, sref, syms, symn = {}, {'local '..iname..'={}'}, {}, 0 + local function gensym(val) return '_'..(tostring(tostring(val)):gsub("[^%w]",""):gsub("(%d%w+)", + -- tostring(val) is needed because __tostring may return a non-string value + function(s) if not syms[s] then symn = symn+1; syms[s] = symn end return tostring(syms[s]) end)) end + local function safestr(s) return type(s) == "number" and (huge and snum[tostring(s)] or numformat:format(s)) + or type(s) ~= "string" and tostring(s) -- escape NEWLINE/010 and EOF/026 + or ("%q"):format(s):gsub("\010","n"):gsub("\026","\\026") end + -- handle radix changes in some locales + if opts.fixradix and (".1f"):format(1.2) ~= "1.2" then + local origsafestr = safestr + safestr = function(s) return type(s) == "number" + and (nohuge and snum[tostring(s)] or numformat:format(s):gsub(",",".")) or origsafestr(s) + end + end + local function comment(s,l) return comm and (l or 0) < comm and ' --[['..select(2, pcall(tostring, s))..']]' or '' end + local function globerr(s,l) return globals[s] and globals[s]..comment(s,l) or not fatal + and safestr(select(2, pcall(tostring, s))) or error("Can't serialize "..tostring(s)) end + local function safename(path, name) -- generates foo.bar, foo[3], or foo['b a r'] + local n = name == nil and '' or name + local plain = type(n) == "string" and n:match("^[%l%u_][%w_]*$") and not keyword[n] + local safe = plain and n or '['..safestr(n)..']' + return (path or '')..(plain and path and '.' or '')..safe, safe end + local alphanumsort = type(opts.sortkeys) == 'function' and opts.sortkeys or function(k, o, n) -- k=keys, o=originaltable, n=padding + local maxn, to = tonumber(n) or 12, {number = 'a', string = 'b'} + local function padnum(d) return ("%0"..tostring(maxn).."d"):format(tonumber(d)) end + table.sort(k, function(a,b) + -- sort numeric keys first: k[key] is not nil for numerical keys + return (k[a] ~= nil and 0 or to[type(a)] or 'z')..(tostring(a):gsub("%d+",padnum)) + < (k[b] ~= nil and 0 or to[type(b)] or 'z')..(tostring(b):gsub("%d+",padnum)) end) end + local function val2str(t, name, indent, insref, path, plainindex, level) + local ttype, level, mt = type(t), (level or 0), getmetatable(t) + local spath, sname = safename(path, name) + local tag = plainindex and + ((type(name) == "number") and '' or name..space..'='..space) or + (name ~= nil and sname..space..'='..space or '') + if seen[t] then -- already seen this element + sref[#sref+1] = spath..space..'='..space..seen[t] + return tag..'nil'..comment('ref', level) + end + -- protect from those cases where __tostring may fail + if type(mt) == 'table' and metatostring ~= false then + local to, tr = pcall(function() return mt.__tostring(t) end) + local so, sr = pcall(function() return mt.__serialize(t) end) + if (to or so) then -- knows how to serialize itself + seen[t] = insref or spath + t = so and sr or tr + ttype = type(t) + end -- new value falls through to be serialized + end + if ttype == "table" then + if level >= maxl then return tag..'{}'..comment('maxlvl', level) end + seen[t] = insref or spath + if next(t) == nil then return tag..'{}'..comment(t, level) end -- table empty + if maxlen and maxlen < 0 then return tag..'{}'..comment('maxlen', level) end + local maxn, o, out = math.min(#t, maxnum or #t), {}, {} + for key = 1, maxn do o[key] = key end + if not maxnum or #o < maxnum then + local n = #o -- n = n + 1; o[n] is much faster than o[#o+1] on large tables + for key in pairs(t) do + if o[key] ~= key then n = n + 1; o[n] = key end + end + end + if maxnum and #o > maxnum then o[maxnum+1] = nil end + if opts.sortkeys and #o > maxn then alphanumsort(o, t, opts.sortkeys) end + local sparse = sparse and #o > maxn -- disable sparsness if only numeric keys (shorter output) + for n, key in ipairs(o) do + local value, ktype, plainindex = t[key], type(key), n <= maxn and not sparse + if opts.valignore and opts.valignore[value] -- skip ignored values; do nothing + or opts.keyallow and not opts.keyallow[key] + or opts.keyignore and opts.keyignore[key] + or opts.valtypeignore and opts.valtypeignore[type(value)] -- skipping ignored value types + or sparse and value == nil then -- skipping nils; do nothing + elseif ktype == 'table' or ktype == 'function' or badtype[ktype] then + if not seen[key] and not globals[key] then + sref[#sref+1] = 'placeholder' + local sname = safename(iname, gensym(key)) -- iname is table for local variables + sref[#sref] = val2str(key,sname,indent,sname,iname,true) + end + sref[#sref+1] = 'placeholder' + local path = seen[t]..'['..tostring(seen[key] or globals[key] or gensym(key))..']' + sref[#sref] = path..space..'='..space..tostring(seen[value] or val2str(value,nil,indent,path)) + else + out[#out+1] = val2str(value,key,indent,nil,seen[t],plainindex,level+1) + if maxlen then + maxlen = maxlen - #out[#out] + if maxlen < 0 then break end + end + end + end + local prefix = string.rep(indent or '', level) + local head = indent and '{\n'..prefix..indent or '{' + local body = table.concat(out, ','..(indent and '\n'..prefix..indent or space)) + local tail = indent and "\n"..prefix..'}' or '}' + return (custom and custom(tag,head,body,tail,level) or tag..head..body..tail)..comment(t, level) + elseif badtype[ttype] then + seen[t] = insref or spath + return tag..globerr(t, level) + elseif ttype == 'function' then + seen[t] = insref or spath + if opts.nocode then return tag.."function() --[[..skipped..]] end"..comment(t, level) end + local ok, res = pcall(string.dump, t) + local func = ok and "((loadstring or load)("..safestr(res)..",'@serialized'))"..comment(t, level) + return tag..(func or globerr(t, level)) + else return tag..safestr(t) end -- handle all other types + end + local sepr = indent and "\n" or ";"..space + local body = val2str(t, name, indent) -- this call also populates sref + local tail = #sref>1 and table.concat(sref, sepr)..sepr or '' + local warn = opts.comment and #sref>1 and space.."--[[incomplete output with shared/self-references skipped]]" or '' + return not name and body..warn or "do local "..body..sepr..tail.."return "..name..sepr.."end" +end + +local function deserialize(data, opts) + local env = (opts and opts.safe == false) and G + or setmetatable({}, { + __index = function(t,k) return t end, + __call = function(t,...) error("cannot call functions") end + }) + local f, res = (loadstring or load)('return '..data, nil, nil, env) + if not f then f, res = (loadstring or load)(data, nil, nil, env) end + if not f then return f, res end + if setfenv then setfenv(f, env) end + return pcall(f) +end + +local function merge(a, b) if b then for k,v in pairs(b) do a[k] = v end end; return a; end +return { _NAME = n, _COPYRIGHT = c, _DESCRIPTION = d, _VERSION = v, serialize = s, + load = deserialize, + dump = function(a, opts) return s(a, merge({name = '_', compact = true, sparse = true}, opts)) end, + line = function(a, opts) return s(a, merge({sortkeys = true, comment = true}, opts)) end, + block = function(a, opts) return s(a, merge({indent = ' ', sortkeys = true, comment = true}, opts)) end } \ No newline at end of file diff --git a/source/tools/monitor/unity/common/system.lua b/source/tools/monitor/unity/common/system.lua new file mode 100644 index 0000000000000000000000000000000000000000..f34a6d92de567b790170c7550f45652301bd88b2 --- /dev/null +++ b/source/tools/monitor/unity/common/system.lua @@ -0,0 +1,50 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/16 10:58 PM +--- + +local socket = require("socket") +local serpent = require("serpent") + +local system = {} + +function system:sleep(t) + socket.select(nil, nil, t) +end + +function system:deepcopy(object) + local lookup_table = {} + local function _copy(object) + if type(object) ~= "table" then + return object + elseif lookup_table[object] then + return lookup_table[object] + end + local new_table = {} + lookup_table[object] = new_table + for index, value in pairs(object) do + new_table[_copy(index)] = _copy(value) + end + return setmetatable(new_table, getmetatable(object)) + end + + return _copy(object) +end + +function system:dump(t) + return serpent.block(t) +end + +function system:tableIsIn(tbl, key) + if type(tbl) ~= "table" then + return false + end + if tbl[key] == nil then + return false + else + return true + end +end + +return system \ No newline at end of file diff --git a/source/tools/monitor/unity/guide/oop/base.lua b/source/tools/monitor/unity/guide/oop/base.lua new file mode 100644 index 0000000000000000000000000000000000000000..b118f20368bf97ae79c201b01a4ddb1614fd749e --- /dev/null +++ b/source/tools/monitor/unity/guide/oop/base.lua @@ -0,0 +1,22 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/16 10:23 AM +--- +require("class") + +local Cbase = class("base") + +function Cbase:_init_(name) + self.name = name +end + +function Cbase:hello() + return self.name +end + +function Cbase:_del_() + print("base del..." .. self.name) +end + +return Cbase diff --git a/source/tools/monitor/unity/guide/oop/one.lua b/source/tools/monitor/unity/guide/oop/one.lua new file mode 100644 index 0000000000000000000000000000000000000000..1e432f0ccc0f771e4c0a77711b75bb973237253e --- /dev/null +++ b/source/tools/monitor/unity/guide/oop/one.lua @@ -0,0 +1,20 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/16 10:20 AM +--- + +require("class") +local Cbase = require("base") + +Cone = class("one", Cbase) + +function Cone:_init_(name) + Cbase._init_(self, name) +end + +function Cone:say() + print("one say " .. self.name) +end + +return Cone diff --git a/source/tools/monitor/unity/guide/oop/three.lua b/source/tools/monitor/unity/guide/oop/three.lua new file mode 100644 index 0000000000000000000000000000000000000000..cae5dd7371f0c2492015b05011d079ad63fd8007 --- /dev/null +++ b/source/tools/monitor/unity/guide/oop/three.lua @@ -0,0 +1,24 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/16 1:07 PM +--- + +require("class") +local Cone = require("one") + +CThree = class("three", Cone) + +function CThree:_init_(name) + Cone._init_(self, name) + self._child = Cone.new("child") +end + + +function CThree:say() + print("three say " .. self.name) + print("child say.") + self._child:say() +end + +return CThree \ No newline at end of file diff --git a/source/tools/monitor/unity/guide/oop/tobj.lua b/source/tools/monitor/unity/guide/oop/tobj.lua new file mode 100644 index 0000000000000000000000000000000000000000..356c9ece70f37cef290499988c202fec121c714b --- /dev/null +++ b/source/tools/monitor/unity/guide/oop/tobj.lua @@ -0,0 +1,25 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/16 10:35 AM +--- +package.path = package.path .. ";../../common/?.lua;" + +local Cone = require("one") +local Ctwo = require("two") +local CThree = require("three") + +local one = Cone.new("1one") +local two = Ctwo.new("2two") +local three = CThree.new("3three") + +assert(one:hello() == "1one") +assert(two:hello() == "2two") +assert(three:hello() == "3three") + +one:say() +two:say() +three:say() + +one = nil +two:say() diff --git a/source/tools/monitor/unity/guide/oop/two.lua b/source/tools/monitor/unity/guide/oop/two.lua new file mode 100644 index 0000000000000000000000000000000000000000..8c8de5b04c5d62d577de0a023ae9e862daa7b791 --- /dev/null +++ b/source/tools/monitor/unity/guide/oop/two.lua @@ -0,0 +1,22 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/16 10:33 AM +--- +--- +require("class") +local Cone = require("one") + +CTwo = class("two", Cone) + +function CTwo:_init_(name) + Cone._init_(self, name) +end + +function CTwo:say() + print("two say " .. self.name) + print("super") + Cone.say(self) +end + +return CTwo \ No newline at end of file diff --git a/source/tools/monitor/unity/httplib/httpApp.lua b/source/tools/monitor/unity/httplib/httpApp.lua new file mode 100644 index 0000000000000000000000000000000000000000..8416d012af5e035ff5d91c46e03da2564a19513f --- /dev/null +++ b/source/tools/monitor/unity/httplib/httpApp.lua @@ -0,0 +1,32 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/22 12:14 PM +--- + +require("class") +local ChttpBase = require("httpBase") +local pystring = require("pystring") + +local ChttpApp = class("ChttpApp", ChttpBase) + +function ChttpApp:_init_(frame) + ChttpBase._init_(self) +end + +function ChttpApp:echo(tRet) + local stat = self:packStat(200) + local tHead = { + ["Content-Type"] = "application/json", + } + local body = self:jencode(tRet) + local headers = self:packHeaders(tHead, #body) + local tHttp = {stat, headers, body} + return pystring:join("\r\n", tHttp) +end + +function ChttpApp:getJson(tReq) + return self:jdecode(tReq.data) +end + +return ChttpApp diff --git a/source/tools/monitor/unity/httplib/httpBase.lua b/source/tools/monitor/unity/httplib/httpBase.lua new file mode 100644 index 0000000000000000000000000000000000000000..10ef0dd3a44e1ae78114e08605f78a27a850a35c --- /dev/null +++ b/source/tools/monitor/unity/httplib/httpBase.lua @@ -0,0 +1,32 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/24 9:52 AM +--- + +require("class") +local ChttpComm = require("httpComm") + +local ChttpBase = class("ChttpBase", ChttpComm) + +function ChttpBase:_init_(frame) + ChttpComm._init_(self) + self._urlCb = {} +end + +function ChttpBase:_install(frame) + for k, _ in pairs(self._urlCb) do + frame:register(k, self) + end +end + +function ChttpBase:echo(tRet) + error("ChttpBase:echo is a virtual function.") +end + +function ChttpBase:call(tReq) + local tRet = self._urlCb[tReq.path](tReq) + return self:echo(tRet) +end + +return ChttpBase diff --git a/source/tools/monitor/unity/httplib/httpCli.lua b/source/tools/monitor/unity/httplib/httpCli.lua new file mode 100644 index 0000000000000000000000000000000000000000..550cb362b66bfe59dc32b14542aedc0848b943cf --- /dev/null +++ b/source/tools/monitor/unity/httplib/httpCli.lua @@ -0,0 +1,61 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/19 4:40 PM +--- + +require("class") +local ChttpComm = require("httpComm") +local ChttpCli = class("httpCli", ChttpComm) + +function ChttpCli:_init_() + ChttpComm._init_(self) + self._http = require("socket.http") + self._ltn12 = require("ltn12") +end + +function ChttpCli:get(Url) + local t = {} + local res, code, head= self._http.request{ + url=Url, + sink = self._ltn12.sink.table(t) + } + local body = table.concat(t) + return { + res = res, + code = code, + head = head, + body = body + } +end + +function ChttpCli:post(Url, reqs, header) + local headers = header or { Connection = 'close' } + local source = self._ltn12.source.string(reqs) + local t = {} + local res, code, head = self._http.request{ + url = Url, + method = "POST", + headers = headers, + source = source, + sink = self._ltn12.sink.table(t) + } + local body = table.concat(t) + return { + res = res, + code = code, + head = head, + body = body + } +end + +function ChttpCli:postTable(Url, t) + local req = self:jencode(t) + local headers = { + ["Content-Type"] = "application/json", + ["Content-Length"] = #req, + } + return self:post(Url, req, headers) +end + +return ChttpCli diff --git a/source/tools/monitor/unity/httplib/httpComm.lua b/source/tools/monitor/unity/httplib/httpComm.lua new file mode 100644 index 0000000000000000000000000000000000000000..43ed0196d754f25d48271d1815e55a24bfa14b34 --- /dev/null +++ b/source/tools/monitor/unity/httplib/httpComm.lua @@ -0,0 +1,107 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/19 10:46 PM +--- + +require("class") +local pystring = require("pystring") +local sockerUrl = require("socket.url") + +local ChttpComm = class("httpComm") + +local cjson = require("cjson") +local json = cjson.new() + +local function codeTable() + return { + [100] = "Continue", + [200] = "Ok", + [201] = "Created", + [202] = "Accepted", + [204] = "No Content", + [206] = "Partial Content", + [301] = "Moved Permanently", + [302] = "Found", + [304] = "Not Modified", + [400] = "Bad Request", + [401] = "Unauthorized", + [403] = "Forbidden", + [404] = "Not Found", + [418] = "I'm a teapot", + [500] = "Internal Server Error", + [501] = "Not Implemented" + } +end + +function ChttpComm:jencode(t) + return json.encode(t) +end + +function ChttpComm:jdecode(s) + return json.decode(s) +end + +local function parseParam(param) + local tParam = pystring:split(param, "&") + local res = {} + for _, s in ipairs(tParam) do + local kv = pystring:split(s, "=") + if #kv ~= 2 then + print("bad param " .. s) + return nil + end + local k = sockerUrl.unescape(kv[1]) + local v = sockerUrl.unescape(kv[2]) + res[k] = v + end + return res +end + +local function parseParams(tUrl) + if tUrl.query then + tUrl.queries = parseParam(tUrl.query) + end + if tUrl.params then + tUrl.paramses = parseParam(tUrl.params) + end + return tUrl +end + +function ChttpComm:parsePath(path) + local res = sockerUrl.parse(path) + return parseParams(res) +end + +local function originHeader() + return { + connection = "close", + server = "beaver/0.0.1", + date = os.date("%a, %d %b %Y %H:%M:%S %Z", os.time()), + } +end + +function ChttpComm:packHeaders(headTable, len) -- just for http out. + local lines = {} + if not headTable["Content-Length"] then + headTable["Content-Length"] = len + end + local origin = originHeader() + + for k, v in pairs(origin) do + table.insert(lines, k .. ": " .. v) + end + + for k, v in pairs(headTable) do + table.insert(lines, k .. ": " .. v) + end + return pystring:join("\r\n", lines) .. "\r\n" +end + +local codeStrTable = codeTable() +function ChttpComm:packStat(code) + local t = {"HTTP/1.1", code, codeStrTable[code]} + return pystring:join(" ", t) +end + +return ChttpComm diff --git a/source/tools/monitor/unity/httplib/httpHtml.lua b/source/tools/monitor/unity/httplib/httpHtml.lua new file mode 100644 index 0000000000000000000000000000000000000000..f7bf570e6f3ff5b2a59034fcdf6a61e37764777c --- /dev/null +++ b/source/tools/monitor/unity/httplib/httpHtml.lua @@ -0,0 +1,55 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/23 11:53 PM +--- + +require("class") +local pystring = require("pystring") +local ChttpBase = require("httpBase") + +local ChttpHtml = class("ChttpHtml", ChttpBase) + +function ChttpHtml:_init_(frame) + ChttpBase._init_(self) +end + +function ChttpHtml:markdown(text) + local md = require("lmd") + return md:toHtml(text) +end + +local function htmlPack(title, content) + local h1 = [[ + + + + +]] + local h2 = [[ + + + +]] + local h3 = [[ + + + +]] + + local bodies = {h1, title, h2, content, h3} + return pystring:join("", bodies) +end + +function ChttpHtml:echo(tRet) + local stat = self:packStat(200) + local tHead = { + ["Content-Type"] = "text/html", + } + local body = htmlPack(tRet.title, tRet.content) + local headers = self:packHeaders(tHead, #body) + local tHttp = {stat, headers, body} + return pystring:join("\r\n", tHttp) +end + +return ChttpHtml diff --git a/source/tools/monitor/unity/httplib/httpPlain.lua b/source/tools/monitor/unity/httplib/httpPlain.lua new file mode 100644 index 0000000000000000000000000000000000000000..65f58d14ee8d42deba19457e3afd3df67f6ae357 --- /dev/null +++ b/source/tools/monitor/unity/httplib/httpPlain.lua @@ -0,0 +1,28 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/24 12:32 AM +--- + +require("class") +local pystring = require("pystring") +local ChttpBase = require("httpBase") + +local ChttpPlain = class("ChttpPlain", ChttpBase) + +function ChttpPlain:_init_(frame) + ChttpBase._init_(self) +end + +function ChttpPlain:echo(tRet) + local stat = self:packStat(200) + local tHead = { + ["Content-Type"] = "text/plain", + } + local body = tRet.text + local headers = self:packHeaders(tHead, #body) + local tHttp = {stat, headers, body} + return pystring:join("\r\n", tHttp) +end + +return ChttpPlain diff --git a/source/tools/monitor/unity/test/all.sh b/source/tools/monitor/unity/test/all.sh new file mode 100755 index 0000000000000000000000000000000000000000..b366f01b9504cb449556ab619a0f010d0af51870 --- /dev/null +++ b/source/tools/monitor/unity/test/all.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +bash protoTest.sh +bash nativeProcFFI.sh diff --git a/source/tools/monitor/unity/test/beaver/beaverLoad.py b/source/tools/monitor/unity/test/beaver/beaverLoad.py new file mode 100644 index 0000000000000000000000000000000000000000..cdce6d114c51c9c40d05f34a1afaef88305bdf7c --- /dev/null +++ b/source/tools/monitor/unity/test/beaver/beaverLoad.py @@ -0,0 +1,26 @@ +import socket +from signal import pause +from threading import Thread + + +class CsockThread(Thread): + def __init__(self): + super(CsockThread, self).__init__() + self.start() + + def run(self): + while True: + s = socket.socket() + s.connect(("127.0.0.1", 8400)) + s.send("hello".encode()) + r = s.recv(16).decode() + assert (r == "hello") + s.close() + + +if __name__ == "__main__": + # echo hello | nc 127.0.0.1 8400 + for i in range(10): + CsockThread() + pause() + diff --git a/source/tools/monitor/unity/test/bees/run.sh b/source/tools/monitor/unity/test/bees/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..d5b31097e6a07f04773811816299f9cce67669de --- /dev/null +++ b/source/tools/monitor/unity/test/bees/run.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/ +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../tsdb/native/ +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../collector/native/ +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../beaver/ +source /etc/profile + +cd ../../beeQ +make +if [ $? -ne 0 ];then + echo " make -- Failed : "$? + exit 0 +fi + +./unity-mon diff --git a/source/tools/monitor/unity/test/collectorProc.lua b/source/tools/monitor/unity/test/collectorProc.lua new file mode 100644 index 0000000000000000000000000000000000000000..c4c30ba8438f4331514e7af34ebeb9c2c4b467e2 --- /dev/null +++ b/source/tools/monitor/unity/test/collectorProc.lua @@ -0,0 +1,18 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/16 10:59 PM +--- + +package.path = package.path .. ";../common/?.lua;" +package.path = package.path .. ";../collector/?.lua;" +package.path = package.path .. ";../collector/native/?.lua;" + +local Cloop = require("loop") +local system = require("system") + +local work = Cloop.new() +while true do + work:work(1) + system:sleep(1) +end \ No newline at end of file diff --git a/source/tools/monitor/unity/test/collectorProc.sh b/source/tools/monitor/unity/test/collectorProc.sh new file mode 100755 index 0000000000000000000000000000000000000000..0e1931c40f8e4138c4f687509b22b277f6fdc25b --- /dev/null +++ b/source/tools/monitor/unity/test/collectorProc.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../collector/native/ +./nativeProcFFI.sh +luajit collectorProc.lua diff --git a/source/tools/monitor/unity/test/curl/beaverApi.py b/source/tools/monitor/unity/test/curl/beaverApi.py new file mode 100644 index 0000000000000000000000000000000000000000..9051077c01396fc9cba4f8d6c9d55505b45928b0 --- /dev/null +++ b/source/tools/monitor/unity/test/curl/beaverApi.py @@ -0,0 +1,30 @@ +import time +import requests +import random +import json + + +def randomNum(): + return random.randint(0, 1000) / 100.0 + + +def post_test(): + url = "http://127.0.0.1:8400/api/" + mod = random.choice(("sum", "sub")) + url += mod + d = {"num1": randomNum(), "num2": randomNum()} + res = requests.post(url, json=d) + ret = res.content.decode() + if mod == "sum": + vLocal = d["num1"] + d["num2"] + vRet = json.loads(ret)[mod] + else: + vLocal = d["num1"] - d["num2"] + vRet = json.loads(ret)[mod] + assert (abs(vRet - vLocal) <= 1e-9) + + +if __name__ == "__main__": + while True: + post_test() + time.sleep(random.randint(1, 100)/100.0) \ No newline at end of file diff --git a/source/tools/monitor/unity/test/curl/curl.lua b/source/tools/monitor/unity/test/curl/curl.lua new file mode 100644 index 0000000000000000000000000000000000000000..47ca750612a3718cf526e8fbe7a3f03b1b4fbc67 --- /dev/null +++ b/source/tools/monitor/unity/test/curl/curl.lua @@ -0,0 +1,28 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/19 9:26 PM +--- + +package.path = package.path .. ";../../common/?.lua;" +package.path = package.path .. ";../../httplib/?.lua;" +local serpent = require("serpent") + +local ChttpCli = require("httpCli") + +local cli = ChttpCli.new() +local res = cli:get("http://100.82.20.22/") +print(serpent.block(res.head)) +print(res.code) +assert(res.code == 200) + +local url = "http://127.0.0.1:8400/api/sum" +local req = {num1 = 101, num2 = 2} +local res = cli:postTable(url, req) +print(res.code) +assert(res.code == 200) +print(serpent.block(res)) +print(#res.body) +print(res.body) +local tRes = cli:jdecode(res.body) +assert(tRes.sum == 103.0) diff --git a/source/tools/monitor/unity/test/curl/promethues_puller.py b/source/tools/monitor/unity/test/curl/promethues_puller.py new file mode 100644 index 0000000000000000000000000000000000000000..8b061244ed6caa8a52326559b971e1ac8d95d019 --- /dev/null +++ b/source/tools/monitor/unity/test/curl/promethues_puller.py @@ -0,0 +1,23 @@ +import time +import requests +import random + + +def randomNum(): + return random.randint(0, 1000) / 100.0 + + +def pull_test(): + url = random.choice(("http://127.0.0.1:8400/export", + "http://127.0.0.1:8400/export/metrics", + "http://127.0.0.1:8400/" + )) + res = requests.get(url) + assert (res.status_code == 200) + assert (len(res.content) > 100) + + +if __name__ == "__main__": + while True: + pull_test() + time.sleep(random.randint(1, 100)/100.0) diff --git a/source/tools/monitor/unity/test/curl/tmd.lua b/source/tools/monitor/unity/test/curl/tmd.lua new file mode 100644 index 0000000000000000000000000000000000000000..ca06232cf3cd2677370caafae17213d4e5bd8283 --- /dev/null +++ b/source/tools/monitor/unity/test/curl/tmd.lua @@ -0,0 +1,9 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/23 10:33 PM +--- + +local md = require("markdown") + +print(md("# tile1\n## title2\n  welcome to use beaver.")) diff --git a/source/tools/monitor/unity/test/curl/turl.lua b/source/tools/monitor/unity/test/curl/turl.lua new file mode 100644 index 0000000000000000000000000000000000000000..313929b6342f6c52ce8d4a6e5e84e71ea30fda84 --- /dev/null +++ b/source/tools/monitor/unity/test/curl/turl.lua @@ -0,0 +1,45 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/21 7:56 PM +--- + +package.path = package.path .. ";../../common/?.lua;" +local pystring = require("pystring") +local url = require("socket.url") +local serpent = require("serpent") + +local function parseParam(param) + local tParam = pystring:split(param, "&") + local res = {} + for i, s in ipairs(tParam) do + local kv = pystring:split(s, "=") + if #kv ~= 2 then + print("bad param " .. s) + return nil + end + local k = url.unescape(kv[1]) + local v = url.unescape(kv[2]) + res[k] = v + end + return res +end + +local function parseParams(tUrl) + if tUrl.query then + tUrl.queries = parseParam(tUrl.query) + end + if tUrl.params then + tUrl.paramses = parseParam(tUrl.params) + end + return tUrl +end + +local path = "/cgilua/index.lua?a=2&b=%3D%3D#there" +local res = url.parse(path) +res = parseParams(res) +print(serpent.block(res)) +path = "/pub/virus.exe;type=i&hello=world" +res = url.parse(path) +res = parseParams(res) +print(serpent.block(res)) diff --git a/source/tools/monitor/unity/test/foxTSDB.sh b/source/tools/monitor/unity/test/foxTSDB.sh new file mode 100755 index 0000000000000000000000000000000000000000..283906015a0630d0a338b1d597e5a32060dd7b88 --- /dev/null +++ b/source/tools/monitor/unity/test/foxTSDB.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../tsdb/native/ +bash nativeFoxFFI.sh +luajit tsdbTime.lua diff --git a/source/tools/monitor/unity/test/lab/Makefile b/source/tools/monitor/unity/test/lab/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9a6c22af317bc32ada0a8be9315548cf17123b98 --- /dev/null +++ b/source/tools/monitor/unity/test/lab/Makefile @@ -0,0 +1,19 @@ +LIB= -lpthread -ldl + +CC=gcc +CFLAG := -g +LDFLAG := -g -lm -ldl -lpthread -lluajit-5.1 + +PRG=crash +OBJ=crash_test.o + +$(PRG): $(OBJ) + $(CC) $(LIB) -o $@ $(OBJ) $(LDFLAG) + +%.o: %.c + $(CC) -O $(CFLAG) -c $< -o $@ + +.PRONY:clean +clean: + @echo "Removing linked and compiled files......" + rm -f $(OBJ) $(PRG) diff --git a/source/tools/monitor/unity/test/lab/clock/Makefile b/source/tools/monitor/unity/test/lab/clock/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..74fe439d3f18b9bc8666043bef01e80808cc91be --- /dev/null +++ b/source/tools/monitor/unity/test/lab/clock/Makefile @@ -0,0 +1,17 @@ +CC=gcc +CFLAG := -g -O0 +LDFLAG := -g -lrt + +PRG=clock +OBJ=clock.o + +$(PRG): $(OBJ) + $(CC) $(LIB) -o $@ $(OBJ) $(LDFLAG) + +%.o: %.c + $(CC) -O $(CFLAG) -c $< -o $@ + +.PRONY:clean +clean: + @echo "Removing linked and compiled files......" + rm -f $(OBJ) $(PRG) \ No newline at end of file diff --git a/source/tools/monitor/unity/test/lab/clock/clock.c b/source/tools/monitor/unity/test/lab/clock/clock.c new file mode 100644 index 0000000000000000000000000000000000000000..258352b9f7f49d39e418eeb876159f8328125161 --- /dev/null +++ b/source/tools/monitor/unity/test/lab/clock/clock.c @@ -0,0 +1,53 @@ +// +// Created by 廖肇燕 on 2022/12/31. +// + +#include +#include +#include +#include + +typedef unsigned long bee_time_t; + +static bee_time_t local_time(void) { + int ret; + struct timespec tp; + + ret = clock_gettime(CLOCK_MONOTONIC, &tp); + if (ret == 0) { + return tp.tv_sec * 1000000 + tp.tv_nsec / 1000; + } else { + perror("get clock failed."); + exit(1); + return 0; + } +} + +void loop(int loop) { + for (int i = 0; i < loop; ++i) { + for (int j = 0; j < loop; ++j) { + j=j; + } + } +} + +void test(int l) { + bee_time_t t1, t2, t3, delta; + t1 = local_time(); + loop(l); + t2 = local_time(); + delta = t1 + 1000000 - t2; + usleep(delta); + t3 = local_time(); + printf("delta: %ld, %ld\n", t3 - t1, delta); +} + +int main(void) { + test(1000); + test(2000); + test(4000); + test(8000); + test(9000); + return 0; +} + diff --git a/source/tools/monitor/unity/test/lab/crash.sh b/source/tools/monitor/unity/test/lab/crash.sh new file mode 100755 index 0000000000000000000000000000000000000000..ac3e17611b79e9c4d05352bd7a431a90d9c5df9f --- /dev/null +++ b/source/tools/monitor/unity/test/lab/crash.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../../collector/native/ +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./native +source /etc/profile + +cd native + +make + +cd - + +make + +if [ $? -ne 0 ];then + echo " make -- Faile : "$? + exit 0 +fi + +./crash diff --git a/source/tools/monitor/unity/test/lab/crashTest.lua b/source/tools/monitor/unity/test/lab/crashTest.lua new file mode 100644 index 0000000000000000000000000000000000000000..cc9011e83dfe14fd72b7b12f58c2785dbc0e8d0f --- /dev/null +++ b/source/tools/monitor/unity/test/lab/crashTest.lua @@ -0,0 +1,19 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/31 4:36 PM +--- + +package.path = package.path .. ";../../common/?.lua;" +package.path = package.path .. ";../../collector/native/?.lua;" + +local procFFI = require("procffi") + +function test() + local line = " 300 400 0 " + local data = procFFI.ffi.new("var_long_t") + assert(procFFI.cffi.var_input_long(procFFI.ffi.string(line), data) == 0) + print("test ok.") +end + +print("load ok.") diff --git a/source/tools/monitor/unity/test/lab/crash_test.c b/source/tools/monitor/unity/test/lab/crash_test.c new file mode 100644 index 0000000000000000000000000000000000000000..cd1dca1e723a7ce9dd2e06344b0cf8834fdf6825 --- /dev/null +++ b/source/tools/monitor/unity/test/lab/crash_test.c @@ -0,0 +1,19 @@ +// +// Created by 廖肇燕 on 2022/12/31. +// + +#include +#include +#include +#include + +int main(void) { + lua_State *L = luaL_newstate(); + luaL_openlibs(L); + luaL_dofile(L, "foxTest.lua"); + lua_getglobal(L, "test"); + lua_pcall(L, 0, 0, 0); + lua_close(L); + printf("OK.\n"); + return 0; +} diff --git a/source/tools/monitor/unity/test/lab/foxTSDB.lua b/source/tools/monitor/unity/test/lab/foxTSDB.lua new file mode 100644 index 0000000000000000000000000000000000000000..7d37d9e53a03a51164bc16bfb4baa5bc920989c7 --- /dev/null +++ b/source/tools/monitor/unity/test/lab/foxTSDB.lua @@ -0,0 +1,273 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/17 11:04 AM +--- + +require("class") +local system = require("system") +local snappy = require("snappy") +local pystring = require("pystring") +local CprotoData = require("protoData") +local foxFFI = require("foxffi") + +local CfoxTSDB = class("CfoxTSDB") + +function CfoxTSDB:_init_() + self.ffi = foxFFI.ffi + self.cffi = foxFFI.cffi + self._proto = CprotoData.new(nil) + print("this is a test module.") +end + +function CfoxTSDB:_del_() + if self._man then + self.cffi.fox_del_man(self._man) + end + self._man = nil +end + +function CfoxTSDB:get_us() + return self.cffi.get_us() +end + +function CfoxTSDB:getDateFrom_us(us) + local foxTime = self.ffi.new("struct foxDate") + + assert(self.cffi.get_date_from_us(us, foxTime) == 0) + + return foxTime +end + +function CfoxTSDB:getDate() + local foxTime = self.ffi.new("struct foxDate") + + assert(self.cffi.get_date(foxTime) == 0) + + return foxTime +end + +function CfoxTSDB:makeStamp(foxTime) + return self.cffi.make_stamp(foxTime) +end + +function CfoxTSDB:date2str(date) + local d = string.format("%04d-%02d-%02d", date.year + 1900, date.mon + 1, date.mday) + local t = string.format("%02d:%02d:%02d", date.hour, date.min, date.sec) + return d .. " " .. t +end + +local function transDate(ds) + local year, mon, mday = unpack(ds) + return tonumber(year) - 1900, tonumber(mon) - 1, tonumber(mday) +end + +local function transTime(ts) + local hour, min, sec = unpack(ts) + return tonumber(hour), tonumber(min), tonumber(sec) +end + +function CfoxTSDB:str2date(s) + local dt = pystring:split(s, " ", 1) + local d, t = dt[1], dt[2] + + local ds = pystring:split(d, "-", 2) + local ts = pystring:split(t, ":", 2) + + local foxTime = self.ffi.new("struct foxDate") + foxTime.year, foxTime.mon, foxTime.mday = transDate(ds) + foxTime.hour, foxTime.min, foxTime.sec = transTime(ts) + + return foxTime +end + +function CfoxTSDB:deltaSec(date) + local delta = 0 + + if date.sec then + delta = delta + date.sec + end + if date.min then + delta = delta + date.min * 60 + end + if date.hour then + delta = delta + date.hour * 60 * 60 + end + if date.day then + delta = delta + date.day * 24 * 60 * 60 + end + return delta +end + +function CfoxTSDB:moveSec(foxTime, off_sec) + local us = self:makeStamp(foxTime) + off_sec * 1e6 + return self:getDateFrom_us(us) +end + +function CfoxTSDB:movesSec(s, off_sec) + local foxTime = self:str2date(s) + return self:date2str(self:moveSec(foxTime, off_sec)) +end + +function CfoxTSDB:moveTime(foxTime, tTable) + local sec = self:deltaSec(tTable) + return self:moveSec(foxTime, sec) +end + +function CfoxTSDB:movesTime(s, tTable) + local foxTime = self:str2date(s) + return self:date2str(self:moveTime(foxTime, tTable)) +end + +function CfoxTSDB:packLine(lines) + return self._proto:encode(lines) +end + +function CfoxTSDB:setupWrite() + assert(self._man == nil, "one fox object should have only one manager.") + self._man = self.ffi.new("struct fox_manager") + local date = self:getDate() + local us = self:get_us() + local ret = self.cffi.fox_setup_write(self._man, date, us) + assert(ret == 0) + return ret +end + +function CfoxTSDB:write(buff) + assert(self._man ~= nil, "this fox object show setup for read or write, you should call setupWrite after new") + local now = self:get_us() + local date = self:getDateFrom_us(now) + local stream = snappy.compress(buff) + print("write for time: ", now) + assert(self.cffi.fox_write(self._man, date, now, self.ffi.string(stream, #stream), #stream) == 0) + --assert(self.cffi.fox_write(self._man, date, now, self.ffi.string(buff), #buff) == 0) +end + +function CfoxTSDB:_setupRead(us) + assert(self._man == nil, "one fox object should have only one manager.") + self._man = self.ffi.new("struct fox_manager") + us = us or (self:get_us() - 15e6) + local date = self:getDateFrom_us(us) + local res = self.cffi.fox_setup_read(self._man, date, us) + assert(res >= 0, string.format("setup read return %d.", res)) + if res > 0 then + self.cffi.fox_del_man(self._man) + self._man = nil + end + return res +end + +function CfoxTSDB:curMove(us) + assert(self._man) + local ret = self.cffi.fox_cur_move(self._man, us) + assert(ret >= 0, string.format("cur move bad ret: %d", ret)) + return self._man.pos +end + +function CfoxTSDB:resize() + assert(self._man) + local ret = self.cffi.fox_read_resize(self._man) + assert(ret >= 0, string.format("resize bad ret: %d", ret)) +end + +function CfoxTSDB:loadData(stop_us) + local stop = false + + local function fLoad() + if stop then + return nil + end + + local data = self.ffi.new("char* [1]") + local us = self.ffi.new("fox_time_t [1]") + local ret = self.cffi.fox_read(self._man, stop_us, data, us) + assert(ret >= 0) + if ret > 0 then + local stream = self.ffi.string(data[0], ret) + local ustr = snappy.decompress(stream) + local line = self._proto:decode(ustr) + self.cffi.fox_free_buffer(data) + + if self._man.fsize == self._man.pos then -- this means cursor is at the end of file. + print("end of file.") + stop = true + end + line['time'] = tonumber(us[0]) + return line + end + return nil + end + return fLoad +end + +function CfoxTSDB:query(start, stop, ms) -- start stop should at the same mday + assert(stop > start) + local dStart = self:getDateFrom_us(start) + local dStop = self:getDateFrom_us(stop) + + assert(self.cffi.check_foxdate(dStart, dStop) == 1) -- check date + assert(self._man) + + self:curMove(start) -- moveto position + + for line in self:loadData(stop) do + local time = line.time + for _, v in ipairs(line.lines) do + local tCell = {time = time, title = v.line} + + local labels = {} + if v.ls then + for _, vlabel in ipairs(v.ls) do + labels[vlabel.name] = vlabel.index + end + end + tCell.labels = labels + + local values = {} + if v.vs then + for _, vvalue in ipairs(v.vs) do + values[vvalue.name] = vvalue.value + end + end + tCell.values = values + + local logs = {} + if v.vlog then + for _, vlog in ipairs(v.log) do + logs[vlog.name] = vlog.log + end + end + tCell.logs = logs + + table.insert(ms, tCell) + end + end + return ms +end + +function CfoxTSDB:qlast(last, ms) + local now = self:get_us() + local date = self:getDateFrom_us(now) + local beg = now - last * 1e6; + + if self._man then -- has setup + if self.cffi.check_pman_date(self._man, date) then -- at the same day + return self:query(beg, now, ms) + else + self:_del_() -- destroy old manager + if self:_setupRead(now) ~= 0 then -- try to create new + return ms + else + return self:query(beg, now, ms) + end + end + else + if self:_setupRead(now) ~= 0 then -- try to create new + return ms + else + return self:query(beg, now, ms) + end + end +end + +return CfoxTSDB diff --git a/source/tools/monitor/unity/test/lab/foxTest.lua b/source/tools/monitor/unity/test/lab/foxTest.lua new file mode 100644 index 0000000000000000000000000000000000000000..7fb9e9eb6c29522f32e4d833db9f86bc15b49184 --- /dev/null +++ b/source/tools/monitor/unity/test/lab/foxTest.lua @@ -0,0 +1,68 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/31 4:52 PM +--- + +package.path = package.path .. ";../../common/?.lua;" +package.path = package.path .. ";../../tsdb/?.lua;" +package.path = package.path .. ";./native/?.lua;" + +local system = require("system") + +local CfoxTSDB = require("foxTSDB") + +local fox = CfoxTSDB.new() + +local line = { + lines = { + { + line = "metric1", + ls = { + { name = "title", index = "hello" } + }, + vs = { + { name = "value", value = 3.3 }, + { name = "cut", value = 3.4 } + } + }, + { + line = "metric2", + vs = { + { name = "value", value = 3.3 }, + { name = "cut", value = 3.4 } + }, + log = { + { name = "hello", log = "world." }, + } + }, + } +} + +function test() + + local s1 = "2022-12-17 11:13:00" + + local foxTime = fox:str2date(s1) + assert(foxTime.year == 2022 - 1900) + assert(foxTime.mon == 12 - 1) + assert(foxTime.mday == 17) + assert(foxTime.hour == 11) + assert(foxTime.min == 13) + assert(foxTime.sec == 0) + + local sCheck = fox:date2str(foxTime) + assert(s1 == sCheck) + + line.lines[1].vs[1].value = line.lines[1].vs[1].value + 1 + line.lines[2].vs[2].value = line.lines[2].vs[2].value + 3 + local res = fox:packLine(line) + assert(string.len(res) > 0) + + local ret = fox:setupWrite() + assert(ret == 0) + --fox:write(res) + print("write.") +end + +print("load ok.") diff --git a/source/tools/monitor/unity/test/lab/native/Makefile b/source/tools/monitor/unity/test/lab/native/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..85686fcc12bfa151fa2cdc8fd52392e5099d8db7 --- /dev/null +++ b/source/tools/monitor/unity/test/lab/native/Makefile @@ -0,0 +1,16 @@ +CC := gcc +CFLAG := -g -fpic +LDFLAG := -g -fpic -shared +OBJS := foxTSDB.o +SO := libfoxTSDB.so + +all: $(SO) + +foxTSDB.o: foxTSDB.c + $(CC) -c $< -o $@ $(CFLAG) + +$(SO): $(OBJS) + $(CC) -o $@ $(OBJS) $(LDFLAG) + +clean: + rm -f $(SO) $(OBJS) \ No newline at end of file diff --git a/source/tools/monitor/unity/test/lab/native/foxTSDB.c b/source/tools/monitor/unity/test/lab/native/foxTSDB.c new file mode 100644 index 0000000000000000000000000000000000000000..373d14a9e98b4df01e74df16342741c9568f1d8b --- /dev/null +++ b/source/tools/monitor/unity/test/lab/native/foxTSDB.c @@ -0,0 +1,718 @@ +// +// Created by 廖肇燕 on 2022/12/13. +// + +#include "foxTSDB.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FNAME_SIZE 16 +#define FOX_MAGIC 0xf030 +#define MICRO_UNIT (1000 * 1000UL) + +#define FOX_VALUE_FLAG (1 << 0ULL) +#define FOX_LOG_FLAG (1 << 1ULL) + +struct fox_head{ + unsigned int prev; + unsigned int next; + fox_time_t t_us; + unsigned short magic; + unsigned short flag; +}; + +fox_time_t get_us(void) { + fox_time_t res = 0; + struct timeval tv; + + if (gettimeofday(&tv, NULL) == 0) { + res = tv.tv_sec * MICRO_UNIT + tv.tv_usec; + } + return res; +} + +static void tm2date(struct tm * ptm, struct foxDate * p) { + p->year = ptm->tm_year; + p->mon = ptm->tm_mon; + p->mday = ptm->tm_mday; + p->hour = ptm->tm_hour; + p->min = ptm->tm_min; + p->sec = ptm->tm_sec; +} + +static void date2tm(struct foxDate * p, struct tm * ptm) { + ptm->tm_year = p->year; + ptm->tm_mon = p->mon; + ptm->tm_mday = p->mday; + ptm->tm_hour = p->hour; + ptm->tm_min = p->min; + ptm->tm_sec = p->sec; + ptm->tm_isdst = -1; +} + +int get_date_from_us(fox_time_t us, struct foxDate * p) { + struct tm * ptm; + + time_t t = us / MICRO_UNIT; + ptm = localtime(&t); + tm2date(ptm, p); + return 0; +} + +int get_date(struct foxDate * p) { + struct timeval tv; + if (gettimeofday(&tv, NULL) == 0) { + struct tm * ptm = localtime(&tv.tv_sec); + tm2date(ptm, p); + return 0; + } + return 1; +} + +fox_time_t make_stamp(struct foxDate * p) { + struct tm tmt; + + date2tm(p, &tmt); + time_t t = mktime(&tmt); + return t * MICRO_UNIT; +} + +static fox_time_t fox_read_init_now(struct fox_manager* pman) { + struct foxDate date; + + date.year = pman->year; + date.mon = pman->mon; + date.mday = pman->mday; + date.hour = date.min = date.sec = 0; + + return make_stamp(&date); +} + +static fox_time_t fox_read_day_max(struct fox_manager* pman) { + struct foxDate date; + + date.year = pman->year; + date.mon = pman->mon; + date.mday = pman->mday; + date.hour = date.min = date.sec = 0; + + return make_stamp(&date) + 24 * 60 * 60 * MICRO_UNIT; +} + +static size_t fd_size(int fd) { + int ret; + struct stat file_info; + + ret = fstat(fd, &file_info); + if (ret < 0) { + fprintf(stderr, "stat file failed. %d, %s\n", errno, strerror(errno)); + } + return (!ret) ? file_info.st_size : -EACCES; +} + +static void pack_fname(char* pname, struct foxDate * p) { + snprintf(pname, FNAME_SIZE, "%04d%02d%02d.fox", p->year, p->mon, p->mday); +} + +static int fox_read_head(int fd, struct fox_head* phead) { + size_t size; + + size = read(fd, phead, sizeof (struct fox_head)); + + if (size == sizeof (struct fox_head)) { + if (phead->magic == FOX_MAGIC) { + return size; + } else { + fprintf(stderr, "bad magic: 0x%x, hope: 0x%x\n", phead->magic, FOX_MAGIC); + return -EINVAL; + } + } else if (size == 0) { + return 0; + } else { + fprintf(stderr, "read file failed. %d, %s\n", errno, strerror(errno)); + return -EACCES; + } +} + +static int fox_check_head(int fd, struct fox_manager* pman) { + int ret; + struct fox_head head; + off_t off = 0; + + head.prev = 0; + while (1) { + off = lseek(fd, off, SEEK_SET); + if (off < 0) { + fprintf(stderr, "seek file failed. %d, %s\n", errno, strerror(errno)); + ret = -EACCES; + goto endSeek; + } + + ret = fox_read_head(fd, &head); + if (ret > 0) { + off = head.next; + } else if (ret == 0) { + pman->last_pos = head.prev; + pman->pos = off; + break; + } else { + fprintf(stderr, "write file failed. pos: 0x%llx\n", off); + goto endHead; + } + } + + return ret; + endHead: + endSeek: + return ret; +} + +static int fox_check(int fd, struct fox_manager* pman) { + int ret = 0; + int retLock = 0; + + ret = lockf(fd, F_LOCK, 0); + if (ret < 0) { + fprintf(stderr, "lock file failed. %d, %s\n", errno, strerror(errno)); + goto endLock; + } + + ret = fox_check_head(fd, pman); + if (ret < 0) { + goto endCheck; + } + + ret = lockf(fd, F_ULOCK, 0); + if (ret < 0) { + fprintf(stderr, "lock file failed. %d, %s\n", errno, strerror(errno)); + goto endUnLock; + } + + return ret; + + endCheck: + retLock = lockf(fd, F_ULOCK, 0); + if (retLock < 0) { + fprintf(stderr, "lock file failed. %d, %s\n", errno, strerror(errno)); + ret = retLock; + goto endUnLock; + } + return ret; + endUnLock: + endLock: + return ret; +} + +int fox_setup_write(struct fox_manager* pman, struct foxDate * p, fox_time_t now) { + char fname[FNAME_SIZE]; + int ret = 0; + + pack_fname(fname, p); + pman->fd = 0; + + pman->fd = open(fname, O_RDWR|O_APPEND|O_CREAT); + if (pman->fd < 0) { + fprintf(stderr, "open %s error, return %d, %s", fname, errno, strerror(errno)); + ret = -ENOENT; + goto endOpen; + } + + ret = fox_check(pman->fd, pman); + if (ret < 0) { + goto endCheck; + } + + pman->year = p->year; + pman->mon = p->mon; + pman->mday = p->mday; + pman->now = now; + + return ret; + endCheck: + close(pman->fd); + pman->fd = 0; + endOpen: + return ret; +} + +int check_foxdate(struct foxDate* d1, struct foxDate* d2) { + return (d1->year == d2->year) && \ + (d1->mon == d2->mon) && \ + (d1->mday == d2->mday); +} + +int check_pman_date(struct fox_manager* pman, struct foxDate* pdate) { + return (pman->year == pdate->year) && \ + (pman->mon == pdate->mon) && \ + (pman->mday == pdate->mday); +} + +static int fox_write_data(struct fox_manager* pman, fox_time_t us, const char* data, int len) { + int ret = 0; + int fd = pman->fd; + struct fox_head head; + + head.prev = pman->last_pos; + head.next = pman->pos + sizeof (struct fox_head) + len; + head.t_us = us; + head.magic = FOX_MAGIC; + head.flag = 0; + + ret = lockf(fd, F_LOCK, 0); + if (ret < 0) { + fprintf(stderr, "lock file failed. %d, %s\n", errno, strerror(errno)); + ret = -EACCES; + goto endLock; + } + + ret = write(fd, &head, sizeof (struct fox_head)); + if (ret < 0) { + fprintf(stderr, "write file failed. %d, %s\n", errno, strerror(errno)); + goto endWrite; + } + ret = write(fd, data, len ); + if (ret < 0) { + fprintf(stderr, "write file failed. %d, %s\n", errno, strerror(errno)); + goto endWrite; + } + + ret = lockf(fd, F_ULOCK, 0); + if (ret < 0) { + fprintf(stderr, "lock file failed. %d, %s\n", errno, strerror(errno)); + ret = -EACCES; + goto endUnLock; + } + + pman->now = us; + pman->last_pos = pman->pos; // record last position + pman->pos = head.next; + return ret; + + endWrite: + ret = lockf(fd, F_ULOCK, 0); + if (ret < 0) { + fprintf(stderr, "lock file failed. %d, %s\n", errno, strerror(errno)); + ret = -EACCES; + goto endUnLock; + } + return ret; + endUnLock: + endLock: + return ret; +} + +int fox_write(struct fox_manager* pman, struct foxDate* pdate, fox_time_t us, + const char* data, int len) { + int res = 0; + + if (!check_pman_date(pman, pdate)) { // new day? + close(pman->fd); // close this file at first. + res = fox_setup_write(pman, pdate, us); + if (res < 0) { + fprintf(stderr, "create new file failed.\n"); + goto endCreateFile; + } + } + + if (pman->now <= us) { // time should monotonically increasing + res = fox_write_data(pman, us, data, len); + } + return res; + + endCreateFile: + return res; +} + +static int fox_cursor_left(int fd, struct fox_manager* pman, fox_time_t now) { + int ret; + off_t pos; + struct fox_head head; + fox_time_t last_t_us = pman->now; + + if (pman->pos == pman->fsize) { + pos = pman->last_pos; + } else { + pos = pman->pos; + } + + while (1) { + ret = lseek(fd, pos, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "seek file failed. %d, %s\n", errno, strerror(errno)); + ret = -EACCES; + goto endSeek; + } + + ret = fox_read_head(fd, &head);; + if (ret < 0) { + goto endRead; + } + + if (head.t_us < now) { + pman->pos = head.next; + pman->now = last_t_us; + pman->last_pos = pos; + break; + } + + last_t_us = head.t_us; + pos = head.prev; + if (pos == 0) { //begin of file + pman->pos = pos; + pman->now = last_t_us; + pman->last_pos = pos; + break; + } + } + ret = 0; + return ret; + endSeek: + endRead: + return ret; +} + +static int fox_cursor_right(int fd, struct fox_manager* pman, fox_time_t now) { + int ret; + off_t last_pos = pman->last_pos; + off_t pos = pman->pos; + struct fox_head head; + + while (1) { + if (pos == pman->fsize) { + pman->last_pos = last_pos; + pman->pos = pos; + pman->now = fox_read_day_max(pman); + ret = 0; + goto endEndoffile; + } else if (pos > pman->fsize) { + ret = -ERANGE; + goto endRange; + } + + ret = lseek(fd, pos, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "seek file failed. %d, %s\n", errno, strerror(errno)); + ret = -EACCES; + goto endSeek; + } + + ret = fox_read_head(fd, &head);; + if (ret < 0) { + goto endRead; + } + + if (head.t_us >= now) { // just > + pman->pos = pos; + pman->now = head.t_us; + pman->last_pos = last_pos; + break; + } + last_pos = pos; + pos = head.next; + } + ret = 0; + return ret; + endEndoffile: + return ret; + endRange: //out of file range. + return ret; + endSeek: + endRead: + endSize: + return ret; +} + +static int fox_cursor_work(int fd, struct fox_manager* pman, fox_time_t now) { + int ret = 0; + + if (pman->now > now) { + ret = fox_cursor_left(fd, pman, now); + if (ret < 0) { + goto endCursor; + } + } else if (pman->now < now) { + ret = fox_cursor_right(fd, pman, now); + if (ret < 0) { + goto endCursor; + } + } + + return ret; + endCursor: + return ret; +} + +static int fox_cursor(int fd, struct fox_manager* pman, fox_time_t now) { + int ret; + + ret = fox_cursor_work(fd, pman, now); + if (ret < 0) { + goto endLock; + } + + return ret; + endLock: + return ret; +} + +int fox_cur_move(struct fox_manager* pman, fox_time_t now) { + int fd; + + fd = pman->fd; + + return fox_cursor(fd, pman, now); +} + +static int fox_cur_next(struct fox_manager* pman, struct fox_head* phead) { + int ret = 0; + off_t pos = phead->next; + struct fox_head head; + int fd = pman->fd; + + pman->pos = pos; + if (pos < pman->fsize) { + ret = lseek(fd, pos, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "seek file failed. %d, %s\n", errno, strerror(errno)); + goto endSeek; + } + + ret = fox_read_head(fd, &head);; + if (ret < 0) { + goto endRead; + } + pman->now = head.t_us; + } else { + pman->now = fox_read_day_max(pman); + } + + return ret; + endSeek: + endRead: + return ret; +} + +static int fox_cur_back(struct fox_manager* pman) { + int ret = 0; + off_t pos = pman->last_pos; + struct fox_head head; + int fd = pman->fd; + + pman->pos = pos; + if (pos > 0) { + ret = lseek(fd, pos, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "seek file failed. %d, %s\n", errno, strerror(errno)); + goto endSeek; + } + + ret = fox_read_head(fd, &head);; + if (ret < 0) { + goto endRead; + } + pman->now = head.t_us; + } else { + pman->now = fox_read_init_now(pman); + } + + return ret; + endSeek: + endRead: + return ret; +} + +int fox_read_resize(struct fox_manager* pman) { + int ret = 0; + + size_t fsize = fd_size(pman->fd); + if (fsize < 0) { + ret = fsize; + goto endSize; + } + + if (fsize > pman->fsize) { + if (pman->pos == pman->fsize) { // at the end of file. + ret = fox_cur_back(pman); + if (ret < 0) { + goto endCur; + } + } + pman->fsize = fsize; + } else { + struct foxDate d; + d.year = pman->year; + d.mon = pman->mon; + d.mday = pman->mday; + d.hour = 0; + d.min = 0; + d.sec = 0; + + fox_time_t now = make_stamp(&d); + + ret = fox_setup_read(pman, &d, now); + if (ret !=0 ) { + ret = -EACCES; + goto endSetup; + } + } + return ret; + endSetup: + endSize: + endCur: + return ret; +} + +int fox_setup_read(struct fox_manager* pman, struct foxDate * p, fox_time_t now) { + char fname[FNAME_SIZE]; + int ret = 0; + + pack_fname(fname, p); + pman->fd = open(fname, O_RDONLY); + if (pman->fd < 0) { + fprintf(stderr, "open %s failed, return %d, %s", fname, errno, strerror(errno)); + ret = 1; + goto endOpen; + } + + pman->year = p->year; + pman->mon = p->mon; + pman->mday = p->mday; + pman->now = fox_read_init_now(pman); + pman->pos = 0; + pman->last_pos = 0; + pman->fsize = fd_size(pman->fd); + if (pman->fsize < 0) { + ret = -EACCES; + goto endSize; + } + + ret = fox_cursor(pman->fd, pman, now); + if (ret < 0) { + goto endCursor; + } + +// printf("setup %s, fd: %d, size: %ld, pos: %lld, pnow: %ld, now:%ld\n", +// fname, pman->fd, pman->fsize, pman->pos, pman->now, now); + return ret; + endSize: + endCursor: + close(pman->fd); + endOpen: + pman->fd = -1; + return ret; +} + +static int fox_read_stream(int fd, char* stream, int size) { + int ret; + + ret = read(fd, stream, size); + if (ret < 0) { + fprintf(stderr, "read file failed. %d, %s\n", errno, strerror(errno)); + goto endRead; + } + return ret; + + endRead: + return ret; +} + +static int fox_read_work(int fd, struct fox_manager* pman, fox_time_t stop, + char **pp, int *len, fox_time_t *us) { + int ret = 0; + off_t pos = pman->pos; + int size; + + if (pman->now <= stop) { + struct fox_head head; + char *p; + + ret = lseek(fd, pos, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "seek file failed. %d, %s\n", errno, strerror(errno)); + ret = -EACCES; + goto endSeek; + } + + ret = fox_read_head(fd, &head); + if (ret < 0) { + goto endRead; + } + + size = head.next - pos - sizeof (struct fox_head); + if (size < 0) { + goto endSize; + } + p = malloc(size); + if (p == NULL) { + fprintf(stderr, "malloc %d failed. %d, %s\n", size, errno, strerror(errno)); + ret = -ENOMEM; + goto endMalloc; + } + + ret = fox_read_stream(fd, p, size); + if (ret < 0) { + free(p); + goto endRead2; + } + + ret = fox_cur_next(pman, &head); // the cursor will to next position. + if (ret < 0) { + free(p); + goto endNext; + } + + *us = head.t_us; + *pp = p; + *len = size; + } else { + *pp = NULL; + *len = 0; + } + return ret; + + endNext: + endRead2: + endSize: + endMalloc: + endRead: + endSeek: + *pp = NULL; + *len = 0; + return ret; +} + +int fox_read(struct fox_manager* pman, fox_time_t stop, char **pp, fox_time_t *us) { + int ret; + int len; + int fd = pman->fd; + + ret = fox_read_work(fd, pman, stop, pp, &len, us); + if (ret < 0) { + goto endWork; + } + return len; + + endWork: + return ret; +} + +void fox_free_buffer(char **pp) { + char *p = *pp; + free((void *)p); +} + +void fox_del_man(struct fox_manager* pman) { + if (pman->fd > 0) { + close(pman->fd); + } + memset(pman, 0, sizeof (struct fox_manager)); +} diff --git a/source/tools/monitor/unity/test/lab/native/foxTSDB.h b/source/tools/monitor/unity/test/lab/native/foxTSDB.h new file mode 100644 index 0000000000000000000000000000000000000000..8d8de51ade4dc07e3d31affe90156cc12500b83c --- /dev/null +++ b/source/tools/monitor/unity/test/lab/native/foxTSDB.h @@ -0,0 +1,50 @@ +// +// Created by 廖肇燕 on 2022/12/13. +// + +#ifndef TINYINFO_FOXTSDB_H +#define TINYINFO_FOXTSDB_H + +#include + +typedef unsigned long fox_time_t; + +struct foxDate { + short year; + char mon; + char mday; + char hour; + char min; + char sec; +}; + +struct fox_manager { + fox_time_t now; + off_t pos; //now offset; + off_t last_pos; // last pos + size_t fsize; // file size. + int fd; + + short year; + char mon; + char mday; +}; + +fox_time_t get_us(void); +int get_date_from_us(fox_time_t us, struct foxDate * p); +int get_date(struct foxDate * p); +fox_time_t make_stamp(struct foxDate * p); +int check_foxdate(struct foxDate* d1, struct foxDate* d2); +int check_pman_date(struct fox_manager* pman, struct foxDate* pdate); + +int fox_setup_write(struct fox_manager* pman, struct foxDate * p, fox_time_t now); +int fox_write(struct fox_manager* pman, struct foxDate* pdate, fox_time_t us, + const char* data, int len); +int fox_setup_read(struct fox_manager* pman, struct foxDate * p, fox_time_t now); +int fox_cur_move(struct fox_manager* pman, fox_time_t now); +int fox_read_resize(struct fox_manager* pman); +int fox_read(struct fox_manager* pman, fox_time_t stop, char **pp, fox_time_t *us); +void fox_free_buffer(char **pp); +void fox_del_man(struct fox_manager* pman); + +#endif //TINYINFO_FOXTSDB_H diff --git a/source/tools/monitor/unity/test/lab/native/foxffi.lua b/source/tools/monitor/unity/test/lab/native/foxffi.lua new file mode 100644 index 0000000000000000000000000000000000000000..8571399fecee56c53e32e11d1bea8f213442c2ac --- /dev/null +++ b/source/tools/monitor/unity/test/lab/native/foxffi.lua @@ -0,0 +1,53 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/17 9:27 AM +--- + +local ffi = require("ffi") +local cffi = ffi.load('foxTSDB') + +ffi.cdef [[ +typedef unsigned long off_t; +typedef unsigned long fox_time_t; + +struct foxDate { + short year; + char mon; + char mday; + char hour; + char min; + char sec; +}; + +struct fox_manager { + fox_time_t now; + off_t pos; //now offset; + off_t last_pos; // last pos + size_t fsize; // file size. + int fd; + + short year; + char mon; + char mday; +}; + +fox_time_t get_us(void); +int get_date_from_us(fox_time_t us, struct foxDate * p); +int get_date(struct foxDate * p); +fox_time_t make_stamp(struct foxDate * p); +int check_foxdate(struct foxDate* d1, struct foxDate* d2); +int check_pman_date(struct fox_manager* pman, struct foxDate* pdate); + +int fox_setup_write(struct fox_manager* pman, struct foxDate * p, fox_time_t now); +int fox_write(struct fox_manager* pman, struct foxDate* pdate, fox_time_t us, + const char* data, int len); +int fox_setup_read(struct fox_manager* pman, struct foxDate * p, fox_time_t now); +int fox_cur_move(struct fox_manager* pman, fox_time_t now); +int fox_read_resize(struct fox_manager* pman); +int fox_read(struct fox_manager* pman, fox_time_t stop, char **pp, fox_time_t *us); +void fox_free_buffer(char **pp); +void fox_del_man(struct fox_manager* pman); +]] + +return {ffi = ffi, cffi = cffi} diff --git a/source/tools/monitor/unity/test/md/test.md b/source/tools/monitor/unity/test/md/test.md new file mode 100644 index 0000000000000000000000000000000000000000..1589469808a2d87d5c3afabc45ee22ce82dc8e21 --- /dev/null +++ b/source/tools/monitor/unity/test/md/test.md @@ -0,0 +1,80 @@ +# hello world. +## hello two world. +### hello three world. +#### hello four world. + +fasf***hello word***, ***world*** + +fasf___hello word___, ***world*** + +fasf**hello word** + +fasf*hello word* + +fasf~~hello word~~ + +> hello, this is a quote test. +> a new quote. +> three quote. +>> child quote. +>>> three quote. + +newline + +1. line1 +2. line2 +3. line3 + 1. child + 1. child2 + 2. + + +* hello +* world + * *how* + * why +* end + +At the command prompt, type `nano`. + +``Use `code` in your Markdown file.`` + + #inlcude + #inlcude + + int main(void) + { + printf("hello, world."); + return 0; + } + + +```C +#inlcude +#inlcude + +int main(void) +{ + printf("hello, world.\n"); + return 0; +} + +``` + +| 姓名 | 年龄 | 工作 | +| :----- | :--: | -------: | +| 小可爱 | 18 | 吃可爱多 | +| 小小勇敢 | 20 | 爬棵[勇敢树](/url/tree) | +| 小小小机智 | 22 | 看一本机智书 | + +--- + +返回[guide](/url/guide) + +end\_line. + +1. unity\_set\_table 中 table 参数长度应该小于32(不含) +2. unity\_set\_index 中 name、index和unity\_set\_value 中 name 参数长度应该要小于16(不含) +3. unity\_set\_index 下标从0开始,并小于 4,即最多4个索引。而且下标数值应该连续,否则数据会从留白处截断 +4. unity\_set\_index 下标从0开始,并小于 32,即最多32个数值。而且下标数值应该连续,否则数据会从留白处截断 + diff --git a/source/tools/monitor/unity/test/md/tmd.lua b/source/tools/monitor/unity/test/md/tmd.lua new file mode 100644 index 0000000000000000000000000000000000000000..589bb4a8903dfc8e86cddd3c3c74fe892e7d1b63 --- /dev/null +++ b/source/tools/monitor/unity/test/md/tmd.lua @@ -0,0 +1,16 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2023/1/2 11:40 PM +--- + +package.path = package.path .. ";../../common/?.lua;" + +local Clmd = require("lmd") + +local f = io.open("test.md","r") +local md = f:read("*all") +f:close() + +local lmd = Clmd.new() +print(lmd:toHtml(md)) diff --git a/source/tools/monitor/unity/test/nativeFoxFFI.lua b/source/tools/monitor/unity/test/nativeFoxFFI.lua new file mode 100644 index 0000000000000000000000000000000000000000..101a6089715275d99b4f88ab8cb4eb45dc80977a --- /dev/null +++ b/source/tools/monitor/unity/test/nativeFoxFFI.lua @@ -0,0 +1,51 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/17 10:22 AM +--- + +package.path = package.path .. ";../common/?.lua;" +package.path = package.path .. ";../tsdb/native/?.lua;" + +local system = require("system") +local foxFFI = require("foxffi") + +local us1 = foxFFI.cffi.get_us() +assert(us1 > 0) +local d1 = foxFFI.ffi.new("struct foxDate") +assert(foxFFI.cffi.get_date_from_us(us1, d1) == 0) +local us2 = foxFFI.cffi.make_stamp(d1) +local d2 = foxFFI.ffi.new("struct foxDate") +foxFFI.cffi.get_date_from_us(us2, d2) +assert(foxFFI.cffi.check_foxdate(d1, d2) == 1) + +system:sleep(1) + +us2 = foxFFI.cffi.get_us() +local delta = us2 - us1 +assert(delta > 1000000) +assert(delta < 1100000) + +assert(foxFFI.cffi.get_date(d2) == 0) +assert(d1.year <= d2.year) +if d1.year == d2.year then + assert(d1.mon <= d2.mon) + if d1.mon == d2.mon then + assert(d1.mday <= d2.mday) + if d1.mday == d2.mday then + assert(d1.hour <= d2.hour) + if d1.hour == d2.hour then + assert(d1.min <= d2.min) + if d1.min == d2.min then + assert(d1.sec < d2.sec) + end + end + end + end +end + +local us3 = foxFFI.cffi.make_stamp(d2) +assert(us3 > us1) +assert(us3 <= us2) + +print("native fox time ok.") diff --git a/source/tools/monitor/unity/test/nativeFoxFFI.sh b/source/tools/monitor/unity/test/nativeFoxFFI.sh new file mode 100755 index 0000000000000000000000000000000000000000..2b748f000e781aeb05628755ddbe35b0bdfe0778 --- /dev/null +++ b/source/tools/monitor/unity/test/nativeFoxFFI.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +cd ../tsdb/native/ +source /opt/rh/devtoolset-9/enable +make +if [ $? -ne 0 ];then + echo " make -- Faile : "$? + exit 0 +fi +cd - +luajit nativeFoxFFI.lua \ No newline at end of file diff --git a/source/tools/monitor/unity/test/nativeProcFFI.lua b/source/tools/monitor/unity/test/nativeProcFFI.lua new file mode 100644 index 0000000000000000000000000000000000000000..4eba78e316d5fa2ee75229652f3b81885a908a81 --- /dev/null +++ b/source/tools/monitor/unity/test/nativeProcFFI.lua @@ -0,0 +1,68 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/16 9:42 PM +--- + +package.path = package.path .. ";../common/?.lua;" +package.path = package.path .. ";../collector/native/?.lua;" + +local procFFI = require("procffi") + +print("test for var_input_long") +local line = " 300 400 0 " +local data = procFFI.ffi.new("var_long_t") +assert(procFFI.cffi.var_input_long(procFFI.ffi.string(line), data) == 0) +assert(data.no == 3) +assert(data.value[0] == 300) +assert(data.value[1] == 400) +assert(data.value[2] == 0) +assert(procFFI.cffi.var_input_long(procFFI.ffi.string(""), data) == 0) +line = "0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9" +data = procFFI.ffi.new("var_long_t") +assert(procFFI.cffi.var_input_long(procFFI.ffi.string(line), data) == 0) +assert(data.no == 64) +assert(data.value[0] == 0) +assert(data.value[10] == 0) + +print("test for var_input_kvs") +local line = " cpu 12110452 0 13242501 191691355 604 0 566813 0 0 0" +local data = procFFI.ffi.new("var_kvs_t") +assert(procFFI.cffi.var_input_kvs(procFFI.ffi.string(line), data) == 0) +assert(procFFI.ffi.string(data.s) == "cpu") +assert(data.no == 10) +assert(data.value[0]== 12110452) +assert(data.value[1]== 0) +assert(data.value[3]== 191691355) +line = "0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9" +data = procFFI.ffi.new("var_kvs_t") +assert(procFFI.cffi.var_input_kvs(procFFI.ffi.string(line), data) == 0) +assert(procFFI.ffi.string(data.s) == "0") +assert(data.no == 64) +assert(data.value[0] == 1) +assert(data.value[10] == 1) + +print("test for var_input_string") +local line = "Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates" +local data = procFFI.ffi.new("var_string_t") +assert(procFFI.cffi.var_input_string(procFFI.ffi.string(line), data) == 0) +assert(data.no == 20) +assert(procFFI.ffi.string(data.s[0]) == "Ip:") +assert(procFFI.ffi.string(data.s[1]) == "Forwarding") +assert(procFFI.ffi.string(data.s[3]) == "InReceives") +assert(procFFI.ffi.string(data.s[19]) == "FragCreates") +line = "0123456789012345678901234567890123456789 123" -- for long line. +data = procFFI.ffi.new("var_string_t") +assert(procFFI.cffi.var_input_string(procFFI.ffi.string(line), data) == 0) +assert(data.no == 2) +assert(procFFI.ffi.string(data.s[0]) == "0123456789012345678901234567890") +assert(procFFI.ffi.string(data.s[1]) == "123") + +line = "0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9" +data = procFFI.ffi.new("var_string_t") +assert(procFFI.cffi.var_input_string(procFFI.ffi.string(line), data) == 0) +assert(data.no == 64) +assert(procFFI.ffi.string(data.s[0]) == "0") +assert(procFFI.ffi.string(data.s[10]) == "0") + +print("test ok.") diff --git a/source/tools/monitor/unity/test/nativeProcFFI.sh b/source/tools/monitor/unity/test/nativeProcFFI.sh new file mode 100755 index 0000000000000000000000000000000000000000..3e8bd68f0e6c5399ac41f6eaa5668779771be43a --- /dev/null +++ b/source/tools/monitor/unity/test/nativeProcFFI.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../collector/native/ +source /etc/profile +cd ../collector/native/ +make +if [ $? -ne 0 ];then + echo " make -- Faile : "$? + exit 0 +fi +cd - +luajit nativeProcFFI.lua diff --git a/source/tools/monitor/unity/test/protoTest.lua b/source/tools/monitor/unity/test/protoTest.lua new file mode 100644 index 0000000000000000000000000000000000000000..85a46f792bce96a40bea82927971bcec7fd48ec4 --- /dev/null +++ b/source/tools/monitor/unity/test/protoTest.lua @@ -0,0 +1,41 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/16 6:44 PM +--- + +package.path = package.path .. ";../common/?.lua;" + +local CprotoData = require("protoData") + +local sample = { + lines = { + { + line = "hello.", + ls = { + { name = "title", index = "hello" } + }, + vs = { + { name = "value", value = 3.3 }, + { name = "cut", value = 3.4 } + }, + }, + { + line = "hello2", + vs = { + { name = "value", value = 3.3 }, + { name = "cut", value = 3.4 } + }, + log = { + { name = "heed", log = "hello, world." }, + { name = "info", log = "hello, info." }, + } + }, + } +} + +local p = CprotoData.new() +local bytes = p:encode(sample) +print(string.len(bytes)) +--print(p:showProto(bytes)) +print("test ok.") diff --git a/source/tools/monitor/unity/test/protoTest.sh b/source/tools/monitor/unity/test/protoTest.sh new file mode 100755 index 0000000000000000000000000000000000000000..5bd47b7753b3b4058d57dc6576196ac3225a877f --- /dev/null +++ b/source/tools/monitor/unity/test/protoTest.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +luajit protoTest.lua diff --git a/source/tools/monitor/unity/test/string/py.lua b/source/tools/monitor/unity/test/string/py.lua new file mode 100644 index 0000000000000000000000000000000000000000..04cb3142b49953f13a015a394ec5b79189a7b16e --- /dev/null +++ b/source/tools/monitor/unity/test/string/py.lua @@ -0,0 +1,65 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2023/1/3 9:31 PM +--- + +package.path = package.path .. ";../../common/?.lua;" + +local pystring = require("pystring") + +-- 字符串分割,默认按照空格分割 +local ret = pystring:split("hello lua language") +assert(#ret == 3) +assert(ret[1] == "hello") +assert(ret[2] == "lua") +assert(ret[3] == "language") + +-- 自定符号分割 +ret = pystring:split("hello*lua *language", "*") +assert(#ret == 3) +assert(ret[1] == "hello") +assert(ret[2] == "lua ") +assert(ret[3] == "language") + +-- 从右边开始规定次数分割 +ret = pystring:rsplit("hello*lua *language", "*", 1) +assert(#ret == 2) +assert(ret[1] == "hello*lua ") + +-- 多字符串分割 +ret = pystring:split("hello*lua *language", "*l") +assert(#ret == 3) +assert(ret[1] == "hello") +assert(ret[2] == "ua ") +assert(ret[3] == "anguage") + +-- strip掉左右空格 +assert(pystring:strip("\t hello world. \t\n") == "hello world.") + +-- strip掉左右指定符号 +assert(pystring:strip("**hello world**", "*") == "hello world") + +-- strip复合符号 +assert(pystring:strip("*?hello world*?", "*?") == "hello world") + +-- strip字符串 +assert(pystring:strip("abcdefhello worldabcdef", "abcdef") == "hello world") + +-- lstrip字符串 +assert(pystring:lstrip("abcdefhello worldabcdef", "abcdef") == "hello worldabcdef") + +-- rstrip字符串 +assert(pystring:rstrip("abcdefhello worldabcdef", "abcdef") == "abcdefhello world") + +-- join 连接 +local s = "abc d ef g" +local ret = pystring:split(s) +assert(pystring:join(" ", ret) == s) + +-- startswith/endswith +assert(pystring:startswith("hello world", "hello")) +assert(pystring:endswith("hello world", "world")) + +-- find +assert(pystring:find("hello world.", "hello") == 1) diff --git a/source/tools/monitor/unity/test/tsdbRead.lua b/source/tools/monitor/unity/test/tsdbRead.lua new file mode 100644 index 0000000000000000000000000000000000000000..ce6142ac42b891eb06a00fae95cf821f645bac25 --- /dev/null +++ b/source/tools/monitor/unity/test/tsdbRead.lua @@ -0,0 +1,47 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/17 1:32 PM +--- + +package.path = package.path .. ";../common/?.lua;" +package.path = package.path .. ";../tsdb/?.lua;" +package.path = package.path .. ";../tsdb/native/?.lua;" + +local serpent = require("serpent") +local CfoxTSDB = require("foxTSDB") + + +local fox = CfoxTSDB.new() + +local date = fox:getDate() +date = fox:moveSec(date, -60) +local us = fox:makeStamp(date) + +fox:_setupRead(date, us) + +date = fox:moveSec(date, -60) +us = fox:makeStamp(date) +local pos1 = fox:curMove(us) +date = fox:moveSec(date, 60) +us = fox:makeStamp(date) +local pos2 = fox:curMove(us) +date = fox:moveSec(date, -60) +us = fox:makeStamp(date) +local pos3 = fox:curMove(us) +date = fox:moveSec(date, 60) +us = fox:makeStamp(date) +local pos4 = fox:curMove(us) +date = fox:moveSec(date, -60) +us = fox:makeStamp(date) +local pos5 = fox:curMove(us) +assert(pos1 == pos3) +assert(pos3 == pos5) +assert( pos2 == pos4) +print("cursor pass.") + +local start = fox:makeStamp(date) +date = fox:moveSec(date, 60) +local stop = fox:makeStamp(date) + +fox:query(start, stop) diff --git a/source/tools/monitor/unity/test/tsdbRead.sh b/source/tools/monitor/unity/test/tsdbRead.sh new file mode 100755 index 0000000000000000000000000000000000000000..776c10ec38a6c0ac09a0f38b4bed337690376a3b --- /dev/null +++ b/source/tools/monitor/unity/test/tsdbRead.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../tsdb/native/ + +bash nativeFoxFFI.sh +if [ $? -ne 0 ];then + echo " native api-- Failed : "$? + exit 0 +fi + +luajit tsdbRead.lua diff --git a/source/tools/monitor/unity/test/tsdbTime.lua b/source/tools/monitor/unity/test/tsdbTime.lua new file mode 100644 index 0000000000000000000000000000000000000000..2b654b2141f5741962e46368f0652daa910ce1d3 --- /dev/null +++ b/source/tools/monitor/unity/test/tsdbTime.lua @@ -0,0 +1,61 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/17 11:39 AM +--- + +package.path = package.path .. ";../common/?.lua;" +package.path = package.path .. ";../tsdb/?.lua;" +package.path = package.path .. ";../tsdb/native/?.lua;" + +local CfoxTSDB = require("foxTSDB") + +local fox = CfoxTSDB.new() + +local s1 = "2022-12-17 11:13:00" + +local foxTime = fox:str2date(s1) +assert(foxTime.year == 2022 - 1900) +assert(foxTime.mon == 12 - 1) +assert(foxTime.mday == 17) +assert(foxTime.hour == 11) +assert(foxTime.min == 13) +assert(foxTime.sec == 0) + +local sCheck = fox:date2str(foxTime) +assert(s1 == sCheck) + +--local s1 = "2022-12-17 11:13:00" +local s2 = "2022-12-17 11:13:05" +sCheck = fox:movesSec(s1, 5) +assert(s2 == sCheck) +s2 = "2022-12-17 11:14:06" +sCheck = fox:movesSec(s1, 66) +assert(s2 == sCheck) +s2 = "2022-12-17 11:12:55" +sCheck = fox:movesSec(s1, -5) +assert(s2 == sCheck) + +--local s1 = "2022-12-17 11:13:00" +s2 = "2022-12-17 11:12:55" +sCheck = fox:movesTime(s1, {sec=-5}) +assert(s2 == sCheck) +s2 = "2022-12-07 11:12:55" +sCheck = fox:movesTime(s1, {sec=-5, day=-10}) +assert(s2 == sCheck) +s2 = "2022-12-17 11:13:05" +sCheck = fox:movesTime(s1, {sec=5}) +assert(s2 == sCheck) +s2 = "2022-12-17 11:15:05" +sCheck = fox:movesTime(s1, {sec=5, min=2}) +assert(s2 == sCheck) +s2 = "2022-12-17 15:15:05" +sCheck = fox:movesTime(s1, {sec=5, min=2, hour=4}) +assert(s2 == sCheck) +s2 = "2022-12-20 15:15:05" +sCheck = fox:movesTime(s1, {sec=5, min=2, hour=4, day=3}) +assert(s2 == sCheck) + + +print("fox time ok.") + diff --git a/source/tools/monitor/unity/test/tsdbWrite.lua b/source/tools/monitor/unity/test/tsdbWrite.lua new file mode 100644 index 0000000000000000000000000000000000000000..6928c9fe185a5441655be5814f2876e86692217b --- /dev/null +++ b/source/tools/monitor/unity/test/tsdbWrite.lua @@ -0,0 +1,51 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/17 1:07 PM +--- + +package.path = package.path .. ";../common/?.lua;" +package.path = package.path .. ";../tsdb/?.lua;" +package.path = package.path .. ";../tsdb/native/?.lua;" + +local system = require("system") + +local CfoxTSDB = require("foxTSDB") + +local fox = CfoxTSDB.new() +local ret = fox:setupWrite() +assert(ret == 0) + +local line = { + lines = { + { + line = "metric1", + ls = { + { name = "title", index = "hello" } + }, + vs = { + { name = "value", value = 3.3 }, + { name = "cut", value = 3.4 } + } + }, + { + line = "metric2", + vs = { + { name = "value", value = 3.3 }, + { name = "cut", value = 3.4 } + }, + log = { + { name = "hello", log = "world." }, + } + }, + } +} + +while true do + system:sleep(1) + line.lines[1].vs[1].value = line.lines[1].vs[1].value + 1 + line.lines[2].vs[2].value = line.lines[2].vs[2].value + 3 + local res = fox:packLine(line) + assert(string.len(res) > 0) + fox:write(res) +end diff --git a/source/tools/monitor/unity/test/tsdbWrite.sh b/source/tools/monitor/unity/test/tsdbWrite.sh new file mode 100755 index 0000000000000000000000000000000000000000..becaef6c08afa4106495c7369b22dbf5f2cc15b5 --- /dev/null +++ b/source/tools/monitor/unity/test/tsdbWrite.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../tsdb/native/ + +bash nativeFoxFFI.sh +if [ $? -ne 0 ];then + echo " native api-- Failed : "$? + exit 0 +fi + +luajit tsdbWrite.lua diff --git a/source/tools/monitor/unity/test/yaml/descr.yaml b/source/tools/monitor/unity/test/yaml/descr.yaml new file mode 100644 index 0000000000000000000000000000000000000000..ec4e3ec502bc2e81961cf1827256a08da35e55e0 --- /dev/null +++ b/source/tools/monitor/unity/test/yaml/descr.yaml @@ -0,0 +1,14 @@ +metrics: + - + title: proc_cpu_total + from: cpu_total + index: [] + field: [user, nice, sys, idle, iowait, hardirq, softirq, steal, guest, guestnice] + help: "cpu usage info for total." + type: "gauge" + - title: proc_cpus + from: cpus + index: [] + field: [user, nice, sys, idle, iowait, hardirq, softirq, steal, guest, guestnice] + help: "cpu usage info for per-cpu." + type: "gauge" \ No newline at end of file diff --git a/source/tools/monitor/unity/test/yaml/me.lua b/source/tools/monitor/unity/test/yaml/me.lua new file mode 100644 index 0000000000000000000000000000000000000000..d7e979e2dcaacaccaa0995b85f828129101f7f32 --- /dev/null +++ b/source/tools/monitor/unity/test/yaml/me.lua @@ -0,0 +1,11 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/24 11:55 PM +--- + +local lyaml = require "lyaml" + +for k, v in pairs(lyaml) do + print(k, v) +end diff --git a/source/tools/monitor/unity/test/yaml/tyaml.lua b/source/tools/monitor/unity/test/yaml/tyaml.lua new file mode 100644 index 0000000000000000000000000000000000000000..e31e02dc52b3ff9388f362bc729f9320ff306129 --- /dev/null +++ b/source/tools/monitor/unity/test/yaml/tyaml.lua @@ -0,0 +1,17 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/25 9:03 AM +--- + +-- refer to https://www.runoob.com/w3cnote/yaml-intro.html + +local lyaml = require "lyaml" +local serpent = require("serpent") + +local f = io.open("descr.yaml","r") +local s = f:read("*all") +f:close() + +local tDescr = lyaml.load(s) +print(serpent.block(tDescr)) diff --git a/source/tools/monitor/unity/third/luarocks-3.9.1.tar.gz b/source/tools/monitor/unity/third/luarocks-3.9.1.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..73a791594828f521de923230900dee155b331791 Binary files /dev/null and b/source/tools/monitor/unity/third/luarocks-3.9.1.tar.gz differ diff --git a/source/tools/monitor/unity/third/v2.0.5.zip b/source/tools/monitor/unity/third/v2.0.5.zip new file mode 100644 index 0000000000000000000000000000000000000000..b37a21ff26d41c922e2576f8caeaad3b243a005c Binary files /dev/null and b/source/tools/monitor/unity/third/v2.0.5.zip differ diff --git a/source/tools/monitor/unity/third/yaml-0.2.5.tar.gz b/source/tools/monitor/unity/third/yaml-0.2.5.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..a78e0d998508e242fc7743d06f803cc0e45b2cf3 Binary files /dev/null and b/source/tools/monitor/unity/third/yaml-0.2.5.tar.gz differ diff --git a/source/tools/monitor/unity/tsdb/foxTSDB.lua b/source/tools/monitor/unity/tsdb/foxTSDB.lua new file mode 100644 index 0000000000000000000000000000000000000000..341ca67e3b6da07606f9a24860c043c3b3b8137c --- /dev/null +++ b/source/tools/monitor/unity/tsdb/foxTSDB.lua @@ -0,0 +1,271 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/17 11:04 AM +--- + +require("class") +local system = require("system") +local snappy = require("snappy") +local pystring = require("pystring") +local CprotoData = require("protoData") +local foxFFI = require("foxffi") + +local CfoxTSDB = class("CfoxTSDB") + +function CfoxTSDB:_init_() + self.ffi = foxFFI.ffi + self.cffi = foxFFI.cffi + self._proto = CprotoData.new(nil) +end + +function CfoxTSDB:_del_() + if self._man then + self.cffi.fox_del_man(self._man) + end + self._man = nil +end + +function CfoxTSDB:get_us() + return self.cffi.get_us() +end + +function CfoxTSDB:getDateFrom_us(us) + local foxTime = self.ffi.new("struct foxDate") + + assert(self.cffi.get_date_from_us(us, foxTime) == 0) + + return foxTime +end + +function CfoxTSDB:getDate() + local foxTime = self.ffi.new("struct foxDate") + + assert(self.cffi.get_date(foxTime) == 0) + + return foxTime +end + +function CfoxTSDB:makeStamp(foxTime) + return self.cffi.make_stamp(foxTime) +end + +function CfoxTSDB:date2str(date) + local d = string.format("%04d-%02d-%02d", date.year + 1900, date.mon + 1, date.mday) + local t = string.format("%02d:%02d:%02d", date.hour, date.min, date.sec) + return d .. " " .. t +end + +local function transDate(ds) + local year, mon, mday = unpack(ds) + return tonumber(year) - 1900, tonumber(mon) - 1, tonumber(mday) +end + +local function transTime(ts) + local hour, min, sec = unpack(ts) + return tonumber(hour), tonumber(min), tonumber(sec) +end + +function CfoxTSDB:str2date(s) + local dt = pystring:split(s, " ", 1) + local d, t = dt[1], dt[2] + + local ds = pystring:split(d, "-", 2) + local ts = pystring:split(t, ":", 2) + + local foxTime = self.ffi.new("struct foxDate") + foxTime.year, foxTime.mon, foxTime.mday = transDate(ds) + foxTime.hour, foxTime.min, foxTime.sec = transTime(ts) + + return foxTime +end + +function CfoxTSDB:deltaSec(date) + local delta = 0 + + if date.sec then + delta = delta + date.sec + end + if date.min then + delta = delta + date.min * 60 + end + if date.hour then + delta = delta + date.hour * 60 * 60 + end + if date.day then + delta = delta + date.day * 24 * 60 * 60 + end + return delta +end + +function CfoxTSDB:moveSec(foxTime, off_sec) + local us = self:makeStamp(foxTime) + off_sec * 1e6 + return self:getDateFrom_us(us) +end + +function CfoxTSDB:movesSec(s, off_sec) + local foxTime = self:str2date(s) + return self:date2str(self:moveSec(foxTime, off_sec)) +end + +function CfoxTSDB:moveTime(foxTime, tTable) + local sec = self:deltaSec(tTable) + return self:moveSec(foxTime, sec) +end + +function CfoxTSDB:movesTime(s, tTable) + local foxTime = self:str2date(s) + return self:date2str(self:moveTime(foxTime, tTable)) +end + +function CfoxTSDB:packLine(lines) + return self._proto:encode(lines) +end + +function CfoxTSDB:setupWrite() + assert(self._man == nil, "one fox object should have only one manager.") + self._man = self.ffi.new("struct fox_manager") + local date = self:getDate() + local us = self:get_us() + local ret = self.cffi.fox_setup_write(self._man, date, us) + assert(ret == 0) + return ret +end + +function CfoxTSDB:write(buff) + assert(self._man ~= nil, "this fox object show setup for read or write, you should call setupWrite after new") + local now = self:get_us() + local date = self:getDateFrom_us(now) + local stream = snappy.compress(buff) + print("write for time: ", now) + assert(self.cffi.fox_write(self._man, date, now, self.ffi.string(stream, #stream), #stream) == 0) + --assert(self.cffi.fox_write(self._man, date, now, self.ffi.string(buff), #buff) == 0) +end + +function CfoxTSDB:_setupRead(us) + assert(self._man == nil, "one fox object should have only one manager.") + self._man = self.ffi.new("struct fox_manager") + us = us or (self:get_us() - 15e6) + local date = self:getDateFrom_us(us) + local res = self.cffi.fox_setup_read(self._man, date, us) + assert(res >= 0, string.format("setup read return %d.", res)) + if res > 0 then + self.cffi.fox_del_man(self._man) + self._man = nil + end + return res +end + +function CfoxTSDB:curMove(us) + assert(self._man) + local ret = self.cffi.fox_cur_move(self._man, us) + assert(ret >= 0, string.format("cur move bad ret: %d", ret)) + return self._man.pos +end + +function CfoxTSDB:resize() + assert(self._man) + local ret = self.cffi.fox_read_resize(self._man) + assert(ret >= 0, string.format("resize bad ret: %d", ret)) +end + +function CfoxTSDB:loadData(stop_us) + local stop = false + + local function fLoad() + if stop then + return nil + end + + local data = self.ffi.new("char* [1]") + local us = self.ffi.new("fox_time_t [1]") + local ret = self.cffi.fox_read(self._man, stop_us, data, us) + assert(ret >= 0) + if ret > 0 then + local stream = self.ffi.string(data[0], ret) + local ustr = snappy.decompress(stream) + local line = self._proto:decode(ustr) + self.cffi.fox_free_buffer(data) + + if self._man.fsize == self._man.pos then -- this means cursor is at the end of file. + stop = true + end + line['time'] = tonumber(us[0]) + return line + end + return nil + end + return fLoad +end + +function CfoxTSDB:query(start, stop, ms) -- start stop should at the same mday + assert(stop > start) + local dStart = self:getDateFrom_us(start) + local dStop = self:getDateFrom_us(stop) + + assert(self.cffi.check_foxdate(dStart, dStop) == 1) -- check date + assert(self._man) + + self:curMove(start) -- moveto position + + for line in self:loadData(stop) do + local time = line.time + for _, v in ipairs(line.lines) do + local tCell = {time = time, title = v.line} + + local labels = {} + if v.ls then + for _, vlabel in ipairs(v.ls) do + labels[vlabel.name] = vlabel.index + end + end + tCell.labels = labels + + local values = {} + if v.vs then + for _, vvalue in ipairs(v.vs) do + values[vvalue.name] = vvalue.value + end + end + tCell.values = values + + local logs = {} + if v.vlog then + for _, vlog in ipairs(v.log) do + logs[vlog.name] = vlog.log + end + end + tCell.logs = logs + + table.insert(ms, tCell) + end + end + return ms +end + +function CfoxTSDB:qlast(last, ms) + local now = self:get_us() + local date = self:getDateFrom_us(now) + local beg = now - last * 1e6; + + if self._man then -- has setup + if self.cffi.check_pman_date(self._man, date) == 1 then -- at the same day + return self:query(beg, now, ms) + else + self:_del_() -- destroy old manager + if self:_setupRead(now) ~= 0 then -- try to create new + return ms + else + return self:query(beg, now, ms) + end + end + else + if self:_setupRead(now) ~= 0 then -- try to create new + return ms + else + return self:query(beg, now, ms) + end + end +end + +return CfoxTSDB diff --git a/source/tools/monitor/unity/tsdb/native/Makefile b/source/tools/monitor/unity/tsdb/native/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..85686fcc12bfa151fa2cdc8fd52392e5099d8db7 --- /dev/null +++ b/source/tools/monitor/unity/tsdb/native/Makefile @@ -0,0 +1,16 @@ +CC := gcc +CFLAG := -g -fpic +LDFLAG := -g -fpic -shared +OBJS := foxTSDB.o +SO := libfoxTSDB.so + +all: $(SO) + +foxTSDB.o: foxTSDB.c + $(CC) -c $< -o $@ $(CFLAG) + +$(SO): $(OBJS) + $(CC) -o $@ $(OBJS) $(LDFLAG) + +clean: + rm -f $(SO) $(OBJS) \ No newline at end of file diff --git a/source/tools/monitor/unity/tsdb/native/foxTSDB.c b/source/tools/monitor/unity/tsdb/native/foxTSDB.c new file mode 100644 index 0000000000000000000000000000000000000000..c1c75ac95553ee1b8c8792daf296d14ee039c391 --- /dev/null +++ b/source/tools/monitor/unity/tsdb/native/foxTSDB.c @@ -0,0 +1,717 @@ +// +// Created by 廖肇燕 on 2022/12/13. +// + +#include "foxTSDB.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FNAME_SIZE 16 +#define FOX_MAGIC 0xf030 +#define MICRO_UNIT (1000 * 1000UL) + +#define FOX_VALUE_FLAG (1 << 0ULL) +#define FOX_LOG_FLAG (1 << 1ULL) + +struct fox_head{ + unsigned int prev; + unsigned int next; + fox_time_t t_us; + unsigned short magic; + unsigned short flag; +}; + +fox_time_t get_us(void) { + fox_time_t res = 0; + struct timeval tv; + + if (gettimeofday(&tv, NULL) == 0) { + res = tv.tv_sec * MICRO_UNIT + tv.tv_usec; + } + return res; +} + +static void tm2date(struct tm * ptm, struct foxDate * p) { + p->year = ptm->tm_year; + p->mon = ptm->tm_mon; + p->mday = ptm->tm_mday; + p->hour = ptm->tm_hour; + p->min = ptm->tm_min; + p->sec = ptm->tm_sec; +} + +static void date2tm(struct foxDate * p, struct tm * ptm) { + ptm->tm_year = p->year; + ptm->tm_mon = p->mon; + ptm->tm_mday = p->mday; + ptm->tm_hour = p->hour; + ptm->tm_min = p->min; + ptm->tm_sec = p->sec; + ptm->tm_isdst = -1; +} + +int get_date_from_us(fox_time_t us, struct foxDate * p) { + struct tm * ptm; + + time_t t = us / MICRO_UNIT; + ptm = localtime(&t); + tm2date(ptm, p); + return 0; +} + +int get_date(struct foxDate * p) { + struct timeval tv; + if (gettimeofday(&tv, NULL) == 0) { + struct tm * ptm = localtime(&tv.tv_sec); + tm2date(ptm, p); + return 0; + } + return 1; +} + +fox_time_t make_stamp(struct foxDate * p) { + struct tm tmt; + + date2tm(p, &tmt); + time_t t = mktime(&tmt); + return t * MICRO_UNIT; +} + +static fox_time_t fox_read_init_now(struct fox_manager* pman) { + struct foxDate date; + + date.year = pman->year; + date.mon = pman->mon; + date.mday = pman->mday; + date.hour = date.min = date.sec = 0; + + return make_stamp(&date); +} + +static fox_time_t fox_read_day_max(struct fox_manager* pman) { + struct foxDate date; + + date.year = pman->year; + date.mon = pman->mon; + date.mday = pman->mday; + date.hour = date.min = date.sec = 0; + + return make_stamp(&date) + 24 * 60 * 60 * MICRO_UNIT; +} + +static size_t fd_size(int fd) { + int ret; + struct stat file_info; + + ret = fstat(fd, &file_info); + if (ret < 0) { + fprintf(stderr, "stat file failed. %d, %s\n", errno, strerror(errno)); + } + return (!ret) ? file_info.st_size : -EACCES; +} + +static void pack_fname(char* pname, struct foxDate * p) { + snprintf(pname, FNAME_SIZE, "%04d%02d%02d.fox", p->year, p->mon, p->mday); +} + +static int fox_read_head(int fd, struct fox_head* phead) { + size_t size; + + size = read(fd, phead, sizeof (struct fox_head)); + + if (size == sizeof (struct fox_head)) { + if (phead->magic == FOX_MAGIC) { + return size; + } else { + fprintf(stderr, "bad magic: 0x%x, hope: 0x%x\n", phead->magic, FOX_MAGIC); + return -EINVAL; + } + } else if (size == 0) { + return 0; + } else { + fprintf(stderr, "read file failed. %d, %s\n", errno, strerror(errno)); + return -EACCES; + } +} + +static int fox_check_head(int fd, struct fox_manager* pman) { + int ret; + struct fox_head head; + off_t off = 0; + + head.prev = 0; + while (1) { + off = lseek(fd, off, SEEK_SET); + if (off < 0) { + fprintf(stderr, "seek file failed. %d, %s\n", errno, strerror(errno)); + ret = -EACCES; + goto endSeek; + } + + ret = fox_read_head(fd, &head); + if (ret > 0) { + off = head.next; + } else if (ret == 0) { + pman->last_pos = head.prev; + pman->pos = off; + break; + } else { + fprintf(stderr, "write file failed. pos: 0x%llx\n", off); + goto endHead; + } + } + + return ret; + endHead: + endSeek: + return ret; +} + +static int fox_check(int fd, struct fox_manager* pman) { + int ret = 0; + int retLock = 0; + + ret = lockf(fd, F_LOCK, 0); + if (ret < 0) { + fprintf(stderr, "lock file failed. %d, %s\n", errno, strerror(errno)); + goto endLock; + } + + ret = fox_check_head(fd, pman); + if (ret < 0) { + goto endCheck; + } + + ret = lockf(fd, F_ULOCK, 0); + if (ret < 0) { + fprintf(stderr, "lock file failed. %d, %s\n", errno, strerror(errno)); + goto endUnLock; + } + + return ret; + + endCheck: + retLock = lockf(fd, F_ULOCK, 0); + if (retLock < 0) { + fprintf(stderr, "lock file failed. %d, %s\n", errno, strerror(errno)); + ret = retLock; + goto endUnLock; + } + return ret; + endUnLock: + endLock: + return ret; +} + +int fox_setup_write(struct fox_manager* pman, struct foxDate * p, fox_time_t now) { + char fname[FNAME_SIZE]; + int ret = 0; + + pack_fname(fname, p); + + pman->fd = open(fname, O_RDWR|O_APPEND|O_CREAT); + if (pman->fd < 0) { + fprintf(stderr, "open %s error, return %d, %s", fname, errno, strerror(errno)); + ret = -ENOENT; + goto endOpen; + } + + ret = fox_check(pman->fd, pman); + if (ret < 0) { + goto endCheck; + } + + pman->year = p->year; + pman->mon = p->mon; + pman->mday = p->mday; + pman->now = now; + + return ret; + endCheck: + close(pman->fd); + pman->fd = 0; + endOpen: + return ret; +} + +int check_foxdate(struct foxDate* d1, struct foxDate* d2) { + return (d1->year == d2->year) && \ + (d1->mon == d2->mon) && \ + (d1->mday == d2->mday); +} + +int check_pman_date(struct fox_manager* pman, struct foxDate* pdate) { + return (pman->year == pdate->year) && \ + (pman->mon == pdate->mon) && \ + (pman->mday == pdate->mday); +} + +static int fox_write_data(struct fox_manager* pman, fox_time_t us, const char* data, int len) { + int ret = 0; + int fd = pman->fd; + struct fox_head head; + + head.prev = pman->last_pos; + head.next = pman->pos + sizeof (struct fox_head) + len; + head.t_us = us; + head.magic = FOX_MAGIC; + head.flag = 0; + + ret = lockf(fd, F_LOCK, 0); + if (ret < 0) { + fprintf(stderr, "lock file failed. %d, %s\n", errno, strerror(errno)); + ret = -EACCES; + goto endLock; + } + + ret = write(fd, &head, sizeof (struct fox_head)); + if (ret < 0) { + fprintf(stderr, "write file failed. %d, %s\n", errno, strerror(errno)); + goto endWrite; + } + ret = write(fd, data, len ); + if (ret < 0) { + fprintf(stderr, "write file failed. %d, %s\n", errno, strerror(errno)); + goto endWrite; + } + + ret = lockf(fd, F_ULOCK, 0); + if (ret < 0) { + fprintf(stderr, "lock file failed. %d, %s\n", errno, strerror(errno)); + ret = -EACCES; + goto endUnLock; + } + + pman->now = us; + pman->last_pos = pman->pos; // record last position + pman->pos = head.next; + return ret; + + endWrite: + ret = lockf(fd, F_ULOCK, 0); + if (ret < 0) { + fprintf(stderr, "lock file failed. %d, %s\n", errno, strerror(errno)); + ret = -EACCES; + goto endUnLock; + } + return ret; + endUnLock: + endLock: + return ret; +} + +int fox_write(struct fox_manager* pman, struct foxDate* pdate, fox_time_t us, + const char* data, int len) { + int res = 0; + + if (!check_pman_date(pman, pdate)) { // new day? + close(pman->fd); // close this file at first. + res = fox_setup_write(pman, pdate, us); + if (res < 0) { + fprintf(stderr, "create new file failed.\n"); + goto endCreateFile; + } + } + + if (pman->now <= us) { // time should monotonically increasing + res = fox_write_data(pman, us, data, len); + } + return res; + + endCreateFile: + return res; +} + +static int fox_cursor_left(int fd, struct fox_manager* pman, fox_time_t now) { + int ret; + off_t pos; + struct fox_head head; + fox_time_t last_t_us = pman->now; + + if (pman->pos == pman->fsize) { + pos = pman->last_pos; + } else { + pos = pman->pos; + } + + while (1) { + ret = lseek(fd, pos, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "seek file failed. %d, %s\n", errno, strerror(errno)); + ret = -EACCES; + goto endSeek; + } + + ret = fox_read_head(fd, &head);; + if (ret < 0) { + goto endRead; + } + + if (head.t_us < now) { + pman->pos = head.next; + pman->now = last_t_us; + pman->last_pos = pos; + break; + } + + last_t_us = head.t_us; + pos = head.prev; + if (pos == 0) { //begin of file + pman->pos = pos; + pman->now = last_t_us; + pman->last_pos = pos; + break; + } + } + ret = 0; + return ret; + endSeek: + endRead: + return ret; +} + +static int fox_cursor_right(int fd, struct fox_manager* pman, fox_time_t now) { + int ret; + off_t last_pos = pman->last_pos; + off_t pos = pman->pos; + struct fox_head head; + + while (1) { + if (pos == pman->fsize) { + pman->last_pos = last_pos; + pman->pos = pos; + pman->now = fox_read_day_max(pman); + ret = 0; + goto endEndoffile; + } else if (pos > pman->fsize) { + ret = -ERANGE; + goto endRange; + } + + ret = lseek(fd, pos, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "seek file failed. %d, %s\n", errno, strerror(errno)); + ret = -EACCES; + goto endSeek; + } + + ret = fox_read_head(fd, &head);; + if (ret < 0) { + goto endRead; + } + + if (head.t_us >= now) { // just > + pman->pos = pos; + pman->now = head.t_us; + pman->last_pos = last_pos; + break; + } + last_pos = pos; + pos = head.next; + } + ret = 0; + return ret; + endEndoffile: + return ret; + endRange: //out of file range. + return ret; + endSeek: + endRead: + endSize: + return ret; +} + +static int fox_cursor_work(int fd, struct fox_manager* pman, fox_time_t now) { + int ret = 0; + + if (pman->now > now) { + ret = fox_cursor_left(fd, pman, now); + if (ret < 0) { + goto endCursor; + } + } else if (pman->now < now) { + ret = fox_cursor_right(fd, pman, now); + if (ret < 0) { + goto endCursor; + } + } + + return ret; + endCursor: + return ret; +} + +static int fox_cursor(int fd, struct fox_manager* pman, fox_time_t now) { + int ret; + + ret = fox_cursor_work(fd, pman, now); + if (ret < 0) { + goto endLock; + } + + return ret; + endLock: + return ret; +} + +int fox_cur_move(struct fox_manager* pman, fox_time_t now) { + int fd; + + fd = pman->fd; + + return fox_cursor(fd, pman, now); +} + +static int fox_cur_next(struct fox_manager* pman, struct fox_head* phead) { + int ret = 0; + off_t pos = phead->next; + struct fox_head head; + int fd = pman->fd; + + pman->pos = pos; + if (pos < pman->fsize) { + ret = lseek(fd, pos, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "seek file failed. %d, %s\n", errno, strerror(errno)); + goto endSeek; + } + + ret = fox_read_head(fd, &head);; + if (ret < 0) { + goto endRead; + } + pman->now = head.t_us; + } else { + pman->now = fox_read_day_max(pman); + } + + return ret; + endSeek: + endRead: + return ret; +} + +static int fox_cur_back(struct fox_manager* pman) { + int ret = 0; + off_t pos = pman->last_pos; + struct fox_head head; + int fd = pman->fd; + + pman->pos = pos; + if (pos > 0) { + ret = lseek(fd, pos, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "seek file failed. %d, %s\n", errno, strerror(errno)); + goto endSeek; + } + + ret = fox_read_head(fd, &head);; + if (ret < 0) { + goto endRead; + } + pman->now = head.t_us; + } else { + pman->now = fox_read_init_now(pman); + } + + return ret; + endSeek: + endRead: + return ret; +} + +int fox_read_resize(struct fox_manager* pman) { + int ret = 0; + + size_t fsize = fd_size(pman->fd); + if (fsize < 0) { + ret = fsize; + goto endSize; + } + + if (fsize > pman->fsize) { + if (pman->pos == pman->fsize) { // at the end of file. + ret = fox_cur_back(pman); + if (ret < 0) { + goto endCur; + } + } + pman->fsize = fsize; + } else { + struct foxDate d; + d.year = pman->year; + d.mon = pman->mon; + d.mday = pman->mday; + d.hour = 0; + d.min = 0; + d.sec = 0; + + fox_time_t now = make_stamp(&d); + + ret = fox_setup_read(pman, &d, now); + if (ret !=0 ) { + ret = -EACCES; + goto endSetup; + } + } + return ret; + endSetup: + endSize: + endCur: + return ret; +} + +int fox_setup_read(struct fox_manager* pman, struct foxDate * p, fox_time_t now) { + char fname[FNAME_SIZE]; + int ret = 0; + + pack_fname(fname, p); + pman->fd = open(fname, O_RDONLY); + if (pman->fd < 0) { + fprintf(stderr, "open %s failed, return %d, %s", fname, errno, strerror(errno)); + ret = 1; + goto endOpen; + } + + pman->year = p->year; + pman->mon = p->mon; + pman->mday = p->mday; + pman->now = fox_read_init_now(pman); + pman->pos = 0; + pman->last_pos = 0; + pman->fsize = fd_size(pman->fd); + if (pman->fsize < 0) { + ret = -EACCES; + goto endSize; + } + + ret = fox_cursor(pman->fd, pman, now); + if (ret < 0) { + goto endCursor; + } + +// printf("setup %s, fd: %d, size: %ld, pos: %lld, pnow: %ld, now:%ld\n", +// fname, pman->fd, pman->fsize, pman->pos, pman->now, now); + return ret; + endSize: + endCursor: + close(pman->fd); + endOpen: + pman->fd = -1; + return ret; +} + +static int fox_read_stream(int fd, char* stream, int size) { + int ret; + + ret = read(fd, stream, size); + if (ret < 0) { + fprintf(stderr, "read file failed. %d, %s\n", errno, strerror(errno)); + goto endRead; + } + return ret; + + endRead: + return ret; +} + +static int fox_read_work(int fd, struct fox_manager* pman, fox_time_t stop, + char **pp, int *len, fox_time_t *us) { + int ret = 0; + off_t pos = pman->pos; + int size; + + if (pman->now <= stop) { + struct fox_head head; + char *p; + + ret = lseek(fd, pos, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "seek file failed. %d, %s\n", errno, strerror(errno)); + ret = -EACCES; + goto endSeek; + } + + ret = fox_read_head(fd, &head); + if (ret < 0) { + goto endRead; + } + + size = head.next - pos - sizeof (struct fox_head); + if (size < 0) { + goto endSize; + } + p = malloc(size); + if (p == NULL) { + fprintf(stderr, "malloc %d failed. %d, %s\n", size, errno, strerror(errno)); + ret = -ENOMEM; + goto endMalloc; + } + + ret = fox_read_stream(fd, p, size); + if (ret < 0) { + free(p); + goto endRead2; + } + + ret = fox_cur_next(pman, &head); // the cursor will to next position. + if (ret < 0) { + free(p); + goto endNext; + } + + *us = head.t_us; + *pp = p; + *len = size; + } else { + *pp = NULL; + *len = 0; + } + return ret; + + endNext: + endRead2: + endSize: + endMalloc: + endRead: + endSeek: + *pp = NULL; + *len = 0; + return ret; +} + +int fox_read(struct fox_manager* pman, fox_time_t stop, char **pp, fox_time_t *us) { + int ret; + int len; + int fd = pman->fd; + + ret = fox_read_work(fd, pman, stop, pp, &len, us); + if (ret < 0) { + goto endWork; + } + return len; + + endWork: + return ret; +} + +void fox_free_buffer(char **pp) { + char *p = *pp; + free((void *)p); +} + +void fox_del_man(struct fox_manager* pman) { + if (pman->fd > 0) { + close(pman->fd); + pman->fd = -1; + } +} diff --git a/source/tools/monitor/unity/tsdb/native/foxTSDB.h b/source/tools/monitor/unity/tsdb/native/foxTSDB.h new file mode 100644 index 0000000000000000000000000000000000000000..8d8de51ade4dc07e3d31affe90156cc12500b83c --- /dev/null +++ b/source/tools/monitor/unity/tsdb/native/foxTSDB.h @@ -0,0 +1,50 @@ +// +// Created by 廖肇燕 on 2022/12/13. +// + +#ifndef TINYINFO_FOXTSDB_H +#define TINYINFO_FOXTSDB_H + +#include + +typedef unsigned long fox_time_t; + +struct foxDate { + short year; + char mon; + char mday; + char hour; + char min; + char sec; +}; + +struct fox_manager { + fox_time_t now; + off_t pos; //now offset; + off_t last_pos; // last pos + size_t fsize; // file size. + int fd; + + short year; + char mon; + char mday; +}; + +fox_time_t get_us(void); +int get_date_from_us(fox_time_t us, struct foxDate * p); +int get_date(struct foxDate * p); +fox_time_t make_stamp(struct foxDate * p); +int check_foxdate(struct foxDate* d1, struct foxDate* d2); +int check_pman_date(struct fox_manager* pman, struct foxDate* pdate); + +int fox_setup_write(struct fox_manager* pman, struct foxDate * p, fox_time_t now); +int fox_write(struct fox_manager* pman, struct foxDate* pdate, fox_time_t us, + const char* data, int len); +int fox_setup_read(struct fox_manager* pman, struct foxDate * p, fox_time_t now); +int fox_cur_move(struct fox_manager* pman, fox_time_t now); +int fox_read_resize(struct fox_manager* pman); +int fox_read(struct fox_manager* pman, fox_time_t stop, char **pp, fox_time_t *us); +void fox_free_buffer(char **pp); +void fox_del_man(struct fox_manager* pman); + +#endif //TINYINFO_FOXTSDB_H diff --git a/source/tools/monitor/unity/tsdb/native/foxffi.lua b/source/tools/monitor/unity/tsdb/native/foxffi.lua new file mode 100644 index 0000000000000000000000000000000000000000..8571399fecee56c53e32e11d1bea8f213442c2ac --- /dev/null +++ b/source/tools/monitor/unity/tsdb/native/foxffi.lua @@ -0,0 +1,53 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by liaozhaoyan. +--- DateTime: 2022/12/17 9:27 AM +--- + +local ffi = require("ffi") +local cffi = ffi.load('foxTSDB') + +ffi.cdef [[ +typedef unsigned long off_t; +typedef unsigned long fox_time_t; + +struct foxDate { + short year; + char mon; + char mday; + char hour; + char min; + char sec; +}; + +struct fox_manager { + fox_time_t now; + off_t pos; //now offset; + off_t last_pos; // last pos + size_t fsize; // file size. + int fd; + + short year; + char mon; + char mday; +}; + +fox_time_t get_us(void); +int get_date_from_us(fox_time_t us, struct foxDate * p); +int get_date(struct foxDate * p); +fox_time_t make_stamp(struct foxDate * p); +int check_foxdate(struct foxDate* d1, struct foxDate* d2); +int check_pman_date(struct fox_manager* pman, struct foxDate* pdate); + +int fox_setup_write(struct fox_manager* pman, struct foxDate * p, fox_time_t now); +int fox_write(struct fox_manager* pman, struct foxDate* pdate, fox_time_t us, + const char* data, int len); +int fox_setup_read(struct fox_manager* pman, struct foxDate * p, fox_time_t now); +int fox_cur_move(struct fox_manager* pman, fox_time_t now); +int fox_read_resize(struct fox_manager* pman); +int fox_read(struct fox_manager* pman, fox_time_t stop, char **pp, fox_time_t *us); +void fox_free_buffer(char **pp); +void fox_del_man(struct fox_manager* pman); +]] + +return {ffi = ffi, cffi = cffi}