From 075accef5fbd934e13cc90079974dd7d8961ba9e Mon Sep 17 00:00:00 2001 From: liuxueli Date: Thu, 15 Nov 2018 17:10:05 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=8C=E6=AD=A5=E5=86=85=E7=BD=91=E7=89=88?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 14 +++ README | 33 ++++++ demo/Makefile | 23 ++++ demo/test_handle_logger.c | 80 +++++++++++++ inc/MESA_handle_logger.h | 68 +++++++++++ lib/libMESA_handle_logger.a | Bin 0 -> 60466 bytes lib/libMESA_handle_logger.so | Bin 0 -> 60123 bytes src/MESA_handle_logger.c | 218 +++++++++++++++++++++++++++++++++++ src/Makefile | 25 ++++ 9 files changed, 461 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 demo/Makefile create mode 100644 demo/test_handle_logger.c create mode 100644 inc/MESA_handle_logger.h create mode 100644 lib/libMESA_handle_logger.a create mode 100644 lib/libMESA_handle_logger.so create mode 100644 src/MESA_handle_logger.c create mode 100644 src/Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1bdf032 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +#opt: OPTFLAGS = -O2 +#export OPTFLAGS + +.PHONY: all clean opt + +all: + cd src && $(MAKE) + cd demo && $(MAKE) +clean: + cd demo && $(MAKE) clean + cd src && $(MAKE) clean + +opt: + $(MAKE) all diff --git a/README b/README new file mode 100644 index 0000000..d933733 --- /dev/null +++ b/README @@ -0,0 +1,33 @@ +/* + *NAME:MESA_handle_logger + *INTRODUCTION:Based on logger and thread_safe, provide runtime_log function with independent handle for different users. + *Author:yangwei@iie.ac.cn + *History: + 2014-03-24 created by yw + 1)first version + + 2014-04-16 modified by yw + 1)strict inspection parameters, compatible with g++ 4.4.4 + + 2014-05-29 update by yw + 1)create directory is supported +------------------------------------------------------------------------------------- + NOTICE: + 1)compatible with g++, extern with c; + 2)thread_safe IS supported; + 3)DO destroy handle process before exit. + 4)demo requires lpthread support +*/ + + + + + + + + + + + + + diff --git a/demo/Makefile b/demo/Makefile new file mode 100644 index 0000000..10956e6 --- /dev/null +++ b/demo/Makefile @@ -0,0 +1,23 @@ +vpath %.h ../inc +vpath %.a ../lib + +CC=gcc + +CFLAGS= -g3 -Wall -fPIC -O -Werror +CFLAGS+=-I../inc/ + +LIB=-L../lib/ +LIB+=-lMESA_handle_logger -lpthread + +LIB_FILE=$(wildcard ../lib/*.a) + +SRC=test_handle_logger.c +TARGET=test_handle_logger + +all:$(TARGET) + +$(TARGET):$(SRC) $(LIB_FILE) + $(CC) $(CFLAGS) $(INC) $(LIBPATH) $< -static $(LIB) -o $@ + +clean : + rm -f $(TARGET) diff --git a/demo/test_handle_logger.c b/demo/test_handle_logger.c new file mode 100644 index 0000000..ce18567 --- /dev/null +++ b/demo/test_handle_logger.c @@ -0,0 +1,80 @@ +#include "MESA_handle_logger.h" + +#include +#include +#include +#include + +void *sample_handle = NULL; +void *test_handle = NULL; + +#define LOG_NUM 100 +#define THREAD_NUM 100 + +void call_logger(int log_num, int thread_num) +{ + int i = 0; + for(i = 0; i < log_num; i++) + { + MESA_handle_runtime_log(sample_handle, RLOG_LV_INFO, "sample", "sample_handle MESA_handle_runtime_log, i = %d, thread_num = %d", i, thread_num); + //sleep(1); + MESA_handle_runtime_log(test_handle, RLOG_LV_INFO, "test", "test_handle MESA_handle_runtime_log, i = %d, thread_num = %d", i, thread_num); + MESA_HANDLE_RUNTIME_LOG(sample_handle, RLOG_LV_FATAL, "sample", "sample_handle RUNTIEM_LOG test, i = %d, thread_num = %d", i, thread_num); + //sleep(1); + MESA_HANDLE_RUNTIME_LOG(test_handle, RLOG_LV_FATAL, "test", "test_handle RUNTIEM_LOG test, i = %d, thread_num = %d", i, thread_num); + } + return; +} + + +void *thread_logger(void *arg) +{ + int thread_num = (int)(unsigned long long)arg; + printf("thread %d created! \n", thread_num); + call_logger(LOG_NUM, thread_num); + printf("thread %d finished! \n", thread_num); + return NULL; +} + +void sig_handler(int sig) +{ + printf("ctrl+c recviced!\n"); + MESA_destroy_runtime_log_handle(sample_handle); + MESA_destroy_runtime_log_handle(test_handle); + sample_handle = NULL; + test_handle = NULL; + exit(0); +} + +int main() +{ + pthread_t t[THREAD_NUM]; + int i = 0; + + sample_handle = MESA_create_runtime_log_handle("./log/", RLOG_LV_DEBUG); + if(sample_handle == NULL) + { + printf("get log sample_handle error\n"); + return -1; + } + + test_handle = MESA_create_runtime_log_handle("./log/test_log", RLOG_LV_DEBUG); + if(test_handle == NULL) + { + printf("get log test_handle error\n"); + return -1; + } + + for(i = 0; i < THREAD_NUM; i++) + { + pthread_create(&t[i], NULL, thread_logger, (void *)(unsigned long)(i)); + } + signal(SIGINT, sig_handler); + while(1) + ; + //MESA_destroy_runtime_log_handle(sample_handle); + //MESA_destroy_runtime_log_handle(test_handle); + //sample_handle = NULL; + //test_handle = NULL; + return 0; +} diff --git a/inc/MESA_handle_logger.h b/inc/MESA_handle_logger.h new file mode 100644 index 0000000..c615b53 --- /dev/null +++ b/inc/MESA_handle_logger.h @@ -0,0 +1,68 @@ +#ifndef MESA_HANDLE__LOGGER_H +#define MESA_HANDLE__LOGGER_H + +/* + * runtime_log with handle, + * based on runtime_log. + * yang wei + * create time:2014-03-24 + * version:20140324 + */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define RLOG_LV_DEBUG 10 +#define RLOG_LV_INFO 20 +#define RLOG_LV_FATAL 30 + + +#define MESA_HANDLE_RUNTIME_LOG(handle, lv, mod, fmt, args...) \ + MESA_handle_runtime_log((handle), (lv), (mod), "file %s, line %d, " fmt, \ + __FILE__, __LINE__, ##args) + +/* + * name: MESA_create_runtime_log_handle + * functionality: get runtime_log handle; + * params: + * file_path: path of log file, like "./log/runtime_log"; + * level: level of log; + * returns: + * not NULL, if succeeded; + * NULL, if file is not absolute path, or failed to create log file; + */ +void *MESA_create_runtime_log_handle(const char *file_path, int level); + +/* + * name: MESA_handle_runtime_log + * functionality: appends log message to runtime log file; + * params: + * handle:handle of runtime log, which is created by MESA_create_runtime_log_handle; + * level: log level, messages with level value smaller the global var + * "runtime_log_level" are ignored; + * module: name of loggin module; + * fmt: format string; + * returns: + * none; + */ +void MESA_handle_runtime_log(void *handle, int level, const char *module, const char *fmt, ...); + +/* + * name: MESA_destroy_runtime_log_handle + * functionality: release runtime log handle memory. + * params: + * handle: runtime log handle which is going to be released; + * returns: + * none; + */ +void MESA_destroy_runtime_log_handle(void *handle); + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/lib/libMESA_handle_logger.a b/lib/libMESA_handle_logger.a new file mode 100644 index 0000000000000000000000000000000000000000..19f576a9fe17e6d7d3dc9e9c15f0e3056d9d023d GIT binary patch literal 60466 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 UIupbGG-v7uQD;}V#i~bL)*_qM%%v|Y; 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 +#include +#include +#include +#include +#include +#include + +typedef struct log_handle_t +{ + int runtime_log_level; + char runtime_log_file[1200]; +} log_handle_t; + +#define THREAD_CTIME(t, buf, len) thread_safe_ctime(t, buf, len) +#define LOGMSG_MAX_LEN 4096 + +const int HANDLE_LOGGER_VERSION_20170816 = 1; + +char *thread_safe_ctime(const time_t *tp, char *buf, int len) +{ + unsigned int year, month, day, weekday, hour, min, sec; + unsigned int year_days = 365; + unsigned int month_days[12] = + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + static unsigned char weekday_str[7][4] = + {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; + static unsigned char month_str[12][4] = {"Jan", "Feb", "Mar", "Apr", + "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + sec = * tp; + min = sec / 60; sec = sec % 60; + hour = min / 60; min = min % 60; hour += 8; + day = hour / 24; hour = hour % 24; + weekday = day % 7; weekday = (weekday + 4) % 7; + + for(year = 1970; day >= year_days;) + { + day -= year_days; + year ++; + + if(0 == year % 4 && (0 != year % 100 || 0 == year % 400)) + year_days = 366; + else year_days = 365; + } + + if(366 == year_days) month_days[1] = 29; + + //bug fix by yw 20120808 + for(month = 0; day >= month_days[month];) + { + day -= month_days[month]; + month ++; + } + + /* + snprintf(buf, len, "%02d:%02d:%02d, %04d/%02d/%02d, %s", + hour, min, sec, year, month, day, weekday_str[week_day]); + */ + snprintf(buf, len, "%s %s %d %02d:%02d:%02d %d", weekday_str[weekday], + month_str[month], day + 1, hour, min, sec, year); + return buf; +} + +static int create_dir(const char *dir_path, int path_len) +{ + if(dir_path == NULL) + return -1; + + char *buf = (char *)calloc(path_len+1, 1); + int ret = -1; + + memcpy(buf, dir_path, path_len); + if(access(buf, R_OK) != 0) + { + if(mkdir(buf, 0755)!= 0) + ret = -1; + else + ret = 0; + } + else + ret = 1; + free(buf); + buf = NULL; + return ret; +} + +static int create_path(const char *path, int path_len) +{ + const char *p_cur = path; + int i = 0; + + if(create_dir(path, path_len) >= 0) + return 0; + + for(;i<=path_len;i++,p_cur++) + { + if(*p_cur == '/') + { + if(create_dir(path, i+1) < 0) + return -1; + } + } + return 0; +} + +void *MESA_create_runtime_log_handle(const char *file_path, int level) +{ + if(file_path == NULL) + return NULL; + + FILE *fp = NULL; + log_handle_t *p_handle = NULL; + + //creating file_path failed, return NULL + char *p_path = rindex(file_path, '/'); + if(p_path != 0) + { + if(create_path(file_path, p_path - file_path) < 0) + return NULL; + } + if(NULL == (fp = fopen(file_path, "w"))) + return NULL; + + fclose(fp); + //remove(file_path); + p_handle = (log_handle_t *)calloc(sizeof(log_handle_t), 1); + + if(p_handle == NULL) + return NULL; + + strncpy(p_handle->runtime_log_file, file_path, 1024); + p_handle->runtime_log_file[1024] = '\0'; + p_handle->runtime_log_level = level; + return (void *)p_handle; +} + +void MESA_destroy_runtime_log_handle(void *handle) +{ + if(handle != NULL) + { + free(handle); + handle = NULL; + } + + return; +} + +void MESA_handle_runtime_log(void *handle, int level, const char *module, const char *fmt, ...) +{ + char buf[LOGMSG_MAX_LEN + 1]; + time_t t; + int len; + va_list ap; + FILE *fp; + struct tm local_time; + char tmp_log_file_name[1201]; + log_handle_t *p_handle = (log_handle_t *)handle; + + if(p_handle == NULL || p_handle->runtime_log_file == NULL)return; + + if(level < p_handle->runtime_log_level) return; + + time(&t); + THREAD_CTIME(&t, buf, LOGMSG_MAX_LEN); + len = strlen(buf); + + switch(level) + { + case RLOG_LV_DEBUG: + len += snprintf(buf + len, + LOGMSG_MAX_LEN - len, ", %s, ", "DEBUG"); + break; + + case RLOG_LV_INFO: + len += snprintf(buf + len, + LOGMSG_MAX_LEN - len, ", %s, ", "INFO"); + break; + + case RLOG_LV_FATAL: + len += snprintf(buf + len, + LOGMSG_MAX_LEN - len, ", %s, ", "FATAL"); + break; + + default: + len += snprintf(buf + len, + LOGMSG_MAX_LEN - len, ", %s, ", "UNKNOWN"); + break; + } + + if(0 >= LOGMSG_MAX_LEN - len) return; + + len += snprintf(buf + len, LOGMSG_MAX_LEN - len, "%s, ", module); + + if(0 >= LOGMSG_MAX_LEN - len) return; + + va_start(ap, fmt); + len += vsnprintf(buf + len, LOGMSG_MAX_LEN - len, fmt, ap); + va_end(ap); + + if(0 >= LOGMSG_MAX_LEN - len) return; + + len += snprintf(buf + len, LOGMSG_MAX_LEN - len, "\n"); + + if(NULL == (localtime_r(&t, &local_time))) return; + + sprintf(tmp_log_file_name, "%s.%04d-%02d-%02d", p_handle->runtime_log_file, + local_time.tm_year + 1900, local_time.tm_mon + 1, + local_time.tm_mday); + + if(NULL == (fp = fopen(tmp_log_file_name, "a"))) return; + + fprintf(fp, "%s", buf); + fclose(fp); +} + diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..a7a913c --- /dev/null +++ b/src/Makefile @@ -0,0 +1,25 @@ +CC=gcc +VPATH=../inc +CFLAGS= -g3 -Wall -fPIC -O -Werror +CFLAGS+=-I../inc/ + +SRC=MESA_handle_logger.c +OBJS=$(SRC:.c=.o) + +TARGET=libMESA_handle_logger.a libMESA_handle_logger.so + +all:$(TARGET) + cp -f $(TARGET) ../lib + +libMESA_handle_logger.a:$(OBJS) + ar cqs $@ $< + +libMESA_handle_logger.so:$(OBJS) + $(CC) $(CFLAGS) -shared $< -o $@ +.c.o: + +#$(OBJS):$(SRC) +# $(CC) $(CFLAGS) $(INC) -c $< -o $@ + +clean : + rm -f $(OBJS) $(TARGET)