15ffd83dbSDimitry Andric //===-- Log.cpp -----------------------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "lldb/Utility/Log.h" 100b57cec5SDimitry Andric #include "lldb/Utility/VASPrintf.h" 110b57cec5SDimitry Andric 120b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 130b57cec5SDimitry Andric #include "llvm/ADT/Twine.h" 140b57cec5SDimitry Andric #include "llvm/ADT/iterator.h" 150b57cec5SDimitry Andric 1681ad6265SDimitry Andric #include "llvm/Support/Casting.h" 170b57cec5SDimitry Andric #include "llvm/Support/Chrono.h" 180b57cec5SDimitry Andric #include "llvm/Support/ManagedStatic.h" 190b57cec5SDimitry Andric #include "llvm/Support/Path.h" 200b57cec5SDimitry Andric #include "llvm/Support/Signals.h" 210b57cec5SDimitry Andric #include "llvm/Support/Threading.h" 220b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric #include <chrono> 250b57cec5SDimitry Andric #include <cstdarg> 260b57cec5SDimitry Andric #include <mutex> 270b57cec5SDimitry Andric #include <utility> 280b57cec5SDimitry Andric 29fe6060f1SDimitry Andric #include <cassert> 300b57cec5SDimitry Andric #if defined(_WIN32) 310b57cec5SDimitry Andric #include <process.h> 320b57cec5SDimitry Andric #else 330b57cec5SDimitry Andric #include <unistd.h> 340b57cec5SDimitry Andric #endif 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric using namespace lldb_private; 370b57cec5SDimitry Andric 3881ad6265SDimitry Andric char LogHandler::ID; 3981ad6265SDimitry Andric char StreamLogHandler::ID; 4081ad6265SDimitry Andric char CallbackLogHandler::ID; 4181ad6265SDimitry Andric char RotatingLogHandler::ID; 42*0fca6ea1SDimitry Andric char TeeLogHandler::ID; 4381ad6265SDimitry Andric 440b57cec5SDimitry Andric llvm::ManagedStatic<Log::ChannelMap> Log::g_channel_map; 450b57cec5SDimitry Andric 469dba64beSDimitry Andric void Log::ForEachCategory( 479dba64beSDimitry Andric const Log::ChannelMap::value_type &entry, 489dba64beSDimitry Andric llvm::function_ref<void(llvm::StringRef, llvm::StringRef)> lambda) { 499dba64beSDimitry Andric lambda("all", "all available logging categories"); 509dba64beSDimitry Andric lambda("default", "default set of logging categories"); 510b57cec5SDimitry Andric for (const auto &category : entry.second.m_channel.categories) 529dba64beSDimitry Andric lambda(category.name, category.description); 539dba64beSDimitry Andric } 549dba64beSDimitry Andric 559dba64beSDimitry Andric void Log::ListCategories(llvm::raw_ostream &stream, 569dba64beSDimitry Andric const ChannelMap::value_type &entry) { 579dba64beSDimitry Andric stream << llvm::formatv("Logging categories for '{0}':\n", entry.first()); 589dba64beSDimitry Andric ForEachCategory(entry, 599dba64beSDimitry Andric [&stream](llvm::StringRef name, llvm::StringRef description) { 609dba64beSDimitry Andric stream << llvm::formatv(" {0} - {1}\n", name, description); 619dba64beSDimitry Andric }); 620b57cec5SDimitry Andric } 630b57cec5SDimitry Andric 64bdd1243dSDimitry Andric Log::MaskType Log::GetFlags(llvm::raw_ostream &stream, 65bdd1243dSDimitry Andric const ChannelMap::value_type &entry, 660b57cec5SDimitry Andric llvm::ArrayRef<const char *> categories) { 670b57cec5SDimitry Andric bool list_categories = false; 68bdd1243dSDimitry Andric Log::MaskType flags = 0; 690b57cec5SDimitry Andric for (const char *category : categories) { 70fe6060f1SDimitry Andric if (llvm::StringRef("all").equals_insensitive(category)) { 71bdd1243dSDimitry Andric flags |= std::numeric_limits<Log::MaskType>::max(); 720b57cec5SDimitry Andric continue; 730b57cec5SDimitry Andric } 74fe6060f1SDimitry Andric if (llvm::StringRef("default").equals_insensitive(category)) { 750b57cec5SDimitry Andric flags |= entry.second.m_channel.default_flags; 760b57cec5SDimitry Andric continue; 770b57cec5SDimitry Andric } 78fe6060f1SDimitry Andric auto cat = llvm::find_if(entry.second.m_channel.categories, 79fe6060f1SDimitry Andric [&](const Log::Category &c) { 80fe6060f1SDimitry Andric return c.name.equals_insensitive(category); 81fe6060f1SDimitry Andric }); 820b57cec5SDimitry Andric if (cat != entry.second.m_channel.categories.end()) { 830b57cec5SDimitry Andric flags |= cat->flag; 840b57cec5SDimitry Andric continue; 850b57cec5SDimitry Andric } 860b57cec5SDimitry Andric stream << llvm::formatv("error: unrecognized log category '{0}'\n", 870b57cec5SDimitry Andric category); 880b57cec5SDimitry Andric list_categories = true; 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric if (list_categories) 910b57cec5SDimitry Andric ListCategories(stream, entry); 920b57cec5SDimitry Andric return flags; 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric 9581ad6265SDimitry Andric void Log::Enable(const std::shared_ptr<LogHandler> &handler_sp, 96bdd1243dSDimitry Andric uint32_t options, Log::MaskType flags) { 970b57cec5SDimitry Andric llvm::sys::ScopedWriter lock(m_mutex); 980b57cec5SDimitry Andric 9904eeddc0SDimitry Andric MaskType mask = m_mask.fetch_or(flags, std::memory_order_relaxed); 1000b57cec5SDimitry Andric if (mask | flags) { 1010b57cec5SDimitry Andric m_options.store(options, std::memory_order_relaxed); 10281ad6265SDimitry Andric m_handler = handler_sp; 1030b57cec5SDimitry Andric m_channel.log_ptr.store(this, std::memory_order_relaxed); 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric } 1060b57cec5SDimitry Andric 107bdd1243dSDimitry Andric void Log::Disable(Log::MaskType flags) { 1080b57cec5SDimitry Andric llvm::sys::ScopedWriter lock(m_mutex); 1090b57cec5SDimitry Andric 11004eeddc0SDimitry Andric MaskType mask = m_mask.fetch_and(~flags, std::memory_order_relaxed); 1110b57cec5SDimitry Andric if (!(mask & ~flags)) { 11281ad6265SDimitry Andric m_handler.reset(); 1130b57cec5SDimitry Andric m_channel.log_ptr.store(nullptr, std::memory_order_relaxed); 1140b57cec5SDimitry Andric } 1150b57cec5SDimitry Andric } 1160b57cec5SDimitry Andric 11781ad6265SDimitry Andric bool Log::Dump(llvm::raw_ostream &output_stream) { 11881ad6265SDimitry Andric llvm::sys::ScopedReader lock(m_mutex); 11981ad6265SDimitry Andric if (RotatingLogHandler *handler = 12081ad6265SDimitry Andric llvm::dyn_cast_or_null<RotatingLogHandler>(m_handler.get())) { 12181ad6265SDimitry Andric handler->Dump(output_stream); 12281ad6265SDimitry Andric return true; 12381ad6265SDimitry Andric } 12481ad6265SDimitry Andric return false; 12581ad6265SDimitry Andric } 12681ad6265SDimitry Andric 1270b57cec5SDimitry Andric const Flags Log::GetOptions() const { 1280b57cec5SDimitry Andric return m_options.load(std::memory_order_relaxed); 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric 131bdd1243dSDimitry Andric Log::MaskType Log::GetMask() const { 1320b57cec5SDimitry Andric return m_mask.load(std::memory_order_relaxed); 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric 13506c3fb27SDimitry Andric void Log::PutCString(const char *cstr) { PutString(cstr); } 13606c3fb27SDimitry Andric 13706c3fb27SDimitry Andric void Log::PutString(llvm::StringRef str) { 13806c3fb27SDimitry Andric std::string FinalMessage; 13906c3fb27SDimitry Andric llvm::raw_string_ostream Stream(FinalMessage); 14006c3fb27SDimitry Andric WriteHeader(Stream, "", ""); 14106c3fb27SDimitry Andric Stream << str << "\n"; 14206c3fb27SDimitry Andric WriteMessage(FinalMessage); 14306c3fb27SDimitry Andric } 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric // Simple variable argument logging with flags. 1460b57cec5SDimitry Andric void Log::Printf(const char *format, ...) { 1470b57cec5SDimitry Andric va_list args; 1480b57cec5SDimitry Andric va_start(args, format); 1490b57cec5SDimitry Andric VAPrintf(format, args); 1500b57cec5SDimitry Andric va_end(args); 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric void Log::VAPrintf(const char *format, va_list args) { 1540b57cec5SDimitry Andric llvm::SmallString<64> Content; 1550b57cec5SDimitry Andric lldb_private::VASprintf(Content, format, args); 15606c3fb27SDimitry Andric PutString(Content); 15706c3fb27SDimitry Andric } 1580b57cec5SDimitry Andric 15906c3fb27SDimitry Andric void Log::Formatf(llvm::StringRef file, llvm::StringRef function, 16006c3fb27SDimitry Andric const char *format, ...) { 16106c3fb27SDimitry Andric va_list args; 16206c3fb27SDimitry Andric va_start(args, format); 16306c3fb27SDimitry Andric VAFormatf(file, function, format, args); 16406c3fb27SDimitry Andric va_end(args); 16506c3fb27SDimitry Andric } 1660b57cec5SDimitry Andric 16706c3fb27SDimitry Andric void Log::VAFormatf(llvm::StringRef file, llvm::StringRef function, 16806c3fb27SDimitry Andric const char *format, va_list args) { 16906c3fb27SDimitry Andric llvm::SmallString<64> Content; 17006c3fb27SDimitry Andric lldb_private::VASprintf(Content, format, args); 17106c3fb27SDimitry Andric Format(file, function, llvm::formatv("{0}", Content)); 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric 1740b57cec5SDimitry Andric // Printing of errors that are not fatal. 1750b57cec5SDimitry Andric void Log::Error(const char *format, ...) { 1760b57cec5SDimitry Andric va_list args; 1770b57cec5SDimitry Andric va_start(args, format); 1780b57cec5SDimitry Andric VAError(format, args); 1790b57cec5SDimitry Andric va_end(args); 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric void Log::VAError(const char *format, va_list args) { 1830b57cec5SDimitry Andric llvm::SmallString<64> Content; 1840b57cec5SDimitry Andric VASprintf(Content, format, args); 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric Printf("error: %s", Content.c_str()); 1870b57cec5SDimitry Andric } 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric // Printing of warnings that are not fatal only if verbose mode is enabled. 1900b57cec5SDimitry Andric void Log::Verbose(const char *format, ...) { 1910b57cec5SDimitry Andric if (!GetVerbose()) 1920b57cec5SDimitry Andric return; 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric va_list args; 1950b57cec5SDimitry Andric va_start(args, format); 1960b57cec5SDimitry Andric VAPrintf(format, args); 1970b57cec5SDimitry Andric va_end(args); 1980b57cec5SDimitry Andric } 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric // Printing of warnings that are not fatal. 2010b57cec5SDimitry Andric void Log::Warning(const char *format, ...) { 2020b57cec5SDimitry Andric llvm::SmallString<64> Content; 2030b57cec5SDimitry Andric va_list args; 2040b57cec5SDimitry Andric va_start(args, format); 2050b57cec5SDimitry Andric VASprintf(Content, format, args); 2060b57cec5SDimitry Andric va_end(args); 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric Printf("warning: %s", Content.c_str()); 2090b57cec5SDimitry Andric } 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric void Log::Register(llvm::StringRef name, Channel &channel) { 2120b57cec5SDimitry Andric auto iter = g_channel_map->try_emplace(name, channel); 2130b57cec5SDimitry Andric assert(iter.second == true); 2145f757f3fSDimitry Andric UNUSED_IF_ASSERT_DISABLED(iter); 2150b57cec5SDimitry Andric } 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric void Log::Unregister(llvm::StringRef name) { 2180b57cec5SDimitry Andric auto iter = g_channel_map->find(name); 2190b57cec5SDimitry Andric assert(iter != g_channel_map->end()); 220bdd1243dSDimitry Andric iter->second.Disable(std::numeric_limits<MaskType>::max()); 2210b57cec5SDimitry Andric g_channel_map->erase(iter); 2220b57cec5SDimitry Andric } 2230b57cec5SDimitry Andric 22481ad6265SDimitry Andric bool Log::EnableLogChannel(const std::shared_ptr<LogHandler> &log_handler_sp, 2250b57cec5SDimitry Andric uint32_t log_options, llvm::StringRef channel, 22681ad6265SDimitry Andric llvm::ArrayRef<const char *> categories, 22781ad6265SDimitry Andric llvm::raw_ostream &error_stream) { 2280b57cec5SDimitry Andric auto iter = g_channel_map->find(channel); 2290b57cec5SDimitry Andric if (iter == g_channel_map->end()) { 2300b57cec5SDimitry Andric error_stream << llvm::formatv("Invalid log channel '{0}'.\n", channel); 2310b57cec5SDimitry Andric return false; 2320b57cec5SDimitry Andric } 233bdd1243dSDimitry Andric MaskType flags = categories.empty() 2340b57cec5SDimitry Andric ? iter->second.m_channel.default_flags 2350b57cec5SDimitry Andric : GetFlags(error_stream, *iter, categories); 23681ad6265SDimitry Andric iter->second.Enable(log_handler_sp, log_options, flags); 2370b57cec5SDimitry Andric return true; 2380b57cec5SDimitry Andric } 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric bool Log::DisableLogChannel(llvm::StringRef channel, 2410b57cec5SDimitry Andric llvm::ArrayRef<const char *> categories, 2420b57cec5SDimitry Andric llvm::raw_ostream &error_stream) { 2430b57cec5SDimitry Andric auto iter = g_channel_map->find(channel); 2440b57cec5SDimitry Andric if (iter == g_channel_map->end()) { 2450b57cec5SDimitry Andric error_stream << llvm::formatv("Invalid log channel '{0}'.\n", channel); 2460b57cec5SDimitry Andric return false; 2470b57cec5SDimitry Andric } 248bdd1243dSDimitry Andric MaskType flags = categories.empty() 249bdd1243dSDimitry Andric ? std::numeric_limits<MaskType>::max() 2500b57cec5SDimitry Andric : GetFlags(error_stream, *iter, categories); 2510b57cec5SDimitry Andric iter->second.Disable(flags); 2520b57cec5SDimitry Andric return true; 2530b57cec5SDimitry Andric } 2540b57cec5SDimitry Andric 25581ad6265SDimitry Andric bool Log::DumpLogChannel(llvm::StringRef channel, 25681ad6265SDimitry Andric llvm::raw_ostream &output_stream, 25781ad6265SDimitry Andric llvm::raw_ostream &error_stream) { 25881ad6265SDimitry Andric auto iter = g_channel_map->find(channel); 25981ad6265SDimitry Andric if (iter == g_channel_map->end()) { 26081ad6265SDimitry Andric error_stream << llvm::formatv("Invalid log channel '{0}'.\n", channel); 26181ad6265SDimitry Andric return false; 26281ad6265SDimitry Andric } 26381ad6265SDimitry Andric if (!iter->second.Dump(output_stream)) { 26481ad6265SDimitry Andric error_stream << llvm::formatv( 26581ad6265SDimitry Andric "log channel '{0}' does not support dumping.\n", channel); 26681ad6265SDimitry Andric return false; 26781ad6265SDimitry Andric } 26881ad6265SDimitry Andric return true; 26981ad6265SDimitry Andric } 27081ad6265SDimitry Andric 2710b57cec5SDimitry Andric bool Log::ListChannelCategories(llvm::StringRef channel, 2720b57cec5SDimitry Andric llvm::raw_ostream &stream) { 2730b57cec5SDimitry Andric auto ch = g_channel_map->find(channel); 2740b57cec5SDimitry Andric if (ch == g_channel_map->end()) { 2750b57cec5SDimitry Andric stream << llvm::formatv("Invalid log channel '{0}'.\n", channel); 2760b57cec5SDimitry Andric return false; 2770b57cec5SDimitry Andric } 2780b57cec5SDimitry Andric ListCategories(stream, *ch); 2790b57cec5SDimitry Andric return true; 2800b57cec5SDimitry Andric } 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric void Log::DisableAllLogChannels() { 2830b57cec5SDimitry Andric for (auto &entry : *g_channel_map) 284bdd1243dSDimitry Andric entry.second.Disable(std::numeric_limits<MaskType>::max()); 2850b57cec5SDimitry Andric } 2860b57cec5SDimitry Andric 2879dba64beSDimitry Andric void Log::ForEachChannelCategory( 2889dba64beSDimitry Andric llvm::StringRef channel, 2899dba64beSDimitry Andric llvm::function_ref<void(llvm::StringRef, llvm::StringRef)> lambda) { 2909dba64beSDimitry Andric auto ch = g_channel_map->find(channel); 2919dba64beSDimitry Andric if (ch == g_channel_map->end()) 2929dba64beSDimitry Andric return; 2939dba64beSDimitry Andric 2949dba64beSDimitry Andric ForEachCategory(*ch, lambda); 2959dba64beSDimitry Andric } 2969dba64beSDimitry Andric 2979dba64beSDimitry Andric std::vector<llvm::StringRef> Log::ListChannels() { 2989dba64beSDimitry Andric std::vector<llvm::StringRef> result; 2999dba64beSDimitry Andric for (const auto &channel : *g_channel_map) 3009dba64beSDimitry Andric result.push_back(channel.first()); 3019dba64beSDimitry Andric return result; 3029dba64beSDimitry Andric } 3039dba64beSDimitry Andric 3040b57cec5SDimitry Andric void Log::ListAllLogChannels(llvm::raw_ostream &stream) { 3050b57cec5SDimitry Andric if (g_channel_map->empty()) { 3060b57cec5SDimitry Andric stream << "No logging channels are currently registered.\n"; 3070b57cec5SDimitry Andric return; 3080b57cec5SDimitry Andric } 3090b57cec5SDimitry Andric 3100b57cec5SDimitry Andric for (const auto &channel : *g_channel_map) 3110b57cec5SDimitry Andric ListCategories(stream, channel); 3120b57cec5SDimitry Andric } 3130b57cec5SDimitry Andric 3140b57cec5SDimitry Andric bool Log::GetVerbose() const { 3150b57cec5SDimitry Andric return m_options.load(std::memory_order_relaxed) & LLDB_LOG_OPTION_VERBOSE; 3160b57cec5SDimitry Andric } 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric void Log::WriteHeader(llvm::raw_ostream &OS, llvm::StringRef file, 3190b57cec5SDimitry Andric llvm::StringRef function) { 3200b57cec5SDimitry Andric Flags options = GetOptions(); 3210b57cec5SDimitry Andric static uint32_t g_sequence_id = 0; 3220b57cec5SDimitry Andric // Add a sequence ID if requested 3230b57cec5SDimitry Andric if (options.Test(LLDB_LOG_OPTION_PREPEND_SEQUENCE)) 3240b57cec5SDimitry Andric OS << ++g_sequence_id << " "; 3250b57cec5SDimitry Andric 3260b57cec5SDimitry Andric // Timestamp if requested 3270b57cec5SDimitry Andric if (options.Test(LLDB_LOG_OPTION_PREPEND_TIMESTAMP)) { 3280b57cec5SDimitry Andric auto now = std::chrono::duration<double>( 3290b57cec5SDimitry Andric std::chrono::system_clock::now().time_since_epoch()); 3300b57cec5SDimitry Andric OS << llvm::formatv("{0:f9} ", now.count()); 3310b57cec5SDimitry Andric } 3320b57cec5SDimitry Andric 3330b57cec5SDimitry Andric // Add the process and thread if requested 3340b57cec5SDimitry Andric if (options.Test(LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD)) 3350b57cec5SDimitry Andric OS << llvm::formatv("[{0,0+4}/{1,0+4}] ", getpid(), 3360b57cec5SDimitry Andric llvm::get_threadid()); 3370b57cec5SDimitry Andric 3380b57cec5SDimitry Andric // Add the thread name if requested 3390b57cec5SDimitry Andric if (options.Test(LLDB_LOG_OPTION_PREPEND_THREAD_NAME)) { 3400b57cec5SDimitry Andric llvm::SmallString<32> thread_name; 3410b57cec5SDimitry Andric llvm::get_thread_name(thread_name); 3420b57cec5SDimitry Andric 3430b57cec5SDimitry Andric llvm::SmallString<12> format_str; 3440b57cec5SDimitry Andric llvm::raw_svector_ostream format_os(format_str); 3450b57cec5SDimitry Andric format_os << "{0,-" << llvm::alignTo<16>(thread_name.size()) << "} "; 3460b57cec5SDimitry Andric OS << llvm::formatv(format_str.c_str(), thread_name); 3470b57cec5SDimitry Andric } 3480b57cec5SDimitry Andric 3490b57cec5SDimitry Andric if (options.Test(LLDB_LOG_OPTION_BACKTRACE)) 3500b57cec5SDimitry Andric llvm::sys::PrintStackTrace(OS); 3510b57cec5SDimitry Andric 3520b57cec5SDimitry Andric if (options.Test(LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION) && 3530b57cec5SDimitry Andric (!file.empty() || !function.empty())) { 3540b57cec5SDimitry Andric file = llvm::sys::path::filename(file).take_front(40); 3550b57cec5SDimitry Andric function = function.take_front(40); 3560b57cec5SDimitry Andric OS << llvm::formatv("{0,-60:60} ", (file + ":" + function).str()); 3570b57cec5SDimitry Andric } 3580b57cec5SDimitry Andric } 3590b57cec5SDimitry Andric 36006c3fb27SDimitry Andric // If we have a callback registered, then we call the logging callback. If we 36106c3fb27SDimitry Andric // have a valid file handle, we also log to the file. 36206c3fb27SDimitry Andric void Log::WriteMessage(llvm::StringRef message) { 3630b57cec5SDimitry Andric // Make a copy of our stream shared pointer in case someone disables our log 3640b57cec5SDimitry Andric // while we are logging and releases the stream 36581ad6265SDimitry Andric auto handler_sp = GetHandler(); 36681ad6265SDimitry Andric if (!handler_sp) 3670b57cec5SDimitry Andric return; 36881ad6265SDimitry Andric handler_sp->Emit(message); 3690b57cec5SDimitry Andric } 3700b57cec5SDimitry Andric 3710b57cec5SDimitry Andric void Log::Format(llvm::StringRef file, llvm::StringRef function, 3720b57cec5SDimitry Andric const llvm::formatv_object_base &payload) { 3730b57cec5SDimitry Andric std::string message_string; 3740b57cec5SDimitry Andric llvm::raw_string_ostream message(message_string); 3750b57cec5SDimitry Andric WriteHeader(message, file, function); 3760b57cec5SDimitry Andric message << payload << "\n"; 3770b57cec5SDimitry Andric WriteMessage(message.str()); 3780b57cec5SDimitry Andric } 37981ad6265SDimitry Andric 38081ad6265SDimitry Andric StreamLogHandler::StreamLogHandler(int fd, bool should_close, 38181ad6265SDimitry Andric size_t buffer_size) 38281ad6265SDimitry Andric : m_stream(fd, should_close, buffer_size == 0) { 38381ad6265SDimitry Andric if (buffer_size > 0) 38481ad6265SDimitry Andric m_stream.SetBufferSize(buffer_size); 38581ad6265SDimitry Andric } 38681ad6265SDimitry Andric 38781ad6265SDimitry Andric StreamLogHandler::~StreamLogHandler() { Flush(); } 38881ad6265SDimitry Andric 38981ad6265SDimitry Andric void StreamLogHandler::Flush() { 39081ad6265SDimitry Andric std::lock_guard<std::mutex> guard(m_mutex); 39181ad6265SDimitry Andric m_stream.flush(); 39281ad6265SDimitry Andric } 39381ad6265SDimitry Andric 39481ad6265SDimitry Andric void StreamLogHandler::Emit(llvm::StringRef message) { 39581ad6265SDimitry Andric if (m_stream.GetBufferSize() > 0) { 39681ad6265SDimitry Andric std::lock_guard<std::mutex> guard(m_mutex); 39781ad6265SDimitry Andric m_stream << message; 39881ad6265SDimitry Andric } else { 39981ad6265SDimitry Andric m_stream << message; 40081ad6265SDimitry Andric } 40181ad6265SDimitry Andric } 40281ad6265SDimitry Andric 40381ad6265SDimitry Andric CallbackLogHandler::CallbackLogHandler(lldb::LogOutputCallback callback, 40481ad6265SDimitry Andric void *baton) 40581ad6265SDimitry Andric : m_callback(callback), m_baton(baton) {} 40681ad6265SDimitry Andric 40781ad6265SDimitry Andric void CallbackLogHandler::Emit(llvm::StringRef message) { 40881ad6265SDimitry Andric m_callback(message.data(), m_baton); 40981ad6265SDimitry Andric } 41081ad6265SDimitry Andric 41181ad6265SDimitry Andric RotatingLogHandler::RotatingLogHandler(size_t size) 41281ad6265SDimitry Andric : m_messages(std::make_unique<std::string[]>(size)), m_size(size) {} 41381ad6265SDimitry Andric 41481ad6265SDimitry Andric void RotatingLogHandler::Emit(llvm::StringRef message) { 41581ad6265SDimitry Andric std::lock_guard<std::mutex> guard(m_mutex); 41681ad6265SDimitry Andric ++m_total_count; 41781ad6265SDimitry Andric const size_t index = m_next_index; 41881ad6265SDimitry Andric m_next_index = NormalizeIndex(index + 1); 41981ad6265SDimitry Andric m_messages[index] = message.str(); 42081ad6265SDimitry Andric } 42181ad6265SDimitry Andric 42281ad6265SDimitry Andric size_t RotatingLogHandler::NormalizeIndex(size_t i) const { return i % m_size; } 42381ad6265SDimitry Andric 42481ad6265SDimitry Andric size_t RotatingLogHandler::GetNumMessages() const { 42581ad6265SDimitry Andric return m_total_count < m_size ? m_total_count : m_size; 42681ad6265SDimitry Andric } 42781ad6265SDimitry Andric 42881ad6265SDimitry Andric size_t RotatingLogHandler::GetFirstMessageIndex() const { 42981ad6265SDimitry Andric return m_total_count < m_size ? 0 : m_next_index; 43081ad6265SDimitry Andric } 43181ad6265SDimitry Andric 43281ad6265SDimitry Andric void RotatingLogHandler::Dump(llvm::raw_ostream &stream) const { 43381ad6265SDimitry Andric std::lock_guard<std::mutex> guard(m_mutex); 43481ad6265SDimitry Andric const size_t start_idx = GetFirstMessageIndex(); 43581ad6265SDimitry Andric const size_t stop_idx = start_idx + GetNumMessages(); 43681ad6265SDimitry Andric for (size_t i = start_idx; i < stop_idx; ++i) { 43781ad6265SDimitry Andric const size_t idx = NormalizeIndex(i); 43881ad6265SDimitry Andric stream << m_messages[idx]; 43981ad6265SDimitry Andric } 44081ad6265SDimitry Andric stream.flush(); 44181ad6265SDimitry Andric } 442*0fca6ea1SDimitry Andric 443*0fca6ea1SDimitry Andric TeeLogHandler::TeeLogHandler(std::shared_ptr<LogHandler> first_log_handler, 444*0fca6ea1SDimitry Andric std::shared_ptr<LogHandler> second_log_handler) 445*0fca6ea1SDimitry Andric : m_first_log_handler(first_log_handler), 446*0fca6ea1SDimitry Andric m_second_log_handler(second_log_handler) { 447*0fca6ea1SDimitry Andric assert(m_first_log_handler && "first log handler must be valid"); 448*0fca6ea1SDimitry Andric assert(m_second_log_handler && "second log handler must be valid"); 449*0fca6ea1SDimitry Andric } 450*0fca6ea1SDimitry Andric 451*0fca6ea1SDimitry Andric void TeeLogHandler::Emit(llvm::StringRef message) { 452*0fca6ea1SDimitry Andric m_first_log_handler->Emit(message); 453*0fca6ea1SDimitry Andric m_second_log_handler->Emit(message); 454*0fca6ea1SDimitry Andric } 455