linux c/c++日志输出

介绍一个在linux下c++开发的一个日志输出的小功能模块,在下面的几个文件当中,代码的设计思路值得我们好好的借鉴

  1 /*
  2  * ILogger.h
  3  *
  4  *  Created on: 2016��1��7��
  5  *      Author: Administrator
  6  */
  7 
  8 #ifndef FRAME_LOG_LOGGER_H_
  9 #define FRAME_LOG_LOGGER_H_
 10 #include <iostream>
 11 #include "Mutex.h"
 12 #include<fstream>
 13 #include<string>
 14 
 15 using namespace std;
 16 
 17 const int MaxFilePathLen = 1024;
 18 const char PathSplitChar = '/';
 19 namespace FrameWork {
 20 enum LogLevel{
 21     /// <summary>
 22     /// 调试
 23     /// </summary>
 24     DEBUG = -1,
 25     /// <summary>
 26     /// 普通日志
 27     /// </summary>
 28     INFO = 0,
 29     /// <summary>
 30     /// 警告
 31     /// </summary>
 32     WARN,
 33     /// <summary>
 34     /// 错误
 35     /// </summary>
 36     ERROR,
 37     /// <summary>
 38     /// 崩溃
 39     /// </summary>
 40     FATAL,
 41     /// <summary>
 42     /// 超出错误级别
 43     /// </summary>
 44     OFF
 45 };
 46 
 47 
 48 class ILogger {
 49 public:
 50     //
 51     virtual ~ILogger() {
 52     }
 53 
 54 //利用宏定义,来简化代码输出,值得推荐
 55 #define ABSTRACT_LOG_FUNC(name) 
 56     virtual void name(string msg)=0; 
 57     virtual void name(const char* fmt,...)=0;
 58 
 59     ABSTRACT_LOG_FUNC(Debug)
 60     ABSTRACT_LOG_FUNC(Info)
 61     ABSTRACT_LOG_FUNC(Warn)
 62     ABSTRACT_LOG_FUNC(Error)
 63     ABSTRACT_LOG_FUNC(Fatal)
 64 
 65 #undef ABSTRACT_LOG_FUNC
 66 #define ABSTRACT_LOG_FUNC_X(name) 
 67     virtual void name(LogLevel lv,string msg)=0; 
 68     virtual void name(LogLevel lv,const char* fmt,...)=0;
 69     virtual void name(const char* file,int line,LogLevel lv,string msg)=0;
 70     virtual void name(const char* file,int line,LogLevel lv,const char* fmt,...)=0;
 71     ABSTRACT_LOG_FUNC_X(Log)
 72 
 73 #undef LOG_FUNC_X
 74 };
 75 
 76 class Logger: public ILogger {
 77     std::string logPath;
 78     std::string logPrefix;
 79     std::fstream logFile;
 80     LogLevel level;
 81     Mutex mutex;
 82 
 83     Logger(LogLevel level, char * folder, char * prefix);
 84 
 85 public:
 86     static Logger& GetInstance();
 87     static Logger* GetInstancePtr();
 88     virtual ~Logger();
 89     inline fstream & stream() {
 90         return logFile;
 91     }
 92 
 93 #define DECLARE_LOG_FUNC(name) 
 94     virtual void name(string msg); 
 95     virtual void name(const char* fmt,...);
 96 
 97 #define DECLARE_LOG_FUNC_X(name) 
 98     virtual void name(LogLevel lv,string msg); 
 99     virtual void name(LogLevel lv,const char* fmt,...);
100     virtual void name(const char* file,int line,LogLevel lv,string msg);
101     virtual void name(const char* file,int line,LogLevel lv,const char* fmt,...);
102 
103     DECLARE_LOG_FUNC(Debug)
104     DECLARE_LOG_FUNC(Info)
105     DECLARE_LOG_FUNC(Warn)
106     DECLARE_LOG_FUNC(Error)
107     DECLARE_LOG_FUNC(Fatal)
108 
109     DECLARE_LOG_FUNC_X(Log)
110 
111 #undef DECLARE_LOG_FUNC_X
112 #undef DECLARE_LOG_FUNC
113 
114 };
115 
116 class LogMessage {
117     Logger* logger;
118     static Mutex mutex;
119 public:
120     LogMessage(const char* file, int line, LogLevel lv);
121     LogMessage(LogLevel lv);
122     ostream& stream() {
123         return logger->stream();
124     }
125     virtual ~LogMessage();
126 };
127 
128 void InitLogging(const char* filename, LogLevel minlevel,
129         const char* destFolder);
130 void CloseLogging();
131 
132 #define LOG(level) LogMessage(__FILE__, __LINE__,level).stream()
133 
134 #define LOGFILE(level) LogMessage(level).stream()
135 
136 #define LOG_IF(severity, condition) 
137     !(condition) ? (void) 0 : LOG(severity)
138 #define LOG_ASSERT(condition)  
139     LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition
140 #define CHECK(condition)  
141     LOG_IF(FATAL, !(condition)) 
142     << "Check failed: " #condition " "
143 
144 } /* namespace FrameWork */
145 
146 #endif /* FRAME_LOG_LOGGER_H_ */
View Code

