logging.cpp revision bdab59a8613c732df5d746328ff2268be8da13ab
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 mutex logging_lock; 131 132#ifdef __ANDROID__ 133static LogFunction gLogger = LogdLogger(); 134#else 135static LogFunction gLogger = StderrLogger; 136#endif 137 138static bool gInitialized = false; 139static LogSeverity gMinimumLogSeverity = INFO; 140static std::unique_ptr<std::string> gProgramInvocationName; 141 142static const char* ProgramInvocationName() { 143 if (gProgramInvocationName == nullptr) { 144 gProgramInvocationName.reset(new std::string(getprogname())); 145 } 146 147 return gProgramInvocationName->c_str(); 148} 149 150void StderrLogger(LogId, LogSeverity severity, const char*, const char* file, 151 unsigned int line, const char* message) { 152 static const char log_characters[] = "VDIWEF"; 153 static_assert(arraysize(log_characters) - 1 == FATAL + 1, 154 "Mismatch in size of log_characters and values in LogSeverity"); 155 char severity_char = log_characters[severity]; 156 fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationName(), 157 severity_char, getpid(), gettid(), file, line, message); 158} 159 160 161#ifdef __ANDROID__ 162LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) { 163} 164 165static const android_LogPriority kLogSeverityToAndroidLogPriority[] = { 166 ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, 167 ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, 168}; 169static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1, 170 "Mismatch in size of kLogSeverityToAndroidLogPriority and values " 171 "in LogSeverity"); 172 173static const log_id kLogIdToAndroidLogId[] = { 174 LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM, 175}; 176static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1, 177 "Mismatch in size of kLogIdToAndroidLogId and values in LogId"); 178 179void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag, 180 const char* file, unsigned int line, 181 const char* message) { 182 int priority = kLogSeverityToAndroidLogPriority[severity]; 183 if (id == DEFAULT) { 184 id = default_log_id_; 185 } 186 187 log_id lg_id = kLogIdToAndroidLogId[id]; 188 189 if (priority == ANDROID_LOG_FATAL) { 190 __android_log_buf_print(lg_id, priority, tag, "%s:%u] %s", file, line, 191 message); 192 } else { 193 __android_log_buf_print(lg_id, priority, tag, "%s", message); 194 } 195} 196#endif 197 198void InitLogging(char* argv[], LogFunction&& logger) { 199 SetLogger(std::forward<LogFunction>(logger)); 200 InitLogging(argv); 201} 202 203// TODO: make this public; it's independently useful. 204class ErrnoRestorer { 205 public: 206 ErrnoRestorer(int saved_errno) : saved_errno_(saved_errno) { 207 } 208 209 ~ErrnoRestorer() { 210 errno = saved_errno_; 211 } 212 213 private: 214 const int saved_errno_; 215}; 216 217void InitLogging(char* argv[]) { 218 if (gInitialized) { 219 return; 220 } 221 222 gInitialized = true; 223 224 // Stash the command line for later use. We can use /proc/self/cmdline on 225 // Linux to recover this, but we don't have that luxury on the Mac, and there 226 // are a couple of argv[0] variants that are commonly used. 227 if (argv != nullptr) { 228 gProgramInvocationName.reset(new std::string(basename(argv[0]))); 229 } 230 231 const char* tags = getenv("ANDROID_LOG_TAGS"); 232 if (tags == nullptr) { 233 return; 234 } 235 236 std::vector<std::string> specs = Split(tags, " "); 237 for (size_t i = 0; i < specs.size(); ++i) { 238 // "tag-pattern:[vdiwefs]" 239 std::string spec(specs[i]); 240 if (spec.size() == 3 && StartsWith(spec, "*:")) { 241 switch (spec[2]) { 242 case 'v': 243 gMinimumLogSeverity = VERBOSE; 244 continue; 245 case 'd': 246 gMinimumLogSeverity = DEBUG; 247 continue; 248 case 'i': 249 gMinimumLogSeverity = INFO; 250 continue; 251 case 'w': 252 gMinimumLogSeverity = WARNING; 253 continue; 254 case 'e': 255 gMinimumLogSeverity = ERROR; 256 continue; 257 case 'f': 258 gMinimumLogSeverity = FATAL; 259 continue; 260 // liblog will even suppress FATAL if you say 's' for silent, but that's 261 // crazy! 262 case 's': 263 gMinimumLogSeverity = FATAL; 264 continue; 265 } 266 } 267 LOG(FATAL) << "unsupported '" << spec << "' in ANDROID_LOG_TAGS (" << tags 268 << ")"; 269 } 270} 271 272void SetLogger(LogFunction&& logger) { 273 lock_guard<mutex> lock(logging_lock); 274 gLogger = std::move(logger); 275} 276 277// We can't use basename(3) because this code runs on the Mac, which doesn't 278// have a non-modifying basename. 279static const char* GetFileBasename(const char* file) { 280 const char* last_slash = strrchr(file, '/'); 281 return (last_slash == nullptr) ? file : last_slash + 1; 282} 283 284// This indirection greatly reduces the stack impact of having lots of 285// checks/logging in a function. 286class LogMessageData { 287 public: 288 LogMessageData(const char* file, unsigned int line, LogId id, 289 LogSeverity severity, int error, int saved_errno) 290 : file_(GetFileBasename(file)), 291 line_number_(line), 292 id_(id), 293 severity_(severity), 294 error_(error), 295 errno_restorer_(saved_errno) { 296 } 297 298 const char* GetFile() const { 299 return file_; 300 } 301 302 unsigned int GetLineNumber() const { 303 return line_number_; 304 } 305 306 LogSeverity GetSeverity() const { 307 return severity_; 308 } 309 310 LogId GetId() const { 311 return id_; 312 } 313 314 int GetError() const { 315 return error_; 316 } 317 318 std::ostream& GetBuffer() { 319 return buffer_; 320 } 321 322 std::string ToString() const { 323 return buffer_.str(); 324 } 325 326 private: 327 std::ostringstream buffer_; 328 const char* const file_; 329 const unsigned int line_number_; 330 const LogId id_; 331 const LogSeverity severity_; 332 const int error_; 333 ErrnoRestorer errno_restorer_; 334 335 DISALLOW_COPY_AND_ASSIGN(LogMessageData); 336}; 337 338LogMessage::LogMessage(const char* file, unsigned int line, LogId id, 339 LogSeverity severity, int error) 340 : data_(new LogMessageData(file, line, id, severity, error, errno)) { 341} 342 343LogMessage::~LogMessage() { 344 if (data_->GetSeverity() < gMinimumLogSeverity) { 345 return; // No need to format something we're not going to output. 346 } 347 348 // Finish constructing the message. 349 if (data_->GetError() != -1) { 350 data_->GetBuffer() << ": " << strerror(data_->GetError()); 351 } 352 std::string msg(data_->ToString()); 353 354 if (msg.find('\n') == std::string::npos) { 355 LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(), 356 data_->GetSeverity(), msg.c_str()); 357 } else { 358 msg += '\n'; 359 size_t i = 0; 360 while (i < msg.size()) { 361 size_t nl = msg.find('\n', i); 362 msg[nl] = '\0'; 363 LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(), 364 data_->GetSeverity(), &msg[i]); 365 i = nl + 1; 366 } 367 } 368 369 // Abort if necessary. 370 if (data_->GetSeverity() == FATAL) { 371#ifdef __ANDROID__ 372 android_set_abort_message(msg.c_str()); 373#endif 374 abort(); 375 } 376} 377 378std::ostream& LogMessage::stream() { 379 return data_->GetBuffer(); 380} 381 382void LogMessage::LogLine(const char* file, unsigned int line, LogId id, 383 LogSeverity severity, const char* message) { 384 const char* tag = ProgramInvocationName(); 385 lock_guard<mutex> lock(logging_lock); 386 gLogger(id, severity, tag, file, line, message); 387} 388 389ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) { 390 old_ = gMinimumLogSeverity; 391 gMinimumLogSeverity = level; 392} 393 394ScopedLogSeverity::~ScopedLogSeverity() { 395 gMinimumLogSeverity = old_; 396} 397 398} // namespace base 399} // namespace android 400