logging.cpp revision 58310b49fc8a7a713b922319a849a419858db79e
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; 112 Split(tags, ' ', &specs); 113 for (size_t i = 0; i < specs.size(); ++i) { 114 // "tag-pattern:[vdiwefs]" 115 std::string spec(specs[i]); 116 if (spec.size() == 3 && StartsWith(spec, "*:")) { 117 switch (spec[2]) { 118 case 'v': 119 gMinimumLogSeverity = VERBOSE; 120 continue; 121 case 'd': 122 gMinimumLogSeverity = DEBUG; 123 continue; 124 case 'i': 125 gMinimumLogSeverity = INFO; 126 continue; 127 case 'w': 128 gMinimumLogSeverity = WARNING; 129 continue; 130 case 'e': 131 gMinimumLogSeverity = ERROR; 132 continue; 133 case 'f': 134 gMinimumLogSeverity = FATAL; 135 continue; 136 // liblog will even suppress FATAL if you say 's' for silent, but that's 137 // crazy! 138 case 's': 139 gMinimumLogSeverity = FATAL; 140 continue; 141 } 142 } 143 LOG(FATAL) << "unsupported '" << spec << "' in ANDROID_LOG_TAGS (" << tags 144 << ")"; 145 } 146} 147 148// This indirection greatly reduces the stack impact of having lots of 149// checks/logging in a function. 150class LogMessageData { 151 public: 152 LogMessageData(const char* file, unsigned int line, LogSeverity severity, 153 int error) 154 : file_(file), line_number_(line), severity_(severity), error_(error) { 155 const char* last_slash = strrchr(file, '/'); 156 file = (last_slash == nullptr) ? file : last_slash + 1; 157 } 158 159 const char* GetFile() const { 160 return file_; 161 } 162 163 unsigned int GetLineNumber() const { 164 return line_number_; 165 } 166 167 LogSeverity GetSeverity() const { 168 return severity_; 169 } 170 171 int GetError() const { 172 return error_; 173 } 174 175 std::ostream& GetBuffer() { 176 return buffer_; 177 } 178 179 std::string ToString() const { 180 return buffer_.str(); 181 } 182 183 private: 184 std::ostringstream buffer_; 185 const char* const file_; 186 const unsigned int line_number_; 187 const LogSeverity severity_; 188 const int error_; 189 190 DISALLOW_COPY_AND_ASSIGN(LogMessageData); 191}; 192 193LogMessage::LogMessage(const char* file, unsigned int line, 194 LogSeverity severity, int error) 195 : data_(new LogMessageData(file, line, severity, error)) { 196} 197 198LogMessage::~LogMessage() { 199 if (data_->GetSeverity() < gMinimumLogSeverity) { 200 return; // No need to format something we're not going to output. 201 } 202 203 // Finish constructing the message. 204 if (data_->GetError() != -1) { 205 data_->GetBuffer() << ": " << strerror(data_->GetError()); 206 } 207 std::string msg(data_->ToString()); 208 209 // Do the actual logging with the lock held. 210 { 211 std::lock_guard<std::mutex> lock(logging_lock); 212 if (msg.find('\n') == std::string::npos) { 213 LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), 214 msg.c_str()); 215 } else { 216 msg += '\n'; 217 size_t i = 0; 218 while (i < msg.size()) { 219 size_t nl = msg.find('\n', i); 220 msg[nl] = '\0'; 221 LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), 222 &msg[i]); 223 i = nl + 1; 224 } 225 } 226 } 227 228 // Abort if necessary. 229 if (data_->GetSeverity() == FATAL) { 230#ifdef __ANDROID__ 231 android_set_abort_message(msg.c_str()); 232#endif 233 abort(); 234 } 235} 236 237std::ostream& LogMessage::stream() { 238 return data_->GetBuffer(); 239} 240 241#ifdef __ANDROID__ 242static const android_LogPriority kLogSeverityToAndroidLogPriority[] = { 243 ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, 244 ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL}; 245static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1, 246 "Mismatch in size of kLogSeverityToAndroidLogPriority and values " 247 "in LogSeverity"); 248#endif 249 250void LogMessage::LogLine(const char* file, unsigned int line, 251 LogSeverity log_severity, const char* message) { 252#ifdef __ANDROID__ 253 const char* tag = ProgramInvocationShortName(); 254 int priority = kLogSeverityToAndroidLogPriority[log_severity]; 255 if (priority == ANDROID_LOG_FATAL) { 256 LOG_PRI(priority, tag, "%s:%u] %s", file, line, message); 257 } else { 258 LOG_PRI(priority, tag, "%s", message); 259 } 260#else 261 static const char* log_characters = "VDIWEF"; 262 CHECK_EQ(strlen(log_characters), FATAL + 1U); 263 char severity = log_characters[log_severity]; 264 fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationShortName(), 265 severity, getpid(), GetTid(), file, line, message); 266#endif 267} 268 269void LogMessage::LogLineLowStack(const char* file, unsigned int line, 270 LogSeverity log_severity, const char* message) { 271#ifdef __ANDROID__ 272 // Use android_writeLog() to avoid stack-based buffers used by 273 // android_printLog(). 274 const char* tag = ProgramInvocationShortName(); 275 int priority = kLogSeverityToAndroidLogPriority[log_severity]; 276 char* buf = nullptr; 277 size_t buf_size = 0u; 278 if (priority == ANDROID_LOG_FATAL) { 279 // Allocate buffer for snprintf(buf, buf_size, "%s:%u] %s", file, line, 280 // message) below. If allocation fails, fall back to printing only the 281 // message. 282 buf_size = strlen(file) + 1 /* ':' */ + 283 std::numeric_limits<typeof(line)>::max_digits10 + 2 /* "] " */ + 284 strlen(message) + 1 /* terminating 0 */; 285 buf = reinterpret_cast<char*>(malloc(buf_size)); 286 } 287 if (buf != nullptr) { 288 snprintf(buf, buf_size, "%s:%u] %s", file, line, message); 289 android_writeLog(priority, tag, buf); 290 free(buf); 291 } else { 292 android_writeLog(priority, tag, message); 293 } 294#else 295 static const char* log_characters = "VDIWEF"; 296 CHECK_EQ(strlen(log_characters), FATAL + 1U); 297 298 const char* program_name = ProgramInvocationShortName(); 299 write(STDERR_FILENO, program_name, strlen(program_name)); 300 write(STDERR_FILENO, " ", 1); 301 write(STDERR_FILENO, &log_characters[log_severity], 1); 302 write(STDERR_FILENO, " ", 1); 303 // TODO: pid and tid. 304 write(STDERR_FILENO, file, strlen(file)); 305 // TODO: line. 306 UNUSED(line); 307 write(STDERR_FILENO, "] ", 2); 308 write(STDERR_FILENO, message, strlen(message)); 309 write(STDERR_FILENO, "\n", 1); 310#endif 311} 312 313ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) { 314 old_ = gMinimumLogSeverity; 315 gMinimumLogSeverity = level; 316} 317 318ScopedLogSeverity::~ScopedLogSeverity() { 319 gMinimumLogSeverity = old_; 320} 321 322} // namespace base 323} // namespace android 324