ceph log的实现

在src/commin/ceph_context.cc 中有初始化ceph的log模块
CephContext::CephContext(uint32_t module_type_, int init_flags_)
  : nref(1),
    _conf(new md_config_t(is_daemon(module_type_))),
    _log(NULL),
{
  ceph_spin_init(&_service_thread_lock);
  ceph_spin_init(&_associated_objs_lock);
  ceph_spin_init(&_fork_watchers_lock);
  ceph_spin_init(&_feature_lock);
  ceph_spin_init(&_cct_perf_lock);

  _log = new ceph::logging::Log(&_conf->subsys);
  _log->start();
}
可以看到首先创建一个log的实例。这里的log 类class Log : private Thread,继承thread。
其log类的实现在src/log/log.cc 中
Log::Log(SubsystemMap *s)
  : m_indirect_this(NULL),
    m_subs(s),
    m_queue_mutex_holder(0),
    m_flush_mutex_holder(0),
    m_new(), m_recent(),
    m_fd(-1),
    m_uid(0),
    m_gid(0),
    m_fd_last_error(0),
    m_syslog_log(-2), m_syslog_crash(-2),
    m_stderr_log(1), m_stderr_crash(-1),
    m_graylog_log(-3), m_graylog_crash(-3),
    m_stop(false),
    m_max_new(DEFAULT_MAX_NEW),
    m_max_recent(DEFAULT_MAX_RECENT),
    m_inject_segv(false)
{
  int ret;

  ret = pthread_mutex_init(&m_flush_mutex, NULL);
  assert(ret == 0);

  ret = pthread_mutex_init(&m_queue_mutex, NULL);
  assert(ret == 0);

  ret = pthread_cond_init(&m_cond_loggers, NULL);
  assert(ret == 0);

  ret = pthread_cond_init(&m_cond_flusher, NULL);
  assert(ret == 0);

  // kludge for prealloc testing
  if (false)
    for (int i=0; i < PREALLOC; i++)
      m_recent.enqueue(new Entry);
}
创建log实例后调用_log->start();开始记录log
void Log::start()
{
  assert(!is_started());
  pthread_mutex_lock(&m_queue_mutex);
  m_stop = false;
  pthread_mutex_unlock(&m_queue_mutex);
  create("log");
}
这里继续调用create("log");
log类没有实现create函数,因此调用的是父类的实现
源码在src/common/thread.cc 中
void Thread::create(const char *name, size_t stacksize)
{
  assert(strlen(name) < 16);
  thread_name = name;

  int ret = try_create(stacksize);
  if (ret != 0) {
    char buf[256];
    snprintf(buf, sizeof(buf), "Thread::try_create(): pthread_create "
	     "failed with error %d", ret);
    dout_emergency(buf);
    assert(ret == 0);
  }
}
继续调用thread.cc 的try_create来设置stack的size
int Thread::try_create(size_t stacksize)
{
  pthread_attr_t *thread_attr = NULL;
  pthread_attr_t thread_attr_loc;
  
  stacksize &= CEPH_PAGE_MASK;  // must be multiple of page
  if (stacksize) {
    thread_attr = &thread_attr_loc;
    pthread_attr_init(thread_attr);
    pthread_attr_setstacksize(thread_attr, stacksize);
  }

  int r;

  // The child thread will inherit our signal mask.  Set our signal mask to
  // the set of signals we want to block.  (It's ok to block signals more
  // signals than usual for a little while-- they will just be delivered to
  // another thread or delieverd to this thread later.)
  sigset_t old_sigset;
  if (g_code_env == CODE_ENVIRONMENT_LIBRARY) {
    block_signals(NULL, &old_sigset);
  }
  else {
    int to_block[] = { SIGPIPE , 0 };
    block_signals(to_block, &old_sigset);
  }
//创建一个thread来记录log,这个thread的回调函数是_entry_func
  r = pthread_create(&thread_id, thread_attr, _entry_func, (void*)this);
  restore_sigset(&old_sigset);

  if (thread_attr) {
    pthread_attr_destroy(thread_attr);	
  }

  return r;
}
thread的回调函数
void *Thread::_entry_func(void *arg) {
  void *r = ((Thread*)arg)->entry_wrapper();
  return r;
}
继续调用thread.cc 的entry_wrapper
void *Thread::entry_wrapper()
{
  int p = ceph_gettid(); // may return -ENOSYS on other platforms
  if (p > 0)
    pid = p;
  if (pid &&
      ioprio_class >= 0 &&
      ioprio_priority >= 0) {
    ceph_ioprio_set(IOPRIO_WHO_PROCESS,
		    pid,
		    IOPRIO_PRIO_VALUE(ioprio_class, ioprio_priority));
  }
  if (pid && cpuid >= 0)
    _set_affinity(cpuid);

  ceph_pthread_setname(pthread_self(), thread_name);
  return entry();
}
这里调用的entry 在thread.cc 没有定义,因此调用子类src/log/log.cc的entry实现
void *Log::entry()
{
  pthread_mutex_lock(&m_queue_mutex);
  m_queue_mutex_holder = pthread_self();
  while (!m_stop) {
    if (!m_new.empty()) {
      m_queue_mutex_holder = 0;
      pthread_mutex_unlock(&m_queue_mutex);
      flush();
      pthread_mutex_lock(&m_queue_mutex);
      m_queue_mutex_holder = pthread_self();
      continue;
    }

    pthread_cond_wait(&m_cond_flusher, &m_queue_mutex);
  }
  m_queue_mutex_holder = 0;
  pthread_mutex_unlock(&m_queue_mutex);
  flush();
  return NULL;
}
这里在while这个死循环中调用flush()来写log
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 从m_new 拿到要写的log,最后调用_flush写log
  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的具体实现如下:
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;
      }
//将log写道syslog中,这里通过syslog标准函数来写log
      if (do_syslog) {
        syslog(LOG_USER|LOG_INFO, "%s", buf);
      }
//将log写道串口中
      if (do_stderr) {
        cerr << buf << std::endl;
      }
//将log写道文件中
      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);
  }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值