📄 nltsappender.h
字号:
#ifndef _NL_TS_APPENDER_H
#define _NL_TS_APPENDER_H
#include "nlkit/NLAppender.h"
#include "nlkit/NLTime.h"
#include <queue>
#include <iostream>
#include "nlkit/ThreadManager.h"
namespace nlkit
{
class NLTSAppender : public NLAppender
{
class ThreadSafeWriter
{
typedef ThreadSafeWriter this_class;
typedef std::basic_ostream<char> ostream_type;
typedef std::basic_string<char> string_type;
// forward declaration
struct thread_info;
friend struct thread_info;
// thread-related definitions
typedef DEFAULT_THREAD_MANAGER thread_manager;
typedef thread_manager::thread_obj_base thread_obj_base;
typedef thread_manager::critical_section critical_section;
typedef thread_manager::auto_lock_unlock auto_lock_unlock;
// so that from our thread we know the object we're manipulating
struct thread_info : public thread_obj_base
{
thread_info() : m_bHasFinished( false ), m_pThis( NULL )
{
}
/* virtual */ void operator()()
{
while ( true )
{
m_pThis->doCheck();/////////////////////
string_type* pstr = NULL;
{
auto_lock_unlock locker( m_pThis->m_cs );
// get the string
if ( m_pThis->m_astrMessages.size() > 0 )
{
pstr = m_pThis->m_astrMessages.front();
m_pThis->m_astrMessages.pop();
}
// ... only when there are no more messages,
// will we ask if we should be destructed
else if ( m_pThis->m_bShouldBeDestructed )
{
// signal to the other thread we've finished
m_bHasFinished = true;
return;
}
}
// write the string
if ( pstr )
{
fprintf( m_pThis->m_pFile, pstr->c_str() );
fflush( m_pThis->m_pFile );
delete pstr;
sem_post( &(m_pThis->sem) );
}
else // nothing to write - wait
{
thread_manager::sleep( 1 );
}
}
}
this_class* m_pThis;
volatile bool m_bHasFinished;
};
public:
void add_message( const string_type& str )
{
sem_wait( &sem );
auto_lock_unlock locker( m_cs );
m_astrMessages.push( new string_type( str ) );
}
ThreadSafeWriter( FILE* & pFILE, NLTSAppender* pOwner, int maxQueueSize)
: m_maxQueueSize( maxQueueSize ),
m_pFile( pFILE ),
m_bShouldBeDestructed( false ),
m_pOwner( pOwner ),
m_astrMessages()
{
m_info.m_pThis = this;
sem_init( &sem, 0, m_maxQueueSize );
thread_manager::create_thread( m_info );
}
~ThreadSafeWriter()
{
// signal to the other thread we're about to be
// destructed
{
auto_lock_unlock locker( m_cs );
m_bShouldBeDestructed = true;
}
// wait while the other thread writes all messages
while ( true )
{
auto_lock_unlock locker( m_cs );
if ( m_info.m_bHasFinished )
// the other thread has finished
{
break;
}
}
sem_destroy( &sem );
}
critical_section& cs() const
{
return m_cs;
}
protected:
void doCheck()
{
if ( NLTime::getCalculateBeginTime(NLTime::gettimeofday(), m_pOwner->m_schedule) >= m_pOwner->m_nextRolloverTime )
{
m_pOwner->rollover(NLTSAppender::TIME_SWITCH);
return;
}
if ( ftell(m_pFile) > m_pOwner->m_maxFileSize )
{
m_pOwner->rollover(NLTSAppender::SIZE_SWITCH);
return;
}
}
private:
// the critical section used for thread-safe locking
mutable critical_section m_cs;
int m_maxQueueSize;
sem_t sem;
// needed to create the other thread
thread_info m_info;
volatile bool m_bShouldBeDestructed;
FILE* & m_pFile;
std::queue<string_type*> m_astrMessages;
NLTSAppender* m_pOwner;
};
friend class ThreadSafeWriter;
public:
/**
* 构造函数
* @param filename: 文件名
* @param schedule: 计划,默认按天
* @param immediateFlush: 是否立即刷新,默认立即
* @param maxFileSize: 最大文件尺寸,默认10M
* @param maxBackupIndex: 最大备份索引值,默认10000
* @param withAdorn: 是否带装饰语,默认带
* @return 无
*/
NLTSAppender(const std::string& filename,
NLDailyRollingSchedule schedule = DAILY,
bool immediateFlush = true,
long long maxFileSize = NLLOG_MAX_FILE_SIZE,
int maxBackupIndex = NLLOG_MAX_INDEX,
bool withAdorn = true,
int maxQueueSize = 1000);
/**
* 虚拟析构函数
* @param 无
* @return 无
*/
virtual ~NLTSAppender();
/**
* 关闭文件附加器
* @param 无
* @return 无
*/
virtual void close();
protected:
/**
* 切换类型
*/
enum switchtype
{
TIME_SWITCH, /**< 时间造成切换 */
SIZE_SWITCH, /**< 文件大小造成切换 */
CLOSE_SWITCH /**< 关闭造成切换 */
};
/**
* 文件附加器处理事件
* @param event: 事件
* @return 无
*/
virtual void append(const NLEvent& event);
/**
* 重新打开文件,并删除原文件
* @param filename: 文件名
* @param mode: 打开模式
* @return 无
*/
void reopen(const std::string& filename, const char* type);
/**
* 切换处理
* @param type: 切换类型
* @return 无
*/
void rollover(switchtype type);
/**
* 取切换时的文件名
* @param t: 当前时间
* @return string: 文件名
*/
std::string getFilename(const NLTime& t) const;
bool m_immediateFlush; /**< 是否立即刷新 */
bool m_withAdorn; /**< 是否带装饰语 */
FILE* m_out; /**< 文件输出流 */
std::string m_filename; /**< 文件名 */
ThreadSafeWriter* m_pTSWriter; /**< 线程安全写 */
NLDailyRollingSchedule m_schedule; /**< 循环类型 */
std::string m_scheduledFilename; /**< 循环问文件名 */
NLTime m_nextRolloverTime; /**< 下一次切换时间 */
int m_maxBackupIndex; /**< 最大备份索引值 */
long long m_maxFileSize; /**< 最大文件尺寸,单位:字节 */
private:
/**
* 初始化
* @param filename: 文件名
* @param type: 打开模式
* @param maxQueueSize: 写线程队列的最大长度
* @return 无
*/
void init(const std::string& filename, const char* type, int maxQueueSize);
/**
* 取当前的索引值
* @param 无
* @return int: 索引值
*/
int getCurIdx();
int m_curIdx; /**< 当前索引 */
NLTSAppender(const NLTSAppender&);
NLTSAppender& operator=(const NLTSAppender&);
};
}
#endif //_NL_TS_APPENDER_H
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -