]>
Commit | Line | Data |
---|---|---|
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 | |
37 | namespace ceph { | |
38 | namespace logging { | |
39 | ||
40 | static OnExitManager exit_callbacks; | |
41 | ||
42 | static 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 |
50 | Log::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 | ||
59 | Log::~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 | ||
72 | void 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 |
108 | void 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 | |
116 | void 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 | 129 | void 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 | 135 | void 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 | 141 | void 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 | 147 | void 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 |
153 | void 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 | ||
177 | void 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 | ||
190 | void 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 | ||
197 | void 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 | ||
204 | void 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 |
211 | void 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 | ||
223 | void Log::stop_graylog() | |
224 | { | |
11fdf7f2 | 225 | std::scoped_lock lock(m_flush_mutex); |
7c673cae | 226 | m_graylog.reset(); |
7c673cae FG |
227 | } |
228 | ||
20effc67 TL |
229 | void 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 | ||
236 | void 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 | ||
244 | void Log::stop_journald_logger() | |
245 | { | |
246 | std::scoped_lock lock(m_flush_mutex); | |
247 | m_journald.reset(); | |
248 | } | |
249 | ||
11fdf7f2 | 250 | void 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 | 270 | void 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 | 288 | void 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 |
302 | void Log::set_stderr_fd(int fd) |
303 | { | |
304 | m_fd_stderr = fd; | |
305 | _configure_stderr(); | |
306 | } | |
307 | ||
308 | void 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 | 365 | void 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 | 373 | void 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 | 453 | void 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 |
470 | template<typename T> |
471 | static 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 |
480 | void 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 | ||
539 | void 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 | ||
549 | void 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 | ||
562 | void *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 | ||
586 | bool Log::is_inside_log_lock() | |
587 | { | |
588 | return | |
589 | pthread_self() == m_queue_mutex_holder || | |
590 | pthread_self() == m_flush_mutex_holder; | |
591 | } | |
592 | ||
593 | void Log::inject_segv() | |
594 | { | |
595 | m_inject_segv = true; | |
596 | } | |
597 | ||
598 | void Log::reset_segv() | |
599 | { | |
600 | m_inject_segv = false; | |
601 | } | |
602 | ||
603 | } // ceph::logging:: | |
604 | } // ceph:: |