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