ceph log机制

Log 是每个项目必须的,他是跟踪问题的最直接的依据。Ceph 也设计自己的log机制。

 

初始化启动log实例,启动log线程。

 

  _log = new ceph::log::Log(&_conf->subsys);

  _log->start();

 

日志的工作函数:

比较简单,交换队列到临时队列t 中,释放条件变量,开始进入_flush的写操作。

void Log::flush()

{

  pthread_mutex_lock(&m_flush_mutex);

  m_flush_mutex_holder = pthread_self();

  pthread_mutex_lock(&m_queue_mutex);

  m_queue_mutex_holder = pthread_self();

  EntryQueue t;

  t.swap(m_new);

  pthread_cond_broadcast(&m_cond_loggers);

  m_queue_mutex_holder = 0;

  pthread_mutex_unlock(&m_queue_mutex);

  _flush(&t, &m_recent, false);

 

  // trim

  while (m_recent.m_len > m_max_recent) {

    delete m_recent.dequeue();

  }

 

  m_flush_mutex_holder = 0;

  pthread_mutex_unlock(&m_flush_mutex);

}

 

_flush函数中主要根据subsys 和 其level决定是否写日志,m_subs是负责管理subsys的一个map表。

这个表是如何生成的呢。

注意参数:crash 当dump_recent的才会被调用。

void Log::_flush(EntryQueue *t, EntryQueue *requeue, bool crash)

{

  Entry *e;

  while ((e = t->dequeue()) != NULL) {

    unsigned sub = e->m_subsys;

 

    bool should_log = crash || m_subs->get_log_level(sub) >= e->m_prio;

    bool do_fd = m_fd >= 0 && should_log;

    bool do_syslog = m_syslog_crash >= e->m_prio && should_log;

    bool do_stderr = m_stderr_crash >= e->m_prio && should_log;

    bool do_graylog2 = m_graylog_crash >= e->m_prio && should_log;

 

    e->hint_size();

    if (do_fd || do_syslog || do_stderr) {

      size_t buflen = 0;

 

      char *buf;

      size_t buf_size = 80 + e->size();

      bool need_dynamic = buf_size >= 0x10000; //avoids >64K buffers

                                                      //allocation at stack

      char buf0[need_dynamic ? 1 : buf_size];

      if (need_dynamic) {

        buf = new char[buf_size];

      } else {

        buf = buf0;

      }

 

      if (crash)

         buflen += snprintf(buf, buf_size, "%6d> ", -t->m_len);

      buflen += e->m_stamp.sprintf(buf + buflen, buf_size-buflen);

      buflen += snprintf(buf + buflen, buf_size-buflen, " %lx %2d ",

                            (unsigned long)e->m_thread, e->m_prio);

 

      buflen += e->snprintf(buf + buflen, buf_size - buflen - 1);

      if (buflen > buf_size - 1) { //paranoid check, buf was declared

                                        //to hold everything

        buflen = buf_size - 1;

        buf[buflen] = 0;

      }

 

      if (do_syslog) {

        syslog(LOG_USER|LOG_INFO, "%s", buf);

      }

 

      if (do_stderr) {

        cerr << buf << std::endl;

      }

      if (do_fd) {

        buf[buflen] = '\n';

        int r = safe_write(m_fd, buf, buflen+1);

         if (r != m_fd_last_error) {

           if (r < 0)

             cerr << "problem writing to " << m_log_file

                    << ": " << cpp_strerror(r)

                    << std::endl;

           m_fd_last_error = r;

         }

      }

      if (need_dynamic)

        delete[] buf;

    }

    if (do_graylog2 && m_graylog) {

      m_graylog->log_entry(e);

    }

 

    requeue->enqueue(e);

  }

}

 

SubsystemMap

负责管理所有的subsys。

 

_log = new ceph::log::Log(&_conf->subsys);

通过参数将其传入到Log.cc中。

 

_conf->subsys的初始化工作,如何做的呢?

首先定义了3个宏

定义宏SUBSYS(name, log, gather) 是执行subsys.add(ceph_subsys_##name, STRINGIFY(name), log, gather);

定义宏DEFAULT_SUBSYS(log, gather) 是执行subsys.add(ceph_subsys_, "none", log, gather);

定义宏#define OPTION(a, b, c) 为空

将config_opts.h展开,依次执行subsys.add即可完成,

 

void md_config_t::init_subsys()

{

#define SUBSYS(name, log, gather)

subsys.add(ceph_subsys_##name, STRINGIFY(name), log, gather);

#define DEFAULT_SUBSYS(log, gather)

subsys.add(ceph_subsys_, "none", log, gather);

#define OPTION(a, b, c)

#include "common/config_opts.h"

#undef OPTION

#undef SUBSYS

#undef DEFAULT_SUBSYS

}

 

ceph_subsys_##name 的值从哪儿来的呢?同样使用了宏的机制。和上一个宏一样,展开后在enum变量中。

enum config_subsys_id {

  ceph_subsys_,   // default

#define OPTION(a,b,c)

#define SUBSYS(name, log, gather) \

  ceph_subsys_##name,

#define DEFAULT_SUBSYS(log, gather)

#include "common/config_opts.h"

#undef SUBSYS

#undef OPTION

#undef DEFAULT_SUBSYS

  ceph_subsys_max

};

 

如何调用ldout 写日志呢?

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

Dout_impl 生成了log_entry 写入到日志文件, dout_prefix 标准输出

posted @ 2017-01-11 10:12  大米粥的博客  阅读(1196)  评论(0编辑  收藏  举报