做網(wǎng)站要法人身份證嗎品牌營銷案例分析
日志系統(tǒng)的實現(xiàn)
- 引言
- 最簡單的日志類 demo
- 按天日志分類和超行日志分類
- 日志信息分級
- 同步和異步兩種寫入方式
引言
日志系統(tǒng)是通過文件來記錄項目的 調(diào)試信息,運(yùn)行狀態(tài),訪問記錄,產(chǎn)生的警告和錯誤的一個系統(tǒng),是項目中非常重要的一部分. 程序員可以通過日志文件觀測項目的運(yùn)行信息,方便及時對項目進(jìn)行調(diào)整.
最簡單的日志類 demo
日志類一般使用單例模式實現(xiàn):
Log.h:
class Log
{
private:Log() {};~Log();
public:bool init(const char* file_name);void write_log(const char* str);static Log* getinstance();private:FILE* file;
};
Log.cpp:
Log::~Log()
{if (file != NULL){fflush(file);fclose(file);}
}Log* Log::getinstance()
{static Log instance;return &instance;
}bool Log::init(const char * file_name)
{file = fopen(file_name,"a");if (file == NULL){return false;}return true;
}void Log::write_log(const char* str)
{if (file == NULL)return;fputs(str, file);
}
main.cpp:
#include"Log.h"int main()
{Log::getinstance()->init("log.txt");Log::getinstance()->write_log("Hello World");
}
這個日志類實現(xiàn)了最簡單的寫日志的功能,但是實際應(yīng)用時,需要在日志系統(tǒng)上開發(fā)出許多額外的功能來滿足工作需要,有些時候還要進(jìn)行日志的分類操作,因為你不能將所有的日志信息都塞到一個日志文件中,這樣會大大降低可讀性,接下來講一下在這個最簡單的日志類的基礎(chǔ)上,怎么添加一些新功能.
按天日志分類和超行日志分類
先說兩個比較簡單的
按天分類和超行分類
按天分類:每一個日志按照天來分類(日志前加上當(dāng)前的日期作為日志的前綴) 并且寫日志前檢查日志的創(chuàng)建時間,如果日志創(chuàng)建時間不是今天,那么就額外新創(chuàng)建一個日志,更新創(chuàng)建時間和行數(shù),然后向新日志中寫日志信息
超行分類:寫日志前檢查本次程序?qū)懭肴罩镜男袛?shù),如果當(dāng)前本次程序?qū)懭肴罩镜男袛?shù)已經(jīng)到達(dá)上限,那么額外創(chuàng)建新的日志,更新創(chuàng)建時間,然后向新日志中寫日志信息
為了實現(xiàn)這兩個小功能,我們需要先向日志類中添加以下成員:
- 程序本次啟動,寫入日志文件的最大行數(shù)
- 程序本次啟動,已經(jīng)寫入日志的行數(shù)
- 日志的創(chuàng)建時間
- 日志的路徑名+文件名(創(chuàng)建新日志的時候,命名要跟之前的命名標(biāo)準(zhǔn)一樣,最好是標(biāo)準(zhǔn)日志名+后綴的形式,這樣便于標(biāo)識)
更新后的日志類:
Log.h:
#pragma once
#include<stdio.h>
#include<string.h>
#include<string>
#include<time.h>
using namespace std;class Log
{
private:Log() ;~Log();public://初始化文件路徑,文件最大行數(shù)bool init(const char* file_name,int split_lines= 5000000);void write_log(const char* str);static Log* getinstance();private:FILE* file;char dir_name[128];//路徑名char log_name[128];//日志名int m_split_lines; //日志文件最大行數(shù)(之前的日志行數(shù)不計,只記錄本次程序啟動寫入的行數(shù))long long m_count; //已經(jīng)寫入日志的行數(shù)int m_today; //日志的創(chuàng)建時間
};
Log.cpp
#define _CRT_SECURE_NO_WARNINGS
#include"Log.h"Log::Log()
{m_count = 0;
}Log::~Log()
{if (file != NULL){fflush(file);fclose(file);}
}Log* Log::getinstance()
{static Log instance;return &instance;
}bool Log::init(const char * file_name,int split_lines)
{m_split_lines = split_lines; //設(shè)置最大行數(shù)time_t t = time(NULL);struct tm* sys_tm = localtime(&t);struct tm my_tm = *sys_tm; //獲取當(dāng)前的時間const char* p = strrchr(file_name, '/');//這里需要注意下,windows和linux的路徑上的 斜杠符浩方向是不同的,windows是\,linux是 / ,而且因為轉(zhuǎn)義符號的原因,必須是 \\char log_full_name[256] = { 0 };if (p == NULL) //判斷是否輸入了完整的路徑+文件名,如果只輸入了文件名{strcpy(log_name, file_name);snprintf(log_full_name, 255, "%d_%02d_%02d_%s", my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday, file_name);}else //如果輸入了完整的路徑名+文件名{strcpy(log_name, p + 1);strncpy(dir_name, file_name, p - file_name + 1);//規(guī)范化命名snprintf(log_full_name,255, "%s%d_%02d_%02d_%s", dir_name, my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday, log_name);}m_today = my_tm.tm_mday; //更新時間file = fopen(log_full_name,"a"); //打開文件,打開方式:追加if (file == NULL){return false;}return true;
}void Log::write_log(const char* str)
{if (file == NULL)return;time_t t = time(NULL); struct tm* sys_tm = localtime(&t); struct tm my_tm = *sys_tm; //獲取當(dāng)前的時間,用來后續(xù)跟日志的創(chuàng)建時間作對比m_count++; //日志行數(shù)+1if (m_today != my_tm.tm_mday || m_count % m_split_lines == 0) //如果創(chuàng)建時間!=當(dāng)前時間或者本次寫入行數(shù)達(dá)到上限{ char new_log[256] = { 0 }; //新日志的文件名fflush(file);fclose(file);char time_now[16] = { 0 }; //格式化當(dāng)前的時間snprintf(time_now, 16, "%d_%02d_%02d_", my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday);if (m_today != my_tm.tm_mday) //如果是創(chuàng)建時間!=今天{ //這里解釋一下,m_today在init函數(shù)被調(diào)用的時候一定會被設(shè)置成當(dāng)天的時間,只有init和write函數(shù)的調(diào)用不在同一天中,才會出現(xiàn)這種情況snprintf(new_log, 255, "%s%s%s", dir_name, time_now, log_name);m_today = my_tm.tm_mday; //更新創(chuàng)建時間m_count = 0; //更新日志的行數(shù)}else //如果是行數(shù)達(dá)到本次我們規(guī)定的寫入上限{snprintf(new_log,255,"%s%s%lld_%s", dir_name, time_now, m_count / m_split_lines,log_name);//加上版本后綴}file = fopen(new_log, "a");}fputs(str, file);fputs("\n", file);
}
運(yùn)行的結(jié)果:
出現(xiàn)了一個以時間開頭命名的日志,實現(xiàn)了按天分類
接下來我將一次性寫入行數(shù)的上限調(diào)成5,看一下如果一次性寫入超過了行數(shù)上限的運(yùn)行結(jié)果是什么樣:
出現(xiàn)了一個后綴_1的新文件
PS:這里有一個小BUG:因為m_count是每次運(yùn)行程序都會重置的一個變量,所以上一次運(yùn)行時可能因為輸出的行數(shù)過多,創(chuàng)建了好多新日志,但是下一次運(yùn)行程序時,還是從第一個日志開始打印的. 而且規(guī)定行數(shù)上限并不是日志中文件行數(shù)的上限,而是每次運(yùn)行程序?qū)懭肴罩疚募男袛?shù)上限,所以這個功能并不完美甚至說非常雞肋暫時還沒優(yōu)化好,在這里僅做一個小小的演示吧.
日志信息分級
我們應(yīng)該將每一條日志信息進(jìn)行分類,可以分為四大類:
Debug: 調(diào)試中產(chǎn)生的信息
WARN: 調(diào)試中產(chǎn)生的警告信息
INFO: 項目運(yùn)行時的狀態(tài)信息
ERROR: 系統(tǒng)的錯誤信息
然后我們可以在日志文件中,每一條日志信息的前面,加上這條信息被寫入的時間和其所屬的分級,這樣會大大增加日志的可讀性.
代碼還是在上面代碼的基礎(chǔ)上繼續(xù)改動
Log.h:
#pragma once
#include<stdio.h>
#include<string.h>
#include<string>
#include<time.h>
using namespace std;class Log
{
private:Log() ;~Log();public://初始化文件路徑,日志緩沖區(qū)大小,文件最大行數(shù)bool init(const char* file_name, int log_buf_size = 8192, int split_lines= 5000000);//新增了一個日志分級void write_log(int level,const char* str);static Log* getinstance();private:FILE* file;char dir_name[128];//路徑名char log_name[128];//日志名int m_split_lines; //日志文件最大行數(shù)long long m_count; //日志當(dāng)前的行數(shù)int m_today; //日志創(chuàng)建的日期,記錄是那一天int m_log_buf_size; //日志緩沖區(qū)的大小,用來存放日志信息字符串char* m_buf; //日志信息字符串;因為后續(xù)要把時間和日志分級也加進(jìn)來,所以開一個新的char *
};
Log.cpp:
#define _CRT_SECURE_NO_WARNINGS
#include"Log.h"Log::Log()
{m_count = 0;
}Log::~Log()
{if (file != NULL){fflush(file);fclose(file);}if (m_buf != NULL){delete[] m_buf;m_buf = nullptr;}
}Log* Log::getinstance()
{static Log instance;return &instance;
}bool Log::init(const char * file_name, int log_buf_size , int split_lines)
{m_log_buf_size = log_buf_size;m_buf = new char[m_log_buf_size];memset(m_buf,'\0', m_log_buf_size);// 開辟緩沖區(qū),準(zhǔn)備存放格式化的日志字符串m_split_lines = split_lines; //設(shè)置最大行數(shù)time_t t = time(NULL);struct tm* sys_tm = localtime(&t);struct tm my_tm = *sys_tm; //獲取當(dāng)前的時間const char* p = strrchr(file_name, '\\');char log_full_name[256] = { 0 };if (p == NULL){snprintf(log_full_name, 255, "%d_%02d_%02d_%s", my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday, file_name);strcpy(log_name, file_name);}else{strcpy(log_name, p + 1);strncpy(dir_name, file_name, p - file_name + 1);//規(guī)范化命名snprintf(log_full_name,255, "%s%d_%02d_%02d_%s", dir_name, my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday, log_name);}m_today = my_tm.tm_mday; //更新日志的創(chuàng)建時間file = fopen(log_full_name,"a"); //打開文件,打開方式:追加if (file == NULL){return false;}return true;
}void Log::write_log(int level,const char* str)
{if (file == NULL)return;time_t t = time(NULL); struct tm* sys_tm = localtime(&t); struct tm my_tm = *sys_tm; //獲取當(dāng)前的時間,用來后續(xù)跟日志的創(chuàng)建時間作對比char level_s[16] = { 0 }; //日志分級switch (level){case 0:strcpy(level_s, "[debug]:");break;case 1:strcpy(level_s, "[info]:"); break;case 2:strcpy(level_s, "[warn]:"); break;case 3:strcpy(level_s, "[erro]:"); break;default:strcpy(level_s, "[info]:"); break;}m_count++; //日志行數(shù)+1if (m_today != my_tm.tm_mday || m_count % m_split_lines == 0) //如果創(chuàng)建時間!=當(dāng)前時間或者行數(shù)達(dá)到上限{char new_log[256] = { 0 }; //新日志的文件名fflush(file);fclose(file);char time_now[16] = { 0 }; //格式化當(dāng)前的時間snprintf(time_now, 16, "%d_%02d_%02d_", my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday);if (m_today != my_tm.tm_mday) //如果是創(chuàng)建時間!=今天{snprintf(new_log, 255, "%s%s%s", dir_name, time_now, log_name);m_today = my_tm.tm_mday; //更新創(chuàng)建時間m_count = 0; //更新日志的行數(shù)}else //如果是行數(shù)達(dá)到文件上限{snprintf(new_log,255,"%s%s%lld_%s", dir_name, time_now, m_count / m_split_lines,log_name);//加上版本后綴}file = fopen(new_log, "a");}int n = snprintf(m_buf, 48, "%d-%02d-%02d %02d:%02d:%02d %s",my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday,my_tm.tm_hour, my_tm.tm_min, my_tm.tm_sec,level_s); int m = snprintf(m_buf + n, m_log_buf_size-n-1,"%s",str);m_buf[n+m] = '\n';m_buf[n+m+1] = '\0';fputs(m_buf, file);}
main.cpp:
#include<iostream>
#include"Log.h"int main()
{Log::getinstance()->init("Log\\log.txt");Log::getinstance()->write_log(0,"Hello World");Log::getinstance()->write_log(1,"Hello World");Log::getinstance()->write_log(2,"Hello World");Log::getinstance()->write_log(3,"Hello World");
}
運(yùn)行結(jié)果:
如圖:日志信息前面已經(jīng)加上了時間和類別分級,增加了可讀性
同步和異步兩種寫入方式
同步寫入和異步寫入的邏輯:
圖片來自公眾號:兩猿社
我先說明一下同步和異步的特點(diǎn):
同步可以理解為順序執(zhí)行,而異步可以理解為并行執(zhí)行
比如說吃飯和燒水兩件事,如果先吃飯后燒水,這種是同步執(zhí)行
如果說一邊吃飯一邊燒水,這種就是異步執(zhí)行
那么同步執(zhí)行和異步執(zhí)行有什么優(yōu)點(diǎn),又使用在什么場景之下呢?
同步:
- 當(dāng)對寫入順序和實時性要求很高時,例如需要確保按照特定順序?qū)懭牖驅(qū)懭爰磿r生效的情況下,同步寫入通常更合適。
- 在數(shù)據(jù)完整性和一致性很重要的情況下,同步寫入能夠提供更好的保證,避免數(shù)據(jù)丟失或不完整。
- 對于一些不頻繁的、關(guān)鍵的寫入操作,同步寫入方式可能更容易確保操作的可靠性。
異步:
- 當(dāng)寫入頻率很高或?qū)懭氩僮飨妮^多時間時,使用異步寫入可以顯著提升系統(tǒng)性能和響應(yīng)速度。
- 對于寫入操作對主線程影響較大,容易阻塞主線程的情況下,通過異步寫入可以將寫入操作移到獨(dú)立的線程中處理,減少主線程負(fù)擔(dān)。
- 在需要降低I/O操作的影響、提高系統(tǒng)吞吐量和并發(fā)能力的場景下,異步寫入方式更為適宜。
然后說一下如何實現(xiàn)同步和異步
同步只需要正常寫入就行了
而異步我們可以借助生產(chǎn)者-消費(fèi)者模型,由子線程執(zhí)行寫入操作.
如果你想了解生產(chǎn)者-消費(fèi)者模型,請點(diǎn)擊鏈接
生產(chǎn)者-消費(fèi)者模型
接下來給出帶有同步和異步兩種寫入方式的日志實現(xiàn),還是在之前代碼的基礎(chǔ)上改動
封裝了生產(chǎn)者-消費(fèi)者模型的阻塞隊列類:
#ifndef BLOCK_QUEUE_H
#define BLOCK_QUEUE_H#include <iostream>
#include <stdlib.h>
#include <pthread.h>
#include <sys/time.h> //包含時間和定時器的頭文件!
#include "../lock/locker.h"
using namespace std;template <class T>
class block_queue
{
public:block_queue(int max_size = 1000){if (max_size <= 0){exit(-1);}m_max_size = max_size;m_array = new T[max_size];m_size = 0;m_front = -1;m_back = -1;}void clear(){m_mutex.lock();m_size = 0;m_front = -1;m_back = -1;m_mutex.unlock();}~block_queue(){m_mutex.lock();if (m_array != NULL)delete [] m_array;m_mutex.unlock();}//判斷隊列是否滿了bool full() {m_mutex.lock();if (m_size >= m_max_size){m_mutex.unlock();return true;}m_mutex.unlock();return false;}//判斷隊列是否為空bool empty() {m_mutex.lock();if (0 == m_size){m_mutex.unlock();return true;}m_mutex.unlock();return false;}//返回隊首元素bool front(T &value) {m_mutex.lock();if (0 == m_size){m_mutex.unlock();return false;}value = m_array[m_front];m_mutex.unlock();return true;}//返回隊尾元素bool back(T &value) {m_mutex.lock();if (0 == m_size){m_mutex.unlock();return false;}value = m_array[m_back];m_mutex.unlock();return true;}int size() {int tmp = 0;m_mutex.lock();tmp = m_size;m_mutex.unlock();return tmp;}int max_size(){int tmp = 0;m_mutex.lock();tmp = m_max_size;m_mutex.unlock();return tmp;}//往隊列添加元素,需要將所有使用隊列的線程先喚醒//當(dāng)有元素push進(jìn)隊列,相當(dāng)于生產(chǎn)者生產(chǎn)了一個元素//若當(dāng)前沒有線程等待條件變量,則喚醒無意義bool push(const T &item){m_mutex.lock();if (m_size >= m_max_size) //這里沒考慮生產(chǎn)者必須在不空的情況下需要等待的問題{m_cond.broadcast();m_mutex.unlock();return false;}m_back = (m_back + 1) % m_max_size;m_array[m_back] = item;m_size++;m_cond.broadcast();m_mutex.unlock();return true;}//pop時,如果當(dāng)前隊列沒有元素,將會等待條件變量bool pop(T &item){m_mutex.lock();while (m_size <= 0){if (!m_cond.wait(m_mutex.get())){m_mutex.unlock();return false;}}m_front = (m_front + 1) % m_max_size;item = m_array[m_front];m_size--;m_mutex.unlock();return true;}
private:locker m_mutex;cond m_cond;T *m_array;int m_size;int m_max_size;int m_front;int m_back;
};
#endif
注意: 這個生產(chǎn)者消費(fèi)者模型并沒有考慮生產(chǎn)者必須要在不滿的情況下才能生產(chǎn)這一情況,不過這樣也能湊活用,先湊活看吧
Log.h:
#pragma once
#include<stdio.h>
#include<string.h>
#include<string>
#include<time.h>
using namespace std;class Log
{
private:Log() ;~Log();//異步寫入方法:void* async_write_log(){string single_log;//要寫入的日志while (m_log_queue->pop(single_log)){m_mutex.lock();//互斥鎖上鎖fputs(single_log.c_str(), file);m_mutex.unlock();//互斥鎖解鎖}}public://初始化文件路徑,日志緩沖區(qū)大小,文件最大行數(shù),阻塞隊列長度(如果阻塞隊列長度為正整數(shù),表示使用異步寫入,否則為同步寫入)bool init(const char* file_name, int log_buf_size = 8192, int split_lines= 5000000,int max_queue_size=0);//新增了一個日志分級void write_log(int level,const char* str);//公有的異步寫入函數(shù),作為消費(fèi)者線程的入口函數(shù)static void* flush_log_thread(void *args){Log::getinstance()->async_write_log();}static Log* getinstance();private:FILE* file;char dir_name[128];//路徑名char log_name[128];//日志名int m_split_lines; //日志文件最大行數(shù)long long m_count; //日志當(dāng)前的行數(shù)int m_today; //日志創(chuàng)建的日期,記錄是那一天int m_log_buf_size; //日志緩沖區(qū)的大小,用來存放日志信息字符串char* m_buf; //日志信息字符串;因為后續(xù)要把時間和日志分級也加進(jìn)來,所以開一個新的char *block_queue<string>* m_log_queue; //阻塞隊列,封裝生產(chǎn)者消費(fèi)者模型bool m_is_async; //異步標(biāo)記,如果為true,表示使用異步寫入方式,否則是同步寫入方式locker m_mutex; //互斥鎖類,內(nèi)部封裝了互斥鎖,用來解決多線程競爭資源問題
};
Log.cpp
#define _CRT_SECURE_NO_WARNINGS
#include"Log.h"
// pthread,mutex等需要在Linux下使用相關(guān)的頭文件才能使用,因為我是windows環(huán)境就暫時不加了.Log::Log()
{m_count = 0;m_is_async = false;
}Log::~Log()
{if (file != NULL){fflush(file);fclose(file);}if (m_buf != NULL){delete[] m_buf;m_buf = nullptr;}
}Log* Log::getinstance()
{static Log instance;return &instance;
}bool Log::init(const char * file_name, int log_buf_size , int split_lines,int max_queue_size)
{if (max_queue_size >= 1){//設(shè)置寫入方式flagm_is_async = true; //設(shè)置為異步寫入方式//創(chuàng)建并設(shè)置阻塞隊列長度m_log_queue = new block_queue<string>(max_queue_size);pthread_t tid;//flush_log_thread為回調(diào)函數(shù),這里表示創(chuàng)建線程異步寫日志pthread_create(&tid, NULL, flush_log_thread, NULL);}m_log_buf_size = log_buf_size;m_buf = new char[m_log_buf_size];memset(m_buf,'\0', m_log_buf_size);// 開辟緩沖區(qū),準(zhǔn)備存放格式化的日志字符串m_split_lines = split_lines; //設(shè)置最大行數(shù)time_t t = time(NULL);struct tm* sys_tm = localtime(&t);struct tm my_tm = *sys_tm; //獲取當(dāng)前的時間const char* p = strrchr(file_name, '\\');char log_full_name[256] = { 0 };if (p == NULL){snprintf(log_full_name, 255, "%d_%02d_%02d_%s", my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday, file_name);strcpy(log_name, file_name);}else{strcpy(log_name, p + 1);strncpy(dir_name, file_name, p - file_name + 1);//規(guī)范化命名snprintf(log_full_name,255, "%s%d_%02d_%02d_%s", dir_name, my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday, log_name);}m_today = my_tm.tm_mday; //更新日志的創(chuàng)建時間file = fopen(log_full_name,"a"); //打開文件,打開方式:追加if (file == NULL){return false;}return true;
}void Log::write_log(int level,const char* str)
{if (file == NULL)return;time_t t = time(NULL); struct tm* sys_tm = localtime(&t); struct tm my_tm = *sys_tm; //獲取當(dāng)前的時間,用來后續(xù)跟日志的創(chuàng)建時間作對比char level_s[16] = { 0 }; //日志分級switch (level){case 0:strcpy(level_s, "[debug]:");break;case 1:strcpy(level_s, "[info]:"); break;case 2:strcpy(level_s, "[warn]:"); break;case 3:strcpy(level_s, "[erro]:"); break;default:strcpy(level_s, "[info]:"); break;}m_mutex.lock(); //互斥鎖上鎖m_count++; //日志行數(shù)+1if (m_today != my_tm.tm_mday || m_count % m_split_lines == 0) //如果創(chuàng)建時間!=當(dāng)前時間或者行數(shù)達(dá)到上限{char new_log[256] = { 0 }; //新日志的文件名fflush(file);fclose(file);char time_now[16] = { 0 }; //格式化當(dāng)前的時間snprintf(time_now, 16, "%d_%02d_%02d_", my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday);if (m_today != my_tm.tm_mday) //如果是創(chuàng)建時間!=今天{snprintf(new_log, 255, "%s%s%s", dir_name, time_now, log_name);m_today = my_tm.tm_mday; //更新創(chuàng)建時間m_count = 0; //更新日志的行數(shù)}else //如果是行數(shù)達(dá)到文件上限{snprintf(new_log,255,"%s%s%lld_%s", dir_name, time_now, m_count / m_split_lines,log_name);//加上版本后綴}file = fopen(new_log, "a");}m_mutex.unlock(); //互斥鎖解鎖string log_str; m_mutex.lock();//格式化int n = snprintf(m_buf, 48, "%d-%02d-%02d %02d:%02d:%02d %s",my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday,my_tm.tm_hour, my_tm.tm_min, my_tm.tm_sec,level_s); int m = snprintf(m_buf + n, m_log_buf_size-n-1,"%s",str);m_buf[n+m] = '\n';m_buf[n+m+1] = '\0';log_str = m_buf;m_mutex.unlock();//如果是異步的寫入方式if (m_is_async && !m_log_queue->full()) {m_log_queue->push(log_str); }else//如果是同步的寫入方式{m_mutex.lock(); fputs(log_str.c_str(), file);m_mutex.unlock(); }
}
日志系統(tǒng)先介紹到這里,我介紹的日志系統(tǒng)還是屬于功能比較稀缺,實際使用上可能遠(yuǎn)遠(yuǎn)比這復(fù)雜,如果想使用日志系統(tǒng),可以以文章介紹的為雛形繼續(xù)添加新功能.
本文中代碼非常可能有錯誤,如果發(fā)現(xiàn)有錯誤,煩請評論區(qū)指正,我會及時修改.