logging.cpp revision ea41c213bea5dcc04dea39a2903dc7f301bd5184
1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "base/logging.h"
18
19#include <libgen.h>
20
21// For getprogname(3) or program_invocation_short_name.
22#if defined(__ANDROID__) || defined(__APPLE__)
23#include <stdlib.h>
24#elif defined(__GLIBC__)
25#include <errno.h>
26#endif
27
28#include <iostream>
29#include <limits>
30#include <sstream>
31#include <string>
32#include <utility>
33#include <vector>
34
35#ifndef _WIN32
36#include <mutex>
37#else
38#include <windows.h>
39#endif
40
41#include "base/macros.h"
42#include "base/strings.h"
43#include "cutils/threads.h"
44
45// Headers for LogMessage::LogLine.
46#ifdef __ANDROID__
47#include <android/set_abort_message.h>
48#include "cutils/log.h"
49#else
50#include <sys/types.h>
51#include <unistd.h>
52#endif
53
54namespace {
55#ifndef _WIN32
56using std::mutex;
57using std::lock_guard;
58
59#if defined(__GLIBC__)
60const char* getprogname() {
61  return program_invocation_short_name;
62}
63#endif
64
65#else
66const char* getprogname() {
67  static bool first = true;
68  static char progname[MAX_PATH] = {};
69
70  if (first) {
71    // TODO(danalbert): This is a full path on Windows. Just get the basename.
72    DWORD nchars = GetModuleFileName(nullptr, progname, sizeof(progname));
73    DCHECK_GT(nchars, 0U);
74    first = false;
75  }
76
77  return progname;
78}
79
80class mutex {
81 public:
82  mutex() {
83    semaphore_ = CreateSemaphore(nullptr, 1, 1, nullptr);
84    CHECK(semaphore_ != nullptr) << "Failed to create Mutex";
85  }
86  ~mutex() {
87    CloseHandle(semaphore_);
88  }
89
90  void lock() {
91    DWORD result = WaitForSingleObject(semaphore_, INFINITE);
92    CHECK_EQ(result, WAIT_OBJECT_0) << GetLastError();
93  }
94
95  void unlock() {
96    bool result = ReleaseSemaphore(semaphore_, 1, nullptr);
97    CHECK(result);
98  }
99
100 private:
101  HANDLE semaphore_;
102};
103
104template <typename LockT>
105class lock_guard {
106 public:
107  explicit lock_guard(LockT& lock) : lock_(lock) {
108    lock_.lock();
109  }
110
111  ~lock_guard() {
112    lock_.unlock();
113  }
114
115 private:
116  LockT& lock_;
117
118  DISALLOW_COPY_AND_ASSIGN(lock_guard);
119};
120#endif
121} // namespace
122
123namespace android {
124namespace base {
125
126static mutex logging_lock;
127
128#ifdef __ANDROID__
129static LogFunction gLogger = LogdLogger();
130#else
131static LogFunction gLogger = StderrLogger;
132#endif
133
134static bool gInitialized = false;
135static LogSeverity gMinimumLogSeverity = INFO;
136static std::unique_ptr<std::string> gProgramInvocationName;
137
138static const char* ProgramInvocationName() {
139  if (gProgramInvocationName == nullptr) {
140    gProgramInvocationName.reset(new std::string(getprogname()));
141  }
142
143  return gProgramInvocationName->c_str();
144}
145
146void StderrLogger(LogId, LogSeverity severity, const char*, const char* file,
147                  unsigned int line, const char* message) {
148  static const char* log_characters = "VDIWEF";
149  CHECK_EQ(strlen(log_characters), FATAL + 1U);
150  char severity_char = log_characters[severity];
151  fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationName(),
152          severity_char, getpid(), gettid(), file, line, message);
153}
154
155
156#ifdef __ANDROID__
157LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) {
158}
159
160static const android_LogPriority kLogSeverityToAndroidLogPriority[] = {
161    ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO,
162    ANDROID_LOG_WARN,    ANDROID_LOG_ERROR, ANDROID_LOG_FATAL,
163};
164static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1,
165              "Mismatch in size of kLogSeverityToAndroidLogPriority and values "
166              "in LogSeverity");
167
168static const log_id kLogIdToAndroidLogId[] = {
169    LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM,
170};
171static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1,
172              "Mismatch in size of kLogIdToAndroidLogId and values in LogId");
173
174void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag,
175                            const char* file, unsigned int line,
176                            const char* message) {
177  int priority = kLogSeverityToAndroidLogPriority[severity];
178  if (id == DEFAULT) {
179    id = default_log_id_;
180  }
181
182  log_id lg_id = kLogIdToAndroidLogId[id];
183
184  if (priority == ANDROID_LOG_FATAL) {
185    __android_log_buf_print(lg_id, priority, tag, "%s:%u] %s", file, line,
186                            message);
187  } else {
188    __android_log_buf_print(lg_id, priority, tag, "%s", message);
189  }
190}
191#endif
192
193void InitLogging(char* argv[], LogFunction&& logger) {
194  SetLogger(std::forward<LogFunction>(logger));
195  InitLogging(argv);
196}
197
198void InitLogging(char* argv[]) {
199  if (gInitialized) {
200    return;
201  }
202
203  gInitialized = true;
204
205  // Stash the command line for later use. We can use /proc/self/cmdline on
206  // Linux to recover this, but we don't have that luxury on the Mac, and there
207  // are a couple of argv[0] variants that are commonly used.
208  if (argv != nullptr) {
209    gProgramInvocationName.reset(new std::string(basename(argv[0])));
210  }
211
212  const char* tags = getenv("ANDROID_LOG_TAGS");
213  if (tags == nullptr) {
214    return;
215  }
216
217  std::vector<std::string> specs = Split(tags, " ");
218  for (size_t i = 0; i < specs.size(); ++i) {
219    // "tag-pattern:[vdiwefs]"
220    std::string spec(specs[i]);
221    if (spec.size() == 3 && StartsWith(spec, "*:")) {
222      switch (spec[2]) {
223        case 'v':
224          gMinimumLogSeverity = VERBOSE;
225          continue;
226        case 'd':
227          gMinimumLogSeverity = DEBUG;
228          continue;
229        case 'i':
230          gMinimumLogSeverity = INFO;
231          continue;
232        case 'w':
233          gMinimumLogSeverity = WARNING;
234          continue;
235        case 'e':
236          gMinimumLogSeverity = ERROR;
237          continue;
238        case 'f':
239          gMinimumLogSeverity = FATAL;
240          continue;
241        // liblog will even suppress FATAL if you say 's' for silent, but that's
242        // crazy!
243        case 's':
244          gMinimumLogSeverity = FATAL;
245          continue;
246      }
247    }
248    LOG(FATAL) << "unsupported '" << spec << "' in ANDROID_LOG_TAGS (" << tags
249               << ")";
250  }
251}
252
253void SetLogger(LogFunction&& logger) {
254  lock_guard<mutex> lock(logging_lock);
255  gLogger = std::move(logger);
256}
257
258// This indirection greatly reduces the stack impact of having lots of
259// checks/logging in a function.
260class LogMessageData {
261 public:
262  LogMessageData(const char* file, unsigned int line, LogId id,
263                 LogSeverity severity, int error)
264      : file_(file),
265        line_number_(line),
266        id_(id),
267        severity_(severity),
268        error_(error) {
269    const char* last_slash = strrchr(file, '/');
270    file = (last_slash == nullptr) ? file : last_slash + 1;
271  }
272
273  const char* GetFile() const {
274    return file_;
275  }
276
277  unsigned int GetLineNumber() const {
278    return line_number_;
279  }
280
281  LogSeverity GetSeverity() const {
282    return severity_;
283  }
284
285  LogId GetId() const {
286    return id_;
287  }
288
289  int GetError() const {
290    return error_;
291  }
292
293  std::ostream& GetBuffer() {
294    return buffer_;
295  }
296
297  std::string ToString() const {
298    return buffer_.str();
299  }
300
301 private:
302  std::ostringstream buffer_;
303  const char* const file_;
304  const unsigned int line_number_;
305  const LogId id_;
306  const LogSeverity severity_;
307  const int error_;
308
309  DISALLOW_COPY_AND_ASSIGN(LogMessageData);
310};
311
312LogMessage::LogMessage(const char* file, unsigned int line, LogId id,
313                       LogSeverity severity, int error)
314    : data_(new LogMessageData(file, line, id, severity, error)) {
315}
316
317LogMessage::~LogMessage() {
318  if (data_->GetSeverity() < gMinimumLogSeverity) {
319    return;  // No need to format something we're not going to output.
320  }
321
322  // Finish constructing the message.
323  if (data_->GetError() != -1) {
324    data_->GetBuffer() << ": " << strerror(data_->GetError());
325  }
326  std::string msg(data_->ToString());
327
328  if (msg.find('\n') == std::string::npos) {
329    LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
330            data_->GetSeverity(), msg.c_str());
331  } else {
332    msg += '\n';
333    size_t i = 0;
334    while (i < msg.size()) {
335      size_t nl = msg.find('\n', i);
336      msg[nl] = '\0';
337      LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
338              data_->GetSeverity(), &msg[i]);
339      i = nl + 1;
340    }
341  }
342
343  // Abort if necessary.
344  if (data_->GetSeverity() == FATAL) {
345#ifdef __ANDROID__
346    android_set_abort_message(msg.c_str());
347#endif
348    abort();
349  }
350}
351
352std::ostream& LogMessage::stream() {
353  return data_->GetBuffer();
354}
355
356void LogMessage::LogLine(const char* file, unsigned int line, LogId id,
357                         LogSeverity severity, const char* message) {
358  const char* tag = ProgramInvocationName();
359  lock_guard<mutex> lock(logging_lock);
360  gLogger(id, severity, tag, file, line, message);
361}
362
363ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) {
364  old_ = gMinimumLogSeverity;
365  gMinimumLogSeverity = level;
366}
367
368ScopedLogSeverity::~ScopedLogSeverity() {
369  gMinimumLogSeverity = old_;
370}
371
372}  // namespace base
373}  // namespace android
374