基于Linux C的简单日志库

        最近由于接手了几个小的开发项目,一直苦于寻找一个调用简单,方便调试,占用资源小的日志库,因为我大部分的嵌入式开发项目都是C/C++的开发。就想着做一个小的日志调用接口C/C++库。最近有时间整理一下。

        alog 由此而生,目前我几个项目中都用到了这个库,个人觉得非常简单,容易理解,使用简单,能马上融入到小型嵌入式项目中去。

首先看调用示例:

#include "alog_printf.h"

int main(void)
{
    alog_printf(ALOG_LVL_DEBUG, TURE,"n************TEST START**************n");
    int a = 0;

    while (1)
    {
        alog_printf(ALOG_LVL_DEBUG, TURE, "test a=%d n", a);
        a++;
        sleep(1);
    }

    return 0;
}

        示例中可以看到,这个日志调用类似于打印函数(其实就是改造的),说是一个日志库文件,不如说就是一个头文件,(这里主要是为了简单-不用去引用其他东西)是不是很简单。

调用原型:alog_printf(level, outputEnable, ...);

首先这个日志库具备这几个功能:

  • 可以设置输出到指定路径下保存成文件-方便导出查看
  • 日志文件以创建时间先后命名
  • 日志文件的大小和个数可设置,当超出设置限制后根据创建时间循环覆盖
  • 日志的保存等级可设置
  • 可控制是否打印在终端
  • 可输出打印时间、调用函数名和行数,方便定位打印

附一段核心实现:

/**
     * @brief :  Ari日志打印
     * @param {unsigned char} level
     * @param {_BOOL} outputEnable
     * @param {const char} *func
     * @param {const long} line
     * @param {const char} *fmt
     * @return {*}
     * @author: LR
     * @Date: 2021-06-25 12:11:49
     */
    static void log_printf(unsigned char level, bool outputEnable, const char *file, const long line, const char *fmt, ...)
    {
        if (level < ALOG_LVL_SET)
            return;

        pthread_mutex_lock(&alogMutex); /* 日志部分上锁 */

        char printf_buf[ALOG_BUF_MAX_SIZE]={0};
        va_list args;
        int printed;
        va_start(args, fmt);
        printed = vsnprintf(printf_buf, ALOG_BUF_MAX_SIZE, fmt, args);
        va_end(args);

        char buf[ALOG_BUF_MAX_SIZE + 200] = {0};
        int g_Count = 0;

        char temp[256];
        char logFileName[50] = {0};
        char logFileNameTemp[50] = {0};
        char logFileNameLast[50] = {"1580-05-05_00-00-00.log"};
        char logFileNameMix[50] = {"3000-05-05_00-00-00.log"};

        int iMax = ALOG_MAX_SIZE;

        FILE *fp = NULL;
        time_t timep;
        struct tm *p;
        time(&timep);
        p = localtime(&timep); //获取当前系统时间

        //将要保存的日志信息和时间戳信息整合
        memset(buf, 0, sizeof(buf));
        sprintf(buf, "▶[%d-%02d-%02d %02d:%02d:%02d -> %s:%ld]  :  ", (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday, (p->tm_hour + 8) % 24, p->tm_min, p->tm_sec, file, line); //星期p->tm_wday
        strcat(buf, printf_buf);
        //strcat(buf, "");

        if (outputEnable == true)
            puts(buf);

        DIR *dir;
        struct dirent *ptr;
        if ((dir = opendir(ALOG_PATH)) == NULL) //打开日志的文件目录,如果没有则建立
        {
            sprintf(temp, "mkdir -p %s", ALOG_PATH);
            system(temp);
            dir = opendir(ALOG_PATH);
        }
        while ((ptr = readdir(dir)) != NULL) //循环读取当前目录下到所有文件
        {
            if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0)
                continue;
            strcpy(logFileNameTemp, ptr->d_name);
            if (strlen(logFileNameTemp) < 18)
            {
                //g_Count++; //统计符合要求的文件个数
                continue;
            }
            if (strcmp(logFileNameTemp, logFileNameLast) > 0) //找到最新的文件
            {
                strcpy(logFileNameLast, logFileNameTemp); //将最新日期的文件名字保存在logFileNameLast
            }
            if (strcmp(logFileNameTemp, logFileNameMix) < 0) //找到最老的文件
            {
                strcpy(logFileNameMix, logFileNameTemp); //将最老日期的文件名字保存在logFileNameMix
            }
            g_Count++; //统计符合要求的文件个数
        }
        closedir(dir);
        sprintf(logFileName, "%s%s", ALOG_PATH, logFileNameLast); //将最新的文件名字匹配到路径中去,如果没有用默认文件名

        fp = fopen(logFileName, "r+");
        if (fp == NULL)
        {
            //进入这个里面证明没有日志文件产生过,第一次创建+
            sprintf(logFileName, "%s%d-%02d-%02d_%02d-%02d-%02d.log", ALOG_PATH, (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday, (p->tm_hour + 8) % 24, p->tm_min, p->tm_sec);
            fp = fopen(logFileName, "w+");
        }
        else
        {
            fseek(fp, 0, 2);       //SEEK_END值为2
            if (ftell(fp) >= iMax) //如果大小已经超出限制
            {
                fclose(fp);
                if (g_Count >= ALOG_MAX_NUM) //如果日志文件的个数达到路限制10个,则按日期进行循环覆盖
                {
                    sprintf(logFileName, "%s%s", ALOG_PATH, logFileNameMix);
                    remove(logFileName); //删除最老的一个日志文件
                    sprintf(logFileName, "%s%d-%02d-%02d_%02d-%02d-%02d.log", ALOG_PATH, (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday, (p->tm_hour + 8) % 24, p->tm_min, p->tm_sec);
                }
                else
                {
                    sprintf(logFileName, "%s%d-%02d-%02d_%02d-%02d-%02d.log", ALOG_PATH, (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday, (p->tm_hour + 8) % 24, p->tm_min, p->tm_sec);
                }
                fp = fopen(logFileName, "w+");
            }
            else
            {
                fclose(fp);
                fp = fopen(logFileName, "a+"); //以追加的方式打开文件
            }
        }
        fwrite(buf, 1, strlen(buf), fp);
        fflush(fp);        //立即刷新缓存区到指定文件流中
        //fsync(fileno(fp)); //将缓存区数据写入磁盘,并等待操作结束
        //fdatasync(fileno(fp));
        fclose(fp);

        pthread_mutex_unlock(&alogMutex); /*写日志部分解锁 */
    }

        这里面最关键的,个人认为根据设定来把时间段内的日志发片。然后根据时间来循环的覆盖日志,这样在我们有限的嵌入式资源中就能把握日志的占用大小。不用人为的去维护,在有需要的时候下载下来,方便记录调试定位问题。

        当然这个只是项目需要写的一个东西,里面我现在想到的就还有很多可以优化增加的功能。现在只是记录一下,拿来用还是没问题的。大家有想法的也可以给我留言。

完整的实现+示例请下载:

CSDN:alog_printf.h-C文档类资源-CSDN下载

GitHub:GitHub - HelloAriLiu/alog: 一个简单的Linux 日志库适用于小型嵌入式


创作不易,您的点赞、评论、收藏是对我最大的支持!

        

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>