C日志


#include "slog.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdarg.h>

#if defined(WIN32)
#include <io.h>
#include <direct.h>
#include <Windows.h>
#include <DbgHelp.h>
#elif defined(linux)
#include <unistd.h>
#include <pthread.h>
#include <sys/stat.h>
#include <execinfo.h>
#endif

#define MAX_LEVEL_STR               (10)
#define MAX_DATE_STR                (20)
#define DATE_STR_FMT                "%04d%02d%02d"
#define MAX_TIME_STR                (20)
#define TIME_STR_FMT                "%04d/%02d/%02d %02d:%02d:%02d"
#define MAX_FILE_PATH               (260)
#define MAX_LOG_LINE                (4096)

#if defined(WIN32)
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define PROC_HANDLE HANDLE
#define SLOG_MUTEX CRITICAL_SECTION 
#elif defined(linux)
#define PROC_HANDLE void *
#define SLOG_MUTEX pthread_mutex_t
#endif

#pragma warning( disable : 4996 )

typedef struct _logger_cfg {
    PROC_HANDLE curr_proc;
    FILE *log_file;
    SLOG_MUTEX mtx;
    slog_level filter_levle;
    int inited;
} logger_cfg;

static logger_cfg g_logger_cfg = {
    NULL, NULL, {0}, S_INFO, FALSE };

static void _slog_init_mutex(SLOG_MUTEX *mtx)
{
#if defined(WIN32)
    InitializeCriticalSection(mtx);
#elif defined(linux)
    pthread_mutex_init(mtx, NULL);
#endif
}

static void _slog_lock(SLOG_MUTEX *mtx)
{
#if defined(WIN32)
    EnterCriticalSection(mtx);
#elif defined(linux)
    pthread_mutex_lock(mtx);
#endif
}

static void _slog_unlock(SLOG_MUTEX *mtx)
{
#if defined(WIN32)
    LeaveCriticalSection(mtx);
#elif defined(linux)
    pthread_mutex_unlock(mtx);
#endif
}

static void _get_curr_date(int datestr_size, char datestr[])
{
    time_t tt = { 0 };
    struct tm *curr_time = NULL;

    time(&tt);
    curr_time = localtime(&tt);
    snprintf(datestr, datestr_size - 1, DATE_STR_FMT,
        curr_time->tm_year + 1900, curr_time->tm_mon + 1, curr_time->tm_mday);
}

static void _get_curr_time(int timestr_size, char timestr[])
{
    time_t tt = { 0 };
    struct tm *curr_time = NULL;

    time(&tt);
    curr_time = localtime(&tt);
    snprintf(timestr, timestr_size - 1, TIME_STR_FMT,
        curr_time->tm_year + 1900, curr_time->tm_mon + 1, curr_time->tm_mday,
        curr_time->tm_hour, curr_time->tm_min, curr_time->tm_sec);
}

static char *_get_level_str(slog_level level)
{
    switch (level) {
    case S_TRACE:
        return "[TRACE]";
    case S_DEBUG:
        return "[DEBUG]";
    case S_INFO:
        return "[INFO ]";
    case S_WARN:
        return "[WARN ]";
    case S_ERROR:
        return "[ERROR]";
    default:
        return "[     ]";
    }
}

static void _write_stacktrace()
{
#define INNER_DEEP         (2)
#define MAX_DEEP           (24)
#define MAX_ST_INFO        (256)
#define MAX_ST_LINE        (512)

    unsigned int i = 0;
    unsigned short frames = 0;
    void *stack[MAX_DEEP] = { 0 };
    char st_line[MAX_ST_LINE] = { 0 };

#if defined(WIN32)
    SYMBOL_INFO *symbol = NULL;

    frames = CaptureStackBackTrace(INNER_DEEP, MAX_DEEP, stack, NULL);
    symbol = (SYMBOL_INFO *)calloc(sizeof(SYMBOL_INFO) + sizeof(char) * MAX_ST_INFO, 1);
    symbol->MaxNameLen = MAX_ST_INFO - 1;
    symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
    for (i = 0; i < frames; ++i) {
        SymFromAddr(g_logger_cfg.curr_proc, (DWORD64)(stack[i]), 0, symbol);
        snprintf(st_line, sizeof(st_line) - 1, "    %d: %s [0x%X]\n", frames - i - 1, symbol->Name, symbol->Address);
        fwrite(st_line, sizeof(char), strlen(st_line), g_logger_cfg.log_file);
    }
#elif defined(linux)
    char **st_arr = NULL;

    frames = backtrace(stack, MAX_DEEP);
    st_arr = backtrace_symbols(stack, frames);
    for (i = 0; i < frames; ++i) {
        snprintf(st_line, sizeof(st_line) - 1, "    %d: %s\n", frames - i - 1, st_arr[i]);
        fwrite(st_line, sizeof(char), strlen(st_line), g_logger_cfg.log_file);
    }
    free(st_arr);
#endif
}

