10 Commits

Author SHA1 Message Date
96a417ba93 调整处理器结构体 2024-08-14 13:02:27 +08:00
d2a2b933a5 修复资源未释放bug,简化释放流程 2024-08-13 22:43:54 +08:00
2608dfa078 完成拦截器设计 2024-08-13 22:23:34 +08:00
a823bab944 修复测试功能 2024-08-12 20:17:31 +08:00
03e05051ea 修复了日志处理器的设计问题 2024-08-12 19:41:47 +08:00
d22ce6956e 修改了不合理设计 2024-08-12 19:39:12 +08:00
dcd6ba0106 修复错误描述信息 2024-08-12 18:18:30 +08:00
20a1ec9033 添加开源协议 2024-08-12 18:13:42 +08:00
ad0fa169ef 添加conan相关文件 2024-08-12 18:06:41 +08:00
addf2cb751 V0.1.0版本 2024-08-12 14:16:11 +08:00
14 changed files with 607 additions and 60 deletions

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@
.vscode/**
bin
build
CMakeUserPresets.json

View File

@@ -11,11 +11,15 @@ set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin)
include_directories(${CMAKE_SOURCE_DIR}/include)
# add_library(${PROJECT_NAME} ${SRC})
# add_library(${PROJECT_NAME} SHARED ${SRC})
add_executable(${PROJECT_NAME}main main.c ${SRC})
if (SHARED)
add_library(${PROJECT_NAME} SHARED ${SRC})
else()
add_library(${PROJECT_NAME} ${SRC})
endif()
if (SKIPTEST)
else()
add_executable(test_simple ${CMAKE_SOURCE_DIR}/test_package/test_simple.c ${SRC})
add_executable(test_interceptor ${CMAKE_SOURCE_DIR}/test_package/test_interceptor.c ${SRC})
endif()

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 youmetme
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

101
README.md
View File

@@ -0,0 +1,101 @@
# C语言日志库logging
## 简介
logging是一个轻量级的简单易用C语言日志库支持日志级别、日志格式、日志输出、日志文件等功能。
## 功能
- 支持日志级别DEBUG、INFO、WARN、ERROR、FATAL
- 支持日志格式:时间戳、日志级别、日志内容
- 支持日志输出:控制台、文件
- 支持日志文件:自动创建、自动滚动、自动删除(未完成)
## 使用方法
### 控制台日志
```c
#include "logging.h"
int main() {
Logging *log = createLogging(); // 创建日志对象
Logger *logger = log->getLogger("testLogger",LOG_DEBUG); //获取日志控制器
logger->addHandler(consoleHandler("test")); //为日志对象添加控制台处理器
logger->info("This is an info message");
logger->error("你好,这是一个错误消息%s", "123");
logger->fatal("This is an fatal message");
logger->debug("This is a debug message");
logger->warning("This is a warning message%s", "123");
destroyLogging(log);
return 0;
}
```
### 文件日志
```c
#include "logging.h"
int main() {
// Your code goes here
Logging *log = createLogging();
Logger *logger = log->getLogger("testLogger",LOG_DEBUG);
logger->addHandler(consoleHandler("test")); //为日志对象添加文件处理器
logger->info("This is an info message");
logger->error("你好,这是一个错误消息%s", "123");
logger->fatal("This is an fatal message");
logger->debug("This is a debug message");
logger->warning("This is a warning message%s", "123");
destroyLogging(log);
return 0;
}
```
### 日志拦截器
> 支持添加自定义的拦截器, 目前内置了子串拦截器
> 拦截器的作用:可以将拦截到的日志重定向到拦截器的专属处理器中
#### 例子
将拦截到的日志重定向到专属文件处理器中
```c
#include "logging.h"
int main() {
Logging *log = createLogging();
Logger *logger = log->getLogger("testLogger",LOG_DEBUG);
logger->addHandler(consoleHandler("test"));
logger->info("This is an info message");
logger->error("你好,这是一个错误消息%s", "123");
logger->fatal("This is an fatal message");
logger->debug("This is a debug message");
logger->warning("This is a warning message%s", "123");
char *test1[] = {"123", "你好"};//要拦截的字符串
//添加拦截器,将拦截到的日志重定向到拦截器的专属处理器中
log_Interceptor * tint = substringInterceptor(test1,2,LOG_DEBUG,fileHandler("被拦截"));
logger->addInterceptor(tint);
printf("Interceptor added\n");
logger->info("This is an info message");
logger->error("你好,这是一个错误消息%s", "123");
logger->fatal("This is an fatal message");
logger->debug("This is a debug message");
logger->warning("This is a warning message%s", "123");
destroyLogging(log);
return 0;
}
```
![](docs/img/![](2024-08-13-22-20-18.png).png)
![](docs/img/2024-08-13-22-21-37.png)

66
conanfile.py Normal file
View File

@@ -0,0 +1,66 @@
from conan import ConanFile
from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps, cmake_layout
from conan.tools.files import copy, get
from conan.tools.build import check_min_cppstd
from conan import tools
import os
class loggingRecipe(ConanFile):
name = "logging"
version = "0.1.1"
license = "MIT"
author = "321640253@qq.com"
url = "https://github.com/WangZhongDian/logging.git"
description = "一个纯C的简单易用的日志库"
topics = ("logging", "C", "simple", "easy-to-use", "log","Logging")
settings = "os", "compiler", "build_type", "arch"
options = {"shared": [True, False], "fPIC": [True, False]}
default_options = {"shared": False, "fPIC": True}
exports_sources = "include/*", "CMakeLists.txt", "src/*"
def config_options(self):
if self.settings.os == "Windows":
del self.options.fPIC
def configure(self):
if self.options.shared:
self.options.rm_safe("fPIC")
def layout(self):
cmake_layout(self)
def generate(self):
deps = CMakeDeps(self)
deps.generate()
tc = CMakeToolchain(self)
tc.variables["SKIPTEST"]=True
if self.options.shared:
tc.variables["SHARED"] = True
else:
tc.variables["SHARED"] = False
tc.generate()
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build(target="Logging")
def package(self):
copy(self, "LICENSE", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses"))
copy(self, pattern="*.h", src=os.path.join(self.source_folder, "include"), dst=os.path.join(self.package_folder, "include"))
copy(self, pattern="*.a", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"), keep_path=False)
copy(self, pattern="*.so", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"), keep_path=False)
copy(self, pattern="*.lib", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"), keep_path=False)
copy(self, pattern="*.dll", src=self.build_folder, dst=os.path.join(self.package_folder, "bin"), keep_path=False)
copy(self, pattern="*.dylib", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"), keep_path=False)
def package_info(self):
self.cpp_info.libs = ["Logging"]

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -7,8 +7,10 @@
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <stdbool.h>
typedef enum {
LOG_FATAL,
LOG_ERROR,
LOG_WARNING,
LOG_INFO,
@@ -20,21 +22,40 @@ typedef enum {
L_OK,
} log_status;
typedef struct Handler {
FILE* file;
log_level level;
typedef struct log_Handler {
void* stream;
bool apply_color;
void (*_free)(struct log_Handler* handler);//释放资源
void (*output)(struct log_Handler* handler,const char* message);
} log_Handler;
typedef struct log_Interceptor {
log_level level; //拦截级别
log_Handler* handler; //拦截目标处理器
bool (*_dispose)(char* level,const char *message, ...); //拦截触发器
void (*_free)(struct log_Interceptor* Interceptor); //释放资源
} log_Interceptor;
//日志操作器
typedef struct Logger
{
log_level level;
log_Handler* handler;
log_Interceptor* interceptor;
const char* name;
void (*fatal)(const char* format, ...);
void (*error)(const char* format, ...);
void (*warning)(const char* format, ...);
void (*info)(const char* format, ...);
void (*debug)(const char* format, ...);
void (*addHandler)(log_Handler* handler);
// void (*addFormat)(const char* format);
// void (*addFilter)(const char* filter);
void (*addInterceptor)(log_Interceptor* Interceptor);
} Logger;
@@ -42,16 +63,25 @@ typedef struct Logger
typedef struct Logging {
Logger* (*getLogger)(const char* name, log_level level);
log_status (*setLevel)(Logger* logger, log_level level);
// void (*addFormat)(const char* format);
// void (*addFilter)(const char* filter);
void (*addHandler)(log_Handler* handler);
} Logging;
Logging* createLogging();
Logging* createLogging();
log_status destroyLogging(Logging* logging);
Logger* getCurrentLogger(void);
log_Handler* fileHandler(const char* name,log_level level);
/**
* @def 创建日志处理器
* @file logging-handler.c
*/
log_Handler* fileHandler(const char* name);
log_Handler* consoleHandler(const char* name);
log_Interceptor* substringInterceptor(char *keywords[], int count, log_level level, log_Handler* handler);
#endif // __LOGGING_H

