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