Ceph日誌管理
Ceph產生的日誌是怎麼進行歸檔或者處理的呢?
在Linux下,基本上都是使用logrotate日誌管理工具來處理日誌的。關於logrotate的詳解可以通過這篇文章瞭解: http://www.ywnds.com/?p=5471
關於Ceph的日誌處理的logrotate的配置,可以查看/etc/logrotate.d/ceph文件,源碼中的話在ceph/src/logrotate.conf中。
我們來看一下這個配置文件:
/var/log/ceph/*.log {
rotate 7
daily
compress
sharedscripts
postrotate
killall -q -1 ceph-mon ceph-mds ceph-osd ceph-fuse radosgw || true
endscript
missingok
notifempty
su root ceph
}
從上面的這個logrotate配置中,我們可以看出:
Ceph日誌是保留7天;
每天做一次壓縮、轉儲;
其中的命令:
postrotate
killall -q -1 ceph-mon ceph-mds ceph-osd ceph-fuse radosgw || true
postrotate是指每次做完轉儲之後要做的命令。killall這條命令就是要執行的。
乍一看這條命令,爲什麼是向ceph的那些進程發送信號呢,豈不是關掉那些進程嗎。
killall的命令中-1就是具體的信號,通過man 7 SIGNAL可以看到信號1就是SIGHUB信號,默認SIGHUP信號的處理是直接中斷服務的。
難道真是停止所有ceph服務嗎?肯定不對,我們就去看看ceph-mon ceph-osd的代碼,看怎麼處理這個信號的。
ceph-mon ceph-osd服務的入口函數都是ceph_mon.cc或者ceph_osd.cc,下面我們以ceph-osd服務來看:
ceph_osd.cc:
int main(int argc, const char **argv)
{
...
register_async_signal_handler(SIGHUP, sighup_handler);
...
unregister_async_signal_handler(SIGHUP, sighup_handler);
...
}
從main函數中可見,註冊了一個信號處理函數,對SIGHUP信號進行處理,回調處理函數是sighup_handler:
void sighup_handler(int signum)
{
g_ceph_context->reopen_logs();
}
reopen_logs函數如下:
void CephContext::reopen_logs()
{
ceph_spin_lock(&_service_thread_lock);
if (_service_thread)
_service_thread->reopen_logs();
ceph_spin_unlock(&_service_thread_lock);
}
然後調用到了reopen_logs:
void reopen_logs()
{
Mutex::Locker l(_lock);
_reopen_logs = true;
_cond.Signal();
}
該函數中,將_reopen_logs這個變量設置爲true,並且,喚醒了等待_cond的函數。
通過搜索_reopen_logs變量,可以看到在如下的函數中處理:
void *entry()
{
while (1) {
if (_cct->_conf->heartbeat_interval) {
utime_t interval(_cct->_conf->heartbeat_interval, 0);
_cond.WaitInterval(_cct, _lock, interval);
} else
_cond.Wait(_lock);
if (_reopen_logs) {
_cct->_log->reopen_log_file();
_reopen_logs = false;
}
...
}
該函數是CephContextServiceThread類型的thread的線程入口函數,在死循環中,會根據heartbeat時間間隔,來進行心跳處理,同時,也在等待_cond這個條件變量,上面的reopen_logs函數喚醒的就是這個。進而,調用了reopen_log_file()函數。
這裏的reopen_log_file是具體的reopen log函數:
void Log::reopen_log_file()
{
if (m_fd >= 0)
VOID_TEMP_FAILURE_RETRY(::close(m_fd));
if (m_log_file.length()) {
m_fd = ::open(m_log_file.c_str(), O_CREAT|O_WRONLY|O_APPEND, 0644);
if (m_fd >= 0 && (m_uid || m_gid)) {
int r = ::fchown(m_fd, m_uid, m_gid);
if (r < 0) {
r = -errno;
cerr << "failed to chown " << m_log_file << ": " << cpp_strerror(r)
<< std::endl;
}
}
} else {
m_fd = -1;
}
}
先看fd是否有效,否則,就創建m_log_file, m_log_file就是具體的log路徑及文件名。