开源日志系统log4cplus(七)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介:

经过短暂的熟悉过程,log4cplus已经被成功应用到了我的项目中去了,效果还不错,:)除了上文提及的
功能之外,下面将介绍log4cplus提供的线程和套接字的使用情况。

### NDC ###
首先我们先了解一下log4cplus中嵌入诊断上下文(Nested Diagnostic Context),即NDC。对log系统而言,
当输入源可能不止一个,而只有一个输出时,往往需要分辩所要输出消息的来源,比如服务器处理来自不同
客户端的消息时就需要作此判断,NDC可以为交错显示的信息打上一个标记(stamp), 使得辨认工作看起来
比较容易些,呵呵。这个标记是线程特有的,利用了线程局部存储机制,称为线程私有数据(Thread-specific
 Data,或TSD)。 看了一下源代码,相关定义如下,包括定义、初始化、获取、设置和清除操作:
linux pthread

 
 
#   define LOG4CPLUS_THREAD_LOCAL_TYPE pthread_key_t*
#   define LOG4CPLUS_THREAD_LOCAL_INIT ::log4cplus::thread::createPthreadKey()
#   define LOG4CPLUS_GET_THREAD_LOCAL_VALUE( key ) pthread_getspecific(*key)
#   define LOG4CPLUS_SET_THREAD_LOCAL_VALUE( key, value ) pthread_setspecific(*key, value)
#   define LOG4CPLUS_THREAD_LOCAL_CLEANUP( key ) pthread_key_delete(*key)

win32

 
 
#   define LOG4CPLUS_THREAD_LOCAL_TYPE DWORD
#   define LOG4CPLUS_THREAD_LOCAL_INIT TlsAlloc()
#   define LOG4CPLUS_GET_THREAD_LOCAL_VALUE( key ) TlsGetValue(key)
#   define LOG4CPLUS_SET_THREAD_LOCAL_VALUE( key, value ) \       TlsSetValue(key, static_cast(value))
#   define LOG4CPLUS_THREAD_LOCAL_CLEANUP( key ) TlsFree(key)
				
使用起来比较简单,在某个线程中:

 
 
    NDC& ndc = log4cplus::getNDC();
    ndc.push("ur ndc string");
    LOG4CPLUS_DEBUG(logger, "this is a NDC test");
      
    ndc.pop();
         
    LOG4CPLUS_DEBUG(logger, "There should be no NDC ");
    ndc.remove();


   
当设定输出格式(Layout)为TTCCLayout时,输出如下:
10-21-04 21:32:58, [3392] DEBUG test 
 
   - this is a NDC test
  
  
10-21-04 21:32:58, [3392] DEBUG test <> - There should be no NDC...
也可以在自定义的输出格式中使用NDC(用%x) ,比如:

 
 
      
  std:: string pattern = "NDC:[%x]  - %m %n";
  std::auto_ptr _layout( new PatternLayout(pattern));
      
 LOG4CPLUS_DEBUG(_logger, "This is the FIRST log message ")
  NDC& ndc = log4cplus::getNDC();
  ndc.push("ur ndc string"); 
  LOG4CPLUS_WARN(_logger, "This is the SECOND log message ")
  ndc.pop();
 ndc.remove(); 
     

   
输出如下:
NDC:[]  - This is the FIRST log message...
NDC:[ur ndc string]  - This is the SECOND log message...
				
另外一种更简单的使用方法是在线程中直接用NDCContextCreator:

 
 
    NDCContextCreator _first_ndc("ur ndc string");
    LOG4CPLUS_DEBUG(logger, "this is a NDC test")

   
不必显式地调用push/pop了,而且当出现异常时,能够确保push与pop的调用是匹配的。
    
### 线程 ###
线程是log4cplus中的副产品, 而且仅作了最基本的实现,使用起来也异常简单,只要且必须要
在派生类中重载run函数即可:

 
 
class TestThread :  public AbstractThread
{
public:
    virtual void run();
}
;
                
void TestThread::run()

   /* do sth. */ 
    
}

