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