Commit 4663663d authored by Sergei Datsenko's avatar Sergei Datsenko Committed by Commit Bot

Present drivefs logs on drive-internals page.

BUG=chromium:856874

Change-Id: I9e7e9645d120b27868618053cffd5953908b99b1
Reviewed-on: https://chromium-review.googlesource.com/1184801Reviewed-by: default avatarLuciano Pacheco <lucmult@chromium.org>
Reviewed-by: default avatarSam McNally <sammc@chromium.org>
Commit-Queue: Sergei Datsenko <dats@chromium.org>
Cr-Commit-Position: refs/heads/master@{#585718}
parent 44f72ec6
...@@ -559,6 +559,13 @@ base::FilePath DriveIntegrationService::GetMountPointPath() const { ...@@ -559,6 +559,13 @@ base::FilePath DriveIntegrationService::GetMountPointPath() const {
: drive::util::GetDriveMountPointPath(profile_); : drive::util::GetDriveMountPointPath(profile_);
} }
base::FilePath DriveIntegrationService::GetDriveFsLogPath() const {
return drivefs_holder_
? drivefs_holder_->drivefs_host()->GetDataPath().Append(
"Logs/drivefs.txt")
: base::FilePath();
}
bool DriveIntegrationService::GetRelativeDrivePath( bool DriveIntegrationService::GetRelativeDrivePath(
const base::FilePath& local_path, const base::FilePath& local_path,
base::FilePath* drive_path) const { base::FilePath* drive_path) const {
......
...@@ -115,6 +115,9 @@ class DriveIntegrationService : public KeyedService, ...@@ -115,6 +115,9 @@ class DriveIntegrationService : public KeyedService,
// |IsMounted()|. // |IsMounted()|.
base::FilePath GetMountPointPath() const; base::FilePath GetMountPointPath() const;
// Returns the path of DriveFS log if enabled or empty path.
base::FilePath GetDriveFsLogPath() const;
// Returns true if |local_path| resides inside |GetMountPointPath()|. // Returns true if |local_path| resides inside |GetMountPointPath()|.
// In this case |drive_path| will contain 'drive' path of this file, e.g. // In this case |drive_path| will contain 'drive' path of this file, e.g.
// reparented to the mount point. // reparented to the mount point.
......
...@@ -142,5 +142,9 @@ ...@@ -142,5 +142,9 @@
<h2 id="event-log-section">Event Log</h2> <h2 id="event-log-section">Event Log</h2>
<ul id="event-log"> <ul id="event-log">
</ul> </ul>
<h2 id="service-log-section">Service Log</h2>
<ul id="service-log">
</ul>
</body> </body>
</html> </html>
...@@ -221,6 +221,15 @@ function updateEventLog(log) { ...@@ -221,6 +221,15 @@ function updateEventLog(log) {
updateKeyValueList(ul, log); updateKeyValueList(ul, log);
} }
/**
* Updates the service log section.
* @param {Array} log Log lines.
*/
function updateServiceLog(log) {
var ul = $('service-log');
updateKeyValueList(ul, log);
}
/** /**
* Creates an element named |elementName| containing the content |text|. * Creates an element named |elementName| containing the content |text|.
* @param {string} elementName Name of the new element to be created. * @param {string} elementName Name of the new element to be created.
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <fstream>
#include <memory> #include <memory>
#include <utility> #include <utility>
...@@ -17,6 +18,8 @@ ...@@ -17,6 +18,8 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "base/strings/pattern.h"
#include "base/strings/strcat.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/sys_info.h" #include "base/sys_info.h"
#include "base/task/post_task.h" #include "base/task/post_task.h"
...@@ -52,6 +55,32 @@ namespace chromeos { ...@@ -52,6 +55,32 @@ namespace chromeos {
namespace { namespace {
constexpr char kKey[] = "key";
constexpr char kValue[] = "value";
constexpr char kClass[] = "class";
constexpr const char* const kLogLevelName[] = {"info", "warning", "error"};
size_t SeverityToLogLevelNameIndex(logging::LogSeverity severity) {
if (severity <= logging::LOG_INFO)
return 0;
if (severity == logging::LOG_WARNING)
return 1;
return 2;
}
size_t LogMarkToLogLevelNameIndex(char mark) {
switch (mark) {
case 'I':
case 'V':
return 0;
case 'W':
return 1;
default:
return 2;
}
}
// Gets metadata of all files and directories in |root_path| // Gets metadata of all files and directories in |root_path|
// recursively. Stores the result as a list of dictionaries like: // recursively. Stores the result as a list of dictionaries like:
// //
...@@ -189,27 +218,73 @@ std::string FormatEntry(const base::FilePath& path, ...@@ -189,27 +218,73 @@ std::string FormatEntry(const base::FilePath& path,
return out; return out;
} }
std::string SeverityToString(logging::LogSeverity severity) { // Appends {'key': key, 'value': value, 'class': clazz} dictionary to the
switch (severity) { // |list|.
case logging::LOG_INFO:
return "info";
case logging::LOG_WARNING:
return "warning";
case logging::LOG_ERROR:
return "error";
default: // Treat all other higher severities as ERROR.
return "error";
}
}
// Appends {'key': key, 'value': value} dictionary to the |list|.
void AppendKeyValue(base::ListValue* list, void AppendKeyValue(base::ListValue* list,
const std::string& key, std::string key,
const std::string& value) { std::string value,
std::string clazz = std::string()) {
auto dict = std::make_unique<base::DictionaryValue>(); auto dict = std::make_unique<base::DictionaryValue>();
dict->SetString("key", key); dict->SetPath({kKey}, base::Value(std::move(key)));
dict->SetString("value", value); dict->SetPath({kValue}, base::Value(std::move(value)));
list->Append(std::move(dict)); if (!clazz.empty())
dict->SetPath({kClass}, base::Value(std::move(clazz)));
list->GetList().push_back(std::move(*dict));
}
ino_t GetInodeValue(const base::FilePath& path) {
struct stat file_stats;
if (stat(path.value().c_str(), &file_stats) != 0)
return 0;
return file_stats.st_ino;
}
std::pair<ino_t, base::ListValue> GetServiceLogContents(
const base::FilePath& log_path,
ino_t inode,
int from_line_number) {
base::ListValue result;
std::ifstream log(log_path.value());
if (log.good()) {
ino_t new_inode = GetInodeValue(log_path);
if (new_inode != inode) {
// Apparently log was recreated. Re-read the log.
from_line_number = 0;
inode = new_inode;
}
base::Time time;
constexpr char kTimestampPattern[] = R"(????-??-??T??:??:??.???Z? )";
const size_t pattern_length = strlen(kTimestampPattern);
std::string line;
int line_number = 0;
while (log.good()) {
std::getline(log, line);
if (line.empty() || ++line_number <= from_line_number) {
continue;
}
base::StringPiece log_line = line;
size_t severity_index = 0;
if (base::MatchPattern(log_line.substr(0, pattern_length),
kTimestampPattern) &&
google_apis::util::GetTimeFromString(
log_line.substr(0, pattern_length - 2), &time)) {
severity_index = LogMarkToLogLevelNameIndex(line[pattern_length - 2]);
line = line.substr(pattern_length);
}
const char* const severity = kLogLevelName[severity_index];
AppendKeyValue(&result,
google_apis::util::FormatTimeAsStringLocaltime(time),
base::StrCat({"[", severity, "] ", line}),
base::StrCat({"log-", severity}));
}
}
return {inode, std::move(result)};
} }
// Class to handle messages from chrome://drive-internals. // Class to handle messages from chrome://drive-internals.
...@@ -255,6 +330,7 @@ class DriveInternalsWebUIHandler : public content::WebUIMessageHandler { ...@@ -255,6 +330,7 @@ class DriveInternalsWebUIHandler : public content::WebUIMessageHandler {
void UpdateCacheContentsSection( void UpdateCacheContentsSection(
drive::DebugInfoCollector* debug_info_collector); drive::DebugInfoCollector* debug_info_collector);
void UpdateEventLogSection(); void UpdateEventLogSection();
void UpdateServiceLogSection();
void UpdatePathConfigurationsSection(); void UpdatePathConfigurationsSection();
// Called when GetGCacheContents() is complete. // Called when GetGCacheContents() is complete.
...@@ -306,9 +382,21 @@ class DriveInternalsWebUIHandler : public content::WebUIMessageHandler { ...@@ -306,9 +382,21 @@ class DriveInternalsWebUIHandler : public content::WebUIMessageHandler {
// Called after file system reset for ResetDriveFileSystem is done. // Called after file system reset for ResetDriveFileSystem is done.
void ResetFinished(bool success); void ResetFinished(bool success);
// Called when service logs are read.
void OnServiceLogRead(std::pair<ino_t, base::ListValue>);
// The last event sent to the JavaScript side. // The last event sent to the JavaScript side.
int last_sent_event_id_; int last_sent_event_id_;
// The last line of service log sent to the JS side.
int last_sent_line_number_;
// The inode of the log file.
ino_t service_log_file_inode_;
// Service log file is being parsed.
bool service_log_file_is_processing_ = false;
base::WeakPtrFactory<DriveInternalsWebUIHandler> weak_ptr_factory_; base::WeakPtrFactory<DriveInternalsWebUIHandler> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(DriveInternalsWebUIHandler); DISALLOW_COPY_AND_ASSIGN(DriveInternalsWebUIHandler);
}; };
...@@ -461,6 +549,9 @@ void DriveInternalsWebUIHandler::OnPageLoaded(const base::ListValue* args) { ...@@ -461,6 +549,9 @@ void DriveInternalsWebUIHandler::OnPageLoaded(const base::ListValue* args) {
// and resent whole the logs to the page. // and resent whole the logs to the page.
last_sent_event_id_ = -1; last_sent_event_id_ = -1;
UpdateEventLogSection(); UpdateEventLogSection();
last_sent_line_number_ = 0;
service_log_file_inode_ = 0;
UpdateServiceLogSection();
} }
void DriveInternalsWebUIHandler::UpdateDriveRelatedPreferencesSection() { void DriveInternalsWebUIHandler::UpdateDriveRelatedPreferencesSection() {
...@@ -763,20 +854,54 @@ void DriveInternalsWebUIHandler::UpdateEventLogSection() { ...@@ -763,20 +854,54 @@ void DriveInternalsWebUIHandler::UpdateEventLogSection() {
if (log[i].id <= last_sent_event_id_) if (log[i].id <= last_sent_event_id_)
continue; continue;
std::string severity = SeverityToString(log[i].severity); const char* const severity =
kLogLevelName[SeverityToLogLevelNameIndex(log[i].severity)];
auto dict = std::make_unique<base::DictionaryValue>(); AppendKeyValue(&list,
dict->SetString("key", google_apis::util::FormatTimeAsStringLocaltime(log[i].when),
google_apis::util::FormatTimeAsStringLocaltime(log[i].when)); base::StrCat({"[", severity, "] ", log[i].what}),
dict->SetString("value", "[" + severity + "] " + log[i].what); base::StrCat({"log-", severity}));
dict->SetString("class", "log-" + severity);
list.Append(std::move(dict));
last_sent_event_id_ = log[i].id; last_sent_event_id_ = log[i].id;
} }
if (!list.empty()) if (!list.empty())
web_ui()->CallJavascriptFunctionUnsafe("updateEventLog", list); web_ui()->CallJavascriptFunctionUnsafe("updateEventLog", list);
} }
void DriveInternalsWebUIHandler::UpdateServiceLogSection() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (service_log_file_is_processing_)
return;
service_log_file_is_processing_ = true;
drive::DriveIntegrationService* integration_service = GetIntegrationService();
if (!integration_service)
return;
base::FilePath log_path = integration_service->GetDriveFsLogPath();
if (log_path.empty())
return;
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
base::BindOnce(&GetServiceLogContents, log_path, service_log_file_inode_,
last_sent_line_number_),
base::BindOnce(&DriveInternalsWebUIHandler::OnServiceLogRead,
weak_ptr_factory_.GetWeakPtr()));
}
void DriveInternalsWebUIHandler::OnServiceLogRead(
std::pair<ino_t, base::ListValue> response) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (service_log_file_inode_ != response.first) {
service_log_file_inode_ = response.first;
last_sent_line_number_ = 0;
}
if (!response.second.empty()) {
web_ui()->CallJavascriptFunctionUnsafe("updateServiceLog", response.second);
last_sent_line_number_ += response.second.GetList().size();
}
service_log_file_is_processing_ = false;
}
void DriveInternalsWebUIHandler::UpdatePathConfigurationsSection() { void DriveInternalsWebUIHandler::UpdatePathConfigurationsSection() {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
...@@ -901,6 +1026,7 @@ void DriveInternalsWebUIHandler::OnPeriodicUpdate(const base::ListValue* args) { ...@@ -901,6 +1026,7 @@ void DriveInternalsWebUIHandler::OnPeriodicUpdate(const base::ListValue* args) {
return; return;
UpdateEventLogSection(); UpdateEventLogSection();
UpdateServiceLogSection();
drive::JobListInterface* job_list = integration_service->job_list(); drive::JobListInterface* job_list = integration_service->job_list();
if (job_list) { if (job_list) {
......
...@@ -79,10 +79,8 @@ class DriveFsHost::MountState : public mojom::DriveFsDelegate, ...@@ -79,10 +79,8 @@ class DriveFsHost::MountState : public mojom::DriveFsDelegate,
pending_token_(base::UnguessableToken::Create()), pending_token_(base::UnguessableToken::Create()),
binding_(this) { binding_(this) {
source_path_ = base::StrCat({kMountScheme, pending_token_.ToString()}); source_path_ = base::StrCat({kMountScheme, pending_token_.ToString()});
std::string datadir_option = base::StrCat( std::string datadir_option =
{"datadir=", host_->profile_path_.Append(kDataPath) base::StrCat({"datadir=", host_->GetDataPath().value()});
.Append(host_->delegate_->GetObfuscatedAccountId())
.value()});
auto bootstrap = auto bootstrap =
mojo::MakeProxy(mojo_connection_delegate_->InitializeMojoConnection()); mojo::MakeProxy(mojo_connection_delegate_->InitializeMojoConnection());
mojom::DriveFsDelegatePtr delegate; mojom::DriveFsDelegatePtr delegate;
...@@ -365,6 +363,11 @@ const base::FilePath& DriveFsHost::GetMountPath() const { ...@@ -365,6 +363,11 @@ const base::FilePath& DriveFsHost::GetMountPath() const {
return mount_state_->mount_path(); return mount_state_->mount_path();
} }
base::FilePath DriveFsHost::GetDataPath() const {
return profile_path_.Append(kDataPath).Append(
delegate_->GetObfuscatedAccountId());
}
mojom::DriveFs* DriveFsHost::GetDriveFsInterface() const { mojom::DriveFs* DriveFsHost::GetDriveFsInterface() const {
if (!mount_state_ || !mount_state_->mounted()) { if (!mount_state_ || !mount_state_->mounted()) {
return nullptr; return nullptr;
......
...@@ -100,6 +100,9 @@ class COMPONENT_EXPORT(DRIVEFS) DriveFsHost ...@@ -100,6 +100,9 @@ class COMPONENT_EXPORT(DRIVEFS) DriveFsHost
// |IsMounted()| returns true. // |IsMounted()| returns true.
const base::FilePath& GetMountPath() const; const base::FilePath& GetMountPath() const;
// Returns the path where DriveFS keeps its data and caches.
base::FilePath GetDataPath() const;
mojom::DriveFs* GetDriveFsInterface() const; mojom::DriveFs* GetDriveFsInterface() const;
private: private:
......
...@@ -372,6 +372,9 @@ class DriveFsHostTest : public ::testing::Test, public mojom::DriveFsBootstrap { ...@@ -372,6 +372,9 @@ class DriveFsHostTest : public ::testing::Test, public mojom::DriveFsBootstrap {
TEST_F(DriveFsHostTest, Basic) { TEST_F(DriveFsHostTest, Basic) {
EXPECT_FALSE(host_->IsMounted()); EXPECT_FALSE(host_->IsMounted());
EXPECT_EQ(base::FilePath("/path/to/profile/GCache/v2/salt-g-ID"),
host_->GetDataPath());
ASSERT_NO_FATAL_FAILURE(DoMount()); ASSERT_NO_FATAL_FAILURE(DoMount());
EXPECT_EQ(base::FilePath("/media/drivefsroot/salt-g-ID"), EXPECT_EQ(base::FilePath("/media/drivefsroot/salt-g-ID"),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment