1 // Copyright 2018 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 "chrome/chrome_cleaner/logging/scoped_logging.h"
6 
7 #include <memory>
8 
9 #include "base/command_line.h"
10 #include "base/file_version_info.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/logging_win.h"
14 #include "base/strings/string_util.h"
15 #include "base/win/current_module.h"
16 #include "chrome/chrome_cleaner/constants/chrome_cleaner_switches.h"
17 #include "chrome/chrome_cleaner/constants/version.h"
18 #include "chrome/chrome_cleaner/logging/logging_service_api.h"
19 #include "chrome/chrome_cleaner/os/disk_util.h"
20 #include "chrome/chrome_cleaner/os/pre_fetched_paths.h"
21 #include "chrome/chrome_cleaner/settings/settings.h"
22 
23 namespace chrome_cleaner {
24 
25 namespace {
26 
27 // {985388DD-5F6A-40A9-A4D2-86D8547EFB52}
28 const GUID kChromeCleanerTraceProviderName = {
29     0x985388DD,
30     0x5F6A,
31     0x40A9,
32     {0xA4, 0xD2, 0x86, 0xD8, 0x54, 0x7E, 0xFB, 0x52}};
33 
34 // The log file extension.
35 const wchar_t kLogFileExtension[] = L"log";
36 
GetLoggingDirectory()37 base::FilePath GetLoggingDirectory() {
38   base::FilePath logging_directory =
39       base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
40           kTestLoggingPathSwitch);
41   if (logging_directory.empty()) {
42     if (!GetAppDataProductDirectory(&logging_directory))
43       return base::FilePath();
44   }
45   return logging_directory;
46 }
47 
48 }  // namespace
49 
ScopedLogging(base::FilePath::StringPieceType suffix)50 ScopedLogging::ScopedLogging(base::FilePath::StringPieceType suffix) {
51   // Log to an ETW facility for convenience.
52   // This swallows all log lines it gets, so we need to initialize it before
53   // LoggingServiceAPI so LoggingServiceAPI can see the logs first, which it
54   // then passes on to LogEventProvider.
55   logging::LogEventProvider::Initialize(kChromeCleanerTraceProviderName);
56 
57   // Initialize the logging global state.
58   LoggingServiceAPI* logging_service = LoggingServiceAPI::GetInstance();
59   logging_service->Initialize(nullptr);
60 
61   const base::FilePath log_file_path = GetLogFilePath(suffix);
62 
63   // Truncate log files to 40kB. This should be enough to cover logs of the
64   // previous run (99th percentile of uploaded raw log line size is 36kB).
65   TruncateLogFileToTail(log_file_path, 40 * 1000);
66 
67   logging::LoggingSettings logging_settings;
68   logging_settings.logging_dest = logging::LOG_TO_FILE;
69   logging_settings.log_file_path = log_file_path.value().c_str();
70 
71   bool success = logging::InitLogging(logging_settings);
72   DCHECK(success);
73   LOG(INFO) << "Starting logs for version: " << CHROME_CLEANER_VERSION_STRING;
74 
75   logging_service->EnableUploads(
76       chrome_cleaner::Settings::GetInstance()->logs_upload_allowed(), nullptr);
77 }
78 
~ScopedLogging()79 ScopedLogging::~ScopedLogging() {
80   // Terminate the service to avoid work being done in the destructor called by
81   // the AtExitManager.
82   LoggingServiceAPI::GetInstance()->Terminate();
83 
84   // Kill our ETW provider.
85   logging::LogEventProvider::Uninitialize();
86 }
87 
88 // static
GetLogFilePath(base::FilePath::StringPieceType suffix)89 base::FilePath ScopedLogging::GetLogFilePath(
90     base::FilePath::StringPieceType suffix) {
91   // Initialize the logging settings to set a specific log file name.
92   std::unique_ptr<FileVersionInfo> version(
93       FileVersionInfo::CreateFileVersionInfoForModule(CURRENT_MODULE()));
94 
95   // Test executables don't have version resources.
96   base::FilePath original_filename;
97   if (version.get()) {
98     original_filename =
99         base::FilePath(base::AsWStringPiece(version->original_filename()));
100   } else {
101     original_filename =
102         PreFetchedPaths::GetInstance()->GetExecutablePath().BaseName();
103   }
104 
105   if (!suffix.empty())
106     original_filename = original_filename.InsertBeforeExtension(suffix);
107 
108   base::FilePath log_file_path =
109       original_filename.ReplaceExtension(kLogFileExtension);
110   base::FilePath logging_directory = GetLoggingDirectory();
111   if (!logging_directory.empty())
112     log_file_path = logging_directory.Append(log_file_path);
113   return log_file_path;
114 }
115 
116 }  // namespace chrome_cleaner
117