| // Copyright 2006-2008 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/logging.h" |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| |
| #include <iomanip> |
| |
| #if defined(OS_POSIX) |
| #include <paths.h> |
| #include <sys/stat.h> |
| #include <sys/time.h> |
| #include <unistd.h> |
| #include "base/posix/safe_strerror.h" |
| #endif // OS_POSIX |
| |
| #if defined(OS_MACOSX) |
| // In macOS 10.12 and iOS 10.0 and later ASL (Apple System Log) was deprecated |
| // in favor of OS_LOG (Unified Logging). |
| #include <AvailabilityMacros.h> |
| #if defined(OS_IOS) |
| #if !defined(__IPHONE_10_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_10_0 |
| #define USE_ASL |
| #endif |
| #else // !defined(OS_IOS) |
| #if !defined(MAC_OS_X_VERSION_10_12) || \ |
| MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_12 |
| #define USE_ASL |
| #endif |
| #endif // defined(OS_IOS) |
| |
| #if defined(USE_ASL) |
| #include <asl.h> |
| #else |
| #include <os/log.h> |
| #endif // USE_ASL |
| |
| #include <CoreFoundation/CoreFoundation.h> |
| #include <pthread.h> |
| |
| #elif defined(OS_LINUX) |
| #include <sys/syscall.h> |
| #include <sys/types.h> |
| #elif defined(OS_WIN) |
| #include <intrin.h> |
| #include <windows.h> |
| #elif defined(OS_FUCHSIA) |
| #include <zircon/process.h> |
| #include <zircon/syscalls.h> |
| #endif |
| |
| #include "base/stl_util.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| |
| namespace logging { |
| |
| namespace { |
| |
| const char* const log_severity_names[] = { |
| "INFO", |
| "WARNING", |
| "ERROR", |
| "ERROR_REPORT", |
| "FATAL" |
| }; |
| |
| LogMessageHandlerFunction g_log_message_handler = nullptr; |
| |
| } // namespace |
| |
| void SetLogMessageHandler(LogMessageHandlerFunction log_message_handler) { |
| g_log_message_handler = log_message_handler; |
| } |
| |
| LogMessageHandlerFunction GetLogMessageHandler() { |
| return g_log_message_handler; |
| } |
| |
| #if defined(OS_WIN) |
| std::string SystemErrorCodeToString(unsigned long error_code) { |
| wchar_t msgbuf[256]; |
| DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | |
| FORMAT_MESSAGE_MAX_WIDTH_MASK; |
| DWORD len = FormatMessage(flags, |
| nullptr, |
| error_code, |
| 0, |
| msgbuf, |
| static_cast<DWORD>(base::size(msgbuf)), |
| nullptr); |
| if (len) { |
| // Most system messages end in a period and a space. Remove the space if |
| // it’s there, because the following StringPrintf() includes one. |
| if (len >= 1 && msgbuf[len - 1] == ' ') { |
| msgbuf[len - 1] = '\0'; |
| } |
| return base::StringPrintf("%s (%u)", |
| base::UTF16ToUTF8(msgbuf).c_str(), error_code); |
| } |
| return base::StringPrintf("Error %u while retrieving error %u", |
| GetLastError(), |
| error_code); |
| } |
| #endif // OS_WIN |
| |
| #if defined(OS_FUCHSIA) |
| zx_koid_t GetKoidForHandle(zx_handle_t handle) { |
| // Get the 64-bit koid (unique kernel object ID) of the given handle. |
| zx_koid_t koid = 0; |
| zx_info_handle_basic_t info; |
| if (zx_object_get_info(handle, |
| ZX_INFO_HANDLE_BASIC, |
| &info, |
| sizeof(info), |
| nullptr, |
| nullptr) == ZX_OK) { |
| // If this fails, there's not much that can be done. As this is used only |
| // for logging, leave it as 0, which is not a valid koid. |
| koid = info.koid; |
| } |
| return koid; |
| } |
| #endif // OS_FUCHSIA |
| |
| LogMessage::LogMessage(const char* function, |
| const char* file_path, |
| int line, |
| LogSeverity severity) |
| : stream_(), |
| file_path_(file_path), |
| message_start_(0), |
| line_(line), |
| severity_(severity) { |
| Init(function); |
| } |
| |
| LogMessage::LogMessage(const char* function, |
| const char* file_path, |
| int line, |
| std::string* result) |
| : stream_(), |
| file_path_(file_path), |
| message_start_(0), |
| line_(line), |
| severity_(LOG_FATAL) { |
| Init(function); |
| stream_ << "Check failed: " << *result << ". "; |
| delete result; |
| } |
| |
| LogMessage::~LogMessage() { |
| stream_ << std::endl; |
| std::string str_newline(stream_.str()); |
| |
| if (g_log_message_handler && |
| g_log_message_handler( |
| severity_, file_path_, line_, message_start_, str_newline)) { |
| return; |
| } |
| |
| fprintf(stderr, "%s", str_newline.c_str()); |
| fflush(stderr); |
| |
| #if defined(OS_MACOSX) |
| const bool log_to_system = []() { |
| struct stat stderr_stat; |
| if (fstat(fileno(stderr), &stderr_stat) == -1) { |
| return true; |
| } |
| if (!S_ISCHR(stderr_stat.st_mode)) { |
| return false; |
| } |
| |
| struct stat dev_null_stat; |
| if (stat(_PATH_DEVNULL, &dev_null_stat) == -1) { |
| return true; |
| } |
| |
| return !S_ISCHR(dev_null_stat.st_mode) || |
| stderr_stat.st_rdev == dev_null_stat.st_rdev; |
| }(); |
| |
| if (log_to_system) { |
| CFBundleRef main_bundle = CFBundleGetMainBundle(); |
| CFStringRef main_bundle_id_cf = |
| main_bundle ? CFBundleGetIdentifier(main_bundle) : nullptr; |
| |
| std::string main_bundle_id_buf; |
| const char* main_bundle_id = nullptr; |
| |
| if (main_bundle_id_cf) { |
| main_bundle_id = |
| CFStringGetCStringPtr(main_bundle_id_cf, kCFStringEncodingUTF8); |
| if (!main_bundle_id) { |
| // 1024 is from 10.10.5 CF-1153.18/CFBundle.c __CFBundleMainID__ (at |
| // the point of use, not declaration). |
| main_bundle_id_buf.resize(1024); |
| if (!CFStringGetCString(main_bundle_id_cf, |
| &main_bundle_id_buf[0], |
| main_bundle_id_buf.size(), |
| kCFStringEncodingUTF8)) { |
| main_bundle_id_buf.clear(); |
| } else { |
| main_bundle_id = &main_bundle_id_buf[0]; |
| } |
| } |
| } |
| |
| #if defined(USE_ASL) |
| // Use ASL when this might run on pre-10.12 systems. Unified Logging |
| // (os_log) was introduced in 10.12. |
| |
| const class ASLClient { |
| public: |
| explicit ASLClient(const char* asl_facility) |
| : client_(asl_open(nullptr, asl_facility, ASL_OPT_NO_DELAY)) {} |
| ~ASLClient() { asl_close(client_); } |
| |
| aslclient get() const { return client_; } |
| |
| private: |
| aslclient client_; |
| DISALLOW_COPY_AND_ASSIGN(ASLClient); |
| } asl_client(main_bundle_id ? main_bundle_id : "com.apple.console"); |
| |
| const class ASLMessage { |
| public: |
| ASLMessage() : message_(asl_new(ASL_TYPE_MSG)) {} |
| ~ASLMessage() { asl_free(message_); } |
| |
| aslmsg get() const { return message_; } |
| |
| private: |
| aslmsg message_; |
| DISALLOW_COPY_AND_ASSIGN(ASLMessage); |
| } asl_message; |
| |
| // By default, messages are only readable by the admin group. Explicitly |
| // make them readable by the user generating the messages. |
| char euid_string[12]; |
| snprintf(euid_string, base::size(euid_string), "%d", geteuid()); |
| asl_set(asl_message.get(), ASL_KEY_READ_UID, euid_string); |
| |
| // Map Chrome log severities to ASL log levels. |
| const char* const asl_level_string = [](LogSeverity severity) { |
| #define ASL_LEVEL_STR(level) ASL_LEVEL_STR_X(level) |
| #define ASL_LEVEL_STR_X(level) #level |
| switch (severity) { |
| case LOG_INFO: |
| return ASL_LEVEL_STR(ASL_LEVEL_INFO); |
| case LOG_WARNING: |
| return ASL_LEVEL_STR(ASL_LEVEL_WARNING); |
| case LOG_ERROR: |
| return ASL_LEVEL_STR(ASL_LEVEL_ERR); |
| case LOG_FATAL: |
| return ASL_LEVEL_STR(ASL_LEVEL_CRIT); |
| default: |
| return severity < 0 ? ASL_LEVEL_STR(ASL_LEVEL_DEBUG) |
| : ASL_LEVEL_STR(ASL_LEVEL_NOTICE); |
| } |
| #undef ASL_LEVEL_STR |
| #undef ASL_LEVEL_STR_X |
| }(severity_); |
| asl_set(asl_message.get(), ASL_KEY_LEVEL, asl_level_string); |
| |
| asl_set(asl_message.get(), ASL_KEY_MSG, str_newline.c_str()); |
| |
| asl_send(asl_client.get(), asl_message.get()); |
| #else |
| // Use Unified Logging (os_log) when this will only run on 10.12 and later. |
| // ASL is deprecated in 10.12. |
| |
| const class OSLog { |
| public: |
| explicit OSLog(const char* subsystem) |
| : os_log_(subsystem ? os_log_create(subsystem, "chromium_logging") |
| : OS_LOG_DEFAULT) {} |
| ~OSLog() { |
| if (os_log_ != OS_LOG_DEFAULT) { |
| os_release(os_log_); |
| } |
| } |
| |
| os_log_t get() const { return os_log_; } |
| |
| private: |
| os_log_t os_log_; |
| DISALLOW_COPY_AND_ASSIGN(OSLog); |
| } log(main_bundle_id); |
| |
| const os_log_type_t os_log_type = [](LogSeverity severity) { |
| switch (severity) { |
| case LOG_INFO: |
| return OS_LOG_TYPE_INFO; |
| case LOG_WARNING: |
| return OS_LOG_TYPE_DEFAULT; |
| case LOG_ERROR: |
| return OS_LOG_TYPE_ERROR; |
| case LOG_FATAL: |
| return OS_LOG_TYPE_FAULT; |
| default: |
| return severity < 0 ? OS_LOG_TYPE_DEBUG : OS_LOG_TYPE_DEFAULT; |
| } |
| }(severity_); |
| |
| os_log_with_type(log.get(), os_log_type, "%{public}s", str_newline.c_str()); |
| #endif |
| } |
| #elif defined(OS_WIN) |
| OutputDebugString(base::UTF8ToUTF16(str_newline).c_str()); |
| #endif // OS_MACOSX |
| |
| if (severity_ == LOG_FATAL) { |
| #if defined(COMPILER_MSVC) |
| __debugbreak(); |
| #if defined(ARCH_CPU_X86_FAMILY) |
| __ud2(); |
| #elif defined(ARCH_CPU_ARM64) |
| __hlt(0); |
| #else |
| #error Unsupported Windows Arch |
| #endif |
| #elif defined(ARCH_CPU_X86_FAMILY) |
| asm("int3; ud2;"); |
| #elif defined(ARCH_CPU_ARMEL) |
| asm("bkpt #0; udf #0;"); |
| #elif defined(ARCH_CPU_ARM64) |
| asm("brk #0; hlt #0;"); |
| #else |
| __builtin_trap(); |
| #endif |
| } |
| } |
| |
| void LogMessage::Init(const char* function) { |
| std::string file_name(file_path_); |
| #if defined(OS_WIN) |
| size_t last_slash = file_name.find_last_of("\\/"); |
| #else |
| size_t last_slash = file_name.find_last_of('/'); |
| #endif |
| if (last_slash != std::string::npos) { |
| file_name.assign(file_name.substr(last_slash + 1)); |
| } |
| |
| #if defined(OS_FUCHSIA) |
| zx_koid_t pid = GetKoidForHandle(zx_process_self()); |
| #elif defined(OS_POSIX) |
| pid_t pid = getpid(); |
| #elif defined(OS_WIN) |
| DWORD pid = GetCurrentProcessId(); |
| #endif |
| |
| #if defined(OS_MACOSX) |
| uint64_t thread; |
| pthread_threadid_np(pthread_self(), &thread); |
| #elif defined(OS_ANDROID) |
| pid_t thread = gettid(); |
| #elif defined(OS_LINUX) |
| pid_t thread = syscall(__NR_gettid); |
| #elif defined(OS_WIN) |
| DWORD thread = GetCurrentThreadId(); |
| #elif defined(OS_FUCHSIA) |
| zx_koid_t thread = GetKoidForHandle(zx_thread_self()); |
| #endif |
| |
| stream_ << '[' |
| << pid |
| << ':' |
| << thread |
| << ':' |
| << std::setfill('0'); |
| |
| #if defined(OS_POSIX) |
| timeval tv; |
| gettimeofday(&tv, nullptr); |
| tm local_time; |
| localtime_r(&tv.tv_sec, &local_time); |
| stream_ << std::setw(4) << local_time.tm_year + 1900 |
| << std::setw(2) << local_time.tm_mon + 1 |
| << std::setw(2) << local_time.tm_mday |
| << ',' |
| << std::setw(2) << local_time.tm_hour |
| << std::setw(2) << local_time.tm_min |
| << std::setw(2) << local_time.tm_sec |
| << '.' |
| << std::setw(6) << tv.tv_usec; |
| #elif defined(OS_WIN) |
| SYSTEMTIME local_time; |
| GetLocalTime(&local_time); |
| stream_ << std::setw(4) << local_time.wYear |
| << std::setw(2) << local_time.wMonth |
| << std::setw(2) << local_time.wDay |
| << ',' |
| << std::setw(2) << local_time.wHour |
| << std::setw(2) << local_time.wMinute |
| << std::setw(2) << local_time.wSecond |
| << '.' |
| << std::setw(3) << local_time.wMilliseconds; |
| #endif |
| |
| stream_ << ':'; |
| |
| if (severity_ >= 0) { |
| stream_ << log_severity_names[severity_]; |
| } else { |
| stream_ << "VERBOSE" << -severity_; |
| } |
| |
| stream_ << ' ' |
| << file_name |
| << ':' |
| << line_ |
| << "] "; |
| |
| message_start_ = stream_.str().size(); |
| } |
| |
| #if defined(OS_WIN) |
| |
| unsigned long GetLastSystemErrorCode() { |
| return GetLastError(); |
| } |
| |
| Win32ErrorLogMessage::Win32ErrorLogMessage(const char* function, |
| const char* file_path, |
| int line, |
| LogSeverity severity, |
| unsigned long err) |
| : LogMessage(function, file_path, line, severity), err_(err) { |
| } |
| |
| Win32ErrorLogMessage::~Win32ErrorLogMessage() { |
| stream() << ": " << SystemErrorCodeToString(err_); |
| } |
| |
| #elif defined(OS_POSIX) |
| |
| ErrnoLogMessage::ErrnoLogMessage(const char* function, |
| const char* file_path, |
| int line, |
| LogSeverity severity, |
| int err) |
| : LogMessage(function, file_path, line, severity), |
| err_(err) { |
| } |
| |
| ErrnoLogMessage::~ErrnoLogMessage() { |
| stream() << ": " |
| << base::safe_strerror(err_) |
| << " (" |
| << err_ |
| << ")"; |
| } |
| |
| #endif // OS_POSIX |
| |
| } // namespace logging |