宏定义log输出

log输出宏定义

丈夫非无泪,不洒离别间。

首先看几个编译器预定义的变量

C&C++预处理器定义了几个对于程序调试很有用的名字:

  • __func__存放函数的名字
  • __FILE__存放文件名的字符串字面值
  • __LINE__存放当前行号的整型字面值
  • __TIME__存放文件编译时间的字符串字面值
  • __DATE__存放文件编译日期的字符串字面值

示例:

void main()
{
    printf("%s hello", __func__);
}

则会输出:

main hello

调试的时候非常方便看是哪里输出的:

image-20211110151723335

看到这里懂了吧。那么想不想拥有它呢,接着看吧。

一、使用C++ 类特性的宏定义

这里我们需要定义一个类如下:

".h"
    
#define AHINFO\
    AH_LOG::getinstance().printTitle(__func__, "Info").printS

#define AHWARNING\
    AH_LOG::getinstance().printTitle(__func__, "Warning").printS

#define AHERROR\
    AH_LOG::getinstance().printTitle(__func__, "Error").printS
    
class AH_LOG{
    AH_LOG();
    ~AH_LOG();
  public:
    AH_LOG &printS(const char *fmt, ...);
    AH_LOG &printTitle(const char *funcName, const char *type);
    static AH_LOG &getinstance();   // 返回自己
  private:
    static AH_LOG* singleInstance;  // 声明一个静态类
};
".cpp"
#include "AH_log.hpp"
#include <iostream>
#include <string>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
    
AH_LOG* AH_LOG::singleInstance = new AH_LOG();

AH_LOG &AH_LOG::printS(const char *fmt, ...){
    char log[500] = {0};
    va_list args;
    va_start(args, fmt);
    vsnprintf(log, sizeof(log) - 1, fmt, args);
    va_end(args);
    std::cout << log;

    if(log[strlen(log)] != '\n')
        std::cout << std::endl;

    return *this;
}

AH_LOG &AH_LOG::printTitle(const char *funcName, const char *type)
{
    std::cout << "[" << type << "] @" << funcName << " ";
    return *this;
}

AH_LOG &AH_LOG::getinstance(){
    return *singleInstance;
}

总的来说就是定义一个返回自己的打印 log 头信息的函数,返回自己后再调用其自定义的PrintS 函数。 大家可以发挥创意,根据需要自己设计自己的LOG 输出函数。

后面会有完整例程。

二、使用宏定义(__VA_ARGS__)输出log

这个特性是可以C 和 C++ 通用的。 如下:

#define LOG(...)    printf(__VA_ARGS__)

这样子 我们使用 LOG("hello"); 就相当于 printf("hello");

示例如下:

".h"

#define UGPRINT(...)    printS(__VA_ARGS__)
#define UGINFO(...)     printLogS(__func__, " info", __VA_ARGS__)
#define UGDEBUG(...)    printLogS(__func__, "debug", __VA_ARGS__)
#define UGERROR(...)    printLogS(__func__, "error", __VA_ARGS__)

void printS(const char *fmt, ...);

void printLogS(const char* funcname,const char* type, const char *fmt, ...);

void ug_log_hal_print(const char *str);
/* C libs */
#include <stdarg.h>
#include <stdio.h>
#include <string.h>

/* my libs */
#include "ug_log.h"

void printS(const char *fmt, ...){
    char log[300] = {0};
    va_list args;
    va_start(args, fmt);
    vsnprintf(log, sizeof(log) - 1, fmt, args);
    va_end(args);
    ug_log_hal_print(log);
    // if(log[strlen(log)] != '\n')
    //     ug_log_hal_print("\n");
}

void printLogS(const char* funcname,const char* type, const char *fmt, ...){
    char log[300] = {0};
    va_list args;
    va_start(args, fmt);
    vsnprintf(log, sizeof(log) - 1, fmt, args);
    va_end(args);

    ug_log_hal_print("[");
    ug_log_hal_print(type);
    ug_log_hal_print("] @");
    ug_log_hal_print(funcname);
    ug_log_hal_print(" ");
    ug_log_hal_print(log);
    if(log[strlen(log)] != '\n')
        ug_log_hal_print("\n");
}

__attribute__((weak)) void ug_log_hal_print(const char* str){
    /* HAL Lib sample */
    // uint32_t cnt = 0;
    // while (str[cnt++] != '\0');
    // HAL_UART_Transmit(&UART1_Handler, str, cnt-1, 500);

    /* STD Lib sample */
    // UartSendStr(USART1, str);
}

三、完整示例

1. C++ 类特性示例代码

.hpp
/*! @file AH_log.hpp
 *  @version 0.0.1
 *  @date April 07 2021
 *
 *  @brief
 *  Print and out log info.
 *
 */
#ifndef __AH_LOG_HPP_
#define __AH_LOG_HPP_

