1dda28197Spatrick //===-- Log.cpp -----------------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Utility/Log.h"
10061da546Spatrick #include "lldb/Utility/VASPrintf.h"
11061da546Spatrick
12061da546Spatrick #include "llvm/ADT/SmallString.h"
13061da546Spatrick #include "llvm/ADT/Twine.h"
14061da546Spatrick #include "llvm/ADT/iterator.h"
15061da546Spatrick
16*f6aab3d8Srobert #include "llvm/Support/Casting.h"
17061da546Spatrick #include "llvm/Support/Chrono.h"
18061da546Spatrick #include "llvm/Support/ManagedStatic.h"
19061da546Spatrick #include "llvm/Support/Path.h"
20061da546Spatrick #include "llvm/Support/Signals.h"
21061da546Spatrick #include "llvm/Support/Threading.h"
22061da546Spatrick #include "llvm/Support/raw_ostream.h"
23061da546Spatrick
24061da546Spatrick #include <chrono>
25061da546Spatrick #include <cstdarg>
26061da546Spatrick #include <mutex>
27061da546Spatrick #include <utility>
28061da546Spatrick
29be691f3bSpatrick #include <cassert>
30061da546Spatrick #if defined(_WIN32)
31061da546Spatrick #include <process.h>
32061da546Spatrick #else
33061da546Spatrick #include <unistd.h>
34061da546Spatrick #endif
35061da546Spatrick
36061da546Spatrick using namespace lldb_private;
37061da546Spatrick
38*f6aab3d8Srobert char LogHandler::ID;
39*f6aab3d8Srobert char StreamLogHandler::ID;
40*f6aab3d8Srobert char CallbackLogHandler::ID;
41*f6aab3d8Srobert char RotatingLogHandler::ID;
42*f6aab3d8Srobert
43061da546Spatrick llvm::ManagedStatic<Log::ChannelMap> Log::g_channel_map;
44061da546Spatrick
ForEachCategory(const Log::ChannelMap::value_type & entry,llvm::function_ref<void (llvm::StringRef,llvm::StringRef)> lambda)45061da546Spatrick void Log::ForEachCategory(
46061da546Spatrick const Log::ChannelMap::value_type &entry,
47061da546Spatrick llvm::function_ref<void(llvm::StringRef, llvm::StringRef)> lambda) {
48061da546Spatrick lambda("all", "all available logging categories");
49061da546Spatrick lambda("default", "default set of logging categories");
50061da546Spatrick for (const auto &category : entry.second.m_channel.categories)
51061da546Spatrick lambda(category.name, category.description);
52061da546Spatrick }
53061da546Spatrick
ListCategories(llvm::raw_ostream & stream,const ChannelMap::value_type & entry)54061da546Spatrick void Log::ListCategories(llvm::raw_ostream &stream,
55061da546Spatrick const ChannelMap::value_type &entry) {
56061da546Spatrick stream << llvm::formatv("Logging categories for '{0}':\n", entry.first());
57061da546Spatrick ForEachCategory(entry,
58061da546Spatrick [&stream](llvm::StringRef name, llvm::StringRef description) {
59061da546Spatrick stream << llvm::formatv(" {0} - {1}\n", name, description);
60061da546Spatrick });
61061da546Spatrick }
62061da546Spatrick
GetFlags(llvm::raw_ostream & stream,const ChannelMap::value_type & entry,llvm::ArrayRef<const char * > categories)63*f6aab3d8Srobert Log::MaskType Log::GetFlags(llvm::raw_ostream &stream,
64*f6aab3d8Srobert const ChannelMap::value_type &entry,
65061da546Spatrick llvm::ArrayRef<const char *> categories) {
66061da546Spatrick bool list_categories = false;
67*f6aab3d8Srobert Log::MaskType flags = 0;
68061da546Spatrick for (const char *category : categories) {
69be691f3bSpatrick if (llvm::StringRef("all").equals_insensitive(category)) {
70*f6aab3d8Srobert flags |= std::numeric_limits<Log::MaskType>::max();
71061da546Spatrick continue;
72061da546Spatrick }
73be691f3bSpatrick if (llvm::StringRef("default").equals_insensitive(category)) {
74061da546Spatrick flags |= entry.second.m_channel.default_flags;
75061da546Spatrick continue;
76061da546Spatrick }
77be691f3bSpatrick auto cat = llvm::find_if(entry.second.m_channel.categories,
78be691f3bSpatrick [&](const Log::Category &c) {
79be691f3bSpatrick return c.name.equals_insensitive(category);
80be691f3bSpatrick });
81061da546Spatrick if (cat != entry.second.m_channel.categories.end()) {
82061da546Spatrick flags |= cat->flag;
83061da546Spatrick continue;
84061da546Spatrick }
85061da546Spatrick stream << llvm::formatv("error: unrecognized log category '{0}'\n",
86061da546Spatrick category);
87061da546Spatrick list_categories = true;
88061da546Spatrick }
89061da546Spatrick if (list_categories)
90061da546Spatrick ListCategories(stream, entry);
91061da546Spatrick return flags;
92061da546Spatrick }
93061da546Spatrick
Enable(const std::shared_ptr<LogHandler> & handler_sp,uint32_t options,Log::MaskType flags)94*f6aab3d8Srobert void Log::Enable(const std::shared_ptr<LogHandler> &handler_sp,
95*f6aab3d8Srobert uint32_t options, Log::MaskType flags) {
96061da546Spatrick llvm::sys::ScopedWriter lock(m_mutex);
97061da546Spatrick
98*f6aab3d8Srobert MaskType mask = m_mask.fetch_or(flags, std::memory_order_relaxed);
99061da546Spatrick if (mask | flags) {
100061da546Spatrick m_options.store(options, std::memory_order_relaxed);
101*f6aab3d8Srobert m_handler = handler_sp;
102061da546Spatrick m_channel.log_ptr.store(this, std::memory_order_relaxed);
103061da546Spatrick }
104061da546Spatrick }
105061da546Spatrick
Disable(Log::MaskType flags)106*f6aab3d8Srobert void Log::Disable(Log::MaskType flags) {
107061da546Spatrick llvm::sys::ScopedWriter lock(m_mutex);
108061da546Spatrick
109*f6aab3d8Srobert MaskType mask = m_mask.fetch_and(~flags, std::memory_order_relaxed);
110061da546Spatrick if (!(mask & ~flags)) {
111*f6aab3d8Srobert m_handler.reset();
112061da546Spatrick m_channel.log_ptr.store(nullptr, std::memory_order_relaxed);
113061da546Spatrick }
114061da546Spatrick }
115061da546Spatrick
Dump(llvm::raw_ostream & output_stream)116*f6aab3d8Srobert bool Log::Dump(llvm::raw_ostream &output_stream) {
117*f6aab3d8Srobert llvm::sys::ScopedReader lock(m_mutex);
118*f6aab3d8Srobert if (RotatingLogHandler *handler =
119*f6aab3d8Srobert llvm::dyn_cast_or_null<RotatingLogHandler>(m_handler.get())) {
120*f6aab3d8Srobert handler->Dump(output_stream);
121*f6aab3d8Srobert return true;
122*f6aab3d8Srobert }
123*f6aab3d8Srobert return false;
124*f6aab3d8Srobert }
125*f6aab3d8Srobert
GetOptions() const126061da546Spatrick const Flags Log::GetOptions() const {
127061da546Spatrick return m_options.load(std::memory_order_relaxed);
128061da546Spatrick }
129061da546Spatrick
GetMask() const130*f6aab3d8Srobert Log::MaskType Log::GetMask() const {
131061da546Spatrick return m_mask.load(std::memory_order_relaxed);
132061da546Spatrick }
133061da546Spatrick
PutCString(const char * cstr)134061da546Spatrick void Log::PutCString(const char *cstr) { Printf("%s", cstr); }
PutString(llvm::StringRef str)135061da546Spatrick void Log::PutString(llvm::StringRef str) { PutCString(str.str().c_str()); }
136061da546Spatrick
137061da546Spatrick // Simple variable argument logging with flags.
Printf(const char * format,...)138061da546Spatrick void Log::Printf(const char *format, ...) {
139061da546Spatrick va_list args;
140061da546Spatrick va_start(args, format);
141061da546Spatrick VAPrintf(format, args);
142061da546Spatrick va_end(args);
143061da546Spatrick }
144061da546Spatrick
145061da546Spatrick // All logging eventually boils down to this function call. If we have a
146061da546Spatrick // callback registered, then we call the logging callback. If we have a valid
147061da546Spatrick // file handle, we also log to the file.
VAPrintf(const char * format,va_list args)148061da546Spatrick void Log::VAPrintf(const char *format, va_list args) {
149061da546Spatrick llvm::SmallString<64> FinalMessage;
150061da546Spatrick llvm::raw_svector_ostream Stream(FinalMessage);
151061da546Spatrick WriteHeader(Stream, "", "");
152061da546Spatrick
153061da546Spatrick llvm::SmallString<64> Content;
154061da546Spatrick lldb_private::VASprintf(Content, format, args);
155061da546Spatrick
156061da546Spatrick Stream << Content << "\n";
157061da546Spatrick
158dda28197Spatrick WriteMessage(std::string(FinalMessage.str()));
159061da546Spatrick }
160061da546Spatrick
161061da546Spatrick // Printing of errors that are not fatal.
Error(const char * format,...)162061da546Spatrick void Log::Error(const char *format, ...) {
163061da546Spatrick va_list args;
164061da546Spatrick va_start(args, format);
165061da546Spatrick VAError(format, args);
166061da546Spatrick va_end(args);
167061da546Spatrick }
168061da546Spatrick
VAError(const char * format,va_list args)169061da546Spatrick void Log::VAError(const char *format, va_list args) {
170061da546Spatrick llvm::SmallString<64> Content;
171061da546Spatrick VASprintf(Content, format, args);
172061da546Spatrick
173061da546Spatrick Printf("error: %s", Content.c_str());
174061da546Spatrick }
175061da546Spatrick
176061da546Spatrick // Printing of warnings that are not fatal only if verbose mode is enabled.
Verbose(const char * format,...)177061da546Spatrick void Log::Verbose(const char *format, ...) {
178061da546Spatrick if (!GetVerbose())
179061da546Spatrick return;
180061da546Spatrick
181061da546Spatrick va_list args;
182061da546Spatrick va_start(args, format);
183061da546Spatrick VAPrintf(format, args);
184061da546Spatrick va_end(args);
185061da546Spatrick }
186061da546Spatrick
187061da546Spatrick // Printing of warnings that are not fatal.
Warning(const char * format,...)188061da546Spatrick void Log::Warning(const char *format, ...) {
189061da546Spatrick llvm::SmallString<64> Content;
190061da546Spatrick va_list args;
191061da546Spatrick va_start(args, format);
192061da546Spatrick VASprintf(Content, format, args);
193061da546Spatrick va_end(args);
194061da546Spatrick
195061da546Spatrick Printf("warning: %s", Content.c_str());
196061da546Spatrick }
197061da546Spatrick
Register(llvm::StringRef name,Channel & channel)198061da546Spatrick void Log::Register(llvm::StringRef name, Channel &channel) {
199061da546Spatrick auto iter = g_channel_map->try_emplace(name, channel);
200061da546Spatrick assert(iter.second == true);
201061da546Spatrick (void)iter;
202061da546Spatrick }
203061da546Spatrick
Unregister(llvm::StringRef name)204061da546Spatrick void Log::Unregister(llvm::StringRef name) {
205061da546Spatrick auto iter = g_channel_map->find(name);
206061da546Spatrick assert(iter != g_channel_map->end());
207*f6aab3d8Srobert iter->second.Disable(std::numeric_limits<MaskType>::max());
208061da546Spatrick g_channel_map->erase(iter);
209061da546Spatrick }
210061da546Spatrick
EnableLogChannel(const std::shared_ptr<LogHandler> & log_handler_sp,uint32_t log_options,llvm::StringRef channel,llvm::ArrayRef<const char * > categories,llvm::raw_ostream & error_stream)211*f6aab3d8Srobert bool Log::EnableLogChannel(const std::shared_ptr<LogHandler> &log_handler_sp,
212061da546Spatrick uint32_t log_options, llvm::StringRef channel,
213*f6aab3d8Srobert llvm::ArrayRef<const char *> categories,
214*f6aab3d8Srobert llvm::raw_ostream &error_stream) {
215061da546Spatrick auto iter = g_channel_map->find(channel);
216061da546Spatrick if (iter == g_channel_map->end()) {
217061da546Spatrick error_stream << llvm::formatv("Invalid log channel '{0}'.\n", channel);
218061da546Spatrick return false;
219061da546Spatrick }
220*f6aab3d8Srobert MaskType flags = categories.empty()
221061da546Spatrick ? iter->second.m_channel.default_flags
222061da546Spatrick : GetFlags(error_stream, *iter, categories);
223*f6aab3d8Srobert iter->second.Enable(log_handler_sp, log_options, flags);
224061da546Spatrick return true;
225061da546Spatrick }
226061da546Spatrick
DisableLogChannel(llvm::StringRef channel,llvm::ArrayRef<const char * > categories,llvm::raw_ostream & error_stream)227061da546Spatrick bool Log::DisableLogChannel(llvm::StringRef channel,
228061da546Spatrick llvm::ArrayRef<const char *> categories,
229061da546Spatrick llvm::raw_ostream &error_stream) {
230061da546Spatrick auto iter = g_channel_map->find(channel);
231061da546Spatrick if (iter == g_channel_map->end()) {
232061da546Spatrick error_stream << llvm::formatv("Invalid log channel '{0}'.\n", channel);
233061da546Spatrick return false;
234061da546Spatrick }
235*f6aab3d8Srobert MaskType flags = categories.empty()
236*f6aab3d8Srobert ? std::numeric_limits<MaskType>::max()
237061da546Spatrick : GetFlags(error_stream, *iter, categories);
238061da546Spatrick iter->second.Disable(flags);
239061da546Spatrick return true;
240061da546Spatrick }
241061da546Spatrick
DumpLogChannel(llvm::StringRef channel,llvm::raw_ostream & output_stream,llvm::raw_ostream & error_stream)242*f6aab3d8Srobert bool Log::DumpLogChannel(llvm::StringRef channel,
243*f6aab3d8Srobert llvm::raw_ostream &output_stream,
244*f6aab3d8Srobert llvm::raw_ostream &error_stream) {
245*f6aab3d8Srobert auto iter = g_channel_map->find(channel);
246*f6aab3d8Srobert if (iter == g_channel_map->end()) {
247*f6aab3d8Srobert error_stream << llvm::formatv("Invalid log channel '{0}'.\n", channel);
248*f6aab3d8Srobert return false;
249*f6aab3d8Srobert }
250*f6aab3d8Srobert if (!iter->second.Dump(output_stream)) {
251*f6aab3d8Srobert error_stream << llvm::formatv(
252*f6aab3d8Srobert "log channel '{0}' does not support dumping.\n", channel);
253*f6aab3d8Srobert return false;
254*f6aab3d8Srobert }
255*f6aab3d8Srobert return true;
256*f6aab3d8Srobert }
257*f6aab3d8Srobert
ListChannelCategories(llvm::StringRef channel,llvm::raw_ostream & stream)258061da546Spatrick bool Log::ListChannelCategories(llvm::StringRef channel,
259061da546Spatrick llvm::raw_ostream &stream) {
260061da546Spatrick auto ch = g_channel_map->find(channel);
261061da546Spatrick if (ch == g_channel_map->end()) {
262061da546Spatrick stream << llvm::formatv("Invalid log channel '{0}'.\n", channel);
263061da546Spatrick return false;
264061da546Spatrick }
265061da546Spatrick ListCategories(stream, *ch);
266061da546Spatrick return true;
267061da546Spatrick }
268061da546Spatrick
DisableAllLogChannels()269061da546Spatrick void Log::DisableAllLogChannels() {
270061da546Spatrick for (auto &entry : *g_channel_map)
271*f6aab3d8Srobert entry.second.Disable(std::numeric_limits<MaskType>::max());
272061da546Spatrick }
273061da546Spatrick
ForEachChannelCategory(llvm::StringRef channel,llvm::function_ref<void (llvm::StringRef,llvm::StringRef)> lambda)274061da546Spatrick void Log::ForEachChannelCategory(
275061da546Spatrick llvm::StringRef channel,
276061da546Spatrick llvm::function_ref<void(llvm::StringRef, llvm::StringRef)> lambda) {
277061da546Spatrick auto ch = g_channel_map->find(channel);
278061da546Spatrick if (ch == g_channel_map->end())
279061da546Spatrick return;
280061da546Spatrick
281061da546Spatrick ForEachCategory(*ch, lambda);
282061da546Spatrick }
283061da546Spatrick
ListChannels()284061da546Spatrick std::vector<llvm::StringRef> Log::ListChannels() {
285061da546Spatrick std::vector<llvm::StringRef> result;
286061da546Spatrick for (const auto &channel : *g_channel_map)
287061da546Spatrick result.push_back(channel.first());
288061da546Spatrick return result;
289061da546Spatrick }
290061da546Spatrick
ListAllLogChannels(llvm::raw_ostream & stream)291061da546Spatrick void Log::ListAllLogChannels(llvm::raw_ostream &stream) {
292061da546Spatrick if (g_channel_map->empty()) {
293061da546Spatrick stream << "No logging channels are currently registered.\n";
294061da546Spatrick return;
295061da546Spatrick }
296061da546Spatrick
297061da546Spatrick for (const auto &channel : *g_channel_map)
298061da546Spatrick ListCategories(stream, channel);
299061da546Spatrick }
300061da546Spatrick
GetVerbose() const301061da546Spatrick bool Log::GetVerbose() const {
302061da546Spatrick return m_options.load(std::memory_order_relaxed) & LLDB_LOG_OPTION_VERBOSE;
303061da546Spatrick }
304061da546Spatrick
WriteHeader(llvm::raw_ostream & OS,llvm::StringRef file,llvm::StringRef function)305061da546Spatrick void Log::WriteHeader(llvm::raw_ostream &OS, llvm::StringRef file,
306061da546Spatrick llvm::StringRef function) {
307061da546Spatrick Flags options = GetOptions();
308061da546Spatrick static uint32_t g_sequence_id = 0;
309061da546Spatrick // Add a sequence ID if requested
310061da546Spatrick if (options.Test(LLDB_LOG_OPTION_PREPEND_SEQUENCE))
311061da546Spatrick OS << ++g_sequence_id << " ";
312061da546Spatrick
313061da546Spatrick // Timestamp if requested
314061da546Spatrick if (options.Test(LLDB_LOG_OPTION_PREPEND_TIMESTAMP)) {
315061da546Spatrick auto now = std::chrono::duration<double>(
316061da546Spatrick std::chrono::system_clock::now().time_since_epoch());
317061da546Spatrick OS << llvm::formatv("{0:f9} ", now.count());
318061da546Spatrick }
319061da546Spatrick
320061da546Spatrick // Add the process and thread if requested
321061da546Spatrick if (options.Test(LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD))
322061da546Spatrick OS << llvm::formatv("[{0,0+4}/{1,0+4}] ", getpid(),
323061da546Spatrick llvm::get_threadid());
324061da546Spatrick
325061da546Spatrick // Add the thread name if requested
326061da546Spatrick if (options.Test(LLDB_LOG_OPTION_PREPEND_THREAD_NAME)) {
327061da546Spatrick llvm::SmallString<32> thread_name;
328061da546Spatrick llvm::get_thread_name(thread_name);
329061da546Spatrick
330061da546Spatrick llvm::SmallString<12> format_str;
331061da546Spatrick llvm::raw_svector_ostream format_os(format_str);
332061da546Spatrick format_os << "{0,-" << llvm::alignTo<16>(thread_name.size()) << "} ";
333061da546Spatrick OS << llvm::formatv(format_str.c_str(), thread_name);
334061da546Spatrick }
335061da546Spatrick
336061da546Spatrick if (options.Test(LLDB_LOG_OPTION_BACKTRACE))
337061da546Spatrick llvm::sys::PrintStackTrace(OS);
338061da546Spatrick
339061da546Spatrick if (options.Test(LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION) &&
340061da546Spatrick (!file.empty() || !function.empty())) {
341061da546Spatrick file = llvm::sys::path::filename(file).take_front(40);
342061da546Spatrick function = function.take_front(40);
343061da546Spatrick OS << llvm::formatv("{0,-60:60} ", (file + ":" + function).str());
344061da546Spatrick }
345061da546Spatrick }
346061da546Spatrick
WriteMessage(const std::string & message)347061da546Spatrick void Log::WriteMessage(const std::string &message) {
348061da546Spatrick // Make a copy of our stream shared pointer in case someone disables our log
349061da546Spatrick // while we are logging and releases the stream
350*f6aab3d8Srobert auto handler_sp = GetHandler();
351*f6aab3d8Srobert if (!handler_sp)
352061da546Spatrick return;
353*f6aab3d8Srobert handler_sp->Emit(message);
354061da546Spatrick }
355061da546Spatrick
Format(llvm::StringRef file,llvm::StringRef function,const llvm::formatv_object_base & payload)356061da546Spatrick void Log::Format(llvm::StringRef file, llvm::StringRef function,
357061da546Spatrick const llvm::formatv_object_base &payload) {
358061da546Spatrick std::string message_string;
359061da546Spatrick llvm::raw_string_ostream message(message_string);
360061da546Spatrick WriteHeader(message, file, function);
361061da546Spatrick message << payload << "\n";
362061da546Spatrick WriteMessage(message.str());
363061da546Spatrick }
364061da546Spatrick
StreamLogHandler(int fd,bool should_close,size_t buffer_size)365*f6aab3d8Srobert StreamLogHandler::StreamLogHandler(int fd, bool should_close,
366*f6aab3d8Srobert size_t buffer_size)
367*f6aab3d8Srobert : m_stream(fd, should_close, buffer_size == 0) {
368*f6aab3d8Srobert if (buffer_size > 0)
369*f6aab3d8Srobert m_stream.SetBufferSize(buffer_size);
370*f6aab3d8Srobert }
371*f6aab3d8Srobert
~StreamLogHandler()372*f6aab3d8Srobert StreamLogHandler::~StreamLogHandler() { Flush(); }
373*f6aab3d8Srobert
Flush()374*f6aab3d8Srobert void StreamLogHandler::Flush() {
375*f6aab3d8Srobert std::lock_guard<std::mutex> guard(m_mutex);
376*f6aab3d8Srobert m_stream.flush();
377*f6aab3d8Srobert }
378*f6aab3d8Srobert
Emit(llvm::StringRef message)379*f6aab3d8Srobert void StreamLogHandler::Emit(llvm::StringRef message) {
380*f6aab3d8Srobert if (m_stream.GetBufferSize() > 0) {
381*f6aab3d8Srobert std::lock_guard<std::mutex> guard(m_mutex);
382*f6aab3d8Srobert m_stream << message;
383*f6aab3d8Srobert } else {
384*f6aab3d8Srobert m_stream << message;
385*f6aab3d8Srobert }
386*f6aab3d8Srobert }
387*f6aab3d8Srobert
CallbackLogHandler(lldb::LogOutputCallback callback,void * baton)388*f6aab3d8Srobert CallbackLogHandler::CallbackLogHandler(lldb::LogOutputCallback callback,
389*f6aab3d8Srobert void *baton)
390*f6aab3d8Srobert : m_callback(callback), m_baton(baton) {}
391*f6aab3d8Srobert
Emit(llvm::StringRef message)392*f6aab3d8Srobert void CallbackLogHandler::Emit(llvm::StringRef message) {
393*f6aab3d8Srobert m_callback(message.data(), m_baton);
394*f6aab3d8Srobert }
395*f6aab3d8Srobert
RotatingLogHandler(size_t size)396*f6aab3d8Srobert RotatingLogHandler::RotatingLogHandler(size_t size)
397*f6aab3d8Srobert : m_messages(std::make_unique<std::string[]>(size)), m_size(size) {}
398*f6aab3d8Srobert
Emit(llvm::StringRef message)399*f6aab3d8Srobert void RotatingLogHandler::Emit(llvm::StringRef message) {
400*f6aab3d8Srobert std::lock_guard<std::mutex> guard(m_mutex);
401*f6aab3d8Srobert ++m_total_count;
402*f6aab3d8Srobert const size_t index = m_next_index;
403*f6aab3d8Srobert m_next_index = NormalizeIndex(index + 1);
404*f6aab3d8Srobert m_messages[index] = message.str();
405*f6aab3d8Srobert }
406*f6aab3d8Srobert
NormalizeIndex(size_t i) const407*f6aab3d8Srobert size_t RotatingLogHandler::NormalizeIndex(size_t i) const { return i % m_size; }
408*f6aab3d8Srobert
GetNumMessages() const409*f6aab3d8Srobert size_t RotatingLogHandler::GetNumMessages() const {
410*f6aab3d8Srobert return m_total_count < m_size ? m_total_count : m_size;
411*f6aab3d8Srobert }
412*f6aab3d8Srobert
GetFirstMessageIndex() const413*f6aab3d8Srobert size_t RotatingLogHandler::GetFirstMessageIndex() const {
414*f6aab3d8Srobert return m_total_count < m_size ? 0 : m_next_index;
415*f6aab3d8Srobert }
416*f6aab3d8Srobert
Dump(llvm::raw_ostream & stream) const417*f6aab3d8Srobert void RotatingLogHandler::Dump(llvm::raw_ostream &stream) const {
418*f6aab3d8Srobert std::lock_guard<std::mutex> guard(m_mutex);
419*f6aab3d8Srobert const size_t start_idx = GetFirstMessageIndex();
420*f6aab3d8Srobert const size_t stop_idx = start_idx + GetNumMessages();
421*f6aab3d8Srobert for (size_t i = start_idx; i < stop_idx; ++i) {
422*f6aab3d8Srobert const size_t idx = NormalizeIndex(i);
423*f6aab3d8Srobert stream << m_messages[idx];
424*f6aab3d8Srobert }
425*f6aab3d8Srobert stream.flush();
426061da546Spatrick }
427