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

Side by Side Diff: chrome/browser/chromeos/system/syslogs_provider.cc

Issue 7324017: Split SystemAccess into TimezoneSettings, StatisticsProvider, and SyslogsProvider. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: address comments Created 9 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 | Annotate | Revision Log
OLDNEW
(Empty)
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 "chrome/browser/chromeos/system/syslogs_provider.h"
6
7 #include "base/command_line.h"
8 #include "base/file_path.h"
9 #include "base/file_util.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/memory/singleton.h"
13 #include "base/string_util.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "content/browser/browser_thread.h"
16
17 namespace chromeos {
18 namespace system {
19 namespace {
20
21 const char kSysLogsScript[] =
22 "/usr/share/userfeedback/scripts/sysinfo_script_runner";
23 const char kBzip2Command[] =
24 "/bin/bzip2";
25 const char kMultilineQuote[] = "\"\"\"";
26 const char kNewLineChars[] = "\r\n";
27 const char kInvalidLogEntry[] = "<invalid characters in log entry>";
28 const char kEmptyLogEntry[] = "<no value>";
29
30 const char kContextFeedback[] = "feedback";
31 const char kContextSysInfo[] = "sysinfo";
32 const char kContextNetwork[] = "network";
33
34 // Reads a key from the input string erasing the read values + delimiters read
35 // from the initial string
36 std::string ReadKey(std::string* data) {
37 size_t equal_sign = data->find("=");
38 if (equal_sign == std::string::npos)
39 return std::string("");
40 std::string key = data->substr(0, equal_sign);
41 data->erase(0, equal_sign);
42 if (data->size() > 0) {
43 // erase the equal to sign also
44 data->erase(0,1);
45 return key;
46 }
47 return std::string();
48 }
49
50 // Reads a value from the input string; erasing the read values from
51 // the initial string; detects if the value is multiline and reads
52 // accordingly
53 std::string ReadValue(std::string* data) {
54 // Trim the leading spaces and tabs. In order to use a multi-line
55 // value, you have to place the multi-line quote on the same line as
56 // the equal sign.
57 //
58 // Why not use TrimWhitespace? Consider the following input:
59 //
60 // KEY1=
61 // KEY2=VALUE
62 //
63 // If we use TrimWhitespace, we will incorrectly trim the new line
64 // and assume that KEY1's value is "KEY2=VALUE" rather than empty.
65 TrimString(*data, " \t", data);
66
67 // If multiline value
68 if (StartsWithASCII(*data, std::string(kMultilineQuote), false)) {
69 data->erase(0, strlen(kMultilineQuote));
70 size_t next_multi = data->find(kMultilineQuote);
71 if (next_multi == std::string::npos) {
72 // Error condition, clear data to stop further processing
73 data->erase();
74 return std::string();
75 }
76 std::string value = data->substr(0, next_multi);
77 data->erase(0, next_multi + 3);
78 return value;
79 } else { // single line value
80 size_t endl_pos = data->find_first_of(kNewLineChars);
81 // if we don't find a new line, we just return the rest of the data
82 std::string value = data->substr(0, endl_pos);
83 data->erase(0, endl_pos);
84 return value;
85 }
86 }
87
88 // Returns a map of system log keys and values.
89 //
90 // Parameters:
91 // temp_filename: This is an out parameter that holds the name of a file in
92 // Reads a value from the input string; erasing the read values from
93 // the initial string; detects if the value is multiline and reads
94 // accordingly
95 // /tmp that contains the system logs in a KEY=VALUE format.
96 // If this parameter is NULL, system logs are not retained on
97 // the filesystem after this call completes.
98 // context: This is an in parameter specifying what context should be
99 // passed to the syslog collection script; currently valid
100 // values are "sysinfo" or "feedback"; in case of an invalid
101 // value, the script will currently default to "sysinfo"
102
103 LogDictionaryType* GetSystemLogs(FilePath* zip_file_name,
104 const std::string& context) {
105 // Create the temp file, logs will go here
106 FilePath temp_filename;
107
108 if (!file_util::CreateTemporaryFile(&temp_filename))
109 return NULL;
110
111 std::string cmd = std::string(kSysLogsScript) + " " + context + " >> " +
112 temp_filename.value();
113
114 // Ignore the return value - if the script execution didn't work
115 // stderr won't go into the output file anyway.
116 if (::system(cmd.c_str()) == -1)
117 LOG(WARNING) << "Command " << cmd << " failed to run";
118
119 // Compress the logs file if requested.
120 if (zip_file_name) {
121 cmd = std::string(kBzip2Command) + " -c " + temp_filename.value() + " > " +
122 zip_file_name->value();
123 if (::system(cmd.c_str()) == -1)
124 LOG(WARNING) << "Command " << cmd << " failed to run";
125 }
126 // Read logs from the temp file
127 std::string data;
128 bool read_success = file_util::ReadFileToString(temp_filename,
129 &data);
130 // if we were using an internal temp file, the user does not need the
131 // logs to stay past the ReadFile call - delete the file
132 file_util::Delete(temp_filename, false);
133
134 if (!read_success)
135 return NULL;
136
137 // Parse the return data into a dictionary
138 LogDictionaryType* logs = new LogDictionaryType();
139 while (data.length() > 0) {
140 std::string key = ReadKey(&data);
141 TrimWhitespaceASCII(key, TRIM_ALL, &key);
142 if (!key.empty()) {
143 std::string value = ReadValue(&data);
144 if (IsStringUTF8(value)) {
145 TrimWhitespaceASCII(value, TRIM_ALL, &value);
146 if (value.empty())
147 (*logs)[key] = kEmptyLogEntry;
148 else
149 (*logs)[key] = value;
150 } else {
151 LOG(WARNING) << "Invalid characters in system log entry: " << key;
152 (*logs)[key] = kInvalidLogEntry;
153 }
154 } else {
155 // no more keys, we're done
156 break;
157 }
158 }
159
160 return logs;
161 }
162
163 } // namespace
164
165 class SyslogsProviderImpl : public SyslogsProvider {
166 public:
167 // SyslogsProvider implementation:
168 virtual Handle RequestSyslogs(
169 bool compress_logs,
170 SyslogsContext context,
171 CancelableRequestConsumerBase* consumer,
172 ReadCompleteCallback* callback);
173
174 // Reads system logs, compresses content if requested.
175 // Called from FILE thread.
176 void ReadSyslogs(
177 scoped_refptr<CancelableRequest<ReadCompleteCallback> > request,
178 bool compress_logs,
179 SyslogsContext context);
180
181 // Loads compressed logs and writes into |zip_content|.
182 void LoadCompressedLogs(const FilePath& zip_file,
183 std::string* zip_content);
184
185 static SyslogsProviderImpl* GetInstance();
186
187 private:
188 friend struct DefaultSingletonTraits<SyslogsProviderImpl>;
189
190 SyslogsProviderImpl();
191
192 // Gets syslogs context string from the enum value.
193 const char* GetSyslogsContextString(SyslogsContext context);
194
195 DISALLOW_COPY_AND_ASSIGN(SyslogsProviderImpl);
196 };
197
198 SyslogsProviderImpl::SyslogsProviderImpl() {
199 }
200
201 CancelableRequestProvider::Handle SyslogsProviderImpl::RequestSyslogs(
202 bool compress_logs,
203 SyslogsContext context,
204 CancelableRequestConsumerBase* consumer,
205 ReadCompleteCallback* callback) {
206 // Register the callback request.
207 scoped_refptr<CancelableRequest<ReadCompleteCallback> > request(
208 new CancelableRequest<ReadCompleteCallback>(callback));
209 AddRequest(request, consumer);
210
211 // Schedule a task on the FILE thread which will then trigger a request
212 // callback on the calling thread (e.g. UI) when complete.
213 BrowserThread::PostTask(
214 BrowserThread::FILE, FROM_HERE,
215 NewRunnableMethod(
216 this, &SyslogsProviderImpl::ReadSyslogs, request,
217 compress_logs, context));
218
219 return request->handle();
220 }
221
222 // Called from FILE thread.
223 void SyslogsProviderImpl::ReadSyslogs(
224 scoped_refptr<CancelableRequest<ReadCompleteCallback> > request,
225 bool compress_logs,
226 SyslogsContext context) {
227 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
228
229 if (request->canceled())
230 return;
231
232 if (compress_logs && !CommandLine::ForCurrentProcess()->HasSwitch(
233 switches::kCompressSystemFeedback))
234 compress_logs = false;
235
236 // Create temp file.
237 FilePath zip_file;
238 if (compress_logs && !file_util::CreateTemporaryFile(&zip_file)) {
239 LOG(ERROR) << "Cannot create temp file";
240 compress_logs = false;
241 }
242
243 LogDictionaryType* logs = NULL;
244 logs = GetSystemLogs(
245 compress_logs ? &zip_file : NULL,
246 GetSyslogsContextString(context));
247
248 std::string* zip_content = NULL;
249 if (compress_logs) {
250 // Load compressed logs.
251 zip_content = new std::string();
252 LoadCompressedLogs(zip_file, zip_content);
253 file_util::Delete(zip_file, false);
254 }
255
256 // Will call the callback on the calling thread.
257 request->ForwardResult(Tuple2<LogDictionaryType*,
258 std::string*>(logs, zip_content));
259 }
260
261
262 void SyslogsProviderImpl::LoadCompressedLogs(const FilePath& zip_file,
263 std::string* zip_content) {
264 DCHECK(zip_content);
265 if (!file_util::ReadFileToString(zip_file, zip_content)) {
266 LOG(ERROR) << "Cannot read compressed logs file from " <<
267 zip_file.value().c_str();
268 }
269 }
270
271 const char* SyslogsProviderImpl::GetSyslogsContextString(
272 SyslogsContext context) {
273 switch (context) {
274 case(SYSLOGS_FEEDBACK):
275 return kContextFeedback;
276 case(SYSLOGS_SYSINFO):
277 return kContextSysInfo;
278 case(SYSLOGS_NETWORK):
279 return kContextNetwork;
280 case(SYSLOGS_DEFAULT):
281 return kContextSysInfo;
282 default:
283 NOTREACHED();
284 return "";
285 }
286 }
287
288 SyslogsProviderImpl* SyslogsProviderImpl::GetInstance() {
289 return Singleton<SyslogsProviderImpl,
290 DefaultSingletonTraits<SyslogsProviderImpl> >::get();
291 }
292
293 SyslogsProvider* SyslogsProvider::GetInstance() {
294 return SyslogsProviderImpl::GetInstance();
295 }
296
297 } // namespace system
298 } // namespace chromeos
299
300 // Allows InvokeLater without adding refcounting. SyslogsProviderImpl is a
301 // Singleton and won't be deleted until it's last InvokeLater is run.
302 DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::system::SyslogsProviderImpl);
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/system/syslogs_provider.h ('k') | chrome/browser/chromeos/system/timezone_settings.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698