blob: a5be52c69a4296586468c20ed5eefe820c7739a0 [file] [log] [blame]
// 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