]> git.proxmox.com Git - ceph.git/blame - ceph/src/log/Log.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / log / Log.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "Log.h"
5
7c673cae
FG
6#include "common/errno.h"
7#include "common/safe_io.h"
7c673cae 8#include "common/Graylog.h"
20effc67 9#include "common/Journald.h"
7c673cae
FG
10#include "common/valgrind.h"
11
11fdf7f2 12#include "include/ceph_assert.h"
7c673cae
FG
13#include "include/compat.h"
14#include "include/on_exit.h"
20effc67 15#include "include/uuid.h"
7c673cae
FG
16
17#include "Entry.h"
11fdf7f2 18#include "LogClock.h"
7c673cae
FG
19#include "SubsystemMap.h"
20
1e59de90
TL
21#include <boost/container/vector.hpp>
22
11fdf7f2
TL
23#include <errno.h>
24#include <fcntl.h>
1e59de90 25#include <limits.h>
11fdf7f2 26#include <syslog.h>
7c673cae 27
1e59de90 28#include <algorithm>
11fdf7f2 29#include <iostream>
9f95a23c 30#include <set>
7c673cae 31
f67539c2 32#include <fmt/format.h>
1e59de90 33#include <fmt/ostream.h>
f67539c2 34
11fdf7f2 35#define MAX_LOG_BUF 65536
7c673cae
FG
36
37namespace ceph {
38namespace logging {
39
40static OnExitManager exit_callbacks;
41
42static void log_on_exit(void *p)
43{
44 Log *l = *(Log **)p;
45 if (l)
46 l->flush();
47 delete (Log **)p;// Delete allocated pointer (not Log object, the pointer only!)
48}
49
11fdf7f2
TL
50Log::Log(const SubsystemMap *s)
51 : m_indirect_this(nullptr),
7c673cae 52 m_subs(s),
11fdf7f2 53 m_recent(DEFAULT_MAX_RECENT)
7c673cae 54{
11fdf7f2 55 m_log_buf.reserve(MAX_LOG_BUF);
1e59de90 56 _configure_stderr();
7c673cae
FG
57}
58
59Log::~Log()
60{
61 if (m_indirect_this) {
11fdf7f2 62 *m_indirect_this = nullptr;
7c673cae
FG
63 }
64
11fdf7f2 65 ceph_assert(!is_started());
1e59de90 66 if (m_fd >= 0) {
7c673cae 67 VOID_TEMP_FAILURE_RETRY(::close(m_fd));
1e59de90
TL
68 m_fd = -1;
69 }
70}
71
72void Log::_configure_stderr()
73{
74#ifndef _WIN32
75 struct stat info;
76 if (int rc = fstat(m_fd_stderr, &info); rc == -1) {
77 std::cerr << "failed to stat stderr: " << cpp_strerror(errno) << std::endl;
78 return;
79 }
80
81 if (S_ISFIFO(info.st_mode)) {
82 /* Set O_NONBLOCK on FIFO stderr file. We want to ensure atomic debug log
83 * writes so they do not get partially read by e.g. buggy container
84 * runtimes. See also IEEE Std 1003.1-2017 and Log::_log_stderr below.
85 *
86 * This isn't required on Windows.
87 */
88 int flags = fcntl(m_fd_stderr, F_GETFL);
89 if (flags == -1) {
90 std::cerr << "failed to get fcntl flags for stderr: " << cpp_strerror(errno) << std::endl;
91 return;
92 }
93 if (!(flags & O_NONBLOCK)) {
94 flags |= O_NONBLOCK;
95 flags = fcntl(m_fd_stderr, F_SETFL, flags);
96 if (flags == -1) {
97 std::cerr << "failed to set fcntl flags for stderr: " << cpp_strerror(errno) << std::endl;
98 return;
99 }
100 }
101 do_stderr_poll = true;
102 }
103#endif // !_WIN32
7c673cae
FG
104}
105
106
107///
11fdf7f2
TL
108void Log::set_coarse_timestamps(bool coarse) {
109 std::scoped_lock lock(m_flush_mutex);
110 if (coarse)
f6b5b4d7 111 Entry::clock().coarsen();
11fdf7f2 112 else
f6b5b4d7 113 Entry::clock().refine();
11fdf7f2 114}
7c673cae
FG
115
116void Log::set_flush_on_exit()
117{
11fdf7f2 118 std::scoped_lock lock(m_flush_mutex);
7c673cae
FG
119 // Make sure we flush on shutdown. We do this by deliberately
120 // leaking an indirect pointer to ourselves (on_exit() can't
121 // unregister a callback). This is not racy only becuase we
122 // assume that exit() won't race with ~Log().
123 if (m_indirect_this == NULL) {
124 m_indirect_this = new (Log*)(this);
125 exit_callbacks.add_callback(log_on_exit, m_indirect_this);
126 }
127}
128
11fdf7f2 129void Log::set_max_new(std::size_t n)
7c673cae 130{
11fdf7f2 131 std::scoped_lock lock(m_queue_mutex);
7c673cae
FG
132 m_max_new = n;
133}
134
11fdf7f2 135void Log::set_max_recent(std::size_t n)
7c673cae 136{
11fdf7f2 137 std::scoped_lock lock(m_flush_mutex);
1e59de90 138 m_recent.set_capacity(n);
7c673cae
FG
139}
140
11fdf7f2 141void Log::set_log_file(std::string_view fn)
7c673cae 142{
11fdf7f2 143 std::scoped_lock lock(m_flush_mutex);
7c673cae
FG
144 m_log_file = fn;
145}
146
11fdf7f2 147void Log::set_log_stderr_prefix(std::string_view p)
b32b8144 148{
11fdf7f2 149 std::scoped_lock lock(m_flush_mutex);
b32b8144
FG
150 m_log_stderr_prefix = p;
151}
152
7c673cae
FG
153void Log::reopen_log_file()
154{
11fdf7f2
TL
155 std::scoped_lock lock(m_flush_mutex);
156 if (!is_started()) {
157 return;
158 }
7c673cae 159 m_flush_mutex_holder = pthread_self();
1e59de90 160 if (m_fd >= 0) {
7c673cae 161 VOID_TEMP_FAILURE_RETRY(::close(m_fd));
1e59de90
TL
162 m_fd = -1;
163 }
7c673cae 164 if (m_log_file.length()) {
91327a77 165 m_fd = ::open(m_log_file.c_str(), O_CREAT|O_WRONLY|O_APPEND|O_CLOEXEC, 0644);
7c673cae 166 if (m_fd >= 0 && (m_uid || m_gid)) {
91327a77
AA
167 if (::fchown(m_fd, m_uid, m_gid) < 0) {
168 int e = errno;
169 std::cerr << "failed to chown " << m_log_file << ": " << cpp_strerror(e)
7c673cae
FG
170 << std::endl;
171 }
172 }
7c673cae
FG
173 }
174 m_flush_mutex_holder = 0;
7c673cae
FG
175}
176
177void Log::chown_log_file(uid_t uid, gid_t gid)
178{
11fdf7f2 179 std::scoped_lock lock(m_flush_mutex);
7c673cae
FG
180 if (m_fd >= 0) {
181 int r = ::fchown(m_fd, uid, gid);
182 if (r < 0) {
183 r = -errno;
11fdf7f2 184 std::cerr << "failed to chown " << m_log_file << ": " << cpp_strerror(r)
7c673cae
FG
185 << std::endl;
186 }
187 }
7c673cae
FG
188}
189
190void Log::set_syslog_level(int log, int crash)
191{
11fdf7f2 192 std::scoped_lock lock(m_flush_mutex);
7c673cae
FG
193 m_syslog_log = log;
194 m_syslog_crash = crash;
7c673cae
FG
195}
196
197void Log::set_stderr_level(int log, int crash)
198{
11fdf7f2 199 std::scoped_lock lock(m_flush_mutex);
7c673cae
FG
200 m_stderr_log = log;
201 m_stderr_crash = crash;
7c673cae
FG
202}
203
204void Log::set_graylog_level(int log, int crash)
205{
11fdf7f2 206 std::scoped_lock lock(m_flush_mutex);
7c673cae
FG
207 m_graylog_log = log;
208 m_graylog_crash = crash;
7c673cae
FG
209}
210
20effc67
TL
211void Log::start_graylog(const std::string& host,
212 const uuid_d& fsid)
7c673cae 213{
11fdf7f2 214 std::scoped_lock lock(m_flush_mutex);
20effc67 215 if (! m_graylog.get()) {
7c673cae 216 m_graylog = std::make_shared<Graylog>(m_subs, "dlog");
20effc67
TL
217 m_graylog->set_hostname(host);
218 m_graylog->set_fsid(fsid);
219 }
7c673cae
FG
220}
221
222
223void Log::stop_graylog()
224{
11fdf7f2 225 std::scoped_lock lock(m_flush_mutex);
7c673cae 226 m_graylog.reset();
7c673cae
FG
227}
228
20effc67
TL
229void Log::set_journald_level(int log, int crash)
230{
231 std::scoped_lock lock(m_flush_mutex);
232 m_journald_log = log;
233 m_journald_crash = crash;
234}
235
236void Log::start_journald_logger()
237{
238 std::scoped_lock lock(m_flush_mutex);
239 if (!m_journald) {
240 m_journald = std::make_unique<JournaldLogger>(m_subs);
241 }
242}
243
244void Log::stop_journald_logger()
245{
246 std::scoped_lock lock(m_flush_mutex);
247 m_journald.reset();
248}
249
11fdf7f2 250void Log::submit_entry(Entry&& e)
7c673cae 251{
11fdf7f2 252 std::unique_lock lock(m_queue_mutex);
7c673cae
FG
253 m_queue_mutex_holder = pthread_self();
254
11fdf7f2 255 if (unlikely(m_inject_segv))
7c673cae
FG
256 *(volatile int *)(0) = 0xdead;
257
258 // wait for flush to catch up
11fdf7f2
TL
259 while (is_started() &&
260 m_new.size() > m_max_new) {
261 if (m_stop) break; // force addition
262 m_cond_loggers.wait(lock);
263 }
7c673cae 264
11fdf7f2
TL
265 m_new.emplace_back(std::move(e));
266 m_cond_flusher.notify_all();
7c673cae 267 m_queue_mutex_holder = 0;
7c673cae
FG
268}
269
11fdf7f2 270void Log::flush()
7c673cae 271{
11fdf7f2
TL
272 std::scoped_lock lock1(m_flush_mutex);
273 m_flush_mutex_holder = pthread_self();
274
275 {
276 std::scoped_lock lock2(m_queue_mutex);
277 m_queue_mutex_holder = pthread_self();
278 assert(m_flush.empty());
279 m_flush.swap(m_new);
280 m_cond_loggers.notify_all();
281 m_queue_mutex_holder = 0;
7c673cae 282 }
11fdf7f2 283
9f95a23c 284 _flush(m_flush, false);
11fdf7f2 285 m_flush_mutex_holder = 0;
7c673cae
FG
286}
287
11fdf7f2 288void Log::_log_safe_write(std::string_view sv)
7c673cae 289{
11fdf7f2
TL
290 if (m_fd < 0)
291 return;
292 int r = safe_write(m_fd, sv.data(), sv.size());
293 if (r != m_fd_last_error) {
294 if (r < 0)
295 std::cerr << "problem writing to " << m_log_file
296 << ": " << cpp_strerror(r)
297 << std::endl;
298 m_fd_last_error = r;
7c673cae
FG
299 }
300}
301
1e59de90
TL
302void Log::set_stderr_fd(int fd)
303{
304 m_fd_stderr = fd;
305 _configure_stderr();
306}
307
308void Log::_log_stderr(std::string_view strv)
309{
310 if (do_stderr_poll) {
311 auto& prefix = m_log_stderr_prefix;
312 size_t const len = prefix.size() + strv.size();
313 boost::container::small_vector<char, PIPE_BUF> buf;
314 buf.resize(len+1, '\0');
315 memcpy(buf.data(), prefix.c_str(), prefix.size());
316 memcpy(buf.data()+prefix.size(), strv.data(), strv.size());
317
318 char const* const start = buf.data();
319 char const* current = start;
320 while ((size_t)(current-start) < len) {
321 auto chunk = std::min<ssize_t>(PIPE_BUF, len-(ssize_t)(current-start));
322 while (1) {
323 ssize_t rc = write(m_fd_stderr, current, chunk);
324 if (rc == chunk) {
325 current += chunk;
326 break;
327 } else if (rc > 0) {
328 /* According to IEEE Std 1003.1-2017, this cannot happen:
329 *
330 * Write requests to a pipe or FIFO shall be handled in the same way as a regular file with the following exceptions:
331 * ...
332 * If the O_NONBLOCK flag is set ...
333 * ...
334 * A write request for {PIPE_BUF} or fewer bytes shall have the
335 * following effect: if there is sufficient space available in
336 * the pipe, write() shall transfer all the data and return the
337 * number of bytes requested. Otherwise, write() shall transfer
338 * no data and return -1 with errno set to [EAGAIN].
339 *
340 * In any case, handle misbehavior gracefully by incrementing current.
341 */
342 current += rc;
343 break;
344 } else if (rc == -1) {
345 if (errno == EAGAIN) {
346 struct pollfd pfd[1];
347 pfd[0].fd = m_fd_stderr;
348 pfd[0].events = POLLOUT;
349 poll(pfd, 1, -1);
350 /* ignore errors / success, just retry the write */
351 } else if (errno == EINTR) {
352 continue;
353 } else {
354 /* some other kind of error, no point logging if stderr writes fail */
355 return;
356 }
357 }
358 }
359 }
360 } else {
361 fmt::print(std::cerr, "{}{}", m_log_stderr_prefix, strv);
362 }
363}
364
11fdf7f2 365void Log::_flush_logbuf()
7c673cae 366{
11fdf7f2
TL
367 if (m_log_buf.size()) {
368 _log_safe_write(std::string_view(m_log_buf.data(), m_log_buf.size()));
369 m_log_buf.resize(0);
7c673cae 370 }
7c673cae
FG
371}
372
9f95a23c 373void Log::_flush(EntryVector& t, bool crash)
7c673cae 374{
11fdf7f2 375 long len = 0;
9f95a23c
TL
376 if (t.empty()) {
377 assert(m_log_buf.empty());
378 return;
379 }
11fdf7f2
TL
380 if (crash) {
381 len = t.size();
382 }
11fdf7f2
TL
383 for (auto& e : t) {
384 auto prio = e.m_prio;
385 auto stamp = e.m_stamp;
386 auto sub = e.m_subsys;
387 auto thread = e.m_thread;
388 auto str = e.strv();
389
390 bool should_log = crash || m_subs->get_log_level(sub) >= prio;
7c673cae 391 bool do_fd = m_fd >= 0 && should_log;
11fdf7f2
TL
392 bool do_syslog = m_syslog_crash >= prio && should_log;
393 bool do_stderr = m_stderr_crash >= prio && should_log;
394 bool do_graylog2 = m_graylog_crash >= prio && should_log;
20effc67 395 bool do_journald = m_journald_crash >= prio && should_log;
7c673cae 396
7c673cae 397 if (do_fd || do_syslog || do_stderr) {
11fdf7f2
TL
398 const std::size_t cur = m_log_buf.size();
399 std::size_t used = 0;
400 const std::size_t allocated = e.size() + 80;
401 m_log_buf.resize(cur + allocated);
7c673cae 402
11fdf7f2
TL
403 char* const start = m_log_buf.data();
404 char* pos = start + cur;
405
406 if (crash) {
407 used += (std::size_t)snprintf(pos + used, allocated - used, "%6ld> ", -(--len));
7c673cae 408 }
11fdf7f2
TL
409 used += (std::size_t)append_time(stamp, pos + used, allocated - used);
410 used += (std::size_t)snprintf(pos + used, allocated - used, " %lx %2d ", (unsigned long)thread, prio);
411 memcpy(pos + used, str.data(), str.size());
412 used += str.size();
413 pos[used] = '\0';
414 ceph_assert((used + 1 /* '\n' */) < allocated);
7c673cae
FG
415
416 if (do_syslog) {
11fdf7f2 417 syslog(LOG_USER|LOG_INFO, "%s", pos);
7c673cae
FG
418 }
419
11fdf7f2
TL
420 /* now add newline */
421 pos[used++] = '\n';
422
1e59de90
TL
423 if (do_stderr) {
424 _log_stderr(std::string_view(pos, used));
425 }
426
7c673cae 427 if (do_fd) {
11fdf7f2
TL
428 m_log_buf.resize(cur + used);
429 } else {
430 m_log_buf.resize(0);
431 }
432
433 if (m_log_buf.size() > MAX_LOG_BUF) {
434 _flush_logbuf();
7c673cae 435 }
7c673cae 436 }
11fdf7f2 437
7c673cae
FG
438 if (do_graylog2 && m_graylog) {
439 m_graylog->log_entry(e);
440 }
441
20effc67
TL
442 if (do_journald && m_journald) {
443 m_journald->log_entry(e);
444 }
445
9f95a23c 446 m_recent.push_back(std::move(e));
7c673cae 447 }
11fdf7f2
TL
448 t.clear();
449
450 _flush_logbuf();
7c673cae
FG
451}
452
f67539c2 453void Log::_log_message(std::string_view s, bool crash)
7c673cae
FG
454{
455 if (m_fd >= 0) {
f67539c2
TL
456 std::string b = fmt::format("{}\n", s);
457 int r = safe_write(m_fd, b.data(), b.size());
7c673cae 458 if (r < 0)
11fdf7f2 459 std::cerr << "problem writing to " << m_log_file << ": " << cpp_strerror(r) << std::endl;
7c673cae
FG
460 }
461 if ((crash ? m_syslog_crash : m_syslog_log) >= 0) {
f67539c2 462 syslog(LOG_USER|LOG_INFO, "%.*s", static_cast<int>(s.size()), s.data());
7c673cae
FG
463 }
464
465 if ((crash ? m_stderr_crash : m_stderr_log) >= 0) {
11fdf7f2 466 std::cerr << s << std::endl;
7c673cae
FG
467 }
468}
469
f67539c2
TL
470template<typename T>
471static uint64_t tid_to_int(T tid)
472{
473 if constexpr (std::is_pointer_v<T>) {
474 return reinterpret_cast<std::uintptr_t>(tid);
475 } else {
476 return tid;
477 }
478}
479
7c673cae
FG
480void Log::dump_recent()
481{
11fdf7f2 482 std::scoped_lock lock1(m_flush_mutex);
7c673cae
FG
483 m_flush_mutex_holder = pthread_self();
484
11fdf7f2
TL
485 {
486 std::scoped_lock lock2(m_queue_mutex);
487 m_queue_mutex_holder = pthread_self();
488 assert(m_flush.empty());
489 m_flush.swap(m_new);
490 m_queue_mutex_holder = 0;
491 }
7c673cae 492
9f95a23c 493 _flush(m_flush, false);
7c673cae 494
7c673cae 495 _log_message("--- begin dump of recent events ---", true);
9f95a23c 496 std::set<pthread_t> recent_pthread_ids;
11fdf7f2
TL
497 {
498 EntryVector t;
499 t.insert(t.end(), std::make_move_iterator(m_recent.begin()), std::make_move_iterator(m_recent.end()));
500 m_recent.clear();
9f95a23c
TL
501 for (const auto& e : t) {
502 recent_pthread_ids.emplace(e.m_thread);
503 }
504 _flush(t, true);
11fdf7f2 505 }
7c673cae 506
7c673cae 507 _log_message("--- logging levels ---", true);
11fdf7f2 508 for (const auto& p : m_subs->m_subsys) {
f67539c2
TL
509 _log_message(fmt::format(" {:2d}/{:2d} {}",
510 p.log_level, p.gather_level, p.name), true);
7c673cae 511 }
f67539c2
TL
512 _log_message(fmt::format(" {:2d}/{:2d} (syslog threshold)",
513 m_syslog_log, m_syslog_crash), true);
514 _log_message(fmt::format(" {:2d}/{:2d} (stderr threshold)",
515 m_stderr_log, m_stderr_crash), true);
9f95a23c
TL
516
517 _log_message("--- pthread ID / name mapping for recent threads ---", true);
518 for (const auto pthread_id : recent_pthread_ids)
519 {
520 char pthread_name[16] = {0}; //limited by 16B include terminating null byte.
521 ceph_pthread_getname(pthread_id, pthread_name, sizeof(pthread_name));
20effc67
TL
522 // we want the ID to be printed in the same format as we use for a log entry.
523 // The reason is easier grepping.
524 _log_message(fmt::format(" {:x} / {}",
f67539c2 525 tid_to_int(pthread_id), pthread_name), true);
9f95a23c
TL
526 }
527
1e59de90
TL
528 _log_message(fmt::format(" max_recent {:9}", m_recent.capacity()), true);
529 _log_message(fmt::format(" max_new {:9}", m_max_new), true);
f67539c2 530 _log_message(fmt::format(" log_file {}", m_log_file), true);
7c673cae
FG
531
532 _log_message("--- end dump of recent events ---", true);
533
9f95a23c 534 assert(m_log_buf.empty());
11fdf7f2 535
7c673cae 536 m_flush_mutex_holder = 0;
7c673cae
FG
537}
538
539void Log::start()
540{
11fdf7f2
TL
541 ceph_assert(!is_started());
542 {
543 std::scoped_lock lock(m_queue_mutex);
544 m_stop = false;
545 }
7c673cae
FG
546 create("log");
547}
548
549void Log::stop()
550{
28e407b8 551 if (is_started()) {
11fdf7f2
TL
552 {
553 std::scoped_lock lock(m_queue_mutex);
554 m_stop = true;
555 m_cond_flusher.notify_one();
556 m_cond_loggers.notify_all();
557 }
28e407b8
AA
558 join();
559 }
7c673cae
FG
560}
561
562void *Log::entry()
563{
11fdf7f2
TL
564 reopen_log_file();
565 {
566 std::unique_lock lock(m_queue_mutex);
567 m_queue_mutex_holder = pthread_self();
568 while (!m_stop) {
569 if (!m_new.empty()) {
570 m_queue_mutex_holder = 0;
571 lock.unlock();
572 flush();
573 lock.lock();
574 m_queue_mutex_holder = pthread_self();
575 continue;
576 }
7c673cae 577
11fdf7f2
TL
578 m_cond_flusher.wait(lock);
579 }
580 m_queue_mutex_holder = 0;
7c673cae 581 }
7c673cae
FG
582 flush();
583 return NULL;
584}
585
586bool Log::is_inside_log_lock()
587{
588 return
589 pthread_self() == m_queue_mutex_holder ||
590 pthread_self() == m_flush_mutex_holder;
591}
592
593void Log::inject_segv()
594{
595 m_inject_segv = true;
596}
597
598void Log::reset_segv()
599{
600 m_inject_segv = false;
601}
602
603} // ceph::logging::
604} // ceph::