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