I made this class (MFC lib) to write a log files. Eventually I want to implement this code in a thread safe way.
Log.h
#pragma once
class CLog
{
public:
CLog();
~CLog();
int CLog::Log(CString log);
void CLog::TWriteAllToLog();
};
Log.cpp
#include "stdafx.h"
#include "Log.h"
#include <queue>
#include <mutex>
using namespace std;
const unsigned long long MAX_LOG_FILE_SIZE{ 1024 * 1024 * 4 };
CStdioFile logFile;
CString _fileName;
CFileStatus fileStatus;
CFileException exceptionEx;
UINT_PTR shownTimer;
BOOL fileOpened;
mutex m;
queue<CString> dataLog;
void DoSafeWrite(CString log);
void PrintQueue();
CLog::CLog()
{
/* want to implement auto flush method to write all
queue items into file in here with timer like method.
but at the moment manually call the function "TWriteAllToLog()" to write log file.
*/
}
CLog::~CLog()
{
}
/*
usage:
CString str;
str.Format(L"This is log test");
CLog _log; //create object
_log.Log(str); //call to Log function
*/
int CLog::Log(CString log)
{
try{
CTime t = CTime::GetCurrentTime();
CString TStamp = t.Format("%a, %b %d, %Y %H:%M:%S -> ");
CString newLine("\n");
log = TStamp + log + newLine;
dataLog.push(log);
return 1;
}
catch (...){
return -1;
}
}
void CLog::TWriteAllToLog(){
PrintQueue();
}
void PrintQueue()
{
while (!dataLog.empty())
{
m.lock();
CString str;
CString &data = dataLog.front();
DoSafeWrite(data);
dataLog.pop();
m.unlock();
}
}
CString GetFileName() //crate a file name
{
COleDateTime dtDate = COleDateTime::GetCurrentTime();
CString file = dtDate.Format(L"Log_%d_%m_%Y__%H_%M_%S.log");
return file;
}
CString GetLastFileName(CString filename, bool write)
{
const int FILE_CONTENT_LEN = 255;
CString logfiledb{ "_FILE_.db" };
char fileContent[FILE_CONTENT_LEN];
CStdioFile lastLog;
CFileStatus status;
CString line;
CFileException exception;
try
{
if (CFile::GetStatus(logfiledb, status)) // craete log file and write the current access file into db
{
lastLog.Open(logfiledb, CFile::modeCreate | CFile::modeWrite | CFile::modeNoTruncate);
lastLog.WriteString(filename);
lastLog.Flush();
lastLog.Close();
return filename;
}
}
catch (CFileException *e)
{
lastLog.Close();
}
}
CString GetLastFileName(CString filename) //Read the '_FILE_.db' and get the last file name
{
const int FILE_CONTENT_LEN = 255;
CString logfiledb{ "_FILE_.db" };
char fileContent[FILE_CONTENT_LEN];
CStdioFile lastLog;
CFileStatus status;
CString line;
CFileException exception;
try
{
if (CFile::GetStatus(logfiledb, status)) //check file exsist
{
if (status.m_size > 5) //check file have alrady contain file name : too lazy method
{
if (lastLog.Open(logfiledb, CFile::modeRead, &exception))
{
lastLog.ReadString(line);
lastLog.Close();
return line;
}
}
else // if file not write the filename
{
lastLog.Open(logfiledb, CFile::modeCreate | CFile::modeWrite | CFile::modeNoTruncate);
lastLog.WriteString(filename);
lastLog.Flush();
lastLog.Close();
return filename;
}
}
else //if file not exsist crate and write the file name
{
lastLog.Open(logfiledb, CFile::modeCreate | CFile::modeWrite | CFile::modeNoTruncate);
lastLog.WriteString(filename);
lastLog.Flush();
lastLog.Close();
return filename;
}
}
catch (CFileException *e)
{
lastLog.Close();
}
}
void DoSafeWrite(CString log)
{
_fileName = GetLastFileName(GetFileName()); //get the file name
try
{
if (CFile::GetStatus(_fileName, fileStatus)) //check file exist
{
unsigned long long fileSize = fileStatus.m_size;
if (fileSize >= MAX_LOG_FILE_SIZE) //check size bound
{
_fileName = GetLastFileName(GetFileName(), true); //if file size not exceed get the last writed file name
fileOpened = logFile.Open(_fileName, CFile::modeCreate | CFile::modeWrite);
if (fileOpened)
{
logFile.SeekToEnd();
logFile.WriteString(log);
logFile.Flush();
logFile.Close();
}
else
{
TRACE("Can't open file %s, error = %u\n", _fileName, exceptionEx.m_cause);
}
}
else
{ //write file if size exceed
fileOpened = logFile.Open(_fileName, CFile::modeCreate | CFile::modeWrite | CFile::modeNoTruncate);
if (fileOpened)
{
logFile.SeekToEnd();
logFile.WriteString(log);
logFile.Flush();
logFile.Close();
}
else
{
TRACE("Can't open file %s, error = %u\n", _fileName, exceptionEx.m_cause);
}
}
}
else
{ //if file not found create new file and write
fileOpened = logFile.Open(_fileName, CFile::modeCreate | CFile::modeWrite | CFile::modeNoTruncate);
if (fileOpened)
{
logFile.SeekToEnd();
logFile.WriteString(log);
logFile.Flush();
logFile.Close();
}
else
{
TRACE("Can't open file %s, error = %u\n", _fileName, exceptionEx.m_cause);
}
}
}
catch (CFileException *e)
{
logFile.Close();
}
}
I want to implement above code in a thread safe way and also write the log file in PrintQueue()
function with using a timer-like function in the CLog
constructor. Can the existing code be improved?
queue
is accessed in an unsynchronized way in two places. \$\endgroup\$