log4cplus的线程没有考虑同步、死锁,有互斥,实现线程切换的小函数挺别致的:

 
 
void log4cplus::thread::yield()
{
#if defined(LOG4CPLUS_USE_PTHREADS)
    ::sched_yield();
#elif defined(LOG4CPLUS_USE_WIN32_THREADS)
    ::Sleep(0);
#endif
}
				
### 套接字 ###
套接字也是log4cplus中的副产品,在namespace log4cplus::helpers中,实现了C/S方式的日志记录。
1. 客户端程序需要做的工作:

 
 
/* 定义一个SocketAppender类型的挂接器 */SharedAppenderPtr _append( new SocketAppender(host, 8888, "ServerName"));
/* 把_append加入到logger中 */Logger::getRoot().addAppender(_append);
/*  SocketAppender类型不需要Layout, 直接调用宏就可以将信息发往loggerServer了 */LOG4CPLUS_INFO(Logger::getRoot(), "This is a test: ")

【注】 这里对宏的调用其实是调用了SocketAppender::append,里面有一个数据传输约定,即先发送
一个后续数据的总长度,然后再发送实际的数据:

 
 
      
    SocketBuffer buffer = convertToBuffer( event, serverName);
    SocketBuffer msgBuffer(LOG4CPLUS_MAX_MESSAGE_SIZE);
    msgBuffer.appendSize_t(buffer.getSize());
    msgBuffer.appendBuffer(buffer);         
				
2. 服务器端程序需要做的工作:

 
 
/* 定义一个ServerSocket */ServerSocket serverSocket(port);
 
/* 调用accept函数创建一个新的socket与客户端连接 */Socket sock = serverSocket.accept();
				
此后即可用该sock进行数据read/write了,形如:

 
 
SocketBuffer msgSizeBuffer( sizeof(unsigned  int));
if(!clientsock.read(msgSizeBuffer))
{
    return;
}

unsigned  int msgSize = msgSizeBuffer.readInt();
SocketBuffer buffer(msgSize);
if(!clientsock.read(buffer))
{
    return;
}

为了将读到的数据正常显示出来,需要将SocketBuffer存放的内容转换成InternalLoggingEvent格式:

 
 
spi::InternalLoggingEvent  event = readFromBuffer(buffer);
然后输出:
Logger logger = Logger::getInstance( event.getLoggerName());
logger.callAppenders( event);
				
【注】 read/write是按照阻塞方式实现的,意味着对其调用直到满足了所接收或发送的个数才返回。
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
19天前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
156 30
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
22天前
|
存储 运维 监控
开源日志Graylog
【10月更文挑战第21天】
80 8
|
22天前
|
存储 数据采集 监控
开源日志Fluentd
【10月更文挑战第21天】
34 7
|
22天前
|
存储 监控 安全
|
21天前
|
存储 数据采集 监控
开源日志分析Elasticsearch
【10月更文挑战第22天】
44 5
|
19天前
|
存储 Linux Docker
centos系统清理docker日志文件
通过以上方法,可以有效清理和管理CentOS系统中的Docker日志文件,防止日志文件占用过多磁盘空间。选择合适的方法取决于具体的应用场景和需求,可以结合手动清理、logrotate和调整日志驱动等多种方式,确保系统的高效运行。
20 2
|
21天前
|
机器学习/深度学习 运维 监控
开源日志分析Kibana
【10月更文挑战第22天】
29 3
|
21天前
|
存储 JSON 监控
开源日志分析Logstash
【10月更文挑战第22天】
35 1
|
23天前
|
存储 运维 监控
开源日志分析工具
【10月更文挑战第20天】
49 3
|
1月前
|
XML JSON 监控
告别简陋:Java日志系统的最佳实践
【10月更文挑战第19天】 在Java开发中,`System.out.println()` 是最基本的输出方法,但它在实际项目中往往被认为是不专业和不足够的。本文将探讨为什么在现代Java应用中应该避免使用 `System.out.println()`,并介绍几种更先进的日志解决方案。
48 1
下一篇
无影云桌面