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