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