logging_installer.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1// Copyright (c) 2011 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 <windows.h>
6
7#include "chrome/installer/util/logging_installer.h"
8
9#include "base/command_line.h"
10#include "base/files/file.h"
11#include "base/files/file_path.h"
12#include "base/files/file_util.h"
13#include "base/logging.h"
14#include "base/logging_win.h"
15#include "base/path_service.h"
16#include "base/strings/string_util.h"
17#include "base/strings/utf_string_conversions.h"
18#include "base/win/scoped_handle.h"
19#include "chrome/installer/util/master_preferences.h"
20#include "chrome/installer/util/master_preferences_constants.h"
21#include "chrome/installer/util/util_constants.h"
22
23// {93BCE0BF-3FAF-43b1-9E28-BEB6FAB5ECE7}
24static const GUID kSetupTraceProvider = { 0x93bce0bf, 0x3faf, 0x43b1,
25    { 0x9e, 0x28, 0xbe, 0xb6, 0xfa, 0xb5, 0xec, 0xe7 } };
26
27namespace installer {
28
29// This should be true for the period between the end of
30// InitInstallerLogging() and the beginning of EndInstallerLogging().
31bool installer_logging_ = false;
32
33TruncateResult TruncateLogFileIfNeeded(const base::FilePath& log_file) {
34  TruncateResult result = LOGFILE_UNTOUCHED;
35
36  int64 log_size = 0;
37  if (base::GetFileSize(log_file, &log_size) &&
38      log_size > kMaxInstallerLogFileSize) {
39    // Cause the old log file to be deleted when we are done with it.
40    uint32 file_flags = base::File::FLAG_OPEN |
41                        base::File::FLAG_READ |
42                        base::File::FLAG_SHARE_DELETE |
43                        base::File::FLAG_DELETE_ON_CLOSE;
44    base::File old_log_file(log_file, file_flags);
45
46    if (old_log_file.IsValid()) {
47      result = LOGFILE_DELETED;
48      base::FilePath tmp_log(log_file.value() + FILE_PATH_LITERAL(".tmp"));
49      // Note that base::Move will attempt to replace existing files.
50      if (base::Move(log_file, tmp_log)) {
51        int64 offset = log_size - kTruncatedInstallerLogFileSize;
52        std::string old_log_data(kTruncatedInstallerLogFileSize, 0);
53        int bytes_read = old_log_file.Read(offset,
54                                           &old_log_data[0],
55                                           kTruncatedInstallerLogFileSize);
56        if (bytes_read > 0 &&
57            (bytes_read == base::WriteFile(log_file, &old_log_data[0],
58                                           bytes_read) ||
59             base::PathExists(log_file))) {
60          result = LOGFILE_TRUNCATED;
61        }
62      }
63    } else if (base::DeleteFile(log_file, false)) {
64      // Couldn't get sufficient access to the log file, optimistically try to
65      // delete it.
66      result = LOGFILE_DELETED;
67    }
68  }
69
70  return result;
71}
72
73
74void InitInstallerLogging(const installer::MasterPreferences& prefs) {
75  if (installer_logging_)
76    return;
77
78  installer_logging_ = true;
79
80  bool value = false;
81  if (prefs.GetBool(installer::master_preferences::kDisableLogging,
82                    &value) && value) {
83    return;
84  }
85
86  base::FilePath log_file_path(GetLogFilePath(prefs));
87  TruncateLogFileIfNeeded(log_file_path);
88
89  logging::LoggingSettings settings;
90  settings.logging_dest = logging::LOG_TO_FILE;
91  settings.log_file = log_file_path.value().c_str();
92  logging::InitLogging(settings);
93
94  if (prefs.GetBool(installer::master_preferences::kVerboseLogging,
95                    &value) && value) {
96    logging::SetMinLogLevel(logging::LOG_VERBOSE);
97  } else {
98    logging::SetMinLogLevel(logging::LOG_ERROR);
99  }
100
101  // Enable ETW logging.
102  logging::LogEventProvider::Initialize(kSetupTraceProvider);
103}
104
105void EndInstallerLogging() {
106  logging::CloseLogFile();
107
108  installer_logging_ = false;
109}
110
111base::FilePath GetLogFilePath(const installer::MasterPreferences& prefs) {
112  std::string path;
113  prefs.GetString(installer::master_preferences::kLogFile, &path);
114  if (!path.empty())
115    return base::FilePath(base::UTF8ToWide(path));
116
117  static const base::FilePath::CharType kLogFilename[] =
118      FILE_PATH_LITERAL("chrome_installer.log");
119
120  // Fallback to current directory if getting the temp directory fails.
121  base::FilePath tmp_path;
122  ignore_result(PathService::Get(base::DIR_TEMP, &tmp_path));
123  return tmp_path.Append(kLogFilename);
124}
125
126}  // namespace installer
127