1 //===-- Log.cpp -------------------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // Project includes 11 #include "lldb/Utility/Log.h" 12 13 #include "lldb/Utility/NameMatches.h" 14 #include "lldb/Utility/StreamString.h" 15 #include "lldb/Utility/VASPrintf.h" 16 17 // Other libraries and framework includes 18 #include "llvm/ADT/STLExtras.h" 19 #include "llvm/ADT/SmallString.h" 20 #include "llvm/Support/Chrono.h" 21 #include "llvm/Support/Path.h" 22 #include "llvm/Support/Signals.h" 23 #include "llvm/Support/Threading.h" 24 #include "llvm/Support/raw_ostream.h" 25 26 // C Includes 27 // C++ Includes 28 #include <cstdarg> 29 #include <cstdio> 30 #include <cstdlib> 31 #include <map> 32 #include <mutex> 33 #include <string> 34 35 using namespace lldb; 36 using namespace lldb_private; 37 38 llvm::ManagedStatic<Log::ChannelMap> Log::g_channel_map; 39 40 void Log::ListCategories(Stream &stream, const ChannelMap::value_type &entry) { 41 stream.Format("Logging categories for '{0}':\n", entry.first()); 42 stream.Format(" all - all available logging categories\n"); 43 stream.Format(" default - default set of logging categories\n"); 44 for (const auto &category : entry.second.m_channel.categories) 45 stream.Format(" {0} - {1}\n", category.name, category.description); 46 } 47 48 uint32_t Log::GetFlags(Stream &stream, const ChannelMap::value_type &entry, 49 llvm::ArrayRef<const char *> categories) { 50 bool list_categories = false; 51 uint32_t flags = 0; 52 for (const char *category : categories) { 53 if (llvm::StringRef("all").equals_lower(category)) { 54 flags |= UINT32_MAX; 55 continue; 56 } 57 if (llvm::StringRef("default").equals_lower(category)) { 58 flags |= entry.second.m_channel.default_flags; 59 continue; 60 } 61 auto cat = llvm::find_if( 62 entry.second.m_channel.categories, 63 [&](const Log::Category &c) { return c.name.equals_lower(category); }); 64 if (cat != entry.second.m_channel.categories.end()) { 65 flags |= cat->flag; 66 continue; 67 } 68 stream.Format("error: unrecognized log category '{0}'\n", category); 69 list_categories = true; 70 } 71 if (list_categories) 72 ListCategories(stream, entry); 73 return flags; 74 } 75 76 void Log::Enable(const std::shared_ptr<llvm::raw_ostream> &stream_sp, 77 uint32_t options, uint32_t flags) { 78 llvm::sys::ScopedWriter lock(m_mutex); 79 80 uint32_t mask = m_mask.fetch_or(flags, std::memory_order_relaxed); 81 if (mask | flags) { 82 m_options.store(options, std::memory_order_relaxed); 83 m_stream_sp = stream_sp; 84 m_channel.log_ptr.store(this, std::memory_order_relaxed); 85 } 86 } 87 88 void Log::Disable(uint32_t flags) { 89 llvm::sys::ScopedWriter lock(m_mutex); 90 91 uint32_t mask = m_mask.fetch_and(~flags, std::memory_order_relaxed); 92 if (!(mask & ~flags)) { 93 m_stream_sp.reset(); 94 m_channel.log_ptr.store(nullptr, std::memory_order_relaxed); 95 } 96 } 97 98 const Flags Log::GetOptions() const { 99 return m_options.load(std::memory_order_relaxed); 100 } 101 102 const Flags Log::GetMask() const { 103 return m_mask.load(std::memory_order_relaxed); 104 } 105 106 void Log::PutCString(const char *cstr) { Printf("%s", cstr); } 107 void Log::PutString(llvm::StringRef str) { PutCString(str.str().c_str()); } 108 109 //---------------------------------------------------------------------- 110 // Simple variable argument logging with flags. 111 //---------------------------------------------------------------------- 112 void Log::Printf(const char *format, ...) { 113 va_list args; 114 va_start(args, format); 115 VAPrintf(format, args); 116 va_end(args); 117 } 118 119 //---------------------------------------------------------------------- 120 // All logging eventually boils down to this function call. If we have 121 // a callback registered, then we call the logging callback. If we have 122 // a valid file handle, we also log to the file. 123 //---------------------------------------------------------------------- 124 void Log::VAPrintf(const char *format, va_list args) { 125 llvm::SmallString<64> FinalMessage; 126 llvm::raw_svector_ostream Stream(FinalMessage); 127 WriteHeader(Stream, "", ""); 128 129 llvm::SmallString<64> Content; 130 lldb_private::VASprintf(Content, format, args); 131 132 Stream << Content << "\n"; 133 134 WriteMessage(FinalMessage.str()); 135 } 136 137 //---------------------------------------------------------------------- 138 // Printing of errors that are not fatal. 139 //---------------------------------------------------------------------- 140 void Log::Error(const char *format, ...) { 141 va_list args; 142 va_start(args, format); 143 VAError(format, args); 144 va_end(args); 145 } 146 147 void Log::VAError(const char *format, va_list args) { 148 llvm::SmallString<64> Content; 149 VASprintf(Content, format, args); 150 151 Printf("error: %s", Content.c_str()); 152 } 153 154 //---------------------------------------------------------------------- 155 // Printing of warnings that are not fatal only if verbose mode is 156 // enabled. 157 //---------------------------------------------------------------------- 158 void Log::Verbose(const char *format, ...) { 159 if (!GetVerbose()) 160 return; 161 162 va_list args; 163 va_start(args, format); 164 VAPrintf(format, args); 165 va_end(args); 166 } 167 168 //---------------------------------------------------------------------- 169 // Printing of warnings that are not fatal. 170 //---------------------------------------------------------------------- 171 void Log::Warning(const char *format, ...) { 172 llvm::SmallString<64> Content; 173 va_list args; 174 va_start(args, format); 175 VASprintf(Content, format, args); 176 va_end(args); 177 178 Printf("warning: %s", Content.c_str()); 179 } 180 181 void Log::Register(llvm::StringRef name, Channel &channel) { 182 auto iter = g_channel_map->try_emplace(name, channel); 183 assert(iter.second == true); 184 (void)iter; 185 } 186 187 void Log::Unregister(llvm::StringRef name) { 188 auto iter = g_channel_map->find(name); 189 assert(iter != g_channel_map->end()); 190 iter->second.Disable(UINT32_MAX); 191 g_channel_map->erase(iter); 192 } 193 194 bool Log::EnableLogChannel( 195 const std::shared_ptr<llvm::raw_ostream> &log_stream_sp, 196 uint32_t log_options, llvm::StringRef channel, 197 llvm::ArrayRef<const char *> categories, Stream &error_stream) { 198 auto iter = g_channel_map->find(channel); 199 if (iter == g_channel_map->end()) { 200 error_stream.Format("Invalid log channel '{0}'.\n", channel); 201 return false; 202 } 203 uint32_t flags = categories.empty() 204 ? iter->second.m_channel.default_flags 205 : GetFlags(error_stream, *iter, categories); 206 iter->second.Enable(log_stream_sp, log_options, flags); 207 return true; 208 } 209 210 bool Log::DisableLogChannel(llvm::StringRef channel, 211 llvm::ArrayRef<const char *> categories, 212 Stream &error_stream) { 213 auto iter = g_channel_map->find(channel); 214 if (iter == g_channel_map->end()) { 215 error_stream.Format("Invalid log channel '{0}'.\n", channel); 216 return false; 217 } 218 uint32_t flags = categories.empty() 219 ? UINT32_MAX 220 : GetFlags(error_stream, *iter, categories); 221 iter->second.Disable(flags); 222 return true; 223 } 224 225 bool Log::ListChannelCategories(llvm::StringRef channel, Stream &stream) { 226 auto ch = g_channel_map->find(channel); 227 if (ch == g_channel_map->end()) { 228 stream.Format("Invalid log channel '{0}'.\n", channel); 229 return false; 230 } 231 ListCategories(stream, *ch); 232 return true; 233 } 234 235 void Log::DisableAllLogChannels(Stream *feedback_strm) { 236 for (auto &entry : *g_channel_map) 237 entry.second.Disable(UINT32_MAX); 238 } 239 240 void Log::ListAllLogChannels(Stream *strm) { 241 if (g_channel_map->empty()) { 242 strm->PutCString("No logging channels are currently registered.\n"); 243 return; 244 } 245 246 for (const auto &channel : *g_channel_map) 247 ListCategories(*strm, channel); 248 } 249 bool Log::GetVerbose() const { 250 return m_options.load(std::memory_order_relaxed) & LLDB_LOG_OPTION_VERBOSE; 251 } 252 253 void Log::WriteHeader(llvm::raw_ostream &OS, llvm::StringRef file, 254 llvm::StringRef function) { 255 Flags options = GetOptions(); 256 static uint32_t g_sequence_id = 0; 257 // Add a sequence ID if requested 258 if (options.Test(LLDB_LOG_OPTION_PREPEND_SEQUENCE)) 259 OS << ++g_sequence_id << " "; 260 261 // Timestamp if requested 262 if (options.Test(LLDB_LOG_OPTION_PREPEND_TIMESTAMP)) { 263 auto now = std::chrono::duration<double>( 264 std::chrono::system_clock::now().time_since_epoch()); 265 OS << llvm::formatv("{0:f9} ", now.count()); 266 } 267 268 // Add the process and thread if requested 269 if (options.Test(LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD)) 270 OS << llvm::formatv("[{0,0+4}/{1,0+4}] ", getpid(), 271 llvm::get_threadid()); 272 273 // Add the thread name if requested 274 if (options.Test(LLDB_LOG_OPTION_PREPEND_THREAD_NAME)) { 275 llvm::SmallString<32> thread_name; 276 llvm::get_thread_name(thread_name); 277 if (!thread_name.empty()) 278 OS << thread_name; 279 } 280 281 if (options.Test(LLDB_LOG_OPTION_BACKTRACE)) 282 llvm::sys::PrintStackTrace(OS); 283 284 if (options.Test(LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION) && 285 (!file.empty() || !function.empty())) { 286 file = llvm::sys::path::filename(file).take_front(40); 287 function = function.take_front(40); 288 OS << llvm::formatv("{0,-60:60} ", (file + ":" + function).str()); 289 } 290 } 291 292 void Log::WriteMessage(const std::string &message) { 293 // Make a copy of our stream shared pointer in case someone disables our 294 // log while we are logging and releases the stream 295 auto stream_sp = GetStream(); 296 if (!stream_sp) 297 return; 298 299 Flags options = GetOptions(); 300 if (options.Test(LLDB_LOG_OPTION_THREADSAFE)) { 301 static std::recursive_mutex g_LogThreadedMutex; 302 std::lock_guard<std::recursive_mutex> guard(g_LogThreadedMutex); 303 *stream_sp << message; 304 stream_sp->flush(); 305 } else { 306 *stream_sp << message; 307 stream_sp->flush(); 308 } 309 } 310 311 void Log::Format(llvm::StringRef file, llvm::StringRef function, 312 const llvm::formatv_object_base &payload) { 313 std::string message_string; 314 llvm::raw_string_ostream message(message_string); 315 WriteHeader(message, file, function); 316 message << payload << "\n"; 317 WriteMessage(message.str()); 318 } 319