1// Copyright 2014 The Android Open Source Project 2// 3// This software is licensed under the terms of the GNU General Public 4// License version 2, as published by the Free Software Foundation, and 5// may be copied, distributed, and modified under those terms. 6// 7// This program is distributed in the hope that it will be useful, 8// but WITHOUT ANY WARRANTY; without even the implied warranty of 9// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10// GNU General Public License for more details. 11 12#define __STDC_LIMIT_MACROS 13#include "android/base/Log.h" 14 15#include <limits.h> 16#include <stdint.h> 17#include <stdio.h> 18#include <stdlib.h> 19#include <string.h> 20 21namespace android { 22namespace base { 23 24namespace { 25 26// The current log output. 27testing::LogOutput* gLogOutput = NULL; 28 29bool gDcheckLevel = false; 30 31// Convert a severity level into a string. 32const char* severityLevelToString(LogSeverity severity) { 33 const char* kSeverityStrings[] = { 34 "INFO", "WARNING", "ERROR", "FATAL", 35 }; 36 if (severity >= 0 && severity < LOG_NUM_SEVERITIES) 37 return kSeverityStrings[severity]; 38 return "UNKNOWN"; 39} 40 41// Default log output function 42void defaultLogMessage(const LogParams& params, 43 const char* message, 44 size_t messageLen) { 45 fprintf(stderr, 46 "%s:%s:%d:%.*s\n", 47 severityLevelToString(params.severity), 48 params.file, 49 params.lineno, 50 int(messageLen), 51 message); 52 // Note: by default, stderr is non buffered, but the program might 53 // have altered this setting, so always flush explicitly to ensure 54 // that the log is displayed as soon as possible. This avoids log 55 // messages being lost when a crash happens, and makes debugging 56 // easier. On the other hand, it means lots of logging will impact 57 // performance. 58 fflush(stderr); 59 60 if (params.severity >= LOG_FATAL) 61 exit(1); 62} 63 64void logMessage(const LogParams& params, 65 const char* message, 66 size_t messageLen) { 67 if (gLogOutput) { 68 gLogOutput->logMessage(params, message, messageLen); 69 } else { 70 defaultLogMessage(params, message, messageLen); 71 } 72} 73 74} // namespace 75 76// DCHECK level. 77 78bool dcheckIsEnabled() { 79 return gDcheckLevel; 80} 81 82bool setDcheckLevel(bool enabled) { 83 bool ret = gDcheckLevel; 84 gDcheckLevel = enabled; 85 return ret; 86} 87 88// LogSeverity 89 90LogSeverity getMinLogLevel() { 91 return 0; 92} 93 94// LogString 95 96LogString::LogString(const char* fmt, ...) : mString(NULL) { 97 size_t capacity = 100; 98 char* message = reinterpret_cast<char*>(::malloc(capacity)); 99 for (;;) { 100 va_list args; 101 va_start(args, fmt); 102 int ret = vsnprintf(message, capacity, fmt, args); 103 va_end(args); 104 if (ret >= 0 && size_t(ret) < capacity) 105 break; 106 capacity *= 2; 107 } 108 mString = message; 109} 110 111LogString::~LogString() { 112 ::free(mString); 113} 114 115// LogStream 116 117LogStream::LogStream(const char* file, int lineno, LogSeverity severity) : 118 mParams(file, lineno, severity), 119 mString(NULL), 120 mSize(0), 121 mCapacity(0) {} 122 123LogStream::~LogStream() { 124 mSize = 0; 125 mCapacity = 0; 126 ::free(mString); 127} 128 129LogStream& LogStream::operator<<(char ch) { 130 if (ch >= 32 && ch < 127) { 131 append(&ch, 1U); 132 } else { 133 char temp[5]; 134 snprintf(temp, sizeof temp, "\\x%02x", ch); 135 append(temp, 4U); 136 } 137 return *this; 138} 139 140LogStream& LogStream::operator<<(const void* ptr) { 141 char temp[20]; 142 int ret = snprintf(temp, sizeof temp, "%p", ptr); 143 append(temp, static_cast<size_t>(ret)); 144 return *this; 145} 146 147LogStream& LogStream::operator<<(int v) { 148 char temp[20]; 149 int ret = snprintf(temp, sizeof temp, "%d", v); 150 append(temp, static_cast<size_t>(ret)); 151 return *this; 152} 153 154LogStream& LogStream::operator<<(unsigned v) { 155 char temp[20]; 156 int ret = snprintf(temp, sizeof temp, "%u", v); 157 append(temp, static_cast<size_t>(ret)); 158 return *this; 159} 160 161LogStream& LogStream::operator<<(long v) { 162 char temp[20]; 163 int ret = snprintf(temp, sizeof temp, "%ld", v); 164 append(temp, static_cast<size_t>(ret)); 165 return *this; 166} 167 168LogStream& LogStream::operator<<(unsigned long v) { 169 char temp[20]; 170 int ret = snprintf(temp, sizeof temp, "%lu", v); 171 append(temp, static_cast<size_t>(ret)); 172 return *this; 173} 174 175LogStream& LogStream::operator<<(long long v) { 176 char temp[20]; 177 int ret = snprintf(temp, sizeof temp, "%lld", v); 178 append(temp, static_cast<size_t>(ret)); 179 return *this; 180} 181 182LogStream& LogStream::operator<<(unsigned long long v) { 183 char temp[20]; 184 int ret = snprintf(temp, sizeof temp, "%llu", v); 185 append(temp, static_cast<size_t>(ret)); 186 return *this; 187} 188 189void LogStream::append(const char* str) { 190 if (str && str[0]) 191 append(str, strlen(str)); 192} 193 194void LogStream::append(const char* str, size_t len) { 195 if (!len || len > INT32_MAX) 196 return; 197 198 size_t newSize = mSize + len; 199 if (newSize > mCapacity) { 200 size_t newCapacity = mCapacity; 201 while (newCapacity < newSize) 202 newCapacity += (newCapacity >> 2) + 32; 203 mString = reinterpret_cast<char*>( 204 ::realloc(mString, newCapacity + 1)); 205 mCapacity = newCapacity; 206 } 207 ::memcpy(mString + mSize, str, len); 208 mSize += len; 209 mString[mSize] = '\0'; 210} 211 212// LogMessage 213 214LogMessage::LogMessage(const char* file, int line, LogSeverity severity) : 215 mStream(new LogStream(file, line, severity)) {} 216 217LogMessage::~LogMessage() { 218 logMessage(mStream->params(), 219 mStream->string(), 220 mStream->size()); 221 delete mStream; 222} 223 224// ErrnoLogMessage 225 226ErrnoLogMessage::ErrnoLogMessage(const char* file, 227 int line, 228 LogSeverity severity, 229 int errnoCode) : 230 mStream(NULL), mErrno(errnoCode) { 231 mStream = new LogStream(file, line, severity); 232} 233 234ErrnoLogMessage::~ErrnoLogMessage() { 235 (*mStream) << "Error message: " << strerror(mErrno); 236 logMessage(mStream->params(), 237 mStream->string(), 238 mStream->size()); 239 delete mStream; 240 // Restore the errno. 241 errno = mErrno; 242} 243 244// LogOutput 245 246namespace testing { 247 248// static 249LogOutput* LogOutput::setNewOutput(LogOutput* newOutput) { 250 LogOutput* ret = gLogOutput; 251 gLogOutput = newOutput; 252 return ret; 253} 254 255} // namespace testing 256 257} // naemspace base 258} // namespace android