Logger的实现,在文件内定义了输助函数的使用

  1 /*
  2  * Logger.cpp
  3  *
  4  *      Author: liu xw
  5  */
  6 
  7 #include "Logger.h"
  8 #include<cstring>
  9 #include<time.h>
 10 #include<cstdarg>
 11 #include<cstdlib>
 12 #include<assert.h>
 13 #include "FileHelper.h"
 14 #include "Mutex.h"
 15 namespace FrameWork {
 16 Mutex LogMessage::mutex;
 17 static char _defaltFolder[]="/var/tmp/";
 18 static char _appName[MaxFilePathLen];
 19 static char _appFolder[MaxFilePathLen];
 20 static char _destFolder[MaxFilePathLen];
 21 static char _destPrefix[MaxFilePathLen];
 22 static LogLevel _destLevel;
 23 static char _levelInfos[][16]={
 24     "Debug","Info","Warn","Error","Fatal"
 25 };
 26 const int BUFFER_SIZE = 8196;
 27 static char _gBuffer[BUFFER_SIZE];
 28 void combine_folder(char** destpath, char* basefolder,char* relativefolder)
 29 {
 30     int lenb = strlen(basefolder);
 31     int lenr = strlen(relativefolder);
 32     char* pret = (char*)malloc((lenb+lenr+1)*sizeof(char));
 33     int pos=lenb-1;
 34     memset(pret,0,lenb+lenr+1);
 35     while(pos>0 && ( basefolder[pos]!='/'))
 36         pos--;
 37     strncpy(*destpath,basefolder,pos+1);
 38     if(relativefolder[0] == '\' || relativefolder[0] == '/'){
 39         strncpy(*destpath+pos+1,relativefolder+1,lenr-1);
 40     }else{
 41         strncpy(*destpath+pos+1,relativefolder,lenr);
 42     }
 43 }
 44 
 45 static void InitPaths(const char* filename,const char* destFolder)
 46 {
 47     memset(_appName,0,MaxFilePathLen);
 48     memset(_appFolder,0,MaxFilePathLen);
 49     memset(_destFolder,0,MaxFilePathLen);
 50     memset(_destPrefix,0,MaxFilePathLen);
 51 
 52     strcpy(_appName,filename);
 53     int len = strlen(filename),lend;
 54     int pos = len-1,posd,start;
 55     while(pos >0 && filename[pos] != PathSplitChar)
 56         pos--;
 57     strncpy(_appFolder,filename,pos+1);
 58     lend = strlen(destFolder);
 59     posd = lend-1;
 60     if(destFolder[lend-1] != PathSplitChar) {
 61         //has prefix
 62         while(posd >0 && destFolder[posd] != PathSplitChar)
 63             posd--;
 64     }
 65     if(destFolder[0] == '.' && destFolder[1] == PathSplitChar){
 66         strncpy(_destFolder,filename,pos+1);
 67         start = 2;
 68     }   else{
 69         pos = 8;
 70         strcpy(_destFolder,_defaltFolder);
 71         if(destFolder[0] != PathSplitChar){
 72             start = 0;
 73         }else{
 74             start = 1;
 75         }
 76     }
 77     strncpy(_destFolder+pos+1,destFolder+start,posd-start+1);
 78     strncpy(_destPrefix,filename,pos+1);
 79     strncpy(_destPrefix+pos+1,destFolder+start,lend-start);
 80 }
 81 
 82 void InitLogging(const char* filename,LogLevel minlevel,const char* destFolder)
 83 {
 84     InitPaths(filename,destFolder);
 85     _destLevel = minlevel;
 86 }
 87 
 88 
 89 
 90 static string GetLocalDate(void)
 91 {
 92     time_t t = time(0);
 93     tm *ld;
 94     char tmp[64] = "";
 95     ld=localtime(&t);
 96     strftime(tmp,sizeof(tmp),"%Y-%m-%d",ld);
 97     return string(tmp);
 98 }
 99 static string GetCurTime(void)
100 {
101     time_t t = time(0);
102     tm *ld;
103     char tmp[64] = "";
104     ld=localtime(&t);
105     strftime(tmp,sizeof(tmp),"%Y-%m-%d %H:%M:%S",ld);
106     return string(tmp);
107 }
108 
109 Logger::Logger(LogLevel level,char * folder,char * prefix)
110     :level(level)
111 {
112     std::string path;
113     path.append(prefix);
114     path.append(GetLocalDate());
115     path.append(".log");
116     FileHelper::CreateDir(folder);
117     logPrefix.append(prefix);
118     logPath = path;
119     logFile.open(path.c_str(),ios::app|ios::out);
120     logFile<<"Log file created at:"<<GetCurTime()<<endl;
121 }
122 
123 Logger::~Logger() {
124     logFile.close();
125 }
126 
127 #define IMPLEMENT_LOG_FUNC1(cname,fname,lv) 
128 void cname::fname(string msg) {
129     if(level <= lv){
130         WriterMutexLock lock(&mutex);
131         logFile<<"["<<GetCurTime().c_str()<<"][" #lv "]"<<msg.c_str()<<endl;
132         logFile.flush();
133     }
134 }
135 
136 #define PRINT_ARGS_TO_BUFFER(fmt,buf) 
137     {
138         memset(buf,0,sizeof(buf));
139         va_list argp;
140         va_start(argp,fmt);
141         vsprintf(buf,fmt,argp);
142         va_end(argp);
143     }
144 
145 #define IMPLEMENT_LOG_FUNC2(cname,fname,lv) 
146 void cname::fname(const char* format,...) {
147     if(level <= lv){
148         WriterMutexLock lock(&mutex);
149         PRINT_ARGS_TO_BUFFER(format,_gBuffer)
150         logFile<<"["<<GetCurTime().c_str()<<"][" #lv "]"<<_gBuffer<<endl;
151         logFile.flush();
152     }
153 }
154 
155 
156 #define IMPLEMENT_LOG_FUNC(cname,fname,lv) 
157 IMPLEMENT_LOG_FUNC1(cname,fname,lv)
158 IMPLEMENT_LOG_FUNC2(cname,fname,lv)
159 
160 IMPLEMENT_LOG_FUNC(Logger,Debug,DEBUG)
161 IMPLEMENT_LOG_FUNC(Logger,Info,INFO)
162 IMPLEMENT_LOG_FUNC(Logger,Warn,WARN)
163 IMPLEMENT_LOG_FUNC(Logger,Error,ERROR)
164 IMPLEMENT_LOG_FUNC(Logger,Fatal,FATAL)
165 
166 Logger& Logger::GetInstance() {
167     static Logger _logger(_destLevel,_destFolder,_destPrefix);
168     return _logger;
169 }
170 
171 void Logger::Log(LogLevel lv, string msg) {
172     if(level <= lv){
173         WriterMutexLock lock(&mutex);
174         logFile<<"["<<GetCurTime().c_str()<<"]["<<_levelInfos[lv+1]<<"]"<<msg.c_str()<<endl;
175         logFile.flush();
176     }
177 }
178 
179 void Logger::Log(LogLevel lv, const char* format,...) {
180     if(level <= lv){
181         WriterMutexLock lock(&mutex);
182         PRINT_ARGS_TO_BUFFER(format,_gBuffer)
183         logFile<<"["<<GetCurTime().c_str()<<"]["<<_levelInfos[lv+1]<<"]"<<_gBuffer<<endl;
184         logFile.flush();
185     }
186 }
187 
188 void Logger::Log(const char* file, int line, LogLevel lv, string msg) {
189     if(level <= lv){
190         WriterMutexLock lock(&mutex);
191         logFile<<"["<<GetCurTime().c_str()<<"]["<<_levelInfos[lv+1]<<"]["<<file<<"]["<<line<<"]"<<msg.c_str();
192         logFile.flush();
193     }
194 }
195 
196 Logger* Logger::GetInstancePtr() {
197     return &GetInstance();
198 }
199 
200 void Logger::Log(const char* file, int line, LogLevel lv, const char* format,...) {
201     if(level <= lv){
202         WriterMutexLock lock(&mutex);
203         PRINT_ARGS_TO_BUFFER(format,_gBuffer)
204         logFile<<"["<<GetCurTime().c_str()<<"]["<<_levelInfos[lv+1]<<"]["<<file<<"]["<<line<<"]"<<_gBuffer;
205         logFile.flush();
206     }
207 }
208 
209 LogMessage::LogMessage(const char* file, int line, LogLevel lv) {
210     logger = Logger::GetInstancePtr();
211     mutex.Lock();
212     logger->Log(file,line,lv,"");
213 }
214 
215 LogMessage::LogMessage(LogLevel lv) {
216     logger = Logger::GetInstancePtr();
217     mutex.Lock();
218     logger->Log(lv,"");
219 }
220 
221 LogMessage::~LogMessage() {
222     logger->stream()<<endl;
223     logger->stream().flush();
224     mutex.Unlock();
225 }
226 
227 } /* namespace FrameWork */
View Code

