原文链接:
一、,需求
(1)封装一个c/c++日志库,提供格式打印接口,编写程序代码时方便使用;
(2) 格式打印接口支持可变参数;
(3)格式打印接口封装成可变参数宏,便于使用;
二,实现
(1)提供格式打印接口;
(2)日志等级分成三个级别,分别是错误、警告、普通信息;
(3)支持输出到终端,同时支持输出到指定日志文件;
(4)格式打印接口支持可变参数;
(5)打印字符串长度无限制;
三,源码
(1)messages.h
/**
*****************************************************************************
* Copyright (C), 2023-2024
*
* @file messages.h
* @brief printf pretty
*
*
* @author sbinhuang
* @date 2023-06-28
* @version v1.0.0 20230628
*----------------------------------------------------------------------------
* @note 历史版本 修改人员 修改日期 修改内容
* @note v1.0 sbinhuang 2023-06-28 1.创建
*
*****************************************************************************
*/
#ifndef _SELF_UTILITY_MESSAGES_H_
#define _SELF_UTILITY_MESSAGES_H_
#include <iostream>
#include <fstream>
namespace SelfUtility {
// message type
enum MessageType {
NONE = 0,
ERROR = 1,
WARN = 2,
INFO = 3
};
class Messages {
public:
// default close file and enable terminal output
static bool Init();
// open log file
// mode = true, open or create file and clear file content
// mode = false, open or create file, doesn't clear file content
static bool OpenLogFile(const char *file_name, bool mode = 0);
// close log file
static bool CloseLogFile();
// enable terminal output
static bool EnableTerminalOutput();
// disable terminal output
static bool DisableTerminalOutput();
// print message for variable argument
static bool Message(const MessageType &type, const char *file_name,
int line_number, const char *format, ...);
// print message for determine argument
static bool Message(const MessageType &type, const char *file_name,
int line_number, const char *format);
private:
static std::ofstream _os;
static bool _terminal_output;
static bool _write_file;
};
} // namespace SelfUtility
#define LOG_ERROR(format, ...) do { \
SelfUtility::Messages::Message(SelfUtility::MessageType::ERROR, \
__FILE__, __LINE__, format, __VA_ARGS__); \
} while (0)
#define LOG_WARN(format, ...) do { \
SelfUtility::Messages::Message(SelfUtility::MessageType::WARN, \
__FILE__, __LINE__, format, __VA_ARGS__); \
} while (0)
#define LOG_INFO(format, ...) do { \
SelfUtility::Messages::Message(SelfUtility::MessageType::INFO, \
__FILE__, __LINE__, format, __VA_ARGS__); \
} while (0)
#define LOG_PRINT(format, ...) do { \
SelfUtility::Messages::Message(SelfUtility::MessageType::NONE, \
__FILE__, __LINE__, format, __VA_ARGS__); \
} while (0)
#define LOG_INIT() do { \
SelfUtility::Messages::Init(); \
} while (0)
#endif // _SELF_UTILITY_MESSAGES_H_
(2) messages.cpp
/**
*****************************************************************************
* Copyright (C), 2023-2024
*
* @file messages.cpp
* @brief printf pretty
*
*
* @author sbinhuang
* @date 2023-06-28
* @version v1.0.0 20230628
*----------------------------------------------------------------------------
* @note 历史版本 修改人员 修改日期 修改内容
* @note v1.0 sbinhuang 2023-06-28 1.创建
*
*****************************************************************************
*/
#include "messages.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <iostream>
#include <fstream>
#include <string>
using SelfUtility::MessageType;
using SelfUtility::Messages;
// static variable define for class Messages
std::ofstream Messages::_os;
bool Messages::_write_file;
bool Messages::_terminal_output;
// initial log print, default output terminal
bool Messages::Init() {
if (_os.is_open()) _os.close();
_terminal_output = true;
_write_file = false;
return true;
}
// Open log file
// mode = true, open or create file and clear file content
// mode = false, open or create file, doesn't clear file content
bool Messages::OpenLogFile(const char *file_name, bool mode) {
if (!file_name) {
std::cout << "Log file name is null pointer!" << std::endl;
return false;
}
// open file
if (true == mode) {
_os.open(file_name, std::ios::out);
} else {
_os.open(file_name, std::ios::app);
}
if (!_os.is_open()) {
std::cout << "File open failed!" << "(" << file_name
<< ")" << std::endl;
return false;
}
_write_file = true;
return true;
}
// close log file
bool Messages::CloseLogFile() {
if (_os.is_open()) _os.close();
_write_file = false;
return true;
}
// enable terminal output
bool Messages::EnableTerminalOutput() {
_terminal_output = true;
return true;
}
// disable terminal output
bool Messages::DisableTerminalOutput() {
_terminal_output = false;
return true;
}
// print message for variable argument
bool Messages::Message(const MessageType &type, const char *file_name,
int line_number, const char *format, ...) {
// print title
if (MessageType::ERROR == type) {
if (true == _terminal_output) {
if (file_name) {
std::cout << "[" << file_name << ": "
<< line_number << "]";
}
std::cout << "ERROR: ";
}
if (true == _write_file) {
if (file_name) {
_os << "[" << file_name << ": "
<< line_number << "]";
}
_os << "ERROR: ";
}
} else if (MessageType::WARN == type) {
if (true == _terminal_output) {
if (file_name) {
std::cout << "[" << file_name << ": "
<< line_number << "]";
}
std::cout << "WARN: ";
}
if (true == _write_file) {
if (file_name) {
_os << "[" << file_name << ": "
<< line_number << "]";
}
_os << "WARN: ";
}
} else if (MessageType::INFO == type) {
if (true == _terminal_output) std::cout << "INFO: ";
if (true == _write_file) std::cout << "INFO: ";
}
// print message
char *buf = NULL;
va_list arg_ptr;
va_start(arg_ptr, format);
vasprintf(&buf, format, arg_ptr);
va_end(arg_ptr);
if (true == _terminal_output) {
std::cout << buf;
}
if (true == _write_file) {
_os << buf;
}
free(buf);
buf = NULL;
return true;
}
// print message for determine argument
bool Messages::Message(const MessageType &type, const char *file_name,
int line_number, const char *format) {
// print title
if (MessageType::ERROR == type) {
if (true == _terminal_output) {
if (file_name) {
std::cout << "[" << file_name << ": "
<< line_number << "]";
}
std::cout << "ERROR: ";
}
if (true == _write_file) {
if (file_name) {
_os << "[" << file_name << ": "
<< line_number << "]";
}
_os << "ERROR: ";
}
} else if (MessageType::WARN == type) {
if (true == _terminal_output) {
if (file_name) {
std::cout << "[" << file_name << ": "
<< line_number << "]";
}
std::cout << "WARN: ";
}
if (true == _write_file) {
if (file_name) {
_os << "[" << file_name << ": "
<< line_number << "]";
}
_os << "WARN: ";
}
} else if (MessageType::INFO == type) {
if (true == _terminal_output) std::cout << "INFO: ";
if (true == _write_file) std::cout << "INFO: ";
}
// print message
if (true == _terminal_output) std::cout << format;
if (true == _write_file) _os << format;
return true;
}