#include <string>
#include <fstream>

// store log file local
// #define LOG_LOCALL_STORE



#if defined(LOG_LOCALL_STORE)
extern std::ofstream g_logFile;  // log file handle
#endif


namespace AH
{

#define AHINFO\
    AH_LOG::getinstance().printTitle(__func__, "Info").printS

#define AHWARNING\
    AH_LOG::getinstance().printTitle(__func__, "Warning").printS

#define AHERROR\
    AH_LOG::getinstance().printTitle(__func__, "Error").printS

#define AHTIPS\
    AH_LOG::getinstance().printTitle(__func__, "Tips").printS

#define AHACTION\
    AH_LOG::getinstance().printTitle(__func__, "Action").printS

typedef enum AH_Log_Mode {
    LOG_MODE_DEFAULT = 0,
    LOG_MODE_SIMPLE,
    LOG_MODE_COMPLEX,
    LOG_MODE_STORE_LOCALLY
} AH_Log_Mode;

typedef enum AH_Log_Type {
    LOG_TYPE_INFO = 0,
    LOG_TYPE_WARNING,
    LOG_TYPE_ACTION,
    LOG_TYPE_TIPS,
    LOG_TYPE_ERROR
} AH_Log_Type;






class AH_LOG{

    AH_LOG();
    ~AH_LOG();

  public:
    AH_LOG &printS(const char *fmt, ...);
    AH_LOG &printTitle(const char *funcName, const char *type);
    static AH_LOG &getinstance();   // 返回自己

  private:
    tm *getSystemTime(void);

    static AH_LOG* singleInstance;  // 声明一个静态类
    bool storeLocall = false;
    
    time_t tt;  // time for log output.
    char fileName[255];
};



};     // namespace AH
#endif // !__AH_LOG_HPP_
.cpp
/*! @file AH_log.cpp
 *  @version 0.0.1
 *  @date April 07 2021
 *
 *  @brief
 *  Print and out log info.
 *
 */


#include "AH_log.hpp"
#include <iostream>
#include <string>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

#if defined(LOG_LOCALL_STORE)
std::ofstream g_logFile;  // log file handle
#endif 


namespace AH
{
AH_LOG* AH_LOG::singleInstance = new AH_LOG();


AH_LOG::AH_LOG()
{
    
    #if defined(LOG_LOCALL_STORE)
    tm *time = getSystemTime();
    // AHINFO("Current system time: %d-%02d-%02d %02d:%02d:%02d",    
    //         time->tm_year + 1900,
    //         time->tm_mon + 1,
    //         time->tm_mday,
    //         time->tm_hour,
    //         time->tm_min,
    //         time->tm_sec);

    // AHINFO("Create Log File.");
    sprintf(fileName, "/home/dji/osdkDemo/Log--%d-%02d-%02d--%02d:%02d.txt",
            time->tm_year + 1900,
            time->tm_mon + 1,
            time->tm_mday,
            time->tm_hour,
            time->tm_min);
    g_logFile.open(fileName , std::ios::app);
  
    
    if (g_logFile.is_open())
    {
        // AHINFO("open file success");
        
        // logFile << "This is a line.\n";
        // logFile << "This is another line.\n"; 
        // g_logFile.close();
        return;
    }
    exit(-1);
    #endif
}
AH_LOG::~AH_LOG()
{
    #if defined(LOG_LOCALL_STORE)

    g_logFile.close();
    #endif
}


/*
format for tm*
    AHINFO("current Time:%d-%02d-%02d %02d:%02d:%02d",    
            time->tm_year + 1900,
            time->tm_mon + 1,
            time->tm_mday,
            time->tm_hour,
            time->tm_min,
            time->tm_sec);
*/
tm* AH_LOG::getSystemTime(void)
{
    time( &tt );
    tt = tt + 8*3600;  // transform the time zone
    tm* t= gmtime( &tt );
    return t;
}


AH_LOG &AH_LOG::printS(const char *fmt, ...){
    char log[500] = {0};
    va_list args;
    va_start(args, fmt);
    vsnprintf(log, sizeof(log) - 1, fmt, args);
    va_end(args);
    std::cout << log;

    if(log[strlen(log)] != '\n')
        std::cout << std::endl;
    #if defined(LOG_LOCALL_STORE)

    g_logFile << log << "\n";
    g_logFile.flush();
    #endif
    return *this;
}

AH_LOG &AH_LOG::printTitle(const char *funcName, const char *type){


    #if defined(LOG_LOCALL_STORE)
    char timeStamp[255] = "hello";
    tm *time = getSystemTime();
    sprintf(timeStamp, "%02d:%02d:%02d || ",
            time->tm_hour,
            time->tm_min,
            time->tm_sec);

    // g_logFile.open(fileName , std::ios::app);        
    g_logFile << timeStamp << "[" << type << "] @" << funcName << " ";
    // g_logFile.close();
    #endif
    std::cout << "[" << type << "] @" << funcName << " ";
    return *this;
}

AH_LOG &AH_LOG::getinstance(){
    return *singleInstance;
}








void printLog(const char *funcName, const char *log, const char *type, AH_Log_Mode mode){

    std::string log_type;

    log_type = type;

    switch (mode)
    {
    case LOG_MODE_DEFAULT:
        std::cout << "@" << funcName << " [" + log_type + "] " + log;
        if(log[strlen(log)] != '\n')
            std::cout << std::endl;

        break;
    case LOG_MODE_SIMPLE:
        std::cout << "@" << funcName << "[" + log_type + "] =>|| " + log ;
        if(log[strlen(log)] != '\n')
            std::cout << std::endl;
        break;
    case LOG_MODE_STORE_LOCALLY:
        std::cout << "@" << funcName << "[" + log_type + "] =>|| " + log;
        if(log[strlen(log)] != '\n')
            std::cout << std::endl;
        //TODO Store log locally.
        break;
    case LOG_MODE_COMPLEX:
        std::cout << "============ " << "@" << funcName <<  "  [" + log_type + "]  ============ \n";
        std::cout << log;
        if(log[strlen(log)] != '\n')
            std::cout << std::endl;
        std::cout << "====================================== \n";
        break;

    default:
        break;
    }

}
void printLog(const char *log, const char *type, AH_Log_Mode mode){

    std::string log_type;

    log_type = type;

    switch (mode)
    {
    case LOG_MODE_DEFAULT:
        std::cout << "[" + log_type + "] " + log;
        if(log[strlen(log)] != '\n')
            std::cout << std::endl;
        break;
    case LOG_MODE_SIMPLE:
        std::cout << "[" + log_type + "] =>|| " + log ;
        if(log[strlen(log)] != '\n')
            std::cout << std::endl;
        break;
    case LOG_MODE_STORE_LOCALLY:
        std::cout << "[" + log_type + "] =>|| " + log;
        if(log[strlen(log)] != '\n')
            std::cout << std::endl;
        //TODO Store log locally.
        break;
    case LOG_MODE_COMPLEX:
        std::cout << "==============  [" + log_type + "]  ============== \n";
        std::cout << log;
        if(log[strlen(log)] != '\n')
            std::cout << std::endl;
        std::cout << "====================================== \n";
        break;

    default:
        break;
    }

}


}; // namespace AH

