gpt4 book ai didi

C++ 线程安全、基于上下文流的日志记录

转载 作者:行者123 更新时间:2023-11-28 06:42:40 26 4
gpt4 key购买 nike

所以我已经编写了一段时间的日志记录类,我决定更改类,以便它使用流而不是具有字符串/整数参数组合的函数。这是我想出的:记录器.h:

#ifndef __LOG_H
#define __LOG_H
class logger {
public:
logger();
void log ( int mlvl );
int Llport;
std::stringstream logstream;
private:
void errException( const int &ecode, const int &line, const std::string &file );
void readCfg();
void setLogLevel( int llvl );
pid_t getPID();
unsigned long getThread();
std::string tStamp();
bool writeLog( const std::string &message );
std::string Lcfgfile;
std::string Lfile;
unsigned long Lthread;
pid_t Lpid;
int Llvl;
};
extern logger mlog;
#endif

记录器.cpp:

#include<iostream>
#include<string>
#include<iomanip>
#include<fstream>
#include<time.h>
#include<stdio.h>
#include<map>
#include<sstream>
#include"log.h"
#include"ConfigFile.h"
#include"util.h"
#include<unistd.h>
#include<boost/lexical_cast.hpp>
#include<boost/thread.hpp>
#include<time.h>
logger::logger(){
Lcfgfile="/home/ianc/www/coding/GDAgent/cfg/GDAgent.conf";
readCfg();
}
std::string logger::tStamp(){
time_t now = time(0);
struct tm tstruct;
char buf[80];
tstruct = *localtime(&now);
strftime( buf, sizeof(buf), "%Y-%m-%d.%X", &tstruct );
return buf;
}
void logger::readCfg() {
cfg::cfg conf( Lcfgfile );
Llvl = 0;
if( conf.keyExists( "logfile" ) ){
Lfile = conf.getValueOfKey<std::string>( "logfile" );
}
else {
Lfile = "/var/log/GDlog";
}
if( conf.keyExists( "DebugLevel" ) ) {
int debuglevel = conf.getValueOfKey<int>( "DebugLevel" );
std::stringstream d;
d << debuglevel;
std::string dd = d.str();
char dl = dd[0];
int dlvl = ccInt( dl );
Llvl = dlvl;
}
if( conf.keyExists( "ListenPort" ) ) {
Llport = conf.getValueOfKey<int>( "ListenPort" );
}
else {
Llport = 8000;
}
}
unsigned long logger::getThread() {
std::string threadID = boost::lexical_cast<std::string>(boost::this_thread::get_id() );
unsigned long threadNumber = 0;
sscanf( threadID.c_str(), "%lx", &threadNumber );
return threadNumber;
}
pid_t logger::getPID() {
Lpid = getpid();
return Lpid;
}
bool logger::writeLog( const std::string &message ) {
Lpid = getPID();
Lthread = getThread();
std::string ts = tStamp();
std::ofstream lmsg( Lfile, std::ofstream::app );
lmsg << ts << " [" << Lpid << "] (" << Lthread << ") " << message;
lmsg.close();
return true;
}
void logger::log( int mlvl ) {
if( mlvl >= Llvl ){
std::string lin = logstream.str();
logstream.str("");
switch( mlvl ) {
case 0:
logstream << "[DEBUG] " << lin << std::endl;
lin = logstream.str();
writeLog( lin );
logstream.str("");
break;
case 1:
logstream<< "[INFO] " << lin << std::endl;
lin = logstream.str();
writeLog( lin );
logstream.str("");
break;
case 2:
logstream<< "[WARN] " << lin << std::endl;
lin = logstream.str();
writeLog( lin );
logstream.str("");
break;
case 3:
logstream<< "[ERR] " << lin << std::endl;
lin = logstream.str();
writeLog( lin );
logstream.str("");
break;
case 4:
logstream<< "[CRITICAL] " << lin << std::endl;
lin = logstream.str();
writeLog( lin );
logstream.str("");
break;
case 5:
logstream<< "[EXCEPTION] " << lin << std::endl;
lin = logstream.str();
logstream.str("");
writeLog( lin );
default:
logstream<< "[GENERAL] " << lin << std::endl;
lin = logstream.str();
writeLog( lin );
logstream.str("");
writeLog( "[ERROR] Invalid identifier given to logger.\n" );
break;
}
}
}
logger mlog;

基本上,我写入字符串流,然后使用消息级别“刷新”流。这在理论上都很可爱,但在实践中......

[4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408) 2014-09-04.06:21:23 [4297] (140377696753408)

这是因为它是一个跨多个线程全局实例化的对象——如果我将参数传递给函数,这会很好,但是……流不断相互覆盖,导致一团糟,最终段错误。我尝试在每个线程中实例化记录器一次并将其作为参数传递给所有函数,但我收到一条关于复制构造函数和 logger() 合成方法的神秘消息,所以我尝试在每个模块中实例化一次,每个模块一次功能,虽然每个模块的解决方案(每个 .cpp 文件中的一个与其他文件不同)在大多数情况下都有效,但最终我收到一条错误消息“文件 _(我的配置文件)无法定位!”并且程序崩溃了。所以我的问题是,有没有更好的方法,既不像将字符串传递给函数那样笨拙,又允许我向日志条目添加上下文(如消息级别)?

最佳答案

您可以在单独的线程中执行使用共享资源的实际日志记录。该线程在共享队列上等待,因此其他线程分别收集它们的信息并通过队列将其发送到日志记录线程。

优点是不需要共享资源,工作线程不必访问外部系统进行日志记录(网络、磁盘、终端)。缺点是崩溃前的日志可能会丢失,但有一些方法可以改善这一点(比如在严重性很严重时等待记录器结束)。

关于C++ 线程安全、基于上下文流的日志记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25663730/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com