读写文件类:FileHelper

  1 /*
  2  * FileHelper.h
  3  *
  4  *  Created on: 2013年9月10日
  5  *      Author: Administrator
  6  */
  7 
  8 #ifndef FILEHELPER_H_
  9 #define FILEHELPER_H_
 10 #include <string>
 11 #include <vector>
 12 #include <fstream>
 13 #include <stdio.h>
 14 #ifdef _WIN32
 15 #include <direct.h>
 16 #include <io.h>
 17 #else
 18 #include <stdarg.h>
 19 #include <sys/stat.h>
 20 #endif
 21 
 22 namespace FrameWork {
 23 #ifdef _WIN32
 24 #define ACCESS _access
 25 #define MKDIR(a) _mkdir((a))
 26 #else
 27 #define ACCESS access
 28 #define MKDIR(a) mkdir((a),0755)
 29 #endif
 30 
 31 class FileHelper {
 32 public:
 33     static bool save(const std::string filename, std::string& content) {
 34         FILE *file = fopen(filename.c_str(), "wb");
 35 
 36         if (file == NULL)
 37             return false;
 38         fwrite(content.c_str(), sizeof(char), content.size(), file);
 39         fclose(file);
 40         return true;
 41     }
 42 
 43     // used to open binary file
 44     static bool open(const std::string filename, std::string& content) {
 45         FILE *file = fopen(filename.c_str(), "rb");
 46 
 47         if (file == NULL)
 48             return false;
 49 
 50         fseek(file, 0, SEEK_END);
 51         int len = ftell(file);
 52         rewind(file);
 53         content.clear();
 54         char *buffer = new char[len];
 55         fread(buffer, sizeof(char), len, file);
 56         content.assign(buffer, len);
 57         delete[] buffer;
 58 
 59         //int nRead;
 60         //content.clear();
 61         //char buffer[80];
 62         //while(!feof(file)){
 63         //  nRead = fread(buffer,sizeof(char),sizeof(buffer),file);
 64         //  if(nRead > 0){
 65         //      content.append(buffer);
 66         //  }
 67         //}
 68         fclose(file);
 69         return true;
 70     }
 71 
 72     // used to open text file
 73     static bool open(const std::string file_name,
 74             std::vector<std::string>& lines) {
 75         std::ifstream file(file_name.c_str(), std::ios::in);
 76         if (!file) {
 77             return false;
 78         }
 79 
 80         lines.clear();
 81         char buffer[BUFFER_SIZE];
 82 
 83         while (file.getline(buffer, BUFFER_SIZE, '
')) {
 84             lines.push_back(buffer);
 85         }
 86 
 87         return true;
 88     }
 89     static bool CreateDir(const char *pszDir) {
 90         size_t i = 0;
 91         size_t iRet;
 92         size_t iLen = strlen(pszDir);
 93         char* buf = new char[iLen + 1];
 94         strncpy(buf, pszDir, iLen + 1);
 95         for (i = 0; i < iLen; i++) {
 96             if (pszDir[i] == '\' || pszDir[i] == '/') {
 97                 buf[i] = '';
 98                 //如果不存在,创建
 99                 iRet = ACCESS(buf, 0);
100                 if (iRet != 0) {
101                     iRet = MKDIR(buf);
102                     if (iRet != 0) {
103                         delete[] buf;
104                         return false;
105                     }
106                 }
107                 //支持linux,将所有换成/
108                 buf[i] = '/';
109             }
110         }
111         delete[] buf;
112         return true;
113     }
114 
115 private:
116 
117     enum {
118         BUFFER_SIZE = 3000
119     };
120 
121 };
122 
123 } /* namespace FrameWork */
124 #endif /* FILEHELPER_H_ */
View Code

为线程安全的使用增加互斥量

  1 /*
  2  * Mutex.h
  3  *
  4  *  Created on: 2016年1月7日
  5  *      Author: Administrator
  6  */
  7 
  8 #ifndef FRAME_LOG_MUTEX_H_
  9 #define FRAME_LOG_MUTEX_H_
 10 
 11 #include <pthread.h>
 12 #include <stdlib.h>
 13 namespace FrameWork {
 14 typedef pthread_mutex_t MutexType;
 15 
 16 class Mutex {
 17 public:
 18     // Create a Mutex that is not held by anybody.  This constructor is
 19     // typically used for Mutexes allocated on the heap or the stack.
 20     // See below for a recommendation for constructing global Mutex
 21     // objects.
 22     inline Mutex();
 23 
 24     // Destructor
 25     inline ~Mutex();
 26 
 27     inline void Lock();    // Block if needed until free then acquire exclusively
 28     inline void Unlock();  // Release a lock acquired via Lock()
 29     inline bool TryLock(); // If free, Lock() and return true, else return false
 30     // Note that on systems that don't support read-write locks, these may
 31     // be implemented as synonyms to Lock() and Unlock().  So you can use
 32     // these for efficiency, but don't use them anyplace where being able
 33     // to do shared reads is necessary to avoid deadlock.
 34     inline void ReaderLock();   // Block until free or shared then acquire a share
 35     inline void ReaderUnlock(); // Release a read share of this Mutex
 36     inline void WriterLock() { Lock(); }     // Acquire an exclusive lock
 37     inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
 38 
 39     // TODO(hamaji): Do nothing, implement correctly.
 40     inline void AssertHeld() {}
 41 private:
 42     MutexType mutex_;
 43     // We want to make sure that the compiler sets is_safe_ to true only
 44     // when we tell it to, and never makes assumptions is_safe_ is
 45     // always true.  volatile is the most reliable way to do that.
 46     volatile bool is_safe_;
 47 
 48     inline void SetIsSafe() { is_safe_ = true; }
 49 
 50     // Catch the error of writing Mutex when intending MutexLock.
 51     Mutex(Mutex* /*ignored*/) {}
 52     // Disallow "evil" constructors
 53     Mutex(const Mutex&);
 54     void operator=(const Mutex&);
 55 };
 56 #define SAFE_PTHREAD(fncall)  do {   /* run fncall if is_safe_ is true */  
 57     if (is_safe_ && fncall(&mutex_) != 0) abort();                           
 58     } while (0)
 59 
 60     Mutex::Mutex()             {
 61         SetIsSafe();
 62         if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort();
 63     }
 64     Mutex::~Mutex()            { SAFE_PTHREAD(pthread_mutex_destroy); }
 65     void Mutex::Lock()         { SAFE_PTHREAD(pthread_mutex_lock); }
 66     void Mutex::Unlock()       { SAFE_PTHREAD(pthread_mutex_unlock); }
 67     bool Mutex::TryLock()      { return is_safe_ ?
 68         pthread_mutex_trylock(&mutex_) == 0 : true; }
 69     void Mutex::ReaderLock()   { Lock(); }
 70     void Mutex::ReaderUnlock() { Unlock(); }
 71     class MutexLock {
 72     public:
 73         explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
 74         ~MutexLock() { mu_->Unlock(); }
 75     private:
 76         Mutex * const mu_;
 77         // Disallow "evil" constructors
 78         MutexLock(const MutexLock&);
 79         void operator=(const MutexLock&);
 80     };
 81 
 82     // ReaderMutexLock and WriterMutexLock do the same, for rwlocks
 83     class ReaderMutexLock {
 84     public:
 85         explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); }
 86         ~ReaderMutexLock() { mu_->ReaderUnlock(); }
 87     private:
 88         Mutex * const mu_;
 89         // Disallow "evil" constructors
 90         ReaderMutexLock(const ReaderMutexLock&);
 91         void operator=(const ReaderMutexLock&);
 92     };
 93 
 94     class WriterMutexLock {
 95     public:
 96         explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
 97         ~WriterMutexLock() { mu_->WriterUnlock(); }
 98     private:
 99         Mutex * const mu_;
100         // Disallow "evil" constructors
101         WriterMutexLock(const WriterMutexLock&);
102         void operator=(const WriterMutexLock&);
103     };
104 } /* namespace FrameWork */
105 
106 #endif /* FRAME_LOG_MUTEX_H_ */
View Code

主函数:

 1 /*
 2  * TestLogMain.cpp
 3  *
 4  *  Created on: 2016
 5  *      Author: Administrator
 6  */
 7 
 8 #include <iostream>
 9 #include "Logger.h"
10 using namespace std;
11 using namespace FrameWork;
12 int Main(int argc, char* argv[]) {
13     InitLogging(argv[0], INFO, "./log/test");
14     cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!
15     LOG(INFO) << "info test";
16     LOG(WARN) << "WARN TEST %d" << 20;
17     LOG(ERROR) << "Error test %d %s" << 20 << "nihao";
18 
19     Logger::GetInstance().Error("error test common");
20     Logger::GetInstance().Fatal("fatal test common %d ", 100);
21     Logger::GetInstance().Info("info test normal %d %s ", 50, "zhongguoren");
22     return 0;
23 }
View Code


该代码并来源于他人分享,但没有记住地址,十分抱歉。但是里面的代码风格与设计思路是应该好好学习的。

感谢大神们的分享!

原文地址:https://www.cnblogs.com/liuxw7/p/5343471.html