2. __VA_ARGS__特性示例代码

.h
/*! @file ug_log.h
 *  @version 0.0.1
 *  @date May 12 2021
 *
 *  @brief
 *  Print and out log info.
 *
 */


#ifndef __UG_LOG_H
#define __UG_LOG_H

#define UGPRINT(...)    printS(__VA_ARGS__)
#define UGINFO(...)     printLogS(__func__, " info", __VA_ARGS__)
#define UGDEBUG(...)    printLogS(__func__, "debug", __VA_ARGS__)
#define UGERROR(...)    printLogS(__func__, "error", __VA_ARGS__)

void printS(const char *fmt, ...);

void printLogS(const char* funcname,const char* type, const char *fmt, ...);

void ug_log_hal_print(const char *str);

#endif // !__UG_LOG_H
.c
/*! @file ug_log.c
 *  @version 0.0.1
 *  @date May 12 2021
 *
 *  @brief
 *  Print and out log info.
 *
 */


/* C libs */
#include <stdarg.h>
#include <stdio.h>
#include <string.h>

/* my libs */
#include "ug_log.h"
// #include "usart.h"


void printS(const char *fmt, ...){
    char log[300] = {0};
    va_list args;
    va_start(args, fmt);
    vsnprintf(log, sizeof(log) - 1, fmt, args);
    va_end(args);
    ug_log_hal_print(log);
    // if(log[strlen(log)] != '\n')
    //     ug_log_hal_print("\n");


}

void printLogS(const char* funcname,const char* type, const char *fmt, ...){
    char log[300] = {0};
    va_list args;
    va_start(args, fmt);
    vsnprintf(log, sizeof(log) - 1, fmt, args);
    va_end(args);

    ug_log_hal_print("[");
    ug_log_hal_print(type);
    ug_log_hal_print("] @");
    ug_log_hal_print(funcname);
    ug_log_hal_print(" ");
    ug_log_hal_print(log);
    if(log[strlen(log)] != '\n')
        ug_log_hal_print("\n");


}

__attribute__((weak)) void ug_log_hal_print(const char* str){

    /* HAL Lib sample */
    // uint32_t cnt = 0;
    // while (str[cnt++] != '\0');
    // HAL_UART_Transmit(&UART1_Handler, str, cnt-1, 500);

    /* STD Lib sample */
    // UartSendStr(USART1, str);
}




本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!