#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cJSON.h" #include "../../../opt/MESA/include/MESA/MESA_prof_load.h" #include "../../../opt/MESA/include/MESA/stream.h" #include "../../../opt/MESA/include/MESA/MESA_prof_load.h" #include "../../../opt/MESA/include/MESA/MESA_handle_logger.h" #include "../../../opt/MESA/include/MESA/MESA_htable.h" #include "../../../opt/MESA/include/MESA/MESA_list.h" #define BUFSIZE 8192 #define MAX_STR_LEN 256 #define MAX_BUF_LEN 1024 #define MAX_NAME_LEN 32 #define CPU_START_POS 14//stat文件的有效起始行数 #define HTTP_TIMEOUT 100 #define RET_OK 0 #define RET_ERROR -1 uint16_t g_http_port; const char *http_check_conf_file = "./plug/business/http_check/http_check.conf"; char g_http_address[MAX_STR_LEN]=""; char http_check_log_path[MAX_STR_LEN] = ""; char http_check_error_log_path[MAX_STR_LEN] = ""; char module_name[MAX_STR_LEN] = ""; void *http_check_log_handler = NULL; void *error_log_handler = NULL; struct route_info { uint32_t dstAddr; uint32_t srcAddr; uint32_t gateWay; char ifName[IF_NAMESIZE]; }; //************************************cpu占用******************** // CPU占用率计算: // 1、读取/proc/pid/stat文件,其中记录了从开机到现在,本进程所占用的CPU时间(单位jiffies) // 2、然后再读取/proc/stat文件,其中记录了从开机到现在,系统所占用的CPU时间(单位jiffies) // 3、取两个时间点,这两个时间点的进程耗时差,除以系统耗时差,得到的就是该进程的CPU占用率 //在字符串中寻找第N次空格出现的地方 char *get_items_by_pos(char *buff, unsigned int numb) { char *crpos = NULL; int i, ttlen, count; crpos = buff; ttlen = strlen(buff); count = 0; for (i = 0; i < ttlen; i++) { if (' ' == *crpos)//以空格为标记符进行识别 { count++; if (count == (numb - 1))//全部个数都找完了 { crpos++; break; } } crpos++; } return crpos; } //获取当前进程的CPU时间 long get_pro_cpu_time(unsigned int pid) { FILE *fp = NULL; char *vpos = NULL, buff[MAX_BUF_LEN] = ""; long utime, stime, cutime, cstime; sprintf(buff, "/proc/%d/stat", pid); fp = fopen(buff, "r"); if(fp == NULL) { MESA_handle_runtime_log(error_log_handler, RLOG_LV_FATAL, module_name, "open /proc/self/stat failed."); printf("====line:%d,%s\n",__LINE__,"open /proc/self/stat failed."); return -1; } fgets(buff, sizeof(buff), fp); vpos = get_items_by_pos(buff, CPU_START_POS); sscanf(vpos, "%ld %ld %ld %ld", &utime, &stime, &cutime, &cstime); //printf("get_data_process:%ld %ld %ld %ld\n", utime, stime, cutime, cstime); fclose(fp); return (utime + stime + cutime + cstime); } //获取整个系统的CPU时间 long get_sys_cpu_time(void) { FILE *fp; char name[MAX_BUF_LEN] = "", buff[MAX_BUF_LEN] = ""; long user, nice, syst, idle; fp = fopen("/proc/stat", "r"); if(fp == NULL) { MESA_handle_runtime_log(error_log_handler, RLOG_LV_FATAL, module_name, "open /proc/stat failed."); printf("====line:%d,%s\n",__LINE__,"open /proc/stat failed."); return -1; } fgets(buff, sizeof(buff), fp); sscanf(buff, "%s %ld %ld %ld %ld", name, &user, &nice, &syst, &idle); //printf("get_data_system:%s %ld %ld %ld %ld\n", name, user, nice, syst, idle); fclose(fp); return (user + nice + syst + idle); } //获取进程的CPU使用率 float get_cpu_stat(unsigned int pid) { float ratio = 0; long s_cur_pro_cpu, s_pre_pro_cpu;//指定程序的本轮/前轮CPU时间 long s_cur_sys_cpu, s_pre_sys_cpu;//整个系统的本轮/前轮CPU时间 s_pre_pro_cpu = get_pro_cpu_time(pid); s_pre_sys_cpu = get_sys_cpu_time(); if(s_pre_pro_cpu < 0 || s_pre_sys_cpu < 0) return 0; sleep(1); s_cur_pro_cpu = get_pro_cpu_time(pid); s_cur_sys_cpu = get_sys_cpu_time(); if(s_cur_pro_cpu < 0 || s_cur_sys_cpu < 0) return 0; if ((s_cur_pro_cpu == s_pre_pro_cpu) || (s_cur_sys_cpu == s_pre_sys_cpu) || (s_cur_pro_cpu == 0) || (s_cur_sys_cpu == 0)) { ratio = 0; } else { if((s_cur_sys_cpu - s_pre_sys_cpu) != 0) ratio = (100.0 * (s_cur_pro_cpu - s_pre_pro_cpu)) / (s_cur_sys_cpu - s_pre_sys_cpu); } return ratio; } //获取默认网关地址 int readNlSock(int sockFd, char *bufPtr) { struct nlmsghdr *nlHdr = NULL; int readLen = 0, msgLen = 0; while(1){ //收到内核的应答 if((readLen = recv(sockFd, bufPtr, BUFSIZE - msgLen, 0)) < 0) { #if 1 if(errno == EAGAIN) { continue; } #endif //printf("sock recv return for readLen < 0!"); return -1; } nlHdr = (struct nlmsghdr *)bufPtr; //检查header是否有效 if((NLMSG_OK(nlHdr, readLen) == 0) || (nlHdr->nlmsg_type == NLMSG_ERROR)) { //printf("sock recv return for header error!\n"); return -1; } if(nlHdr->nlmsg_type == NLMSG_DONE)//内核返回最后一条消息的类型为NLMSG_DONE { break; } else { bufPtr += readLen; msgLen += readLen; } if((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0) { break; } } return msgLen; } //分析返回的路由信息 int parseRoutes(struct nlmsghdr *nlHdr,char *gateway,unsigned int len) { struct rtmsg *rtMsg = NULL; struct rtattr *rtAttr = NULL; int rtLen; char dst_address[MAX_STR_LEN] = ""; struct route_info rtInfo; int ret = RET_ERROR; memset(&rtInfo, 0, sizeof(struct route_info)); rtMsg = (struct rtmsg *)NLMSG_DATA(nlHdr); // If the route is not for AF_INET or does not belong to main routing table //then return. //RT_TABLE_LOCAL存储目的地址是本机的路由表项,这些目的地址就是为各个网卡配置的IP地址; //RT_TABLE_MAIN存储到其它主机的路由表项; if((rtMsg->rtm_family != AF_INET) || (rtMsg->rtm_table != RT_TABLE_MAIN)) { return ret; } rtAttr = (struct rtattr *)RTM_RTA(rtMsg); //路由信息 rtLen = RTM_PAYLOAD(nlHdr); for(;RTA_OK(rtAttr,rtLen);rtAttr = RTA_NEXT(rtAttr,rtLen)) { switch(rtAttr->rta_type) { case RTA_OIF: if_indextoname(*(int *)RTA_DATA(rtAttr), rtInfo.ifName); break; case RTA_GATEWAY: rtInfo.gateWay = *(uint32_t *)RTA_DATA(rtAttr); break; case RTA_PREFSRC: rtInfo.srcAddr = *(uint32_t *)RTA_DATA(rtAttr); break; case RTA_DST: rtInfo.dstAddr = *(uint32_t *)RTA_DATA(rtAttr); break; } } inet_ntop(AF_INET, &rtInfo.dstAddr, dst_address, MAX_STR_LEN); if (strstr(dst_address, "0.0.0.0")) { if(rtInfo.gateWay) inet_ntop(AF_INET, &rtInfo.gateWay, gateway, len); else if(rtInfo.ifName) strncpy(gateway, rtInfo.ifName, IF_NAMESIZE); ret = RET_OK; } return ret; } int get_gateway(char *gateway, unsigned int length) { struct nlmsghdr *nlMsg = NULL; char msgBuf[BUFSIZE] = ""; int sock, len, msgSeq = 0; if((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) { MESA_handle_runtime_log(error_log_handler, RLOG_LV_FATAL, module_name, "socket create error."); printf("====line:%d,%s\n",__LINE__,"socket create error."); return -1; } //memset(msgBuf, 0, BUFSIZE); nlMsg = (struct nlmsghdr *)msgBuf; nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); // Length of message. nlMsg->nlmsg_type = RTM_GETROUTE; // Get the routes from kernel routing table nlMsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; // The message is a request for dump nlMsg->nlmsg_seq = msgSeq++; // Sequence of the message packet nlMsg->nlmsg_pid = getpid(); // PID of process sending the request if(send(sock, nlMsg, nlMsg->nlmsg_len, 0) < 0) { MESA_handle_runtime_log(error_log_handler, RLOG_LV_FATAL, module_name, "write to socket failed."); printf("====line:%d,%s\n",__LINE__,"write to socket failed."); goto OUT; } if((len = readNlSock(sock, msgBuf)) < 0) { MESA_handle_runtime_log(error_log_handler, RLOG_LV_FATAL, module_name, "read from socket failed."); printf("====line:%d,%s\n",__LINE__,"read from socket failed."); goto OUT; } for(;NLMSG_OK(nlMsg,len);nlMsg = NLMSG_NEXT(nlMsg,len)) { if(!parseRoutes(nlMsg, gateway, length)) break; } OUT: close(sock); return 0; } //status回响应 void http_handler_status_msg(struct evhttp_request *req,void *arg) { struct sysinfo info; time_t cur_time = 0; time_t boot_time = 0; struct tm *ptm = NULL; unsigned int run_days,run_hour,run_minute,run_second; pid_t process_id; memset(&info, 0, sizeof(struct sysinfo)); //启动时间,启动时长 if (sysinfo(&info)) { MESA_handle_runtime_log(error_log_handler, RLOG_LV_FATAL, module_name, "failed to get sysinfo."); printf("====line:%d,%s\n",__LINE__,"failed to get sysinfo!"); return ; } time(&cur_time); boot_time = cur_time - info.uptime; ptm = localtime(&boot_time); /*printf("System boot time:%d-%-d-%d %d:%d:%d\n", ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec);*/ run_days=info.uptime / 86400; run_hour=(info.uptime % 86400)/3600; run_minute=(info.uptime % 3600)/60; run_second=info.uptime % 60; //printf("system running time:%dday %dhour %dminute %dsecond\n",run_days,run_hour,run_minute,run_second); //进程号 process_id = getpid(); //printf("process id:%d\n", process_id); //默认网关地址 char default_gateway_tmp[MAX_STR_LEN]=""; get_gateway(default_gateway_tmp ,MAX_STR_LEN); //printf("gateway:%s\n",buff); //内存(虚存,实存) unsigned int n_rss, n_resident, n_share, n_text, n_lib, n_data, n_dt; char mem_buf_tmp[MAX_STR_LEN] = ""; char boot_time_tmp[MAX_STR_LEN] = ""; char running_time_tmp[MAX_STR_LEN] = ""; char cpu_usage_tmp[MAX_STR_LEN] = ""; FILE *fp = fopen("/proc/self/statm","r"); if(fp) { fscanf(fp,"%u%u%u%u%u%u%u",&n_rss,&n_resident,&n_share,&n_text,&n_lib,&n_data,&n_dt); fclose(fp); } else { MESA_handle_runtime_log(error_log_handler, RLOG_LV_FATAL, module_name, "open /proc/self/statm failed."); printf("====line:%d,%s\n",__LINE__,"open /proc/self/statm failed."); return; } n_rss = n_rss * (getpagesize()/1024); n_resident = n_resident * (getpagesize()/1024); sprintf(mem_buf_tmp, "VmSize=%ludkB, VmRss=%lukB\n", n_rss, n_resident); //printf("memory info:%s\n",buf); //当前进程cpu占用 float cpu_rate; unsigned int cpu_num; cpu_rate = get_cpu_stat(process_id); cpu_num = get_nprocs();//获取可用cpu数 //printf("cpu usage = %f\n", cpu_rate*cpu_num); struct evbuffer *retbuff = NULL; retbuff = evbuffer_new(); if(retbuff == NULL) { MESA_handle_runtime_log(error_log_handler, RLOG_LV_FATAL, module_name, "status evbuffer_new failed."); printf("====line:%d,%s\n",__LINE__,"status evbuffer_new failed."); return; } sprintf(boot_time_tmp, "%d-%-d-%d %d:%d:%d", ptm->tm_year + 1900,ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec); sprintf(running_time_tmp, "%ddays %dhours %dminutes %dseconds", run_days,run_hour,run_minute,run_second); sprintf(cpu_usage_tmp, "%f", cpu_rate*cpu_num); cJSON * root = cJSON_CreateObject(); if(!root) { MESA_handle_runtime_log(error_log_handler, RLOG_LV_FATAL, module_name, "status cjson createObject error."); printf("====line:%d,%s\n",__LINE__,"status cjson createObject error."); return; } //根节点下添加 cJSON_AddItemToObject(root, "boot time", cJSON_CreateString(boot_time_tmp)); cJSON_AddItemToObject(root, "running time", cJSON_CreateString(running_time_tmp)); cJSON_AddItemToObject(root, "process id", cJSON_CreateNumber(process_id)); cJSON_AddItemToObject(root, "server ip", cJSON_CreateString(g_http_address)); cJSON_AddItemToObject(root, "default gateway", cJSON_CreateString(default_gateway_tmp)); cJSON_AddItemToObject(root, "memory info", cJSON_CreateString(mem_buf_tmp)); cJSON_AddItemToObject(root, "cpu usage", cJSON_CreateString(cpu_usage_tmp)); //printf("cjson_status_print:%s\n", cJSON_Print(root)); MESA_handle_runtime_log(http_check_log_handler, RLOG_LV_INFO, module_name, cJSON_Print(root)); //evbuffer_add_printf(retbuff,"System boot time: %d-%-d-%d %d:%d:%d\r\nsystem running time:%dday %dhour %dminute %dsecond\r\nprocess id:%d\r\ngateway:%s\r\nmemory info:%s\r\ncpu% = %f\r\n", // ptm->tm_year + 1900,ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, run_days,run_hour,run_minute,run_second,process_id,buff,buf,cpu_rate*cpu_num); evbuffer_add_printf(retbuff,cJSON_Print(root)); evhttp_send_reply(req,HTTP_OK,"OK",retbuff); evbuffer_free(retbuff); if(root) { cJSON_Delete(root); } return; } //keepalive回响应 void http_handler_keepalive_msg(struct evhttp_request *req,void *arg) { struct tm *local = NULL; time_t tt; tt=time(NULL); local=localtime(&tt); struct evbuffer *retbuff = NULL; retbuff = evbuffer_new(); if(retbuff == NULL) { MESA_handle_runtime_log(error_log_handler, RLOG_LV_FATAL, module_name, "keepalive evbuffer_new failed."); printf("====line:%d,%s\n",__LINE__,"keepalive evbuffer_new failed."); return; } cJSON * root = cJSON_CreateObject(); if(!root) { MESA_handle_runtime_log(error_log_handler, RLOG_LV_FATAL, module_name, "keepalive cjson_createobject error."); printf("====line:%d,%s\n",__LINE__,"keepalice cjson_createobject error."); return; } cJSON_AddItemToObject(root, "current time", cJSON_CreateString(asctime(local))); //printf("cjson_keepalive_print:%s\n", cJSON_Print(root)); MESA_handle_runtime_log(http_check_log_handler, RLOG_LV_INFO, module_name, cJSON_Print(root)); evbuffer_add_printf(retbuff,cJSON_Print(root)); evhttp_send_reply(req,HTTP_OK,"OK",retbuff); evbuffer_free(retbuff); if(root) { cJSON_Delete(root); } return; } void *http_check_dispatch(void *arg) { //循环监听 event_dispatch(); //evhttp_free(http_server); return NULL; } int http_check_init() { pthread_t tidp; struct evhttp *http_server = NULL; int log_level = 30; MESA_load_profile_int_def(http_check_conf_file, "HTTP", "SERVER_PORT", (int *)(&g_http_port), 10000); MESA_load_profile_string_nodef(http_check_conf_file, "HTTP", "SERVER_IP", g_http_address, MAX_STR_LEN); MESA_load_profile_string_nodef(http_check_conf_file, "HTTP", "HTTP_CHECK_LOG_PATH", http_check_log_path, MAX_STR_LEN); MESA_load_profile_string_nodef(http_check_conf_file, "HTTP", "HTTP_CHECK_ERR_LOG_PATH", http_check_error_log_path, MAX_STR_LEN); MESA_load_profile_string_nodef(http_check_conf_file, "HTTP", "MODULE_NAME", module_name, MAX_STR_LEN); MESA_load_profile_int_def(http_check_conf_file, "HTTP", "LOG_LEVEL", &log_level, 30); //printf("*v12*******read_ip:%s,read_port:%d\n",g_http_address, g_http_port); http_check_log_handler = MESA_create_runtime_log_handle(http_check_log_path, log_level); error_log_handler = MESA_create_runtime_log_handle(http_check_error_log_path, log_level); if (http_check_log_handler == NULL || error_log_handler == NULL) { MESA_handle_runtime_log(error_log_handler, RLOG_LV_FATAL, module_name, "http check init error."); printf("====line:%d,%s\n",__LINE__,"http check init error."); return -1; } //初始化 event_init(); //启动http服务端 http_server = evhttp_start(g_http_address,g_http_port); if(http_server == NULL) { MESA_handle_runtime_log(error_log_handler, RLOG_LV_FATAL, module_name, "evhttp_start failed."); printf("====line:%d,%s\n",__LINE__,"evhttp_start failed."); return 0; } //设置请求超时时间(s) evhttp_set_timeout(http_server,HTTP_TIMEOUT); //设置事件处理函数,针对每一个事件(请求)注册一个处理函数,为特定的URI指定callback evhttp_set_cb(http_server,"/status",http_handler_status_msg,NULL); evhttp_set_cb(http_server,"/keepalive",http_handler_keepalive_msg,NULL); if ((pthread_create(&tidp, NULL, http_check_dispatch, NULL)) == -1) { MESA_handle_runtime_log(error_log_handler, RLOG_LV_FATAL, module_name, "http_check_dispatch thread create failed."); printf("====line:%d,%s\n",__LINE__,"http_check_dispatch thread create failed."); return 0; } return 0; } void http_check_destory() { if (http_check_log_handler) { MESA_destroy_runtime_log_handle(http_check_log_handler); } if (error_log_handler) { MESA_destroy_runtime_log_handle(error_log_handler); } return; }