static int _slog_mkdir(const char *log_dir)
{
#if defined(WIN32)
    if (_mkdir(log_dir) != 0) {
        return FALSE;
    }
#elif defined(linux)
    if (mkdir(log_dir, 0744) != 0) {
        return FALSE;
    }
#endif
    return TRUE;
}

static int _get_curr_proc_handle()
{
#if defined(WIN32)
    g_logger_cfg.curr_proc = GetCurrentProcess();
    if (NULL == g_logger_cfg.curr_proc) {
        return FALSE;
    }
    if (SymInitialize(g_logger_cfg.curr_proc, NULL, TRUE) != TRUE) {
        return FALSE;
    }
#elif defined(linux)
    g_logger_cfg.curr_proc = NULL;
#endif
    return TRUE;
}

int init_logger(const char *log_dir, slog_level level)
{
    char log_filepath[MAX_FILE_PATH] = { 0 };
    char datestr[MAX_DATE_STR] = { 0 };

    if (TRUE == g_logger_cfg.inited) {
        return TRUE;
    }

    if (_access(log_dir, 0) != 0) {
        if (_slog_mkdir(log_dir) != TRUE) {
            return FALSE;
        }
    }

    _slog_init_mutex(&g_logger_cfg.mtx);
    if (_get_curr_proc_handle() != TRUE) {
        return FALSE;
    }
    _get_curr_date(sizeof(datestr), datestr);
    snprintf(log_filepath, sizeof(log_filepath) - 1, "%s/%s.log", log_dir, datestr);
    g_logger_cfg.log_file = fopen(log_filepath, "a+");
    if (NULL == g_logger_cfg.log_file) {
        return FALSE;
    }
    g_logger_cfg.filter_levle = level;
    g_logger_cfg.inited = TRUE;

    return TRUE;
}

void write_log(slog_level level, int print_stacktrace, const char *file_name, const char *func_name, int line, const char *fmt, ...)
{
	init_logger("log", level);

    va_list args;
    char *level_str = NULL;
    char timestr[MAX_TIME_STR] = { 0 };
    char log_content[MAX_LOG_LINE] = { 0 };
    char log_line[MAX_LOG_LINE] = { 0 };

    if (g_logger_cfg.filter_levle > level) {
        return;
    }
    va_start(args, fmt);
    vsnprintf(log_content, sizeof(log_content) - 1, fmt, args);
    va_end(args);
    _get_curr_time(sizeof(timestr), timestr);
    level_str = _get_level_str(level);
    snprintf(log_line, sizeof(log_line) - 1, "%s %s %s %s:%d -| %s\n",
        level_str, timestr, file_name, func_name, line, log_content);
    _slog_lock(&g_logger_cfg.mtx);
    fwrite(log_line, sizeof(char), strlen(log_line), g_logger_cfg.log_file);
    if (TRUE == print_stacktrace) {
        _write_stacktrace();
    }
    fflush(g_logger_cfg.log_file);
    _slog_unlock(&g_logger_cfg.mtx);
}
#ifndef _S_LOG_H_
#define _S_LOG_H_

#ifndef NULL
#define NULL         (0)
#endif

#ifndef TRUE
#define TRUE         (1)
#endif

#ifndef FALSE        
#define FALSE        (0)
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef enum _slog_level {
    S_TRACE = 1,
    S_DEBUG = 2,
    S_INFO = 3,
    S_WARN = 4,
    S_ERROR = 5
} slog_level;

int init_logger(const char *log_dir, slog_level level);
void write_log(slog_level level, int print_stacktrace, const char * file_name, const char *func_name, int line, const char *fmt, ...);

#define SLOG_ST_ERROR(fmt, ...) write_log(S_ERROR, TRUE, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
#define SLOG_ST_WARN(fmt, ...) write_log(S_WARN, TRUE, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
#define SLOG_ST_INFO(fmt, ...) write_log(S_INFO, TRUE, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
#define SLOG_ST_DEBUG(fmt, ...) write_log(S_DEBUG, TRUE, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
#define SLOG_ST_TRACE(fmt, ...) write_log(S_TRACE, TRUE, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
#define SLOG_ERROR(fmt, ...) write_log(S_ERROR, FALSE, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
#define SLOG_WARN(fmt, ...) write_log(S_WARN, FALSE, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
#define SLOG_INFO(fmt, ...) write_log(S_INFO, FALSE, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
#define SLOG_DEBUG(fmt, ...) write_log(S_DEBUG, FALSE, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
#define SLOG_TRACE(fmt, ...) write_log(S_TRACE, FALSE, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)

#ifdef __cplusplus
}
#endif

#endif // !_S_LOG_H_

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值