| // Copyright 2014 The Android Open Source Project |
| // |
| // This software is licensed under the terms of the GNU General Public |
| // License version 2, as published by the Free Software Foundation, and |
| // may be copied, distributed, and modified under those terms. |
| // |
| // This program is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| // GNU General Public License for more details. |
| |
| #define __STDC_LIMIT_MACROS |
| #include "android/base/Log.h" |
| |
| #include <limits.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| namespace android { |
| namespace base { |
| |
| namespace { |
| |
| // The current log output. |
| testing::LogOutput* gLogOutput = NULL; |
| |
| bool gDcheckLevel = false; |
| |
| // Convert a severity level into a string. |
| const char* severityLevelToString(LogSeverity severity) { |
| const char* kSeverityStrings[] = { |
| "INFO", "WARNING", "ERROR", "FATAL", |
| }; |
| if (severity >= 0 && severity < LOG_NUM_SEVERITIES) |
| return kSeverityStrings[severity]; |
| return "UNKNOWN"; |
| } |
| |
| // Default log output function |
| void defaultLogMessage(const LogParams& params, |
| const char* message, |
| size_t messageLen) { |
| fprintf(stderr, |
| "%s:%s:%d:%.*s\n", |
| severityLevelToString(params.severity), |
| params.file, |
| params.lineno, |
| int(messageLen), |
| message); |
| // Note: by default, stderr is non buffered, but the program might |
| // have altered this setting, so always flush explicitly to ensure |
| // that the log is displayed as soon as possible. This avoids log |
| // messages being lost when a crash happens, and makes debugging |
| // easier. On the other hand, it means lots of logging will impact |
| // performance. |
| fflush(stderr); |
| |
| if (params.severity >= LOG_FATAL) |
| exit(1); |
| } |
| |
| void logMessage(const LogParams& params, |
| const char* message, |
| size_t messageLen) { |
| if (gLogOutput) { |
| gLogOutput->logMessage(params, message, messageLen); |
| } else { |
| defaultLogMessage(params, message, messageLen); |
| } |
| } |
| |
| } // namespace |
| |
| // DCHECK level. |
| |
| bool dcheckIsEnabled() { |
| return gDcheckLevel; |
| } |
| |
| bool setDcheckLevel(bool enabled) { |
| bool ret = gDcheckLevel; |
| gDcheckLevel = enabled; |
| return ret; |
| } |
| |
| // LogSeverity |
| |
| LogSeverity getMinLogLevel() { |
| return 0; |
| } |
| |
| // LogString |
| |
| LogString::LogString(const char* fmt, ...) : mString(NULL) { |
| size_t capacity = 100; |
| char* message = reinterpret_cast<char*>(::malloc(capacity)); |
| for (;;) { |
| va_list args; |
| va_start(args, fmt); |
| int ret = vsnprintf(message, capacity, fmt, args); |
| va_end(args); |
| if (ret >= 0 && size_t(ret) < capacity) |
| break; |
| capacity *= 2; |
| } |
| mString = message; |
| } |
| |
| LogString::~LogString() { |
| ::free(mString); |
| } |
| |
| // LogStream |
| |
| LogStream::LogStream(const char* file, int lineno, LogSeverity severity) : |
| mParams(file, lineno, severity), |
| mString(NULL), |
| mSize(0), |
| mCapacity(0) {} |
| |
| LogStream::~LogStream() { |
| mSize = 0; |
| mCapacity = 0; |
| ::free(mString); |
| } |
| |
| LogStream& LogStream::operator<<(char ch) { |
| if (ch >= 32 && ch < 127) { |
| append(&ch, 1U); |
| } else { |
| char temp[5]; |
| snprintf(temp, sizeof temp, "\\x%02x", ch); |
| append(temp, 4U); |
| } |
| return *this; |
| } |
| |
| LogStream& LogStream::operator<<(const void* ptr) { |
| char temp[20]; |
| int ret = snprintf(temp, sizeof temp, "%p", ptr); |
| append(temp, static_cast<size_t>(ret)); |
| return *this; |
| } |
| |
| LogStream& LogStream::operator<<(int v) { |
| char temp[20]; |
| int ret = snprintf(temp, sizeof temp, "%d", v); |
| append(temp, static_cast<size_t>(ret)); |
| return *this; |
| } |
| |
| LogStream& LogStream::operator<<(unsigned v) { |
| char temp[20]; |
| int ret = snprintf(temp, sizeof temp, "%u", v); |
| append(temp, static_cast<size_t>(ret)); |
| return *this; |
| } |
| |
| LogStream& LogStream::operator<<(long v) { |
| char temp[20]; |
| int ret = snprintf(temp, sizeof temp, "%ld", v); |
| append(temp, static_cast<size_t>(ret)); |
| return *this; |
| } |
| |
| LogStream& LogStream::operator<<(unsigned long v) { |
| char temp[20]; |
| int ret = snprintf(temp, sizeof temp, "%lu", v); |
| append(temp, static_cast<size_t>(ret)); |
| return *this; |
| } |
| |
| LogStream& LogStream::operator<<(long long v) { |
| char temp[20]; |
| int ret = snprintf(temp, sizeof temp, "%lld", v); |
| append(temp, static_cast<size_t>(ret)); |
| return *this; |
| } |
| |
| LogStream& LogStream::operator<<(unsigned long long v) { |
| char temp[20]; |
| int ret = snprintf(temp, sizeof temp, "%llu", v); |
| append(temp, static_cast<size_t>(ret)); |
| return *this; |
| } |
| |
| void LogStream::append(const char* str) { |
| if (str && str[0]) |
| append(str, strlen(str)); |
| } |
| |
| void LogStream::append(const char* str, size_t len) { |
| if (!len || len > INT32_MAX) |
| return; |
| |
| size_t newSize = mSize + len; |
| if (newSize > mCapacity) { |
| size_t newCapacity = mCapacity; |
| while (newCapacity < newSize) |
| newCapacity += (newCapacity >> 2) + 32; |
| mString = reinterpret_cast<char*>( |
| ::realloc(mString, newCapacity + 1)); |
| mCapacity = newCapacity; |
| } |
| ::memcpy(mString + mSize, str, len); |
| mSize += len; |
| mString[mSize] = '\0'; |
| } |
| |
| // LogMessage |
| |
| LogMessage::LogMessage(const char* file, int line, LogSeverity severity) : |
| mStream(new LogStream(file, line, severity)) {} |
| |
| LogMessage::~LogMessage() { |
| logMessage(mStream->params(), |
| mStream->string(), |
| mStream->size()); |
| delete mStream; |
| } |
| |
| // ErrnoLogMessage |
| |
| ErrnoLogMessage::ErrnoLogMessage(const char* file, |
| int line, |
| LogSeverity severity, |
| int errnoCode) : |
| mStream(NULL), mErrno(errnoCode) { |
| mStream = new LogStream(file, line, severity); |
| } |
| |
| ErrnoLogMessage::~ErrnoLogMessage() { |
| (*mStream) << "Error message: " << strerror(mErrno); |
| logMessage(mStream->params(), |
| mStream->string(), |
| mStream->size()); |
| delete mStream; |
| // Restore the errno. |
| errno = mErrno; |
| } |
| |
| // LogOutput |
| |
| namespace testing { |
| |
| // static |
| LogOutput* LogOutput::setNewOutput(LogOutput* newOutput) { |
| LogOutput* ret = gLogOutput; |
| gLogOutput = newOutput; |
| return ret; |
| } |
| |
| } // namespace testing |
| |
| } // naemspace base |
| } // namespace android |