Linux:日志的编写及使用

cpp 复制代码
#pragma once
#include <iostream>
#include <fstream>
#include <cstdio>
#include <string>
#include <ctime>
#include <cstdarg>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include "LockGuard.hpp"

bool gIsSave=false;//默认false是向显示器进行打印,true是向文件进行写入
const std::string logname="log.txt";

//1.日志是有等级的
enum Level
{
    DEBUG=0,//调试
    INFO,//正常
    WARNING,//警告
    ERROR,//错误
    FATAL//严重的错误
};

void SaveFile(const std::string &filename,const std::string &message)//改变日志的打印目标
{
    std::ofstream out(filename,std::ios::app);
    if(!out.is_open())
    {
        return;
    }
    out<<message;
    out.close();
}

std::string LevelToString(int level)//将等级转换成字符串
{
    switch(level)
    {
        case DEBUG:
            return "Debug";
        case INFO:
            return "INFO";
        case WARNING:
            return "Warning";
        case ERROR:
            return "Error";
        case FATAL:
            return "Fatal";
        default:
            return "Unknown";
    }
}

std::string GetTimeString()//以字符串形式获取当前时间
{
    time_t curr_time=time(nullptr);
    struct tm *format_time=localtime(&curr_time);//tm是time库函数中的一个结构体类型,内部可以存储日期时间等信息
    if(format_time==nullptr)
    {
        return "None";
    }
    char time_buffer[1024];
    snprintf(time_buffer,sizeof(time_buffer),"%d-%d-%d %d:%d:%d",
            format_time->tm_year+1900,
            format_time->tm_mon+1,
            format_time->tm_mday,
            format_time->tm_hour,
            format_time->tm_min,
            format_time->tm_sec);
    return time_buffer;
}

pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;
//2.日志是有格式的
//日志等级 时间 代码所在的文件名/行数 日志的内容
//filename 需要写入的目标文件名
//line 写入该条日志信息的所在行数
//issave 是否向文件进行写入
//level 日志等级
//
void LogMessage(std::string filename,int line,bool issave,int level,const char*format)
{

    std::string levelstr=LevelTostring(level);//等级
    std::string timestr=GetTimeString();//时间信息
    pid_t selfid=getpid();//当前线程PID

    char buffer[1024];
    va_list arg;//本质上是一个指针
    va_start(arg,format);//用format的地址来初始化arg(即让其指向可变参数部分),arg本质上是一个    
    //void类型的指针

    vsnprintf(buffer,sizeof(buffer),format,arg);
    va_end(arg);//将arg进行清空

    std::string message="["+timestr+"]"+"["+levelstr+"]"+
                        "["+std::to_string(selfid)+"]"+
                        "["+filename+"]"+"["+std::to_string(line)+"]"+buffer+"\n";
    LockGuard lockguard(&lock);
    if(!issave)
    {
        std::cout<<message;
    }
    else
    {
        SaveFile(logname,message);
    }
}

// C99新特性__VA_ARGS__
#define LOG(level,format,...)
    do
    {
        LogMessage(__FILE__,__LINE__,gIsSave,level,format,##__VA_ARGS__);
    }while(0)

#define EnableFile()
    do
    {
        gIsSave=true;
    }while(0)
#define EnableScreen()
    do
    {
        gIsSave=false;
    }while(0)

va_start和va_arg

cpp 复制代码
va_start(arg,num);
va_arg(arg,int);

1、arg指针可以根据num的地址然后减去num类型的大小指向num之后一个元素的地址。

2、data进行读取数据时将arg强转成int*然后进行解引用,重复以上的操作,这样就可以将可变参数全部读取完毕。

vsprintf/vsnprintf

将内容printf到第一个参数所指向的字符串中,长度为第二个参数size,

将指向可变部分ap以format格式,将格式化完成后的字符串存入第一个参数,str字符串中。vsnprintf则是更安全的方式,按照用户要求的长度将其放到str中。

宏替换的使用及C++14语法的使用

考虑到用户便捷和使用的方便,可以使用宏的方式对日志的调用以及传参进行替换,结合C++14的语法特性对其进行do while操作。

cpp 复制代码
#define LOG(level,format,...)
    do
    {
        LogMessage(__FILE__,__LINE__,gIsSave,level,format,##__VA_ARGS__);
    }while(0)

//通过宏来直接对gIs进行修改
#define EnableFile()//向文件写入日志
    do
    {
        gIsSave=true;
    }while(0)
#define EnableScreen()//向显示器写入日志
    do
    {
        gIsSave=false;
    }while(0)
相关推荐
AOwhisky2 小时前
Linux(CentOS)系统管理入门笔记(第二十一期)——防火墙管理(Firewalld)——zone、服务端口、富规则与端口转发
linux·运维·笔记·安全·centos·防火墙
腾飞开源2 小时前
01_K8s干货笔记之认识K8s
运维·笔记·云原生·容器·kubernetes·k8s·容器化部署
tg_xianheyun8 小时前
CDN节点分布如何影响网页加载速度和用户体验
服务器·cdn加速·全球访问优化
lsh曙光8 小时前
延时at指令和定时cron指令
linux·服务器·网络
圆山猫9 小时前
[Virtualization](四):Linux KVM/RISC-V 的 vCPU 运行路径
java·linux·risc-v
布鲁飞丝9 小时前
vivo Pulsar 万亿级消息处理实践()-Ansible运维部署
运维·ansible
XR1234567889 小时前
企业全光网络架构选型技术白皮书:从物理层到运维层的全链路分析
运维·网络·架构
似的8359 小时前
一步一步学习使用FireMonkey动画() 使用TAnimator类创建动画
linux·学习·nginx
HiDev_9 小时前
【非标自动化】2、认识元器件(直线模组)
运维·自动化
夏殇之殁10 小时前
包中创建自定义列表项。 . 使用自定义列表项进行数据绑定 . 将天气预报数据保存到本地内存表,通过LiveBindings进行显示。 ...
服务器·前端·javascript