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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/system/syslogs_provider.cc
diff --git a/chrome/browser/chromeos/system/syslogs_provider.cc b/chrome/browser/chromeos/system/syslogs_provider.cc
new file mode 100644
index 0000000000000000000000000000000000000000..57c76cfeb9dd5cdb4dce8cc5ca775b1d8d1059bf
--- /dev/null
+++ b/chrome/browser/chromeos/system/syslogs_provider.cc
@@ -0,0 +1,302 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/system/syslogs_provider.h"
+
+#include "base/command_line.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/string_util.h"
+#include "chrome/common/chrome_switches.h"
+#include "content/browser/browser_thread.h"
+
+namespace chromeos {
+namespace system {
+namespace {
+
+const char kSysLogsScript[] =
+ "/usr/share/userfeedback/scripts/sysinfo_script_runner";
+const char kBzip2Command[] =
+ "/bin/bzip2";
+const char kMultilineQuote[] = "\"\"\"";
+const char kNewLineChars[] = "\r\n";
+const char kInvalidLogEntry[] = "<invalid characters in log entry>";
+const char kEmptyLogEntry[] = "<no value>";
+
+const char kContextFeedback[] = "feedback";
+const char kContextSysInfo[] = "sysinfo";
+const char kContextNetwork[] = "network";
+
+// Reads a key from the input string erasing the read values + delimiters read
+// from the initial string
+std::string ReadKey(std::string* data) {
+ size_t equal_sign = data->find("=");
+ if (equal_sign == std::string::npos)
+ return std::string("");
+ std::string key = data->substr(0, equal_sign);
+ data->erase(0, equal_sign);
+ if (data->size() > 0) {
+ // erase the equal to sign also
+ data->erase(0,1);
+ return key;
+ }
+ return std::string();
+}
+
+// Reads a value from the input string; erasing the read values from
+// the initial string; detects if the value is multiline and reads
+// accordingly
+std::string ReadValue(std::string* data) {
+ // Trim the leading spaces and tabs. In order to use a multi-line
+ // value, you have to place the multi-line quote on the same line as
+ // the equal sign.
+ //
+ // Why not use TrimWhitespace? Consider the following input:
+ //
+ // KEY1=
+ // KEY2=VALUE
+ //
+ // If we use TrimWhitespace, we will incorrectly trim the new line
+ // and assume that KEY1's value is "KEY2=VALUE" rather than empty.
+ TrimString(*data, " \t", data);
+
+ // If multiline value
+ if (StartsWithASCII(*data, std::string(kMultilineQuote), false)) {
+ data->erase(0, strlen(kMultilineQuote));
+ size_t next_multi = data->find(kMultilineQuote);
+ if (next_multi == std::string::npos) {
+ // Error condition, clear data to stop further processing
+ data->erase();
+ return std::string();
+ }
+ std::string value = data->substr(0, next_multi);
+ data->erase(0, next_multi + 3);
+ return value;
+ } else { // single line value
+ size_t endl_pos = data->find_first_of(kNewLineChars);
+ // if we don't find a new line, we just return the rest of the data
+ std::string value = data->substr(0, endl_pos);
+ data->erase(0, endl_pos);
+ return value;
+ }
+}
+
+// Returns a map of system log keys and values.
+//
+// Parameters:
+// temp_filename: This is an out parameter that holds the name of a file in
+// Reads a value from the input string; erasing the read values from
+// the initial string; detects if the value is multiline and reads
+// accordingly
+// /tmp that contains the system logs in a KEY=VALUE format.
+// If this parameter is NULL, system logs are not retained on
+// the filesystem after this call completes.
+// context: This is an in parameter specifying what context should be
+// passed to the syslog collection script; currently valid
+// values are "sysinfo" or "feedback"; in case of an invalid
+// value, the script will currently default to "sysinfo"
+
+LogDictionaryType* GetSystemLogs(FilePath* zip_file_name,
+ const std::string& context) {
+ // Create the temp file, logs will go here
+ FilePath temp_filename;
+
+ if (!file_util::CreateTemporaryFile(&temp_filename))
+ return NULL;
+
+ std::string cmd = std::string(kSysLogsScript) + " " + context + " >> " +
+ temp_filename.value();
+
+ // Ignore the return value - if the script execution didn't work
+ // stderr won't go into the output file anyway.
+ if (::system(cmd.c_str()) == -1)
+ LOG(WARNING) << "Command " << cmd << " failed to run";
+
+ // Compress the logs file if requested.
+ if (zip_file_name) {
+ cmd = std::string(kBzip2Command) + " -c " + temp_filename.value() + " > " +
+ zip_file_name->value();
+ if (::system(cmd.c_str()) == -1)
+ LOG(WARNING) << "Command " << cmd << " failed to run";
+ }
+ // Read logs from the temp file
+ std::string data;
+ bool read_success = file_util::ReadFileToString(temp_filename,
+ &data);
+ // if we were using an internal temp file, the user does not need the
+ // logs to stay past the ReadFile call - delete the file
+ file_util::Delete(temp_filename, false);
+
+ if (!read_success)
+ return NULL;
+
+ // Parse the return data into a dictionary
+ LogDictionaryType* logs = new LogDictionaryType();
+ while (data.length() > 0) {
+ std::string key = ReadKey(&data);
+ TrimWhitespaceASCII(key, TRIM_ALL, &key);
+ if (!key.empty()) {
+ std::string value = ReadValue(&data);
+ if (IsStringUTF8(value)) {
+ TrimWhitespaceASCII(value, TRIM_ALL, &value);
+ if (value.empty())
+ (*logs)[key] = kEmptyLogEntry;
+ else
+ (*logs)[key] = value;
+ } else {
+ LOG(WARNING) << "Invalid characters in system log entry: " << key;
+ (*logs)[key] = kInvalidLogEntry;
+ }
+ } else {
+ // no more keys, we're done
+ break;
+ }
+ }
+
+ return logs;
+}
+
+} // namespace
+
+class SyslogsProviderImpl : public SyslogsProvider {
+ public:
+ // SyslogsProvider implementation:
+ virtual Handle RequestSyslogs(
+ bool compress_logs,
+ SyslogsContext context,
+ CancelableRequestConsumerBase* consumer,
+ ReadCompleteCallback* callback);
+
+ // Reads system logs, compresses content if requested.
+ // Called from FILE thread.
+ void ReadSyslogs(
+ scoped_refptr<CancelableRequest<ReadCompleteCallback> > request,
+ bool compress_logs,
+ SyslogsContext context);
+
+ // Loads compressed logs and writes into |zip_content|.
+ void LoadCompressedLogs(const FilePath& zip_file,
+ std::string* zip_content);
+
+ static SyslogsProviderImpl* GetInstance();
+
+ private:
+ friend struct DefaultSingletonTraits<SyslogsProviderImpl>;
+
+ SyslogsProviderImpl();
+
+ // Gets syslogs context string from the enum value.
+ const char* GetSyslogsContextString(SyslogsContext context);
+
+ DISALLOW_COPY_AND_ASSIGN(SyslogsProviderImpl);
+};
+
+SyslogsProviderImpl::SyslogsProviderImpl() {
+}
+
+CancelableRequestProvider::Handle SyslogsProviderImpl::RequestSyslogs(
+ bool compress_logs,
+ SyslogsContext context,
+ CancelableRequestConsumerBase* consumer,
+ ReadCompleteCallback* callback) {
+ // Register the callback request.
+ scoped_refptr<CancelableRequest<ReadCompleteCallback> > request(
+ new CancelableRequest<ReadCompleteCallback>(callback));
+ AddRequest(request, consumer);
+
+ // Schedule a task on the FILE thread which will then trigger a request
+ // callback on the calling thread (e.g. UI) when complete.
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ this, &SyslogsProviderImpl::ReadSyslogs, request,
+ compress_logs, context));
+
+ return request->handle();
+}
+
+// Called from FILE thread.
+void SyslogsProviderImpl::ReadSyslogs(
+ scoped_refptr<CancelableRequest<ReadCompleteCallback> > request,
+ bool compress_logs,
+ SyslogsContext context) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ if (request->canceled())
+ return;
+
+ if (compress_logs && !CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kCompressSystemFeedback))
+ compress_logs = false;
+
+ // Create temp file.
+ FilePath zip_file;
+ if (compress_logs && !file_util::CreateTemporaryFile(&zip_file)) {
+ LOG(ERROR) << "Cannot create temp file";
+ compress_logs = false;
+ }
+
+ LogDictionaryType* logs = NULL;
+ logs = GetSystemLogs(
+ compress_logs ? &zip_file : NULL,
+ GetSyslogsContextString(context));
+
+ std::string* zip_content = NULL;
+ if (compress_logs) {
+ // Load compressed logs.
+ zip_content = new std::string();
+ LoadCompressedLogs(zip_file, zip_content);
+ file_util::Delete(zip_file, false);
+ }
+
+ // Will call the callback on the calling thread.
+ request->ForwardResult(Tuple2<LogDictionaryType*,
+ std::string*>(logs, zip_content));
+}
+
+
+void SyslogsProviderImpl::LoadCompressedLogs(const FilePath& zip_file,
+ std::string* zip_content) {
+ DCHECK(zip_content);
+ if (!file_util::ReadFileToString(zip_file, zip_content)) {
+ LOG(ERROR) << "Cannot read compressed logs file from " <<
+ zip_file.value().c_str();
+ }
+}
+
+const char* SyslogsProviderImpl::GetSyslogsContextString(
+ SyslogsContext context) {
+ switch (context) {
+ case(SYSLOGS_FEEDBACK):
+ return kContextFeedback;
+ case(SYSLOGS_SYSINFO):
+ return kContextSysInfo;
+ case(SYSLOGS_NETWORK):
+ return kContextNetwork;
+ case(SYSLOGS_DEFAULT):
+ return kContextSysInfo;
+ default:
+ NOTREACHED();
+ return "";
+ }
+}
+
+SyslogsProviderImpl* SyslogsProviderImpl::GetInstance() {
+ return Singleton<SyslogsProviderImpl,
+ DefaultSingletonTraits<SyslogsProviderImpl> >::get();
+}
+
+SyslogsProvider* SyslogsProvider::GetInstance() {
+ return SyslogsProviderImpl::GetInstance();
+}
+
+} // namespace system
+} // namespace chromeos
+
+// Allows InvokeLater without adding refcounting. SyslogsProviderImpl is a
+// Singleton and won't be deleted until it's last InvokeLater is run.
+DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::system::SyslogsProviderImpl);
« 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