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

Side by Side Diff: chrome/browser/chromeos/system_logs/debug_log_writer.cc

Issue 329853010: Additional methods for chrome.logPrivate API (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 5 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 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/browser/chromeos/system_logs/debug_log_writer.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback.h"
10 #include "base/command_line.h"
11 #include "base/file_util.h"
12 #include "base/files/file.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/process/kill.h"
15 #include "base/process/launch.h"
16 #include "chrome/common/logging_chrome.h"
17 #include "chromeos/dbus/dbus_thread_manager.h"
18 #include "chromeos/dbus/debug_daemon_client.h"
19 #include "content/public/browser/browser_thread.h"
20
21 namespace chromeos {
22
23 namespace {
24
25 // Callback for returning status of executed external command.
26 typedef base::Callback<void(bool succeeded)> CommandCompletionCallback;
27
28 const char kGzipCommand[] = "/bin/gzip";
29 const char kTarCommand[] = "/bin/tar";
30
31 scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner(
32 const std::string sequence_name) {
33 base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
34 return pool->GetSequencedTaskRunnerWithShutdownBehavior(
35 pool->GetNamedSequenceToken(sequence_name),
36 base::SequencedWorkerPool::BLOCK_SHUTDOWN);
37 }
38
39 // Called upon completion of |WriteDebugLogToFile|. Closes file
40 // descriptor, deletes log file in the case of failure and calls
41 // |callback|.
42 void WriteDebugLogToFileCompleted(
43 const base::FilePath& file_path,
44 const std::string& sequence_token_name,
45 const DebugLogWriter::StoreLogsCallback& callback,
46 bool succeeded) {
47 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
48 if (!succeeded) {
49 bool posted = GetSequencedTaskRunner(sequence_token_name)->PostTaskAndReply(
50 FROM_HERE,
51 base::Bind(base::IgnoreResult(&base::DeleteFile), file_path, false),
52 base::Bind(callback, file_path, false));
53 DCHECK(posted);
54 return;
55 }
56 callback.Run(file_path, true);
57 }
58
59 // Stores into |file_path| debug logs in the .tgz format. Calls
60 // |callback| upon completion.
61 void WriteDebugLogToFile(base::File* file,
62 const std::string& sequence_token_name,
63 const base::FilePath& file_path,
64 bool should_compress,
65 const DebugLogWriter::StoreLogsCallback& callback) {
66 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
67 if (!file->IsValid()) {
68 LOG(ERROR) << "Can't create debug log file: " << file_path.AsUTF8Unsafe()
69 << ", "
70 << "error: " << file->error_details();
71 return;
72 }
73 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->DumpDebugLogs(
74 should_compress,
75 file->Pass(),
76 base::Bind(&WriteDebugLogToFileCompleted,
77 file_path,
78 sequence_token_name,
79 callback));
80 }
81
82 // Runs command with its parameters as defined in |argv|.
83 // Upon completion, it will report command run outcome via |callback| on the
84 // same thread from where it was initially called from.
85 void RunCommand(const std::vector<std::string>& argv,
86 const CommandCompletionCallback& callback) {
87 base::ProcessHandle handle = base::kNullProcessHandle;
88 if (!base::LaunchProcess(argv, base::LaunchOptions(), &handle)) {
89 LOG(ERROR) << "Failed to execute command " << argv[0];
90 callback.Run(false);
91 return;
92 }
93
94 int exit_code = 0;
95 if (!base::WaitForExitCode(handle, &exit_code)) {
96 LOG(ERROR) << "Can't get exit code for pid " << handle;
97 callback.Run(false);
98 return;
99 }
100 callback.Run(exit_code == 0);
101 }
102
103 // Callback for handling the outcome of CompressArchive(). It reports
104 // the final outcome of log retreival process at via |callback|.
105 void OnCompressArchiveCompleted(
106 const base::FilePath& tar_file_path,
107 const base::FilePath& compressed_output_path,
108 const DebugLogWriter::StoreLogsCallback& callback,
109 bool compression_command_success) {
110 if (!compression_command_success) {
111 LOG(ERROR) << "Failed compressing " << compressed_output_path.value();
112 content::BrowserThread::PostTask(
113 content::BrowserThread::UI,
114 FROM_HERE,
115 base::Bind(callback, base::FilePath(), false));
116 base::DeleteFile(tar_file_path, true);
117 base::DeleteFile(compressed_output_path, true);
118 return;
119 }
120
121 content::BrowserThread::PostTask(
122 content::BrowserThread::UI,
123 FROM_HERE,
124 base::Bind(callback, compressed_output_path, true));
125 }
126
127 // Gzips |tar_file_path| and stores results in |compressed_output_path|.
128 void CompressArchive(const base::FilePath& tar_file_path,
129 const base::FilePath& compressed_output_path,
130 const DebugLogWriter::StoreLogsCallback& callback,
131 bool add_user_logs_command_success) {
132 if (!add_user_logs_command_success) {
133 LOG(ERROR) << "Failed adding user logs to " << tar_file_path.value();
134 content::BrowserThread::PostTask(
135 content::BrowserThread::UI,
136 FROM_HERE,
137 base::Bind(callback, base::FilePath(), false));
138 base::DeleteFile(tar_file_path, true);
139 return;
140 }
141
142 std::vector<std::string> argv;
143 argv.push_back(kGzipCommand);
144 argv.push_back(tar_file_path.value());
145 RunCommand(argv,
146 base::Bind(&OnCompressArchiveCompleted,
147 tar_file_path,
148 compressed_output_path,
149 callback));
150 }
151
152 // Adds user sessions specific logs from |user_log_dir| into tar archive file
153 // at |tar_file_path|. Upon completion, it will call CompressArchive() to
154 // produce |compressed_output_path|.
155 void AddUserLogsToArchive(const base::FilePath& user_log_dir,
156 const base::FilePath& tar_file_path,
157 const base::FilePath& compressed_output_path,
158 const DebugLogWriter::StoreLogsCallback& callback) {
159 std::vector<std::string> argv;
160 argv.push_back(kTarCommand);
161 argv.push_back("-rvf");
162 argv.push_back(tar_file_path.value());
163 argv.push_back(user_log_dir.value());
164 RunCommand(
165 argv,
166 base::Bind(
167 &CompressArchive, tar_file_path, compressed_output_path, callback));
168 }
169
170 // Appends user logs after system logs are archived into |tar_file_path|.
171 void OnSystemLogsAdded(const DebugLogWriter::StoreLogsCallback& callback,
172 const base::FilePath& tar_file_path,
173 bool succeeded) {
174 if (!succeeded) {
175 callback.Run(base::FilePath(), false);
176 return;
177 }
178
179 base::FilePath compressed_output_path =
180 tar_file_path.AddExtension(FILE_PATH_LITERAL(".gz"));
181 base::FilePath user_log_dir =
182 logging::GetSessionLogDir(*CommandLine::ForCurrentProcess());
183
184 content::BrowserThread::PostBlockingPoolTask(
185 FROM_HERE,
186 base::Bind(&AddUserLogsToArchive,
187 user_log_dir,
188 tar_file_path,
189 compressed_output_path,
190 callback));
191 }
192
193 void IntializeLogFile(base::File* file,
194 const base::FilePath& file_path,
195 uint32 flags) {
196 base::FilePath dir = file_path.DirName();
197 if (!base::DirectoryExists(dir)) {
198 if (!base::CreateDirectory(dir)) {
199 LOG(ERROR) << "Can not create " << dir.value();
200 return;
201 }
202 }
203
204 file->Initialize(file_path, flags);
205 }
206
207 // Starts logs retrieval process. The output will be stored in file with name
208 // derived from |file_name_template|.
209 void StartLogRetrieval(const base::FilePath& file_name_template,
210 bool should_compress,
211 const std::string& sequence_token_name,
212 const DebugLogWriter::StoreLogsCallback& callback) {
213 base::FilePath file_path =
214 logging::GenerateTimestampedName(file_name_template, base::Time::Now());
215
216 int flags = base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE;
217 base::File* file = new base::File;
218 GetSequencedTaskRunner(sequence_token_name)->PostTaskAndReply(
219 FROM_HERE,
220 base::Bind(&IntializeLogFile, base::Unretained(file), file_path, flags),
221 base::Bind(&WriteDebugLogToFile,
222 base::Owned(file),
223 sequence_token_name,
224 file_path,
225 should_compress,
226 callback));
227 }
228
229 const char kDefaultSequenceName[] = "DebugLogWriter";
230
231 } // namespace
232
233 // static.
234 void DebugLogWriter::StoreLogs(const base::FilePath& fileshelf,
235 bool should_compress,
236 const StoreLogsCallback& callback) {
237 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
238 DCHECK(!callback.is_null());
239
240 base::FilePath file_path =
241 fileshelf.Append(should_compress ? FILE_PATH_LITERAL("debug-logs.tgz")
242 : FILE_PATH_LITERAL("debug-logs.tar"));
243
244 StartLogRetrieval(file_path, should_compress, kDefaultSequenceName, callback);
245 }
246
247 // static.
248 void DebugLogWriter::StoreCombinedLogs(const base::FilePath& fileshelf,
249 const std::string& sequence_token_name,
250 const StoreLogsCallback& callback) {
251 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
252 DCHECK(!callback.is_null());
253
254 base::FilePath file_path =
255 fileshelf.Append(FILE_PATH_LITERAL("combined-logs.tar"));
256
257 // Get system logs from /var/log first, then add user-specific stuff.
258 StartLogRetrieval(file_path,
259 false,
260 sequence_token_name,
261 base::Bind(&OnSystemLogsAdded, callback));
262 }
263
264 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698