blob: c2c243f38f0d30bdde3942741031fe9e4edd91c8 [file] [log] [blame]
Scott Graham66962112018-06-08 12:42:08 -07001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/logging.h"
6
7#include <limits.h>
8#include <stdint.h>
9
Scott Grahamce047c92018-06-19 15:56:56 -070010#include <thread>
11
Scott Graham66962112018-06-08 12:42:08 -070012#include "base/macros.h"
Scott Graham76a8dc72018-06-18 13:37:29 -070013#include "util/build_config.h"
Scott Graham66962112018-06-08 12:42:08 -070014
15#if defined(OS_WIN)
16#include <io.h>
17#include <windows.h>
Scott Graham66962112018-06-08 12:42:08 -070018// Windows warns on using write(). It prefers _write().
19#define write(fd, buf, count) _write(fd, buf, static_cast<unsigned int>(count))
20// Windows doesn't define STDERR_FILENO. Define it here.
21#define STDERR_FILENO 2
22
Scott Graham66962112018-06-08 12:42:08 -070023#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
Scott Grahamce047c92018-06-19 15:56:56 -070024#include <sys/time.h>
Scott Graham66962112018-06-08 12:42:08 -070025#include <time.h>
26#endif
27
Scott Graham66962112018-06-08 12:42:08 -070028#if defined(OS_POSIX) || defined(OS_FUCHSIA)
29#include <errno.h>
30#include <paths.h>
31#include <pthread.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <sys/stat.h>
36#include <unistd.h>
Scott Graham66962112018-06-08 12:42:08 -070037#endif
38
39#include <algorithm>
40#include <cstring>
41#include <ctime>
42#include <iomanip>
43#include <ostream>
44#include <string>
45#include <utility>
46
Scott Graham66962112018-06-08 12:42:08 -070047#include "base/callback.h"
Scott Graham66962112018-06-08 12:42:08 -070048#include "base/containers/stack.h"
Scott Graham66962112018-06-08 12:42:08 -070049#include "base/posix/eintr_wrapper.h"
50#include "base/strings/string_piece.h"
51#include "base/strings/string_util.h"
52#include "base/strings/stringprintf.h"
Scott Graham66962112018-06-08 12:42:08 -070053#include "base/strings/utf_string_conversions.h"
Scott Graham66962112018-06-08 12:42:08 -070054
55#if defined(OS_POSIX) || defined(OS_FUCHSIA)
56#include "base/posix/safe_strerror.h"
57#endif
58
59namespace logging {
60
61namespace {
62
Scott Graham66962112018-06-08 12:42:08 -070063const char* const log_severity_names[] = {"INFO", "WARNING", "ERROR", "FATAL"};
64static_assert(LOG_NUM_SEVERITIES == arraysize(log_severity_names),
65 "Incorrect number of log_severity_names");
66
67const char* log_severity_name(int severity) {
68 if (severity >= 0 && severity < LOG_NUM_SEVERITIES)
69 return log_severity_names[severity];
70 return "UNKNOWN";
71}
72
73int g_min_log_level = 0;
74
Scott Graham66962112018-06-08 12:42:08 -070075// For LOG_ERROR and above, always print to stderr.
76const int kAlwaysPrintErrorLevel = LOG_ERROR;
77
Scott Graham66962112018-06-08 12:42:08 -070078} // namespace
79
80#if DCHECK_IS_CONFIGURABLE
81// In DCHECK-enabled Chrome builds, allow the meaning of LOG_DCHECK to be
82// determined at run-time. We default it to INFO, to avoid it triggering
83// crashes before the run-time has explicitly chosen the behaviour.
Scott Graham44598072018-06-14 22:01:37 -070084logging::LogSeverity LOG_DCHECK = LOG_INFO;
Scott Graham66962112018-06-08 12:42:08 -070085#endif // DCHECK_IS_CONFIGURABLE
86
87// This is never instantiated, it's just used for EAT_STREAM_PARAMETERS to have
88// an object of the correct type on the LHS of the unused part of the ternary
89// operator.
90std::ostream* g_swallow_stream;
91
Scott Graham66962112018-06-08 12:42:08 -070092void SetMinLogLevel(int level) {
93 g_min_log_level = std::min(LOG_FATAL, level);
94}
95
96int GetMinLogLevel() {
97 return g_min_log_level;
98}
99
100bool ShouldCreateLogMessage(int severity) {
101 if (severity < g_min_log_level)
102 return false;
103
104 // Return true here unless we know ~LogMessage won't do anything. Note that
105 // ~LogMessage writes to stderr if severity_ >= kAlwaysPrintErrorLevel, even
106 // when g_logging_destination is LOG_NONE.
Scott Graham76a8dc72018-06-18 13:37:29 -0700107 return severity >= kAlwaysPrintErrorLevel;
Scott Graham66962112018-06-08 12:42:08 -0700108}
109
110// Explicit instantiations for commonly used comparisons.
Scott Graham98cd3ca2018-06-14 22:26:55 -0700111template std::string* MakeCheckOpString<int, int>(const int&,
112 const int&,
113 const char* names);
Scott Graham66962112018-06-08 12:42:08 -0700114template std::string* MakeCheckOpString<unsigned long, unsigned long>(
Scott Graham98cd3ca2018-06-14 22:26:55 -0700115 const unsigned long&,
116 const unsigned long&,
117 const char* names);
Scott Graham66962112018-06-08 12:42:08 -0700118template std::string* MakeCheckOpString<unsigned long, unsigned int>(
Scott Graham98cd3ca2018-06-14 22:26:55 -0700119 const unsigned long&,
120 const unsigned int&,
121 const char* names);
Scott Graham66962112018-06-08 12:42:08 -0700122template std::string* MakeCheckOpString<unsigned int, unsigned long>(
Scott Graham98cd3ca2018-06-14 22:26:55 -0700123 const unsigned int&,
124 const unsigned long&,
125 const char* names);
Scott Graham66962112018-06-08 12:42:08 -0700126template std::string* MakeCheckOpString<std::string, std::string>(
Scott Graham98cd3ca2018-06-14 22:26:55 -0700127 const std::string&,
128 const std::string&,
129 const char* name);
Scott Graham66962112018-06-08 12:42:08 -0700130
131void MakeCheckOpValueString(std::ostream* os, std::nullptr_t p) {
132 (*os) << "nullptr";
133}
134
Scott Graham66962112018-06-08 12:42:08 -0700135#if defined(OS_WIN)
Scott Graham98cd3ca2018-06-14 22:26:55 -0700136LogMessage::SaveLastError::SaveLastError() : last_error_(::GetLastError()) {}
Scott Graham66962112018-06-08 12:42:08 -0700137
138LogMessage::SaveLastError::~SaveLastError() {
139 ::SetLastError(last_error_);
140}
141#endif // defined(OS_WIN)
142
143LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
144 : severity_(severity), file_(file), line_(line) {
145 Init(file, line);
146}
147
148LogMessage::LogMessage(const char* file, int line, const char* condition)
149 : severity_(LOG_FATAL), file_(file), line_(line) {
150 Init(file, line);
151 stream_ << "Check failed: " << condition << ". ";
152}
153
154LogMessage::LogMessage(const char* file, int line, std::string* result)
155 : severity_(LOG_FATAL), file_(file), line_(line) {
156 Init(file, line);
157 stream_ << "Check failed: " << *result;
158 delete result;
159}
160
Scott Graham98cd3ca2018-06-14 22:26:55 -0700161LogMessage::LogMessage(const char* file,
162 int line,
163 LogSeverity severity,
Scott Graham66962112018-06-08 12:42:08 -0700164 std::string* result)
165 : severity_(severity), file_(file), line_(line) {
166 Init(file, line);
167 stream_ << "Check failed: " << *result;
168 delete result;
169}
170
171LogMessage::~LogMessage() {
Scott Graham7e8fdb32018-06-14 11:22:06 -0700172 if (severity_ == LOG_FATAL) {
Scott Graham66962112018-06-08 12:42:08 -0700173 stream_ << std::endl; // Newline to separate from log message.
Scott Graham66962112018-06-08 12:42:08 -0700174 }
Scott Graham66962112018-06-08 12:42:08 -0700175 stream_ << std::endl;
176 std::string str_newline(stream_.str());
177
Scott Graham66962112018-06-08 12:42:08 -0700178#if defined(OS_WIN)
Scott Graham76a8dc72018-06-18 13:37:29 -0700179 OutputDebugStringA(str_newline.c_str());
Scott Graham66962112018-06-08 12:42:08 -0700180#endif
Scott Graham76a8dc72018-06-18 13:37:29 -0700181 ignore_result(fwrite(str_newline.data(), str_newline.size(), 1, stderr));
182 fflush(stderr);
Scott Graham66962112018-06-08 12:42:08 -0700183
184 if (severity_ == LOG_FATAL) {
Scott Graham894986a2018-06-14 14:15:50 -0700185 abort();
Scott Graham66962112018-06-08 12:42:08 -0700186 }
187}
188
189// writes the common header info to the stream
190void LogMessage::Init(const char* file, int line) {
191 base::StringPiece filename(file);
192 size_t last_slash_pos = filename.find_last_of("\\/");
193 if (last_slash_pos != base::StringPiece::npos)
194 filename.remove_prefix(last_slash_pos + 1);
195
196 // TODO(darin): It might be nice if the columns were fixed width.
197
Scott Graham98cd3ca2018-06-14 22:26:55 -0700198 stream_ << '[';
Scott Grahamce047c92018-06-19 15:56:56 -0700199 stream_ << std::this_thread::get_id() << ':';
Scott Graham66962112018-06-08 12:42:08 -0700200#if defined(OS_WIN)
Scott Graham76a8dc72018-06-18 13:37:29 -0700201 SYSTEMTIME local_time;
202 GetLocalTime(&local_time);
203 stream_ << std::setfill('0') << std::setw(2) << local_time.wMonth
204 << std::setw(2) << local_time.wDay << '/' << std::setw(2)
205 << local_time.wHour << std::setw(2) << local_time.wMinute
206 << std::setw(2) << local_time.wSecond << '.' << std::setw(3)
207 << local_time.wMilliseconds << ':';
Scott Graham66962112018-06-08 12:42:08 -0700208#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
Scott Graham76a8dc72018-06-18 13:37:29 -0700209 timeval tv;
210 gettimeofday(&tv, nullptr);
211 time_t t = tv.tv_sec;
212 struct tm local_time;
213 localtime_r(&t, &local_time);
214 struct tm* tm_time = &local_time;
215 stream_ << std::setfill('0') << std::setw(2) << 1 + tm_time->tm_mon
216 << std::setw(2) << tm_time->tm_mday << '/' << std::setw(2)
217 << tm_time->tm_hour << std::setw(2) << tm_time->tm_min << std::setw(2)
218 << tm_time->tm_sec << '.' << std::setw(6) << tv.tv_usec << ':';
Scott Graham66962112018-06-08 12:42:08 -0700219#else
220#error Unsupported platform
221#endif
Scott Graham66962112018-06-08 12:42:08 -0700222 if (severity_ >= 0)
223 stream_ << log_severity_name(severity_);
224 else
225 stream_ << "VERBOSE" << -severity_;
226
227 stream_ << ":" << filename << "(" << line << ")] ";
228
229 message_start_ = stream_.str().length();
230}
231
232#if defined(OS_WIN)
233// This has already been defined in the header, but defining it again as DWORD
234// ensures that the type used in the header is equivalent to DWORD. If not,
235// the redefinition is a compile error.
236typedef DWORD SystemErrorCode;
237#endif
238
239SystemErrorCode GetLastSystemErrorCode() {
240#if defined(OS_WIN)
241 return ::GetLastError();
242#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
243 return errno;
244#endif
245}
246
Scott Graham44598072018-06-14 22:01:37 -0700247std::string SystemErrorCodeToString(SystemErrorCode error_code) {
Scott Graham66962112018-06-08 12:42:08 -0700248#if defined(OS_WIN)
249 const int kErrorMessageBufferSize = 256;
250 char msgbuf[kErrorMessageBufferSize];
251 DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
252 DWORD len = FormatMessageA(flags, nullptr, error_code, 0, msgbuf,
253 arraysize(msgbuf), nullptr);
254 if (len) {
255 // Messages returned by system end with line breaks.
256 return base::CollapseWhitespaceASCII(msgbuf, true) +
257 base::StringPrintf(" (0x%lX)", error_code);
258 }
259 return base::StringPrintf("Error (0x%lX) while retrieving error. (0x%lX)",
260 GetLastError(), error_code);
261#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
262 return base::safe_strerror(error_code) +
263 base::StringPrintf(" (%d)", error_code);
264#endif // defined(OS_WIN)
265}
266
Scott Graham66962112018-06-08 12:42:08 -0700267#if defined(OS_WIN)
268Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
269 int line,
270 LogSeverity severity,
271 SystemErrorCode err)
Scott Graham98cd3ca2018-06-14 22:26:55 -0700272 : err_(err), log_message_(file, line, severity) {}
Scott Graham66962112018-06-08 12:42:08 -0700273
274Win32ErrorLogMessage::~Win32ErrorLogMessage() {
275 stream() << ": " << SystemErrorCodeToString(err_);
Scott Graham66962112018-06-08 12:42:08 -0700276}
277#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
278ErrnoLogMessage::ErrnoLogMessage(const char* file,
279 int line,
280 LogSeverity severity,
281 SystemErrorCode err)
Scott Graham98cd3ca2018-06-14 22:26:55 -0700282 : err_(err), log_message_(file, line, severity) {}
Scott Graham66962112018-06-08 12:42:08 -0700283
284ErrnoLogMessage::~ErrnoLogMessage() {
285 stream() << ": " << SystemErrorCodeToString(err_);
Scott Graham66962112018-06-08 12:42:08 -0700286}
287#endif // defined(OS_WIN)
288
Scott Graham66962112018-06-08 12:42:08 -0700289void RawLog(int level, const char* message) {
290 if (level >= g_min_log_level && message) {
291 size_t bytes_written = 0;
292 const size_t message_len = strlen(message);
293 int rv;
294 while (bytes_written < message_len) {
Scott Graham98cd3ca2018-06-14 22:26:55 -0700295 rv = HANDLE_EINTR(write(STDERR_FILENO, message + bytes_written,
296 message_len - bytes_written));
Scott Graham66962112018-06-08 12:42:08 -0700297 if (rv < 0) {
298 // Give up, nothing we can do now.
299 break;
300 }
301 bytes_written += rv;
302 }
303
304 if (message_len > 0 && message[message_len - 1] != '\n') {
305 do {
306 rv = HANDLE_EINTR(write(STDERR_FILENO, "\n", 1));
307 if (rv < 0) {
308 // Give up, nothing we can do now.
309 break;
310 }
311 } while (rv != 1);
312 }
313 }
314
315 if (level == LOG_FATAL)
Scott Graham7e8fdb32018-06-14 11:22:06 -0700316 abort();
Scott Graham66962112018-06-08 12:42:08 -0700317}
318
319// This was defined at the beginning of this file.
320#undef write
321
Scott Graham44598072018-06-14 22:01:37 -0700322void LogErrorNotReached(const char* file, int line) {
Scott Graham98cd3ca2018-06-14 22:26:55 -0700323 LogMessage(file, line, LOG_ERROR).stream() << "NOTREACHED() hit.";
Scott Graham66962112018-06-08 12:42:08 -0700324}
325
326} // namespace logging
327
328std::ostream& std::operator<<(std::ostream& out, const wchar_t* wstr) {
329 return out << (wstr ? base::WideToUTF8(wstr) : std::string());
330}