ceph log源码分析

ceph log源码分析

ceph中log的处理方法是,主线程生成并提交日志条目给log线程处理,典型用法如下:
ldout (cct, log_level)<< msg << dendl, 其中msg是要写入日志的内容.
以src/librbd/librbd.cc为例:

// 子系统名称,ceph的每个log模块是一个子系统
#define dout_subsys ceph_subsys_rbd
// 根据子系统重新定义dout_prefix,因为它最初定义在src/commom/dout.h中
#undef dout_prefix
#define dout_prefix *_dout << "librbd: "

// aio_read中log的用法, bl是读入数据的buffer
ldout(ictx->cct, 10) << "Image::aio_read() buf=" << (void *)bl.c_str() << "~"
			 << (void *)(bl.c_str() + len - 1) << dendl;

宏ldout和dend定义在文件src/common/dout.h中,如下所示:

#define dout_prefix *_dout

// sub: 子系统名称, v: 日志级别
#define dout_impl(cct, sub, v)						\
  do {									\
    if (cct->_conf->subsys.should_gather(sub, v)) {			\
    	if (0) {								\
        char __array[((v >= -1) && (v <= 200)) ? 0 : -1] __attribute__((unused)); \
  }									\
    static size_t _log_exp_length=80; \
    ceph::log::Entry *_dout_e = cct->_log->create_entry(v, sub, &_log_exp_length);	\
    ostream _dout_os(&_dout_e->m_streambuf);				\
    CephContext *_dout_cct = cct;					\
    std::ostream* _dout = &_dout_os;

#define ldout(cct, v)  dout_impl(cct, dout_subsys, v) dout_prefix

#define dendl std::flush;				\
  _ASSERT_H->_log->submit_entry(_dout_e);		\
    }						\
  } while (0)
// 宏替换之前
ldout(ictx->cct, 10) << "Image::aio_read() buf=" << (void *)bl.c_str() << "~"
			 << (void *)(bl.c_str() + len - 1) << dendl;
// 宏替换之后
do {									\
	if (cct->_conf->subsys.should_gather(ceph_subsys_rbd, v)) {			\
    	if (0) {								\
        	char __array[((v >= -1) && (v <= 200)) ? 0 : -1] __attribute__((unused)); \
        }									\
	    static size_t _log_exp_length=80; \
	    ceph::log::Entry *_dout_e = cct->_log->create_entry(v, ceph_subsys_rbd, &_log_exp_length);	\
	    ostream _dout_os(&_dout_e->m_streambuf);				\
	    CephContext *_dout_cct = cct;					\
	    std::ostream* _dout = &_dout_os;
	    *_dout << "librbd: "<< "Image::aio_read() buf=" << (void *)bl.c_str() << "~"
				 << (void *)(bl.c_str() + len - 1) << std::flush;				\
	  	_dout_cct->_log->submit_entry(_dout_e);		\
	}						\
} while (0)

从以上代码可以看出,由宏ldoutdendl组成一条完整的do { … } while(0)代码块,并在do中进行日志的生成和提交.其中利用**create_entry(来生成一个日志条目,利用submit_entry()**来提交一个日志条目.这两个工作都是由主线程调用log线程进行的处理的.

日志定义

log子系统主要的实现在目录src/log中,里面有一个很重要的类Log,它继承自线程类,自带线程处理日志功能. 因为打印日志,会影响系统的性能,特别是c++的流,对性能影响更明显.ceph这里采取了一些优化:

  1. ceph 对每个子系统的日志都预先定义了日志级别,并且可动态修改.
  2. 每条log都带有日志级别,日志级别越低,优先级越高.低于预先定义的级别才会被打印.
  3. log 信息只需要提交到Log类的线程即可,由log线程接管后台打印日志的任务.对提交log的线程影响较小

Log类的实现比较简单,维护两个队列,m_new用于提交新日志,flush的时候获取m_new的entry用来刷新,m_recent用来存放最近的日志,比如用户通过admin socket发送dump log的命令时,就会将m_recent的日志dump到文件:

class Log : private Thread
{
  Log **m_indirect_this;

  SubsystemMap *m_subs; // 每个子系统的日志级别的map
  
  pthread_mutex_t m_queue_mutex; // 这个锁专门用来提交日志
  pthread_mutex_t m_flush_mutex; // 这个锁用来打印提交的日志
  pthread_cond_t m_cond_loggers;
  pthread_cond_t m_cond_flusher;

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值