在记录器向其写入 10000 行后,我有一个函数CloseLogFile
被调用以关闭日志文件。我将要记录的行存储在deque
类型std::string
中。这是标题
#pragma once
#include <deque>
#include <string>
#include <fstream>
#include <map>
#include <iostream>
#include <pthread.h>
#include <time.h>
#define MAX_LINES 1000
#define MESSAGES_PER_WRITE 100
class AtlLogger
{
friend class Driver;
friend class OrderManagementSystem;
public:
static AtlLogger* Instance();
void Log(const std::string line, const std::string prefix);
void DeleteInstance();
void WriteToFile();
private:
AtlLogger();
//the pointer versions of logging is reserved for internal use
//we don't want a strategy to log with pointers and deal with
//memory management
void Log(const std::string*);
void Log(const std::string*, std::string prefix);
struct LogRequest
{
const std::string* line;
std::string prefix;
};
struct FileInfo
{
std::string* name;
std::ofstream ofs;
int lines;
};
static AtlLogger* instance;
void OpenLogFile(const std::string&);
void CloseLogFile(const std::string&);
bool run;
std::deque<LogRequest*> message_queue;
std::map<std::string, FileInfo*> file_map;
};
这是 .cpp 文件:
#include "AtlLogger.h"
AtlLogger* AtlLogger::instance = NULL;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
using std::cout;
using std::endl;
/*
* @construct
* @param
* @description creates a logger to record system information
*/
AtlLogger::AtlLogger()
{
std::string prefix("Audit");
OpenLogFile(prefix);
run = true;
}
/*
* @return instance: pointer to singleton class
* @description creates an instance of the singleton
* if it does not already exist
*/
AtlLogger* AtlLogger::Instance()
{
if(instance == NULL)
{
instance = new AtlLogger;
}
return instance;
}
/*
* @param
* @return
* @description deletes the logger after closing all IO
*/
void AtlLogger::DeleteInstance()
{
usleep(100000);
pthread_mutex_lock(&mutex);
run = false;
std::map<std::string, FileInfo* >::iterator it;
for (it = file_map.begin(); it != file_map.end(); it++)
{
//TODO ofstream* file = (*file_it).second;
//file->close();
}
pthread_mutex_unlock(&mutex);
delete instance;
instance = NULL;
}
/*
* @param line: string to be logged
* @return
* @description adds a line to the queue of lines that
* will be written to the log
*/
void AtlLogger::Log(const std::string* line)
{
pthread_mutex_lock(&mutex);
LogRequest* request = new LogRequest;
request->line = line;
request->prefix = "Audit";
message_queue.push_back(request);
pthread_mutex_unlock(&mutex);
}
/*
* @param line: string to be logged
* @param name: name of the file to log with
* @return
* @description add the line to the given log file
*/
void AtlLogger::Log(const std::string* line, std::string prefix)
{
pthread_mutex_lock(&mutex);
if (file_map.find(prefix) == file_map.end())
{
OpenLogFile(prefix);
}
LogRequest* request = new LogRequest;
request->line = line;
request->prefix = prefix;
message_queue.push_back(request);
pthread_mutex_unlock(&mutex);
}
/*
* @param line: string to be logged
* @param name: name of the file to log with
* @return
* @description add the line to the given log file
*/
void AtlLogger::Log(const std::string line, std::string prefix)
{
pthread_mutex_lock(&mutex);
if (file_map.find(prefix) == file_map.end())
{
OpenLogFile(prefix);
}
LogRequest* request = new LogRequest;
request->line = new std::string(line);
request->prefix = prefix;
message_queue.push_back(request);
pthread_mutex_unlock(&mutex);
}
/*
* @param
* @return
* @description runs in its own thread, checking whether it needs
* to write log statements periodically
*/
void AtlLogger::WriteToFile()
{
std::map<std::string, FileInfo* >::iterator it;
while(run)
{
char timestamp[16];
time_t now;
time(&now);
struct tm* current = localtime(&now);
sprintf(timestamp, "%02u%02u%04u|%02u%02u%02u|", (current->tm_mon+1),
current->tm_mday,(1900 + current->tm_year), current->tm_hour,
current->tm_min, current->tm_sec);
pthread_mutex_lock(&mutex);
for(it=file_map.begin(); it != file_map.end(); ++it)
{
if(it->second->lines > MAX_LINES)
{
CloseLogFile(it->first);
OpenLogFile(it->first);
}
else
{
int written = 0;
while(!message_queue.empty() && written < MESSAGES_PER_WRITE)
{
LogRequest* request = message_queue.front();
message_queue.pop_front();
std::string line(timestamp, 16);
line.append(*(request->line));
FileInfo* info = file_map[request->prefix];
info->ofs << line << std::endl;
info->lines++;
written++;
delete request;
}
}
}
pthread_mutex_unlock(&mutex);
usleep(1000);
}
}
/*
* @param
* @return
* @description opens a new file for logging with a timestamp
* as the filename
*/
void AtlLogger::OpenLogFile(const std::string& prefix)
{
//get timestamp to use
char timestamp[15];
time_t now;
time(&now);
struct tm* current = localtime(&now);
sprintf(timestamp, "%02u%02u%04u_%02u%02u%02u", (current->tm_mon+1),
current->tm_mday,(1900 + current->tm_year), current->tm_hour,
current->tm_min, current->tm_sec);
FileInfo* info = new FileInfo;
cout << "1" << endl;
cout << prefix << endl;
info->name = new std::string("logs/" + prefix + ".log_" + timestamp);
cout << "2" << endl;
cout << "3" << endl;
cout << info->name->c_str() << endl;
info->ofs.open(info->name->c_str());
cout << "4" << endl;
info->lines = 0;
cout << "5" << endl;
file_map[prefix] = info;
cout << "Creating New Log File: " << timestamp << endl;
}
/*
* @param
* @return
* @description closes the current log file
*/
void AtlLogger::CloseLogFile(const std::string& prefix)
{
cout << "Attempting to Close File!" << endl;
cout << prefix << endl;
cout << "Is Open?: " << file_map[prefix]->ofs.is_open() << endl;
cout << "good?: " << file_map[prefix]->ofs.good() << endl;
cout << "eof?: " << file_map[prefix]->ofs.eof() << endl;
cout << "fail?: " << file_map[prefix]->ofs.fail() << endl;
cout << "bad?: " << file_map[prefix]->ofs.bad() << endl;
cout << "name? " << *file_map[prefix]->name << endl;
cout << "lines? " << file_map[prefix]->lines << endl;
//cout << "rdbuf: " << file_map[prefix]->ofs.rdbuf() << endl;
cout << "rdbuf open?: " << file_map[prefix]->ofs.rdbuf()->is_open() << endl;
file_map[prefix]->ofs.close();
cout << "closed stream" << endl;
delete file_map[prefix];
cout << "deleted memory" << endl;
file_map.erase(prefix);
cout << "Close File End!"<< endl;
}
有时,我的程序段错误,我似乎无法确定这是为什么。它工作了很多次,最终会出现段错误,有时是第一次调用,有时是多次调用。
这是我从 gdb 的回溯:
0 0x0000003d8786d1b3 in _IO_un_link_internal () from /lib64/libc.so.6
1 0x0000003d87860da7 in fclose@@GLIBC_2.2.5 () from /lib64/libc.so.6
2 0x000000336febb968 in std::__basic_file<char>::close() () from /usr/lib64/libstdc++.so.6
3 0x000000336fe69c17 in std::basic_filebuf<char, std::char_traits<char> >::close() ()
from /usr/lib64/libstdc++.so.6
4 0x000000336fe69cad in std::basic_ofstream<char, std::char_traits<char> >::close() () from /usr/lib64/libstdc++.so.6
5 0x00000000004c2a25 in AtlLogger::CloseLogFile() ()
6 0x00000000004c2ef1 in AtlLogger::WriteToFile() ()
7 0x0000000000482270 in Driver::launchLog (this=0x7fffffffe86f) at driver.cpp:672
8 0x000000000048228f in launchLogThread (ptr=0x7fffffffe86f) at driver.cpp:654
9 0x0000003d8840673d in start_thread () from /lib64/libpthread.so.0
10 0x0000003d878d3d1d in clone () from /lib64/libc.so.6
这是段错误之前的控制台输出:
Attempting to Close File!
test
Is Open?: 1
good?: 1
eof?: 0
fail?: 0
bad?: 0
name? logs/test.log_09132012_095549
lines? 1001
rdbuf open?: 1
谁能告诉我这可能出了什么问题?(顺便说一句,为什么在 gdb 中我看到跟踪的某些部分的行号,而不是其他部分的行号?)
日志记录功能可与以下内容一起使用:
Logger::Instance()->Log("Log This", "File");