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