Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3110)

Unified Diff: base/logging.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/logging.h ('k') | base/logging/build.scons » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/logging.cc
diff --git a/base/logging.cc b/base/logging.cc
deleted file mode 100644
index 928551094087668f78e3143e2bf1a8f058c7872a..0000000000000000000000000000000000000000
--- a/base/logging.cc
+++ /dev/null
@@ -1,1369 +0,0 @@
-// Copyright 2003-2009 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-// ========================================================================
-//
-// Tracing and logging system.
-//
-// The log output goes to "All Users/Application Data/Google/Update/Log/".
-// The log configuration file is under
-// "%Program Files%/C:\Program Files\Google\Common\Update".
-// By default, the logging is on in debug modes and off in opt mode although in
-// opt mode only the OPT_LOG statements write to the log.
-//
-// The log is open to all the users to write to. There is a known vulnerability
-// where a DOS can be created by holding on to the logging mutex.
-//
-// In this module use of ASSERT & REPORT is banned. This is to prevent any
-// possible recursion issues between logging (logging.h) and
-// asserting/reporting (debug.h). Both are basement-level systems that need to
-// work when almost nothing else works and interdependencies are best avoided.
-// One unavoidable interdependency is that debugASSERT will send messages to
-// the logger via Logger::OutputMessage - which then broadcasts it to each
-// LogWriter's OutputMessage. So these methods should be as simple as
-// possible. (Also, unlike asserting/reporting - this module will not avoid
-// use of the heap, however the code executed from Logger::OutputMessage
-// doesn't use the heap (for all the LogWriters in this file).)
-//
-// TODO(omaha): implement the minidump handling in terms of breakpad.
-// Log initialization if full of lazy init. Consider doing
-// eager init of log and its registered log writers when the
-// log is created and initialized.
-// Reimplement in terms of smart handles and locks.
-// Reimplement without dependency on any other compilation unit
-// that can call assert, verify, or the log itself.
-// Redo the history logging feature
-
-#include "omaha/base/logging.h"
-
-#include <excpt.h> // Microsoft specific: structured exceptions.
-#include <shlobj.h>
-#include <shlwapi.h>
-#include <string.h>
-#include <atlpath.h>
-#include <atlsecurity.h>
-#include "base/basictypes.h"
-#include "omaha/base/app_util.h"
-#include "omaha/base/const_debug.h"
-#include "omaha/base/constants.h"
-#include "omaha/base/debug.h"
-#include "omaha/base/etw_log_writer.h"
-#include "omaha/base/file.h"
-#include "omaha/base/path.h"
-#include "omaha/base/string.h"
-#include "omaha/base/time.h"
-#include "omaha/base/utils.h"
-
-namespace omaha {
-
-// enforce ban on ASSERT/REPORT
-#undef ASSERT
-#undef REPORT
-
-#ifdef LOGGING
-
-#define kNumLockRetries (20)
-#define kLockRetryDelayMs (50)
-
-// Circular buffer to log history.
-static wchar_t history_buffer[kMaxHistoryBufferSize];
-
-// Index into the history buffer to begin writing at.
-static int history_buffer_next_idx = 0;
-
-// Indicates whether the history buffer has ever reached its full capacity.
-// Once this boolean is true, if never becomes false.
-static bool history_buffer_full = false;
-
-//
-// Table of category names to categories.
-//
-#define LC_ENTRY(lc_value) (L#lc_value), (lc_value)
-struct {
- wchar_t* category_name;
- LogCategory category;
-} static LogCategoryNames[] = {
- LC_ENTRY(LC_UTIL),
- LC_ENTRY(LC_SETUP),
- LC_ENTRY(LC_SHELL),
- LC_ENTRY(LC_CORE),
- LC_ENTRY(LC_JS),
- LC_ENTRY(LC_PLUGIN),
- LC_ENTRY(LC_SERVICE),
- LC_ENTRY(LC_OPT),
- LC_ENTRY(LC_NET),
- LC_ENTRY(LC_REPORT),
-};
-
-COMPILE_ASSERT(arraysize(LogCategoryNames) == LC_MAX_CAT - 1,
- LogCategoryNames_missing_category);
-
-static CString StripBackslashes(const CString& name) {
- int n = String_FindChar(name, L'\\');
- if (n == -1) {
- return name;
- } else {
- CString result;
- for (int i = 0; i < name.GetLength(); ++i) {
- if (name[i] != L'\\') {
- result += name[i];
- }
- }
- return result;
- }
-}
-
-static CString GetProcName() {
- CString proc_name(app_util::GetAppNameWithoutExtension());
- CString module_name(app_util::GetCurrentModuleNameWithoutExtension());
- CString result(proc_name);
- if (module_name.CompareNoCase(proc_name) != 0) {
- result += L":";
- result += module_name;
- }
- return result;
-}
-
-// Formats a line prefix with the current time min:sec:milisec if wanted,
-// otherwise just the process:module.
-static void FormatLinePrefix(bool show_time,
- const wchar_t* proc_name,
- CString& result) {
- if (show_time) {
- SYSTEMTIME system_time = {0};
- GetLocalTime(&system_time);
- result.Format(L"[%02d/%02d/%02d %02d:%02d:%02d.%03d]",
- system_time.wMonth, system_time.wDay, system_time.wYear % 100,
- system_time.wHour, system_time.wMinute, system_time.wSecond,
- system_time.wMilliseconds);
- }
- result.AppendFormat(L"[%s][%u:%u]",
- proc_name,
- ::GetCurrentProcessId(),
- ::GetCurrentThreadId());
-}
-
-static bool g_logging_valid = false;
-static Logging g_logging;
-
-// Singleton factory for the Logging object.
-Logging* GetLogging() {
- return g_logging_valid ? &g_logging : NULL;
-}
-
-// Force the logging system to be initialized during elaboration of static
-// constructors, while the program is still single-threaded. This global
-// static object will cause the static logger inside of GetLogging() to be
-// constructed. However, it might not be the first call to GetLogging() -
-// another static object in another object file might get constructed first,
-// and in its constructor call a logging API. Just as long as it is done when
-// the system is single threaded. (Reason: because the Logger object has a
-// LLock object which has a Win32 critical section which needs to be
-// initialized - only once!)
-
-
-Logging::Logging()
- : logging_initialized_(false),
- logging_enabled_(true),
- force_show_time_(false),
- show_time_(true),
- log_to_file_(true),
- log_to_debug_out_(true),
- append_to_file_(true),
- logging_shutdown_(false),
- num_writers_(0),
- file_log_writer_(NULL),
- debug_out_writer_(NULL),
- etw_log_writer_(NULL),
- is_initializing_(false),
- log_file_name_(kDefaultLogFileName),
- config_file_path_(GetConfigurationFilePath()) {
- g_last_category_check_time = 0;
- for (int i = 0; i < max_writers; ++i) {
- writers_[i] = NULL;
- }
- proc_name_ = GetProcName();
- g_logging_valid = true;
-
- // Read initial settings from the config file.
- ReadLoggingSettings();
-}
-
-// TODO(omaha): why aren't we using a mutexscope and what if an the code
-// throws? Will the lock be unlocked?
-Logging::~Logging() {
- // Acquire the lock outside the try/except block so we'll always release it
- lock_.Lock();
-
- __try {
- // prevent further access to the system
- // necessary because the static destructors happen
- // in a non-deterministic order
- logging_shutdown_ = true;
-
- // Delete all registered LogWriters
- for (int i = 0; i < num_writers_; ++i) {
- if (writers_[i]) {
- delete writers_[i];
- }
- }
-
- logging_initialized_ = false;
- } __except(SehNoMinidump(GetExceptionCode(),
- GetExceptionInformation(),
- __FILE__,
- __LINE__,
- true)) {
- OutputDebugStringA("Unexpected exception in: " __FUNCTION__ "\r\n");
- logging_initialized_ = false;
- }
-
- g_logging_valid = false;
- lock_.Unlock();
-}
-
-void Logging::UpdateCatAndLevel(const wchar_t* cat_name, LogCategory cat) {
- if (cat_name == NULL) {
- return;
- }
- if (cat >= LC_MAX_CAT) {
- return;
- }
- int log_level = kDefaultLogLevel;
- CString config_file = GetCurrentConfigurationFilePath();
- if (!config_file.IsEmpty()) {
- log_level = GetPrivateProfileInt(kConfigSectionLoggingLevel,
- cat_name,
- kDefaultLogLevel,
- config_file);
- }
- category_list_[cat].enabled = (log_level != 0);
- category_list_[cat].log_level = static_cast<LogLevel>(log_level);
-}
-
-void Logging::ReadLoggingSettings() {
- CString config_file = GetCurrentConfigurationFilePath();
- if (!config_file.IsEmpty()) {
- logging_enabled_ = ::GetPrivateProfileInt(
- kConfigSectionLoggingSettings,
- kConfigAttrEnableLogging,
- kDefaultLoggingEnabled,
- config_file) == 0 ? false : true;
-
- show_time_ = ::GetPrivateProfileInt(
- kConfigSectionLoggingSettings,
- kConfigAttrShowTime,
- kDefaultShowTime,
- config_file) == 0 ? false : true;
-
- log_to_file_ = ::GetPrivateProfileInt(
- kConfigSectionLoggingSettings,
- kConfigAttrLogToFile,
- kDefaultLogToFile,
- config_file) == 0 ? false : true;
-
- log_to_debug_out_ = ::GetPrivateProfileInt(
- kConfigSectionLoggingSettings,
- kConfigAttrLogToOutputDebug,
- kDefaultLogToOutputDebug,
- config_file) == 0 ? false : true;
-
- append_to_file_ = ::GetPrivateProfileInt(
- kConfigSectionLoggingSettings,
- kConfigAttrAppendToFile,
- kDefaultAppendToFile,
- config_file) == 0 ? false : true;
-
- ::GetPrivateProfileString(kConfigSectionLoggingSettings,
- kConfigAttrLogFilePath,
- kDefaultLogFileName,
- CStrBuf(log_file_name_, MAX_PATH),
- MAX_PATH,
- config_file);
- } else {
- logging_enabled_ = kDefaultLoggingEnabled;
- show_time_ = kDefaultShowTime;
- log_to_file_ = kDefaultLogToFile;
- log_to_debug_out_ = kDefaultLogToOutputDebug;
- append_to_file_ = kDefaultAppendToFile;
- log_file_name_ = kDefaultLogFileName;
- }
-
- if (force_show_time_) {
- show_time_ = true;
- }
-
- // The "default" category is always enabled.
- category_list_[LC_LOGGING].enabled = true;
- category_list_[LC_LOGGING].log_level = LEVEL_ALL;
-
- // Read each category from the ini file.
- for (size_t i = 0; i < arraysize(LogCategoryNames); ++i) {
- UpdateCatAndLevel(LogCategoryNames[i].category_name,
- LogCategoryNames[i].category);
- }
-
- g_last_category_check_time = GetCurrent100NSTime();
-}
-
-CString Logging::GetDefaultLogDirectory() const {
- CString path;
- CStrBuf buf(path, MAX_PATH);
- HRESULT hr = ::SHGetFolderPath(NULL,
- CSIDL_COMMON_APPDATA,
- NULL,
- SHGFP_TYPE_CURRENT,
- buf);
- if (FAILED(hr)) {
- return L"";
- }
- if (!::PathAppend(buf, OMAHA_REL_LOG_DIR)) {
- return L"";
- }
- return path;
-}
-
-CString Logging::GetLogFilePath() const {
- if (log_file_name_.IsEmpty()) {
- return CString();
- }
-
- if (!ATLPath::IsRelative(log_file_name_)) {
- return log_file_name_;
- }
-
- CString path = GetDefaultLogDirectory();
- if (path.IsEmpty()) {
- return CString();
- }
-
- if (!::PathAppend(CStrBuf(path, MAX_PATH), log_file_name_)) {
- return CString();
- }
-
- return path;
-}
-
-void Logging::ConfigureETWLogWriter() {
- // Always create the ETW log writer, as its log level is controlled
- // at runtime through Event Tracing for Windows.
- if (etw_log_writer_ == NULL) {
- etw_log_writer_ = EtwLogWriter::Create();
- if (debug_out_writer_ == NULL) {
- OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: ERROR - "
- L"Cannot create ETW log writer",
- proc_name_));
- }
- }
-
- if (etw_log_writer_ != NULL) {
- InternalRegisterWriter(etw_log_writer_);
- }
-}
-
-void Logging::ConfigureFileLogWriter() {
- if (!log_to_file_) {
- return;
- }
-
- // Create the logging file.
- if (file_log_writer_ == NULL) {
- CString path = GetLogFilePath();
- if (path.IsEmpty()) {
- return;
- }
-
- // Extract the final target directory which will not be what
- // GetDefaultLogDirectory() returns if log_file_name_ is an absolute path.
- CString log_file_dir = GetDirectoryFromPath(path);
- if (!File::Exists(log_file_dir)) {
- if (FAILED(CreateDir(log_file_dir, NULL))) {
- return;
- }
- }
- file_log_writer_ = FileLogWriter::Create(path, append_to_file_);
- if (file_log_writer_ == NULL) {
- OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: ERROR - "
- L"Cannot create log writer to %s",
- proc_name_, path));
- }
- }
-
- if (file_log_writer_ != NULL) {
- InternalRegisterWriter(file_log_writer_);
- }
-}
-
-void Logging::ConfigureDebugOutLogWriter() {
- if (!log_to_debug_out_) {
- return;
- }
-
- if (debug_out_writer_ == NULL) {
- debug_out_writer_ = OutputDebugStringLogWriter::Create();
- if (debug_out_writer_ == NULL) {
- OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: ERROR - "
- L"Cannot create OutputDebugString log writer",
- proc_name_));
- }
- }
-
- if (debug_out_writer_ != NULL) {
- InternalRegisterWriter(debug_out_writer_);
- }
-}
-
-// Configures/unconfigures the log writers for the current settings.
-bool Logging::ConfigureLogging() {
- ConfigureETWLogWriter();
- ConfigureFileLogWriter();
- ConfigureDebugOutLogWriter();
-
- return num_writers_ > 0;
-}
-
-void Logging::UnconfigureLogging() {
- if (etw_log_writer_ != NULL) {
- InternalUnregisterWriter(etw_log_writer_);
- }
- if (file_log_writer_ != NULL) {
- InternalUnregisterWriter(file_log_writer_);
- }
- if (debug_out_writer_ != NULL) {
- InternalUnregisterWriter(debug_out_writer_);
- }
-}
-
-bool Logging::InternalInitialize() {
- __try {
- if (logging_shutdown_ == true) {
- OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: ERROR - "
- L"Calling the logging system after "
- L"it has been shut down \n",
- GetProcName()));
- return false;
- }
-
- if (logging_initialized_ == true) {
- return true;
- }
- // If something called by this method is attempting to do logging,
- // just ignore it. The cost/benefit ratio is too high to do otherwise.
- if (is_initializing_) {
- return false;
- }
- is_initializing_ = true;
-
- // Read the initial settings from the config file.
- ReadLoggingSettings();
-
- // Initialize logging system if enabled at start.
- if (logging_enabled_) {
- logging_initialized_ = ConfigureLogging();
- }
- } __except(SehNoMinidump(GetExceptionCode(),
- GetExceptionInformation(),
- __FILE__,
- __LINE__,
- true)) {
- OutputDebugStringA("Unexpected exception in: " __FUNCTION__ "\r\n");
- logging_initialized_ = false;
- return false;
- }
-
- is_initializing_ = false;
- return true;
-}
-
-bool Logging::InitializeLogging() {
- // Double-checked locking idiom is broken, especially on multicore machines.
- // TODO(omaha): understand how this works and fix it.
- if (logging_shutdown_ == true) {
- OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: ERROR - Calling the logging "
- L"system after it has been shut down \n",
- GetProcName()));
- return false;
- }
-
- if (logging_initialized_ == true) {
- return true;
- }
-
- // Acquire the lock outside the try/except block so we'll always release it.
- __mutexScope(lock_);
- return InternalInitialize();
-}
-
-// Enables/disables the logging mechanism. Allows turning logging on/off
-// in mid-run.
-// TODO(omaha): same comment as for the destructor.
-void Logging::EnableLogging() {
- if (!InitializeLogging()) {
- return;
- }
-
- // Acquire the lock outside the try/except block so we'll always release it.
- lock_.Lock();
-
- __try {
- if (!logging_enabled_) {
- ConfigureLogging();
- logging_enabled_ = true;
- }
- } __except(SehNoMinidump(GetExceptionCode(),
- GetExceptionInformation(),
- __FILE__,
- __LINE__,
- true)) {
- OutputDebugStringA("Unexpected exception in: " __FUNCTION__ "\r\n");
- logging_enabled_ = false;
- }
-
- lock_.Unlock();
-}
-
-void Logging::DisableLogging() {
- if (!InitializeLogging()) {
- return;
- }
-
- // Acquire the lock outside the try/except block so we'll always release it.
- lock_.Lock();
-
- __try {
- if (logging_enabled_) {
- logging_enabled_ = false;
- UnconfigureLogging();
- }
- } __except(SehNoMinidump(GetExceptionCode(),
- GetExceptionInformation(),
- __FILE__,
- __LINE__,
- true)) {
- OutputDebugStringA("Unexpected exception in: " __FUNCTION__ "\r\n");
- logging_enabled_ = false;
- }
-
- lock_.Unlock();
-}
-
-// Checks if logging is enabled - and updates logging settings from the
-// configuration file every kLogSettingsCheckInterval seconds.
-bool Logging::IsLoggingEnabled() {
- if (!InitializeLogging()) {
- return false;
- }
-
- // Dynamic update - including reading a new value of logging_enabled_.
- bool prev_logging_enabled = logging_enabled_;
- if (GetCurrent100NSTime() >
- g_last_category_check_time + kLogSettingsCheckInterval) {
- ReadLoggingSettings();
- }
-
- // If enabled state has changed either enable or disable logging.
- if (prev_logging_enabled != logging_enabled_) {
- if (logging_enabled_) {
- EnableLogging();
- } else {
- DisableLogging();
- }
- }
-
- return logging_enabled_;
-}
-
-bool Logging::IsLoggingAlreadyEnabled() const {
- return logging_enabled_;
-}
-
-void Logging::ForceShowTimestamp(bool force_show_time) {
- force_show_time_ = show_time_ = force_show_time;
-}
-
-// Get category level
-LogLevel Logging::GetCatLevel(LogCategory category) const {
- if (!IsLoggingAlreadyEnabled()) {
- return kDefaultLogLevel;
- }
-
- if (category >= LC_MAX_CAT) {
- return kDefaultLogLevel;
- }
-
- return category_list_[category].log_level;
-}
-
-// Check if logging is enabled for a given category and level
-DWORD Logging::IsCatLevelEnabled(LogCategory category, LogLevel level) {
- if (!IsLoggingEnabled()) {
- return 0;
- }
-
- if (category >= LC_MAX_CAT) {
- return 0;
- }
-
- // If the config value is to log: then log to all writers.
- if (category_list_[category].enabled &&
- level <= category_list_[category].log_level) {
- return static_cast<DWORD>(all_writers_mask);
- }
-
- // Check each of the registered loggers to see if they want to override the
- // negative config value.
- DWORD mask = 0;
- for (int i = num_writers_ - 1; i >= 0; --i) {
- mask <<= 1;
- if (writers_[i] && writers_[i]->IsCatLevelEnabled(category, level)) {
- mask |= 1;
- }
- }
-
- return mask;
-}
-
-// TODO(omaha): For now this is hard coded and there is no way to override
-// writing other log categories into the history. Add a store_in_history
-// boolean into the CategoryInfo struct that allows reading from the config
-// file. This will enable other log categories to get buffered in the history.
-bool Logging::IsCategoryEnabledForBuffering(LogCategory cat) {
- return cat == LC_REPORT;
-}
-
-void Logging::LogMessage(LogCategory cat, LogLevel level,
- const wchar_t* fmt, ...) {
- va_list args;
- va_start(args, fmt);
- LogMessageVA(cat, level, fmt, args);
- va_end(args);
-}
-
-void Logging::LogMessageVA(LogCategory cat, LogLevel level,
- const wchar_t* fmt, va_list args) {
- LogMessageMaskedVA(static_cast<DWORD>(all_writers_mask),
- cat,
- level,
- fmt,
- args);
-}
-
-void Logging::InternalLogMessageMaskedVA(DWORD writer_mask,
- LogCategory cat,
- LogLevel level,
- CString* log_buffer,
- CString* prefix,
- const wchar_t* fmt,
- va_list args) {
- __try {
- // Initial buffer size in characters.
- // It will adjust dynamically if the message is bigger.
- DWORD buffer_size = 512;
-
- // Count of chars / bytes written.
- int num_chars = 0;
- bool result = false;
-
- // Write the message in the buffer.
- // Dynamically adjust the size to hold the entire message.
-
- while ((num_chars = _vsnwprintf_s(
- log_buffer->GetBufferSetLength(buffer_size),
- buffer_size,
- _TRUNCATE,
- fmt,
- args)) == -1) {
- // Truncate if the message is too big.
- if (buffer_size >= kMaxLogMessageSize) {
- num_chars = buffer_size;
- break;
- }
-
- // Get a buffer that is big enough.
- buffer_size *= 2;
- }
-
- log_buffer->ReleaseBuffer(num_chars);
-
- FormatLinePrefix(show_time_, proc_name_, *prefix);
-
- // Log the message.
- OutputInfo info(cat, level, *prefix, *log_buffer);
- OutputMessage(writer_mask, &info);
- } __except(SehSendMinidump(GetExceptionCode(),
- GetExceptionInformation(),
- kMinsTo100ns)) {
- OutputDebugStringA("Unexpected exception in: " __FUNCTION__ "\r\n");
- OutputDebugString(fmt);
- OutputDebugString(L"\n\r");
- }
-}
-
-void Logging::LogMessageMaskedVA(DWORD writer_mask,
- LogCategory cat,
- LogLevel level,
- const wchar_t* fmt,
- va_list args) {
- if (!fmt) {
- return;
- }
-
- if (writer_mask == 0 && level > kMaxLevelToStoreInLogHistory) {
- return;
- }
-
- CString log_buffer; // The buffer for formatted log messages.
- CString prefix;
-
- int i = 0;
- while (++i <= kNumLockRetries) {
- if (lock_.Lock(0)) {
- InternalLogMessageMaskedVA(writer_mask, cat, level, &log_buffer,
- &prefix, fmt, args);
- lock_.Unlock();
- break;
- }
-
- Sleep(kLockRetryDelayMs);
- }
-
- if (i > kNumLockRetries) {
- OutputDebugStringA("LOG_SYSTEM: Couldn't acquire lock - ");
- OutputDebugString(fmt);
- OutputDebugString(L"\n\r");
- }
-}
-
-void Logging::OutputMessage(DWORD writer_mask, LogCategory cat, LogLevel level,
- const wchar_t* msg1, const wchar_t* msg2) {
- OutputInfo info(cat, level, msg1, msg2);
- OutputMessage(writer_mask, &info);
-}
-
-// Store log message in in-memory history buffer.
-void Logging::StoreInHistory(const OutputInfo* output_info) {
- AppendToHistory(output_info->msg1);
- AppendToHistory(output_info->msg2);
- AppendToHistory(L"\r\n");
-}
-
-// Append string to in-memory history buffer.
-// history_buffer_next_idx points to the next index to write at,
-// thus it should always be in (0 - kHistoryBufferEndIdx).
-void Logging::AppendToHistory(const wchar_t* msg) {
- int msg_len = wcslen(msg);
- if (msg_len == 0) {
- return;
- }
-
- if (msg_len >= kMaxHistoryBufferSize) {
- // Write the first kMaxHistoryBufferSize chars.
- memcpy(history_buffer, msg, kMaxHistoryBufferSize * sizeof(TCHAR));
- history_buffer_next_idx = 0;
- history_buffer_full = true;
- return;
- }
-
- // Determine if the message fits into the portion of the buffer after
- // history_buffer_next_idx.
- if (msg_len + history_buffer_next_idx < kMaxHistoryBufferSize) {
- memcpy(history_buffer + history_buffer_next_idx, msg,
- msg_len * sizeof(TCHAR));
- history_buffer_next_idx += msg_len;
- return;
- }
-
- // Have to split the input message into the part that fits in
- // history_buffer_next_idx to kMaxHistoryBufferSize and the remaining message.
- int msg_first_part_len = kMaxHistoryBufferSize - history_buffer_next_idx;
- int msg_second_part_len = msg_len - msg_first_part_len;
- memcpy(history_buffer + history_buffer_next_idx,
- msg,
- msg_first_part_len * sizeof(TCHAR));
-
- history_buffer_full = true;
- history_buffer_next_idx = msg_second_part_len;
- if (msg_second_part_len) {
- memcpy(history_buffer,
- msg + msg_first_part_len,
- msg_second_part_len * sizeof(TCHAR));
- }
-}
-
-// Retrieve in-memory history buffer.
-CString Logging::GetHistory() {
- CString history;
-
- if (history_buffer_full) {
- history.Append(history_buffer + history_buffer_next_idx,
- kMaxHistoryBufferSize - history_buffer_next_idx);
- }
- history.Append(history_buffer, history_buffer_next_idx);
-
- // Reset the history buffer to the original state.
- history_buffer_next_idx = 0;
- history_buffer_full = false;
- memset(history_buffer, 0, kMaxHistoryBufferSize * sizeof(TCHAR));
-
- return history;
-}
-
-void Logging::OutputMessage(DWORD writer_mask,
- const OutputInfo* output_info) {
- if (output_info->level <= kMaxLevelToStoreInLogHistory &&
- IsCategoryEnabledForBuffering(output_info->category)) {
- StoreInHistory(output_info);
- }
-
- for (int i = 0; i < num_writers_; ++i) {
- if (writer_mask & 1) {
- __try {
- if (logging_enabled_ || writers_[i]->WantsToLogRegardless()) {
- writers_[i]->OutputMessage(output_info);
- }
- }
- __except(SehNoMinidump(GetExceptionCode(),
- GetExceptionInformation(),
- __FILE__,
- __LINE__,
- true)) {
- // Just eat errors that happen from within the LogWriters. This is
- // important so that if such an error happens when OutputMessage is
- // called from debugASSERT we don't go recursively into more
- // error handling ...
- }
- }
- writer_mask >>= 1;
- }
-}
-
-bool Logging::InternalRegisterWriter(LogWriter* log_writer) {
- if (num_writers_ >= max_writers) {
- return false;
- }
- writers_[num_writers_++] = log_writer;
- return true;
-}
-
-bool Logging::RegisterWriter(LogWriter* log_writer) {
- if (!InternalRegisterWriter(log_writer)) {
- return false;
- }
- if (log_writer->WantsToLogRegardless()) {
- EnableLogging();
- }
- return true;
-}
-
-bool Logging::InternalUnregisterWriter(LogWriter* log_writer) {
- bool result = false;
- for (int i = 0; i < num_writers_; ++i) {
- if (writers_[i] == log_writer) {
- // Replace this entry with last entry in array, then truncate.
- writers_[i] = writers_[--num_writers_];
- result = true;
- break;
- }
- }
- return result;
-}
-
-bool Logging::UnregisterWriter(LogWriter* log_writer) {
- if (!InternalUnregisterWriter(log_writer)) {
- return false;
- }
- if (num_writers_ == 0) {
- DisableLogging();
- }
- return true;
-}
-
-// The primary configuration file under %PROGRAMFILES%\Google\Update is
-// removed on uninstall. This is midly inconvenient during development
-// therefore a fallback location for the configuration file is desired.
-CString Logging::GetCurrentConfigurationFilePath() const {
- if (!config_file_path_.IsEmpty() &&
- File::Exists(config_file_path_)) {
- return config_file_path_;
- } else {
- return L"";
- }
-}
-
-CString Logging::GetConfigurationFilePath() const {
- CString file_path;
- CString system_drive = GetEnvironmentVariableAsString(_T("SystemDrive"));
- if (!system_drive.IsEmpty()) {
- file_path = system_drive;
- file_path += L"\\";
- }
- return file_path + kLogConfigFileName;
-}
-
-LogWriter::LogWriter() {
-}
-
-LogWriter::~LogWriter() {
-}
-
-void LogWriter::Cleanup() {}
-
-bool LogWriter::WantsToLogRegardless() const { return false; }
-
-bool LogWriter::IsCatLevelEnabled(LogCategory, LogLevel) const {
- return false;
-}
-
-void LogWriter::OutputMessage(const OutputInfo*) { }
-
-bool LogWriter::Register() {
- Logging* logger = GetLogging();
- if (logger) {
- return logger->RegisterWriter(this);
- } else {
- return false;
- }
-}
-
-bool LogWriter::Unregister() {
- Logging* logger = GetLogging();
- if (logger) {
- return logger->RegisterWriter(this);
- } else {
- return false;
- }
-}
-
-// FileLogWriter
-
-FileLogWriter* FileLogWriter::Create(const wchar_t* file_name, bool append) {
- return new FileLogWriter(file_name, append);
-}
-
-FileLogWriter::FileLogWriter(const wchar_t* file_name, bool append)
- : initialized_(false),
- valid_(false),
- file_name_(file_name),
- log_file_mutex_(NULL),
- log_file_(NULL),
- append_(append),
- max_file_size_(kDefaultMaxLogFileSize),
- log_file_wide_(kDefaultLogFileWide) {
- Logging* logger = GetLogging();
- if (logger) {
- CString config_file_path = logger->GetCurrentConfigurationFilePath();
- if (!config_file_path.IsEmpty()) {
- max_file_size_ = ::GetPrivateProfileInt(
- kConfigSectionLoggingSettings,
- kConfigAttrMaxLogFileSize,
- kDefaultMaxLogFileSize,
- config_file_path);
- log_file_wide_ = ::GetPrivateProfileInt(
- kConfigSectionLoggingSettings,
- kConfigAttrLogFileWide,
- kDefaultLogFileWide,
- config_file_path) == 0 ? false : true;
- } else {
- max_file_size_ = kDefaultMaxLogFileSize;
- log_file_wide_ = kDefaultLogFileWide;
- }
- proc_name_ = logger->proc_name();
- }
-}
-
-FileLogWriter::~FileLogWriter() {
- // TODO(omaha): Figure out a way to pass the proc_name - and possibly
- // the show_time var - into here.
- Logging* logger = GetLogging();
- if (logger && logger->IsLoggingAlreadyEnabled()) {
- // OutputInfo info(LEVEL_WARNING, NULL, kEndOfLogMessage);
- // OutputMessage(&info);
- }
- Cleanup();
-}
-
-void FileLogWriter::Initialize() {
- if (initialized_) {
- return;
- }
-
- initialized_ = true;
-
- bool already_created = CreateLoggingMutex();
- if (!log_file_mutex_) {
- return;
- }
-
- if (already_created) {
- append_ = true;
- }
-
- if (!GetMutex()) {
- ::OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: "
- L"Could not acquire logging mutex %s\n",
- proc_name_,
- log_file_mutex_name_));
- return;
- }
-
- CreateLoggingFile();
- if (!log_file_) {
- ::OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: "
- L"Could not create logging file %s\n",
- proc_name_,
- file_name_));
- valid_ = false;
- }
-
- valid_ = true;
- ReleaseMutex();
-}
-
-void FileLogWriter::Cleanup() {
- if (log_file_) {
- ::CloseHandle(log_file_);
- }
- if (log_file_mutex_) {
- ::ReleaseMutex(log_file_mutex_);
- ::CloseHandle(log_file_mutex_);
- }
-}
-
-bool FileLogWriter::CreateLoggingMutex() {
- log_file_mutex_name_ = StripBackslashes(kLoggingMutexName L"_" + file_name_);
- // TODO(omaha): I don't see where this class is used, but I guess the
- // caller is always in the same context. We should use the default security
- // here. If the caller can be in different contexts (System Service, Usermode
- // applications, etc), then we should revisit this code to give access only
- // to those who really need it. What if a malicious piece a code decide
- // to get the mutex and lock it? If it happens, everytime you try to log
- // something, the thread would hang for 500ms and then fail to log the
- // message.
- CSecurityDesc sd;
- GetEveryoneDaclSecurityDescriptor(&sd, GENERIC_ALL, GENERIC_ALL);
- CSecurityAttributes sa(sd);
- log_file_mutex_ = CreateMutexWithSyncAccess(log_file_mutex_name_, &sa);
- if (log_file_mutex_) {
- return ERROR_ALREADY_EXISTS == ::GetLastError();
- }
- return false;
-}
-
-bool FileLogWriter::CreateLoggingFile() {
- uint32 file_size(0);
- File::GetFileSizeUnopen(file_name_, &file_size);
- if (file_size > max_file_size_) {
- ArchiveLoggingFile();
- }
- log_file_ = ::CreateFile(file_name_,
- GENERIC_WRITE,
- FILE_SHARE_WRITE | FILE_SHARE_READ,
- NULL,
- append_ ? OPEN_ALWAYS : CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- if (log_file_ == INVALID_HANDLE_VALUE) {
- // The code in this file is written with the assumption that log_file_ is
- // NULL on creation errors. The easy fix is to set it to NULL here. The
- // long term fix should be implementing it in terms of a smart handle.
- log_file_ = NULL;
- return false;
- }
-
- // Allow users to read, write, and delete the log file.
- ACCESS_MASK mask = GENERIC_READ | GENERIC_WRITE | DELETE;
- CDacl dacl;
- if (dacl.AddAllowedAce(ATL::Sids::Users(), mask)) {
- AtlSetDacl(file_name_, SE_FILE_OBJECT, dacl);
- }
-
- // Insert a BOM in the newly created file.
- if (GetLastError() != ERROR_ALREADY_EXISTS && log_file_wide_) {
- DWORD num = 0;
- ::WriteFile(log_file_, &kUnicodeBom, sizeof(kUnicodeBom), &num, NULL);
- }
- return true;
-}
-
-bool FileLogWriter::TruncateLoggingFile() {
- DWORD share_mode = FILE_SHARE_WRITE;
- HANDLE log_file = ::CreateFile(file_name_,
- GENERIC_WRITE,
- FILE_SHARE_WRITE | FILE_SHARE_READ,
- NULL,
- TRUNCATE_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- if (log_file_ == INVALID_HANDLE_VALUE) {
- return false;
- }
-
- // Insert a BOM in the newly created file.
- if (log_file_wide_) {
- DWORD num = 0;
- ::WriteFile(log_file, &kUnicodeBom, sizeof(kUnicodeBom), &num, NULL);
- }
- ::CloseHandle(log_file);
- return true;
-}
-
-bool FileLogWriter::ArchiveLoggingFile() {
- ::OutputDebugString(L"LOG_SYSTEM: trying to move log file to backup\n");
- CString backup_file_name = file_name_ + L".bak";
- HRESULT hr = File::Move(file_name_, backup_file_name, true);
- if (FAILED(hr)) {
- ::OutputDebugString(L"LOG_SYSTEM: failed to move log file to backup\n");
-
- // Trying to move the log file when loggers have it open returns
- // ERROR_SHARING_VIOLATION. Each call to MoveFileAfterReboot inserts the
- // file into PendingFileRenames list. Moving files at reboot requires the
- // user to be either the LocalSystem account or in the Administrators
- // group.
- if (!IsArchivePending()) {
- File::MoveAfterReboot(file_name_, backup_file_name);
- }
- return false;
- }
- return true;
-}
-
-bool FileLogWriter::IsArchivePending() {
- // We look at the PendingFileRenameOperations to see if our log file is
- // pending a rename. The list is a REG_MULTI_SZ, which is a sequence of
- // null-terminated strings, terminated by an empty string "\0".
- // The strings have the structure:
- // \??\file1\0!\??\file2\0\file3\0\0...\0\0. where file1 is to be renamed to
- // file2 and file3 is to be deleted.
- // It is valid for the PFR list to include an empty string in the middle
- // of the sequence.
- const wchar_t sub_key_name[] = L"SYSTEM\\CurrentControlSet\\Control\\"
- L"Session Manager";
- HKEY key = NULL;
- int res = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
- sub_key_name,
- 0,
- KEY_READ,
- &key);
- if (res != ERROR_SUCCESS) {
- return false;
- }
- DWORD bytes = 0;
- DWORD type = REG_MULTI_SZ;
- res = ::RegQueryValueEx(key,
- L"PendingFileRenameOperations",
- 0,
- &type,
- NULL,
- &bytes);
- if (!(res == ERROR_SUCCESS && type == REG_MULTI_SZ)) {
- return false;
- }
- scoped_array<byte> buf(new byte[bytes]);
- memset(buf.get(), 0, bytes);
- res = ::RegQueryValueEx(key,
- L"PendingFileRenameOperations",
- 0,
- NULL,
- buf.get(),
- &bytes);
- if (res != ERROR_SUCCESS) {
- return false;
- }
- const wchar_t* multi_str = reinterpret_cast<const wchar_t*>(buf.get());
- size_t count = bytes / sizeof(*multi_str);
- const size_t kMaxRegistryValueLen = 1024 * 1024; // 1MB
- if (!(count >= 2 &&
- count < kMaxRegistryValueLen &&
- multi_str[count - 2] == L'\0' &&
- multi_str[count - 1] == L'\0')) {
- return false;
- }
- // The file names in the PFR list are prefixed by \??\.
- CString file_name = L"\\??\\" + file_name_;
- return FindFirstInMultiString(multi_str, count, file_name) != -1;
-}
-
-int FileLogWriter::FindFirstInMultiString(const wchar_t* multi_str,
- size_t count,
- const wchar_t* str) {
- const wchar_t* p = multi_str;
- size_t i = 0;
- while (i < count) {
- p = multi_str + i;
- if (lstrcmp(p, str) == 0) {
- return i;
- } else {
- size_t len = lstrlen(p);
- i += len + 1;
- }
- }
- return -1;
-}
-
-void FileLogWriter::OutputMessage(const OutputInfo* output_info) {
- if (!initialized_) {
- Initialize();
- }
-
- if (!valid_) {
- return;
- }
-
- // Acquire the mutex.
- if (!GetMutex()) {
- return;
- }
-
- // Move to end of file.
- DWORD pos = ::SetFilePointer(log_file_, 0, NULL, FILE_END);
- int64 stop_gap_file_size = kStopGapLogFileSizeFactor *
- static_cast<int64>(max_file_size_);
- if (pos >= stop_gap_file_size) {
- if (!TruncateLoggingFile()) {
- // Logging stops until the log can be archived over since we do not
- // want to overfill the disk.
- return;
- }
- }
- pos = ::SetFilePointer(log_file_, 0, NULL, FILE_END);
-
- // Write the date, followed by a CRLF
- DWORD written_size = 0;
- if (output_info->msg1) {
- if (log_file_wide_) {
- ::WriteFile(log_file_, output_info->msg1,
- lstrlen(output_info->msg1) * sizeof(wchar_t), &written_size,
- NULL);
- } else {
- CStringA msg(WideToAnsiDirect(output_info->msg1));
- ::WriteFile(log_file_, msg.GetString(), msg.GetLength(), &written_size,
- NULL);
- }
- }
-
- if (output_info->msg2) {
- if (log_file_wide_) {
- ::WriteFile(log_file_, output_info->msg2,
- lstrlen(output_info->msg2) * sizeof(wchar_t), &written_size,
- NULL);
- } else {
- CStringA msg(WideToAnsiDirect(output_info->msg2));
- ::WriteFile(log_file_, msg.GetString(), msg.GetLength(), &written_size,
- NULL);
- }
- }
-
- if (log_file_wide_) {
- ::WriteFile(log_file_, L"\r\n", 2 * sizeof(wchar_t), &written_size, NULL);
- } else {
- ::WriteFile(log_file_, "\r\n", 2, &written_size, NULL);
- }
-
- ReleaseMutex();
-}
-
-bool FileLogWriter::GetMutex() {
- if (!log_file_mutex_) {
- return false;
- }
-
- DWORD res = ::WaitForSingleObject(log_file_mutex_, kMaxMutexWaitTimeMs);
- if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) {
- ::OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: "
- L"Could not acquire logging mutex %s\n",
- proc_name_, log_file_mutex_name_));
- valid_ = false;
- return false;
- }
-
- return true;
-}
-
-void FileLogWriter::ReleaseMutex() {
- if (log_file_mutex_) {
- ::ReleaseMutex(log_file_mutex_);
- }
-}
-
-// OutputDebugStringLogWriter.
-OutputDebugStringLogWriter* OutputDebugStringLogWriter::Create() {
- return new OutputDebugStringLogWriter();
-}
-
-OutputDebugStringLogWriter::OutputDebugStringLogWriter() {}
-
-OutputDebugStringLogWriter::~OutputDebugStringLogWriter() {
- Logging* logger = GetLogging();
- if (logger && logger->IsLoggingAlreadyEnabled()) {
- // OutputInfo info(LEVEL_WARNING, NULL, kEndOfLogMessage);
- // OutputMessage(&info);
- }
- Cleanup();
-}
-
-void OutputDebugStringLogWriter::OutputMessage(const OutputInfo* output_info) {
- // Combine everything into one string so that messages coming from
- // multiple threads don't get interleaved.
- ::OutputDebugString(SPRINTF(L"%s%s\n", output_info->msg1, output_info->msg2));
-}
-
-// OverrideConfigLogWriter.
-OverrideConfigLogWriter* OverrideConfigLogWriter::Create(LogCategory category,
- LogLevel level, LogWriter* log_writer, bool force_logging_enabled) {
- return new OverrideConfigLogWriter(category,
- level,
- log_writer,
- force_logging_enabled);
-}
-
-OverrideConfigLogWriter::OverrideConfigLogWriter(LogCategory category,
- LogLevel level,
- LogWriter* log_writer,
- bool force_logging_enabled)
- : category_(category),
- level_(level),
- log_writer_(log_writer),
- force_logging_enabled_(force_logging_enabled) {}
-
-void OverrideConfigLogWriter::Cleanup() {
- if (log_writer_) {
- delete log_writer_;
- }
-}
-
-bool OverrideConfigLogWriter::WantsToLogRegardless() const {
- return force_logging_enabled_;
-}
-
-bool OverrideConfigLogWriter::IsCatLevelEnabled(LogCategory category,
- LogLevel level) const {
- if (category != category_) {
- return false;
- }
- if (level > level_) {
- return false;
- }
- return true;
-}
-
-void OverrideConfigLogWriter::OutputMessage(const OutputInfo* output_info) {
- if (log_writer_) {
- log_writer_->OutputMessage(output_info);
- }
- return;
-}
-
-} // namespace omaha
-
-#endif // LOGGING
-
« no previous file with comments | « base/logging.h ('k') | base/logging/build.scons » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698