14
main.c
View File

@@ -1,14 +0,0 @@
#include "logging.h"
int main() {
// Your code goes here
Logging *log = createLogging();
Logger *logger = log->getLogger("testLogger",LOG_INFO);
logger->info("This is an info message");
logger->error("This is an error message");
logger->debug("This is a debug message");
logger->warning("This is a warning message");
return 0;
}

View File

@@ -1,16 +1,62 @@
/********************************************
* @Date: 2024 08 12
* @Description: 日志处理器
********************************************/
#include "logging.h"
/**
* @description :释放文件日志处理器相关资源
* @param
* @return
*/
static void __freeFileHandler(log_Handler* handler){
fclose(handler->stream);
free(handler);
}
static void outputFileHandler(log_Handler *handler, const char * message){
fputs(message,handler->stream);
}
log_Handler* fileHandler(const char* name,log_level level){
FILE* fp = fopen(name, "w");
/**
* @description :文件日志处理器
* @param
* @return
*/
log_Handler* fileHandler(const char* name){
char new_file_name[100];
sprintf(new_file_name, "%s.log", name);
FILE* fp = fopen(new_file_name, "at");
log_Handler* handler = (log_Handler*)malloc(sizeof(log_Handler));
handler->file = fp;
handler->level = level;
handler->stream = fp;
handler->apply_color = false;
handler->_free = __freeFileHandler;
handler->output = outputFileHandler;
return handler;
}
static void __freeConsoleHandler(log_Handler* handler){
free(handler);
}
static void outputConsoleHandler(log_Handler* handler,const char * message){
fputs(message,handler->stream);
}
/**
* @description :控制台日志处理器
* @param
* @return
*/
log_Handler* consoleHandler(const char* name){
log_Handler* handler = (log_Handler*)malloc(sizeof(log_Handler));
handler->stream = stdout;
handler->apply_color = true;
handler->_free = __freeConsoleHandler;
handler->output = outputConsoleHandler;
return handler;
}

119
src/logging-interceptor.c Normal file
View File

@@ -0,0 +1,119 @@
/********************************************
* @Date: 2024 08 12
* @Description: 日志拦截器
*********************************************/
#include "logging.h"
static log_Interceptor* G_interceptor = NULL;
static char **G_keywords = NULL;
static void get_next(char *str, int *next) {
next[1] = 0;
int i=1;
int j=0;
while (i < strlen(str)) {
if (j==0|| str[i] == str[j]) {
next[++i] = ++j;
}
else {
j = next[j];
}
}
}
static bool kmp_search(char *substr, char *master) {
int i = 0;
int j = 0;
int substrlen = strlen(substr);
int masterlen = strlen(master);
int *next = (int *)malloc(sizeof(int) * substrlen + 1);
get_next(substr, next);
while (i < masterlen && j < substrlen) {
if (master[i] == substr[j]) {
i++;
j++;
} else {
if(j == 0) {
i++;
} else {
j = next[j];
}
}
}
free(next);
if (j == substrlen)return true;
else return false;
}
/**
* @description 处理
* @param
* @return
*/
static bool _disposeSubstring(char* level,const char *message, ...){
int count = 0;
if (G_keywords == NULL) {
return false;
}
while (G_keywords[count] != NULL)
{
if (kmp_search(G_keywords[count],(char*)message)) {
return true;
}
count++;
}
return false;
}
/**
* @description : 完成拦截器自我释放内存
*/
static void _freeSubstring(log_Interceptor* interceptor) {
int sum = 0;
while (G_keywords[sum] != NULL) {
free(G_keywords[sum]);
sum++;
}
free(G_keywords);
G_keywords = NULL;
if(interceptor->handler != NULL){
interceptor->handler->_free(interceptor->handler);
}
free(interceptor);
}
/**
* @description : 子字符串拦截器
*/
log_Interceptor* substringInterceptor(char *keywords[], int count, log_level level, log_Handler* handler) {
log_Interceptor* interceptor = (log_Interceptor*)malloc(sizeof(log_Interceptor));
interceptor->_dispose = _disposeSubstring;
interceptor->handler = handler;
interceptor->level = level;
interceptor->_free = _freeSubstring;
G_keywords = (char**)malloc( (sizeof(G_keywords)*count) + 1);
for (int i = 0; i < count; i++) {
G_keywords[i] = (char*)malloc(strlen(keywords[i])+1);
strcpy(G_keywords[i], keywords[i]);
}
G_keywords[count] = NULL;
G_interceptor = interceptor;
return G_interceptor;
}

View File

@@ -1,7 +1,10 @@
/********************************************
* @Date: 2024 08 12
* @Description: 日志模块
********************************************/
#include "logging.h"
Logger* G_LOGGER = NULL;
#define RED "\033[0;31m"
@@ -14,57 +17,134 @@ Logger* G_LOGGER = NULL;
#define WHITE "\033[0;37m"
#define BLACK "\033[0;30m"
#define LOG_BUFFER_SIZE 1024
static void getTimeStr(char * timeStr){
time_t t = time(NULL);
struct tm* p = localtime(&t);
char _timeStr[18];
char _timeStr[20];
strftime(_timeStr, sizeof(_timeStr), "%Y-%m-%d %H:%M:%S", p);
strcpy(timeStr, _timeStr);
}
/**
* @description : 添加日志处理器
*/
static void addHandler(log_Handler* handler){
if (G_LOGGER == NULL){
return;
}
if (G_LOGGER->handler == NULL){
G_LOGGER->handler = handler;
return;
}
G_LOGGER->handler->_free(G_LOGGER->handler);
G_LOGGER->handler = handler;
}
void addInterceptor(log_Interceptor* Interceptor){
if (G_LOGGER == NULL){
return;
}
if (G_LOGGER->interceptor == NULL){
G_LOGGER->interceptor = Interceptor;
return;
}
G_LOGGER->interceptor->_free(G_LOGGER->interceptor);
G_LOGGER->interceptor = Interceptor;
}
/**
* @description : 内置日志记录函数
*/
static void _builtin_log(char* level, const char *color, const char* message, ...){
if (G_LOGGER == NULL){
return;
}
if (G_LOGGER->handler == NULL){
return;
}
char timeStr[20];
getTimeStr(timeStr);
char logStr[LOG_BUFFER_SIZE];
log_Handler * handler = G_LOGGER->handler;
//通过拦截器
if (G_LOGGER->interceptor != NULL){
if(G_LOGGER->interceptor->_dispose(level,message)){
if(G_LOGGER->interceptor->handler != NULL){
handler = G_LOGGER->interceptor->handler;
}
}
}
//判断处理器是否应用颜色
if (handler->apply_color) sprintf(logStr, "%s %s%s%s %s\n", timeStr, color,level,RESET, message);
else sprintf(logStr, "%s %s %s\n", timeStr, level, message);
handler->output(handler,logStr);
}
//*************************记录日志******************************* */
static void error(const char* format, ...){
static void fatal(const char* message, ...){
if (G_LOGGER->level >= LOG_ERROR){
char timeStr[18];
getTimeStr(timeStr);
printf("%sError%s %s %s\n",RED,RESET, timeStr, format);
char logStr[LOG_BUFFER_SIZE];
va_list args;
va_start(args, message);
vsprintf(logStr, message, args);
va_end(args);
_builtin_log("Fatal",RED, logStr, args);
}
}
static void warning(const char* format, ...){
static void error(const char* message, ...){
if (G_LOGGER->level >= LOG_ERROR){
char logStr[LOG_BUFFER_SIZE];
va_list args;
va_start(args, message);
vsprintf(logStr, message, args);
va_end(args);
_builtin_log("Error",RED, logStr, args);
}
}
static void warning(const char* message, ...){
if (G_LOGGER->level >= LOG_WARNING){
char timeStr[18];
getTimeStr(timeStr);
printf("%sWarning%s %s %s\n",YELLOW,RESET, timeStr, format);
char logStr[LOG_BUFFER_SIZE];
va_list args;
va_start(args, message);
vsprintf(logStr, message, args);
va_end(args);
_builtin_log("Warning",YELLOW, logStr, args);
}
}
static void info(const char* format, ...){
static void info(const char* message, ...){
if (G_LOGGER->level >= LOG_INFO){
char timeStr[18];
getTimeStr(timeStr);
printf("%sInfo%s %s %s\n",GREEN,RESET, timeStr, format);
char logStr[LOG_BUFFER_SIZE];
va_list args;
va_start(args, message);
vsprintf(logStr, message, args);
va_end(args);
_builtin_log("Info",GREEN, logStr, args);
}
}
static void debug(const char* format, ...){
static void debug(const char* message, ...){
if (G_LOGGER->level >= LOG_DEBUG){
char timeStr[18];
getTimeStr(timeStr);
printf("%sDebug%s %s %s\n",CYAN,RESET, timeStr, format);
char logStr[LOG_BUFFER_SIZE];
va_list args;
va_start(args, message);
vsprintf(logStr, message, args);
va_end(args);
_builtin_log("Debug",CYAN, logStr, args);
}
}
//*************************记录日志******************************* */
@@ -76,19 +156,30 @@ static void debug(const char* format, ...){
* @return
*/
static Logger* getLogger(const char* name, log_level level){
if (G_LOGGER != NULL){
return G_LOGGER;
}
Logger* logger = (Logger*)malloc(sizeof(Logger));
logger->fatal = fatal;
logger->error = error;
logger->warning = warning;
logger->info = info;
logger->debug = debug;
logger->addHandler = addHandler;
logger->addInterceptor = addInterceptor;
logger->level = level;
logger->handler = NULL;
logger->name = name;
logger->interceptor = NULL;
G_LOGGER = logger;
return G_LOGGER;
}
/**
* @description :创建一个日志对象
* @return :Logging* 返回一个日志对象
@@ -96,6 +187,42 @@ static Logger* getLogger(const char* name, log_level level){
Logging* createLogging(){
Logging* logging = (Logging*)malloc(sizeof(Logging));
logging->getLogger = getLogger;
logging->addHandler = addHandler;
return logging;
}
}
/**
* @description :销毁日志对象
*/
log_status destroyLogging(Logging* logging){
if (logging == NULL){
return L_ERROR;
}
if (G_LOGGER != NULL){
if (G_LOGGER->handler != NULL){
G_LOGGER->handler->_free(G_LOGGER->handler);
}
if (G_LOGGER->interceptor != NULL){
G_LOGGER->interceptor->_free(G_LOGGER->interceptor);
}
free(G_LOGGER);
G_LOGGER = NULL;
}
free(logging);
return L_OK;
}
/**
* @description :获取当前日志操作对象
* @return 当前唯一的日志操作对象
*/
Logger* getCurrentLogger(void){
if (G_LOGGER == NULL){
return NULL;
}
return G_LOGGER;
}

View File

@@ -0,0 +1,29 @@
#include "logging.h"
int main() {
Logging *log = createLogging();
Logger *logger = log->getLogger("testLogger",LOG_DEBUG);
logger->addHandler(consoleHandler("test"));
logger->info("This is an info message");
logger->error("你好,这是一个错误消息%s", "123");
logger->fatal("This is an fatal message");
logger->debug("This is a debug message");
logger->warning("This is a warning message%s", "123");
char *test1[] = {"123", "你好"};//要拦截的字符串
//添加拦截器,将拦截到的日志重定向到拦截器的专属处理器中
log_Interceptor * tint = substringInterceptor(test1,2,LOG_DEBUG,fileHandler("被拦截"));
logger->addInterceptor(tint);
printf("Interceptor added\n");
logger->info("This is an info message");
logger->error("你好,这是一个错误消息%s", "123");
logger->fatal("This is an fatal message");
logger->debug("This is a debug message");
logger->warning("This is a warning message%s", "123");
destroyLogging(log);
return 0;
}

View File

@@ -0,0 +1,17 @@
#include "logging.h"
int main() {
Logging *log = createLogging();
Logger *logger = log->getLogger("testLogger",LOG_DEBUG);
logger->addHandler(consoleHandler("test"));
logger->info("This is an info message");
logger->error("你好,这是一个错误消息%s", "123");
logger->fatal("This is an fatal message");
logger->debug("This is a debug message");
logger->warning("This is a warning message%s", "123");
destroyLogging(log);
return 0;
}