logging.cpp revision 47328c96d91ca71b57b8976df2df1fe51579a955
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 <iostream> 20#include <limits> 21#include <sstream> 22#include <string> 23#include <vector> 24 25#include "base/strings.h" 26 27// Headers for LogMessage::LogLine. 28#ifdef __ANDROID__ 29#include <android/set_abort_message.h> 30#include "cutils/log.h" 31#else 32#include <sys/types.h> 33#include <unistd.h> 34#endif 35 36// For GetTid. 37#if defined(__APPLE__) 38#include "AvailabilityMacros.h" // For MAC_OS_X_VERSION_MAX_ALLOWED 39#include <sys/syscall.h> 40#include <sys/time.h> 41#elif !defined(__BIONIC__) 42#include <syscall.h> 43#endif 44 45namespace android { 46namespace base { 47 48static std::mutex logging_lock; 49 50static LogSeverity gMinimumLogSeverity = INFO; 51static std::unique_ptr<std::string> gCmdLine; 52static std::unique_ptr<std::string> gProgramInvocationName; 53static std::unique_ptr<std::string> gProgramInvocationShortName; 54 55#ifndef __ANDROID__ 56static pid_t GetTid() { 57#if defined(__APPLE__) 58 uint64_t owner; 59 // Requires Mac OS 10.6 60 CHECK_PTHREAD_CALL(pthread_threadid_np, (NULL, &owner), __FUNCTION__); 61 return owner; 62#else 63 return syscall(__NR_gettid); 64#endif 65} 66#endif // __ANDROID__ 67 68const char* GetCmdLine() { 69 return (gCmdLine.get() != nullptr) ? gCmdLine->c_str() : nullptr; 70} 71 72const char* ProgramInvocationName() { 73 return (gProgramInvocationName.get() != nullptr) 74 ? gProgramInvocationName->c_str() 75 : "unknown"; 76} 77 78const char* ProgramInvocationShortName() { 79 return (gProgramInvocationShortName.get() != nullptr) 80 ? gProgramInvocationShortName->c_str() 81 : "unknown"; 82} 83 84void InitLogging(char* argv[]) { 85 if (gCmdLine.get() != nullptr) { 86 return; 87 } 88 89 // Stash the command line for later use. We can use /proc/self/cmdline on 90 // Linux to recover this, but we don't have that luxury on the Mac, and there 91 // are a couple of argv[0] variants that are commonly used. 92 if (argv != nullptr) { 93 gCmdLine.reset(new std::string(argv[0])); 94 for (size_t i = 1; argv[i] != nullptr; ++i) { 95 gCmdLine->append(" "); 96 gCmdLine->append(argv[i]); 97 } 98 gProgramInvocationName.reset(new std::string(argv[0])); 99 const char* last_slash = strrchr(argv[0], '/'); 100 gProgramInvocationShortName.reset( 101 new std::string((last_slash != nullptr) ? last_slash + 1 : argv[0])); 102 } else { 103 // TODO: fall back to /proc/self/cmdline when argv is NULL on Linux. 104 gCmdLine.reset(new std::string("<unset>")); 105 } 106 const char* tags = getenv("ANDROID_LOG_TAGS"); 107 if (tags == nullptr) { 108 return; 109 } 110 111 std::vector<std::string> specs = Split(tags, " "); 112 for (size_t i = 0; i < specs.size(); ++i) { 113 // "tag-pattern:[vdiwefs]" 114 std::string spec(specs[i]); 115 if (spec.size() == 3 && StartsWith(spec, "*:")) { 116 switch (spec[2]) { 117 case 'v': 118 gMinimumLogSeverity = VERBOSE; 119 continue; 120 case 'd': 121 gMinimumLogSeverity = DEBUG; 122 continue; 123 case 'i': 124 gMinimumLogSeverity = INFO; 125 continue; 126 case 'w': 127 gMinimumLogSeverity = WARNING; 128 continue; 129 case 'e': 130 gMinimumLogSeverity = ERROR; 131 continue; 132 case 'f': 133 gMinimumLogSeverity = FATAL; 134 continue; 135 // liblog will even suppress FATAL if you say 's' for silent, but that's 136 // crazy! 137 case 's': 138 gMinimumLogSeverity = FATAL; 139 continue; 140 } 141 } 142 LOG(FATAL) << "unsupported '" << spec << "' in ANDROID_LOG_TAGS (" << tags 143 << ")"; 144 } 145} 146 147// This indirection greatly reduces the stack impact of having lots of 148// checks/logging in a function. 149class LogMessageData { 150 public: 151 LogMessageData(const char* file, unsigned int line, LogSeverity severity, 152 int error) 153 : file_(file), line_number_(line), severity_(severity), error_(error) { 154 const char* last_slash = strrchr(file, '/'); 155 file = (last_slash == nullptr) ? file : last_slash + 1; 156 } 157 158 const char* GetFile() const { 159 return file_; 160 } 161 162 unsigned int GetLineNumber() const { 163 return line_number_; 164 } 165 166 LogSeverity GetSeverity() const { 167 return severity_; 168 } 169 170 int GetError() const { 171 return error_; 172 } 173 174 std::ostream& GetBuffer() { 175 return buffer_; 176 } 177 178 std::string ToString() const { 179 return buffer_.str(); 180 } 181 182 private: 183 std::ostringstream buffer_; 184 const char* const file_; 185 const unsigned int line_number_; 186 const LogSeverity severity_; 187 const int error_; 188 189 DISALLOW_COPY_AND_ASSIGN(LogMessageData); 190}; 191 192LogMessage::LogMessage(const char* file, unsigned int line, 193 LogSeverity severity, int error) 194 : data_(new LogMessageData(file, line, severity, error)) { 195} 196 197LogMessage::~LogMessage() { 198 if (data_->GetSeverity() < gMinimumLogSeverity) { 199 return; // No need to format something we're not going to output. 200 } 201 202 // Finish constructing the message. 203 if (data_->GetError() != -1) { 204 data_->GetBuffer() << ": " << strerror(data_->GetError()); 205 } 206 std::string msg(data_->ToString()); 207 208 // Do the actual logging with the lock held. 209 { 210 std::lock_guard<std::mutex> lock(logging_lock); 211 if (msg.find('\n') == std::string::npos) { 212 LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), 213 msg.c_str()); 214 } else { 215 msg += '\n'; 216 size_t i = 0; 217 while (i < msg.size()) { 218 size_t nl = msg.find('\n', i); 219 msg[nl] = '\0'; 220 LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), 221 &msg[i]); 222 i = nl + 1; 223 } 224 } 225 } 226 227 // Abort if necessary. 228 if (data_->GetSeverity() == FATAL) { 229#ifdef __ANDROID__ 230 android_set_abort_message(msg.c_str()); 231#endif 232 abort(); 233 } 234} 235 236std::ostream& LogMessage::stream() { 237 return data_->GetBuffer(); 238} 239 240#ifdef __ANDROID__ 241static const android_LogPriority kLogSeverityToAndroidLogPriority[] = { 242 ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, 243 ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL}; 244static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1, 245 "Mismatch in size of kLogSeverityToAndroidLogPriority and values " 246 "in LogSeverity"); 247#endif 248 249void LogMessage::LogLine(const char* file, unsigned int line, 250 LogSeverity log_severity, const char* message) { 251#ifdef __ANDROID__ 252 const char* tag = ProgramInvocationShortName(); 253 int priority = kLogSeverityToAndroidLogPriority[log_severity]; 254 if (priority == ANDROID_LOG_FATAL) { 255 LOG_PRI(priority, tag, "%s:%u] %s", file, line, message); 256 } else { 257 LOG_PRI(priority, tag, "%s", message); 258 } 259#else 260 static const char* log_characters = "VDIWEF"; 261 CHECK_EQ(strlen(log_characters), FATAL + 1U); 262 char severity = log_characters[log_severity]; 263 fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationShortName(), 264 severity, getpid(), GetTid(), file, line, message); 265#endif 266} 267 268void LogMessage::LogLineLowStack(const char* file, unsigned int line, 269 LogSeverity log_severity, const char* message) { 270#ifdef __ANDROID__ 271 // Use android_writeLog() to avoid stack-based buffers used by 272 // android_printLog(). 273 const char* tag = ProgramInvocationShortName(); 274 int priority = kLogSeverityToAndroidLogPriority[log_severity]; 275 char* buf = nullptr; 276 size_t buf_size = 0u; 277 if (priority == ANDROID_LOG_FATAL) { 278 // Allocate buffer for snprintf(buf, buf_size, "%s:%u] %s", file, line, 279 // message) below. If allocation fails, fall back to printing only the 280 // message. 281 buf_size = strlen(file) + 1 /* ':' */ + 282 std::numeric_limits<typeof(line)>::max_digits10 + 2 /* "] " */ + 283 strlen(message) + 1 /* terminating 0 */; 284 buf = reinterpret_cast<char*>(malloc(buf_size)); 285 } 286 if (buf != nullptr) { 287 snprintf(buf, buf_size, "%s:%u] %s", file, line, message); 288 android_writeLog(priority, tag, buf); 289 free(buf); 290 } else { 291 android_writeLog(priority, tag, message); 292 } 293#else 294 static const char* log_characters = "VDIWEF"; 295 CHECK_EQ(strlen(log_characters), FATAL + 1U); 296 297 const char* program_name = ProgramInvocationShortName(); 298 write(STDERR_FILENO, program_name, strlen(program_name)); 299 write(STDERR_FILENO, " ", 1); 300 write(STDERR_FILENO, &log_characters[log_severity], 1); 301 write(STDERR_FILENO, " ", 1); 302 // TODO: pid and tid. 303 write(STDERR_FILENO, file, strlen(file)); 304 // TODO: line. 305 UNUSED(line); 306 write(STDERR_FILENO, "] ", 2); 307 write(STDERR_FILENO, message, strlen(message)); 308 write(STDERR_FILENO, "\n", 1); 309#endif 310} 311 312ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) { 313 old_ = gMinimumLogSeverity; 314 gMinimumLogSeverity = level; 315} 316 317ScopedLogSeverity::~ScopedLogSeverity() { 318 gMinimumLogSeverity = old_; 319} 320 321} // namespace base 322} // namespace android 323