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 <mutex> 31 #include <sstream> 32 #include <string> 33 #include <utility> 34 #include <vector> 35 36 #include "base/strings.h" 37 #include "cutils/threads.h" 38 39 // Headers for LogMessage::LogLine. 40 #ifdef __ANDROID__ 41 #include <android/set_abort_message.h> 42 #include "cutils/log.h" 43 #else 44 #include <sys/types.h> 45 #include <unistd.h> 46 #endif 47 48 namespace android { 49 namespace base { 50 51 static std::mutex logging_lock; 52 53 #ifdef __ANDROID__ 54 static LogFunction gLogger = LogdLogger(); 55 #else 56 static LogFunction gLogger = StderrLogger; 57 #endif 58 59 static bool gInitialized = false; 60 static LogSeverity gMinimumLogSeverity = INFO; 61 static std::unique_ptr<std::string> gProgramInvocationName; 62 63 #if defined(__GLIBC__) 64 static const char* getprogname() { 65 return program_invocation_short_name; 66 } 67 #endif 68 69 static const char* ProgramInvocationName() { 70 if (gProgramInvocationName == nullptr) { 71 gProgramInvocationName.reset(new std::string(getprogname())); 72 } 73 74 return gProgramInvocationName->c_str(); 75 } 76 77 void StderrLogger(LogId, LogSeverity severity, const char*, const char* file, 78 unsigned int line, const char* message) { 79 static const char* log_characters = "VDIWEF"; 80 CHECK_EQ(strlen(log_characters), FATAL + 1U); 81 char severity_char = log_characters[severity]; 82 fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationName(), 83 severity_char, getpid(), gettid(), file, line, message); 84 } 85 86 87 #ifdef __ANDROID__ 88 LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) { 89 } 90 91 static const android_LogPriority kLogSeverityToAndroidLogPriority[] = { 92 ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, 93 ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, 94 }; 95 static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1, 96 "Mismatch in size of kLogSeverityToAndroidLogPriority and values " 97 "in LogSeverity"); 98 99 static const log_id kLogIdToAndroidLogId[] = { 100 LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM, 101 }; 102 static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1, 103 "Mismatch in size of kLogIdToAndroidLogId and values in LogId"); 104 105 void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag, 106 const char* file, unsigned int line, 107 const char* message) { 108 int priority = kLogSeverityToAndroidLogPriority[severity]; 109 if (id == DEFAULT) { 110 id = default_log_id_; 111 } 112 113 log_id lg_id = kLogIdToAndroidLogId[id]; 114 115 if (priority == ANDROID_LOG_FATAL) { 116 __android_log_buf_print(lg_id, priority, tag, "%s:%u] %s", file, line, 117 message); 118 } else { 119 __android_log_buf_print(lg_id, priority, tag, "%s", message); 120 } 121 } 122 #endif 123 124 void InitLogging(char* argv[], LogFunction&& logger) { 125 SetLogger(std::forward<LogFunction>(logger)); 126 InitLogging(argv); 127 } 128 129 void InitLogging(char* argv[]) { 130 if (gInitialized) { 131 return; 132 } 133 134 gInitialized = true; 135 136 // Stash the command line for later use. We can use /proc/self/cmdline on 137 // Linux to recover this, but we don't have that luxury on the Mac, and there 138 // are a couple of argv[0] variants that are commonly used. 139 if (argv != nullptr) { 140 gProgramInvocationName.reset(new std::string(basename(argv[0]))); 141 } 142 143 const char* tags = getenv("ANDROID_LOG_TAGS"); 144 if (tags == nullptr) { 145 return; 146 } 147 148 std::vector<std::string> specs = Split(tags, " "); 149 for (size_t i = 0; i < specs.size(); ++i) { 150 // "tag-pattern:[vdiwefs]" 151 std::string spec(specs[i]); 152 if (spec.size() == 3 && StartsWith(spec, "*:")) { 153 switch (spec[2]) { 154 case 'v': 155 gMinimumLogSeverity = VERBOSE; 156 continue; 157 case 'd': 158 gMinimumLogSeverity = DEBUG; 159 continue; 160 case 'i': 161 gMinimumLogSeverity = INFO; 162 continue; 163 case 'w': 164 gMinimumLogSeverity = WARNING; 165 continue; 166 case 'e': 167 gMinimumLogSeverity = ERROR; 168 continue; 169 case 'f': 170 gMinimumLogSeverity = FATAL; 171 continue; 172 // liblog will even suppress FATAL if you say 's' for silent, but that's 173 // crazy! 174 case 's': 175 gMinimumLogSeverity = FATAL; 176 continue; 177 } 178 } 179 LOG(FATAL) << "unsupported '" << spec << "' in ANDROID_LOG_TAGS (" << tags 180 << ")"; 181 } 182 } 183 184 void SetLogger(LogFunction&& logger) { 185 std::lock_guard<std::mutex> lock(logging_lock); 186 gLogger = std::move(logger); 187 } 188 189 // This indirection greatly reduces the stack impact of having lots of 190 // checks/logging in a function. 191 class LogMessageData { 192 public: 193 LogMessageData(const char* file, unsigned int line, LogId id, 194 LogSeverity severity, int error) 195 : file_(file), 196 line_number_(line), 197 id_(id), 198 severity_(severity), 199 error_(error) { 200 const char* last_slash = strrchr(file, '/'); 201 file = (last_slash == nullptr) ? file : last_slash + 1; 202 } 203 204 const char* GetFile() const { 205 return file_; 206 } 207 208 unsigned int GetLineNumber() const { 209 return line_number_; 210 } 211 212 LogSeverity GetSeverity() const { 213 return severity_; 214 } 215 216 LogId GetId() const { 217 return id_; 218 } 219 220 int GetError() const { 221 return error_; 222 } 223 224 std::ostream& GetBuffer() { 225 return buffer_; 226 } 227 228 std::string ToString() const { 229 return buffer_.str(); 230 } 231 232 private: 233 std::ostringstream buffer_; 234 const char* const file_; 235 const unsigned int line_number_; 236 const LogId id_; 237 const LogSeverity severity_; 238 const int error_; 239 240 DISALLOW_COPY_AND_ASSIGN(LogMessageData); 241 }; 242 243 LogMessage::LogMessage(const char* file, unsigned int line, LogId id, 244 LogSeverity severity, int error) 245 : data_(new LogMessageData(file, line, id, severity, error)) { 246 } 247 248 LogMessage::~LogMessage() { 249 if (data_->GetSeverity() < gMinimumLogSeverity) { 250 return; // No need to format something we're not going to output. 251 } 252 253 // Finish constructing the message. 254 if (data_->GetError() != -1) { 255 data_->GetBuffer() << ": " << strerror(data_->GetError()); 256 } 257 std::string msg(data_->ToString()); 258 259 if (msg.find('\n') == std::string::npos) { 260 LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(), 261 data_->GetSeverity(), msg.c_str()); 262 } else { 263 msg += '\n'; 264 size_t i = 0; 265 while (i < msg.size()) { 266 size_t nl = msg.find('\n', i); 267 msg[nl] = '\0'; 268 LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(), 269 data_->GetSeverity(), &msg[i]); 270 i = nl + 1; 271 } 272 } 273 274 // Abort if necessary. 275 if (data_->GetSeverity() == FATAL) { 276 #ifdef __ANDROID__ 277 android_set_abort_message(msg.c_str()); 278 #endif 279 abort(); 280 } 281 } 282 283 std::ostream& LogMessage::stream() { 284 return data_->GetBuffer(); 285 } 286 287 void LogMessage::LogLine(const char* file, unsigned int line, LogId id, 288 LogSeverity severity, const char* message) { 289 const char* tag = ProgramInvocationName(); 290 std::lock_guard<std::mutex> lock(logging_lock); 291 gLogger(id, severity, tag, file, line, message); 292 } 293 294 ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) { 295 old_ = gMinimumLogSeverity; 296 gMinimumLogSeverity = level; 297 } 298 299 ScopedLogSeverity::~ScopedLogSeverity() { 300 gMinimumLogSeverity = old_; 301 } 302 303 } // namespace base 304 } // namespace android 305