This source file includes following definitions.
- ReadKey
- ReadValue
- GetSystemLogs
- RequestSyslogs
- zip_content_
- OnDetailsAvailable
- ReadSyslogs
- LoadCompressedLogs
- GetSyslogsContextString
- RunCallbackIfNotCanceled
- GetInstance
- GetInstance
#include "chrome/browser/chromeos/system/syslogs_provider.h"
#include "ash/shell.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/strings/string_util.h"
#include "base/task_runner.h"
#include "base/threading/sequenced_worker_pool.h"
#include "chrome/browser/feedback/feedback_util.h"
#include "chrome/browser/memory_details.h"
#include "chrome/common/chrome_switches.h"
#include "chromeos/network/network_event_log.h"
#include "content/public/browser/browser_thread.h"
#include "dbus/dbus_statistics.h"
using content::BrowserThread;
namespace chromeos {
namespace system {
const size_t kFeedbackMaxLength = 4 * 1024;
const size_t kFeedbackMaxLineCount = 40;
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";
std::string ReadKey(std::string* data) {
std::string key;
size_t equal_sign = data->find("=");
if (equal_sign == std::string::npos)
return key;
key = data->substr(0, equal_sign);
data->erase(0, equal_sign);
if (data->empty())
return key;
data->erase(0, 1);
return key;
}
std::string ReadValue(std::string* data) {
base::TrimString(*data, " \t", data);
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) {
data->erase();
return std::string();
}
std::string value = data->substr(0, next_multi);
data->erase(0, next_multi + 3);
return value;
} else {
size_t endl_pos = data->find_first_of(kNewLineChars);
std::string value = data->substr(0, endl_pos);
data->erase(0, endl_pos);
return value;
}
}
LogDictionaryType* GetSystemLogs(base::FilePath* zip_file_name,
const std::string& context) {
base::FilePath temp_filename;
if (!base::CreateTemporaryFile(&temp_filename))
return NULL;
std::string cmd = std::string(kSysLogsScript) + " " + context + " >> " +
temp_filename.value();
if (::system(cmd.c_str()) == -1)
LOG(WARNING) << "Command " << cmd << " failed to run";
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";
}
std::string data;
bool read_success = base::ReadFileToString(temp_filename, &data);
base::DeleteFile(temp_filename, false);
if (!read_success)
return NULL;
LogDictionaryType* logs = new LogDictionaryType();
while (data.length() > 0) {
std::string key = ReadKey(&data);
base::TrimWhitespaceASCII(key, base::TRIM_ALL, &key);
if (!key.empty()) {
std::string value = ReadValue(&data);
if (IsStringUTF8(value)) {
base::TrimWhitespaceASCII(value, base::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 {
break;
}
}
return logs;
}
}
class SyslogsProviderImpl : public SyslogsProvider {
public:
virtual base::CancelableTaskTracker::TaskId RequestSyslogs(
bool compress_logs,
SyslogsContext context,
const ReadCompleteCallback& callback,
base::CancelableTaskTracker* tracker) OVERRIDE;
static SyslogsProviderImpl* GetInstance();
private:
friend struct DefaultSingletonTraits<SyslogsProviderImpl>;
void ReadSyslogs(
const base::CancelableTaskTracker::IsCanceledCallback& is_canceled,
bool compress_logs,
SyslogsContext context,
const ReadCompleteCallback& callback);
void LoadCompressedLogs(const base::FilePath& zip_file,
std::string* zip_content);
SyslogsProviderImpl();
const char* GetSyslogsContextString(SyslogsContext context);
static void RunCallbackIfNotCanceled(
const base::CancelableTaskTracker::IsCanceledCallback& is_canceled,
base::TaskRunner* origin_runner,
const ReadCompleteCallback& callback,
LogDictionaryType* logs,
std::string* zip_content);
DISALLOW_COPY_AND_ASSIGN(SyslogsProviderImpl);
};
SyslogsProviderImpl::SyslogsProviderImpl() {
}
base::CancelableTaskTracker::TaskId SyslogsProviderImpl::RequestSyslogs(
bool compress_logs,
SyslogsContext context,
const ReadCompleteCallback& callback,
base::CancelableTaskTracker* tracker) {
base::CancelableTaskTracker::IsCanceledCallback is_canceled;
base::CancelableTaskTracker::TaskId id =
tracker->NewTrackedTaskId(&is_canceled);
ReadCompleteCallback callback_runner =
base::Bind(&SyslogsProviderImpl::RunCallbackIfNotCanceled,
is_canceled, base::MessageLoopProxy::current(), callback);
BrowserThread::PostBlockingPoolTask(
FROM_HERE,
base::Bind(&SyslogsProviderImpl::ReadSyslogs, base::Unretained(this),
is_canceled, compress_logs, context, callback_runner));
return id;
}
class SyslogsMemoryHandler : public MemoryDetails {
public:
typedef SyslogsProvider::ReadCompleteCallback ReadCompleteCallback;
SyslogsMemoryHandler(const ReadCompleteCallback& callback,
LogDictionaryType* logs,
std::string* zip_content);
virtual void OnDetailsAvailable() OVERRIDE;
private:
virtual ~SyslogsMemoryHandler();
ReadCompleteCallback callback_;
LogDictionaryType* logs_;
std::string* zip_content_;
DISALLOW_COPY_AND_ASSIGN(SyslogsMemoryHandler);
};
SyslogsMemoryHandler::SyslogsMemoryHandler(
const ReadCompleteCallback& callback,
LogDictionaryType* logs,
std::string* zip_content)
: callback_(callback),
logs_(logs),
zip_content_(zip_content) {
DCHECK(!callback_.is_null());
}
void SyslogsMemoryHandler::OnDetailsAvailable() {
(*logs_)["mem_usage"] = ToLogString();
callback_.Run(logs_, zip_content_);
}
SyslogsMemoryHandler::~SyslogsMemoryHandler() {}
void SyslogsProviderImpl::ReadSyslogs(
const base::CancelableTaskTracker::IsCanceledCallback& is_canceled,
bool compress_logs,
SyslogsContext context,
const ReadCompleteCallback& callback) {
DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
if (is_canceled.Run())
return;
base::FilePath zip_file;
if (compress_logs && !base::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) {
zip_content = new std::string();
LoadCompressedLogs(zip_file, zip_content);
base::DeleteFile(zip_file, false);
}
(*logs)["dbus"] = dbus::statistics::GetAsString(
dbus::statistics::SHOW_INTERFACE,
dbus::statistics::FORMAT_ALL);
(*logs)["network_event_log"] = network_event_log::GetAsString(
network_event_log::OLDEST_FIRST,
"time,file,desc",
network_event_log::kDefaultLogLevel,
system::kFeedbackMaxLineCount);
scoped_refptr<SyslogsMemoryHandler>
handler(new SyslogsMemoryHandler(callback, logs, zip_content));
handler->StartFetch(MemoryDetails::UPDATE_USER_METRICS);
}
void SyslogsProviderImpl::LoadCompressedLogs(const base::FilePath& zip_file,
std::string* zip_content) {
DCHECK(zip_content);
if (!base::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 "";
}
}
void SyslogsProviderImpl::RunCallbackIfNotCanceled(
const base::CancelableTaskTracker::IsCanceledCallback& is_canceled,
base::TaskRunner* origin_runner,
const ReadCompleteCallback& callback,
LogDictionaryType* logs,
std::string* zip_content) {
DCHECK(!is_canceled.is_null() && !callback.is_null());
if (is_canceled.Run()) {
delete logs;
delete zip_content;
return;
}
if (origin_runner->RunsTasksOnCurrentThread()) {
callback.Run(logs, zip_content);
} else {
origin_runner->PostTask(FROM_HERE, base::Bind(callback, logs, zip_content));
}
}
SyslogsProviderImpl* SyslogsProviderImpl::GetInstance() {
return Singleton<SyslogsProviderImpl,
DefaultSingletonTraits<SyslogsProviderImpl> >::get();
}
SyslogsProvider* SyslogsProvider::GetInstance() {
return SyslogsProviderImpl::GetInstance();
}
}
}