diff options
author | tbarzic@chromium.org <tbarzic@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-29 23:46:56 +0000 |
---|---|---|
committer | tbarzic@chromium.org <tbarzic@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-29 23:46:56 +0000 |
commit | cd6522da39348968884d53d2db709f48d8b7716b (patch) | |
tree | ff1cf75f41b21fb72af64a901bacb8541e4c4f90 /chrome | |
parent | 739cb54e6f2d9357d3af821edfdfcec133fc3534 (diff) | |
download | chromium_src-cd6522da39348968884d53d2db709f48d8b7716b.zip chromium_src-cd6522da39348968884d53d2db709f48d8b7716b.tar.gz chromium_src-cd6522da39348968884d53d2db709f48d8b7716b.tar.bz2 |
Added tab that shows filtered network realated ChromeOS system logs to net-internals ui
We are showing folowing logs:
** /var/log/messages [syslog] filtered for: flimflam, wpa_supplicant,
l2tpipsec_vpn, ipsec, xl2tpd, and pppd
** /var/log/ui/ui.LATEST [ui_log] filtered for: chromeos_network
** /var/log/chrome/chrome [chrome_system_log] filtered for: network_library
** /home/chronos/user/chrome [chrome_log] filtered for: network_library
BUG=chromium-os:15080
TEST=on ChromeOS go to chromeos://net-internals. In Logs tab make sure that
clicking Show button shows specified log, that Hide.. button hides it,
Show all.. shows all logs and hide all.. hides all logs. Clicking refresh
logs should refresh all shown logs.
Review URL: http://codereview.chromium.org/6990024
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@87210 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/resources/net_internals/index.html | 22 | ||||
-rw-r--r-- | chrome/browser/resources/net_internals/logsview.js | 176 | ||||
-rw-r--r-- | chrome/browser/resources/net_internals/main.css | 49 | ||||
-rw-r--r-- | chrome/browser/resources/net_internals/main.js | 29 | ||||
-rw-r--r-- | chrome/browser/ui/webui/net_internals_ui.cc | 190 |
5 files changed, 463 insertions, 3 deletions
diff --git a/chrome/browser/resources/net_internals/index.html b/chrome/browser/resources/net_internals/index.html index b79ea03..fc23e98 100644 --- a/chrome/browser/resources/net_internals/index.html +++ b/chrome/browser/resources/net_internals/index.html @@ -31,6 +31,7 @@ found in the LICENSE file. <script src="spdyview.js"></script> <script src="serviceprovidersview.js"></script> <script src="httpthrottlingview.js"></script> + <script src="logsview.js"></script> </head> <body onload="onLoaded()"> <!-- Tab switcher for main categories. --> @@ -48,6 +49,7 @@ found in the LICENSE file. <li><a href="#serviceProviders" id=serviceProvidersTab style="display: none;">SPIs</a></li> <li><a href="#tests" id=testTab>Tests</a></li> <li><a href="#hsts" id=hstsTab>HSTS</a></li> + <li><a href="#logs" id=logsTab style="display: none;">Logs</a></li> </ul> <div style="clear: both;"></div> </div> @@ -473,5 +475,25 @@ function displayHelpForBugDump() { </div> <div id=detailsLogBox></div> <div id=detailsTimelineBox></div> + + <!-- ============================ Logs View ============================ --> + <div id=logsTabContent style="display: none;"> + <h4>Network Log Data</h4> + <button id=logsGlobalShowBtn class=logsGlobalButton>Show all...</button> + <button id=logsGlobalHideBtn class=logsGlobalButton>Hide all...</button> + <button id=logsRefreshBtn class=logsGlobalButton>Refresh logs...</button> + <div style="clear: both"></div> + <table width=100% class=styledTable> + <thead> + <tr id=logTableHeaderRow> + <th width=10%>Log Name</th> + <th width=8%></th> + <th width=82%>Log</th> + </tr> + </thead> + <tbody id=logTable> + </tbody> + </table> + </div> </body> </html> diff --git a/chrome/browser/resources/net_internals/logsview.js b/chrome/browser/resources/net_internals/logsview.js new file mode 100644 index 0000000..032d4577 --- /dev/null +++ b/chrome/browser/resources/net_internals/logsview.js @@ -0,0 +1,176 @@ +// 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. + +/** + * This view displays network related log data and is specific fo ChromeOS. + * We get log data from chrome by filtering system logs for network related + * keywords. Logs are not fetched until we actually need them. + * + * @constructor + */ +function LogsView(mainBoxId, tableId, globalShowButtonId, globalHideButtonId, + refreshLogsButtonId) { + var tableDiv = document.getElementById(tableId); + this.rows = []; + this.PopulateTable(tableDiv, this.logFilterList); + document.getElementById(globalShowButtonId).addEventListener('click', + this.onGlobalChangeVisibleClick_.bind(this, true)); + document.getElementById(globalHideButtonId).addEventListener('click', + this.onGlobalChangeVisibleClick_.bind(this, false)); + document.getElementById(refreshLogsButtonId).addEventListener('click', + this.onLogsRefresh_.bind(this)); + DivView.call(this, mainBoxId); +}; + +inherits(LogsView, DivView); + +/** + * Contains log keys we are interested in. + */ +LogsView.prototype.logFilterList = [ + { + key:'syslog', + }, + { + key:'ui_log', + }, + { + key:'chrome_system_log', + }, + { + key:'chrome_log', + }, +]; + +/** + * Called during View's initialization. Creates the row of a table logs will be + * shown in. Each row has 4 cells. + * + * First cell's content will be set to |logKey|, second will contain a button + * that will be used to show or hide third cell, which will contain the filtered + * log. + * |logKey| also tells us which log we are getting data from. + */ +LogsView.prototype.CreateTableRow = function(logKey) { + var row = document.createElement('tr'); + + var cells = []; + for (var i = 0; i < 3; i++) { + var rowCell = document.createElement('td'); + cells.push(rowCell); + row.appendChild(rowCell); + } + // Log key cell. + cells[0].className = 'logCellText'; + cells[0].textContent = logKey; + // Cell log is displayed in. Log content is in div element that is initially + // hidden and empty. + cells[2].className = 'logCellText'; + var logDiv = document.createElement('div'); + logDiv.textContent = ''; + logDiv.className = 'logCellLog'; + logDiv.id = 'logsView.logCell.' + this.rows.length; + cells[2].appendChild(logDiv); + + // Button that we use to show or hide div element with log content. Logs are + // not visible initially, so we initialize button accordingly. + var expandButton = document.createElement('button'); + expandButton.textContent = 'Show...'; + expandButton.className = 'logButton'; + expandButton.addEventListener('click', + this.onButtonClicked_.bind(this, row)); + + // Cell that contains show/hide button. + cells[1].appendChild(expandButton); + cells[1].className = 'logTableButtonColumn'; + + // Initially, log is not visible. + row.className = 'logRowCollapsed'; + + // We will need those to process row buttons' onclick events. + row.logKey = logKey; + row.expandButton = expandButton; + row.logDiv = logDiv; + row.logVisible = false; + this.rows.push(row); + + return row; +}; + +/** + * Initializes |tableDiv| to represent data from |logList| which should be of + * type LogsView.logFilterList. + */ +LogsView.prototype.PopulateTable = function(tableDiv, logList) { + for (var i = 0; i < logList.length; i++) { + var logSource = this.CreateTableRow(logList[i].key); + tableDiv.appendChild(logSource); + } +}; + +/** + * Processes clicks on buttons that show or hide log contents in log row. + * Row containing the clicked button is given to the method since it contains + * all data we need to process the click (unlike button object itself). + */ +LogsView.prototype.onButtonClicked_ = function(containingRow) { + if (!containingRow.logVisible) { + containingRow.className = 'logRowExpanded'; + containingRow.expandButton.textContent = 'Hide...'; + var logDiv = containingRow.logDiv; + if (logDiv.textContent == '') { + logDiv.textContent = 'Getting logs...'; + // Callback will be executed by g_browser. + g_browser.getSystemLog(containingRow.logKey, + containingRow.logDiv.id); + } + } else { + containingRow.className = 'logRowCollapsed'; + containingRow.expandButton.textContent = 'Show...'; + } + containingRow.logVisible = !containingRow.logVisible; +}; + +/** + * Processes click on one of the buttons that are used to show or hide all logs + * we care about. + */ +LogsView.prototype.onGlobalChangeVisibleClick_ = function(isShowAll) { + for (var row in this.rows) { + if (isShowAll != this.rows[row].logVisible) { + this.onButtonClicked_(this.rows[row]); + } + } +}; + +/** + * Processes click event on the button we use to refresh fetched logs. we get + * the newest logs from libcros, and refresh content of the visible log cells. + */ +LogsView.prototype.onLogsRefresh_ = function() { + g_browser.refreshSystemLogs(); + + var visibleLogRows = []; + var hiddenLogRows = []; + for (var row in this.rows) { + if (this.rows[row].logVisible) { + visibleLogRows.push(this.rows[row]); + } else { + hiddenLogRows.push(this.rows[row]); + } + } + + // We have to refresh text content in visible rows. + for (row in visibleLogRows) { + visibleLogRows[row].logDiv.textContent = 'Getting logs...'; + g_browser.getSystemLog(visibleLogRows[row].logKey, + visibleLogRows[row].logDiv.id); + } + + // In hidden rows we just clear potential log text, so we know we have to get + // new contents when we show the row next time. + for (row in hiddenLogRows) { + hiddenLogRows[row].logDiv.textContent = ''; + } +}; diff --git a/chrome/browser/resources/net_internals/main.css b/chrome/browser/resources/net_internals/main.css index f7c575c..609a808 100644 --- a/chrome/browser/resources/net_internals/main.css +++ b/chrome/browser/resources/net_internals/main.css @@ -109,6 +109,55 @@ body { color: red; } +.logCellEmpty { + background-color: gray; +} + +.logCellText, .logCellLog { + background-color: white; +} + +.logRowCollapsed .logCellLog { + display: none; +} + +.logRowExpanded .logCellLog { + display: table-cell; +} + +.logTableButtonColumn { + text-align: center; +} + +.logButton { + width: 85px; +} + +.logsGlobalButton { + width: 135px; + float: left; + margin: 5px; + margin-top: 0; +} + +#logTable td { + padding: 0 5px; + padding-top: 3px; + vertical-align: top; + line-height: 17px; + font-family: 'Courier New', monospace; + white-space: pre; + font-size: 12px; +} + +#logTableHeaderRow th { + text-align: left; +} + +#logsTabContent { + padding: 5px; +} + .tabSwitcher { margin-top: 10px; margin-left: 10px; diff --git a/chrome/browser/resources/net_internals/main.js b/chrome/browser/resources/net_internals/main.js index 9f500df..cffcc4e 100644 --- a/chrome/browser/resources/net_internals/main.js +++ b/chrome/browser/resources/net_internals/main.js @@ -126,6 +126,15 @@ function onLoaded() { var httpThrottlingView = new HttpThrottlingView( 'httpThrottlingTabContent', 'enableHttpThrottlingCheckbox'); + var logsView; + if (g_browser.isChromeOS()) { + logsView = new LogsView('logsTabContent', + 'logTable', + 'logsGlobalShowBtn', + 'logsGlobalHideBtn', + 'logsRefreshBtn'); + } + // Create a view which lets you tab between the different sub-views. var categoryTabSwitcher = new TabSwitcherView('categoryTabHandles'); g_browser.setTabSwitcher(categoryTabSwitcher); @@ -143,6 +152,8 @@ function onLoaded() { categoryTabSwitcher.addTab('testTab', testView, false); categoryTabSwitcher.addTab('hstsTab', hstsView, false); categoryTabSwitcher.addTab('httpThrottlingTab', httpThrottlingView, false); + if (g_browser.isChromeOS()) + categoryTabSwitcher.addTab('logsTab', logsView, false); // Build a map from the anchor name of each tab handle to its "tab ID". // We will consider navigations to the #hash as a switch tab request. @@ -292,6 +303,10 @@ BrowserBridge.prototype.isPlatformWindows = function() { return /Win/.test(navigator.platform); }; +BrowserBridge.prototype.isChromeOS = function() { + return /CrOS/.test(navigator.userAgent); +}; + BrowserBridge.prototype.sendGetProxySettings = function() { // The browser will call receivedProxySettings on completion. chrome.send('getProxySettings'); @@ -383,7 +398,15 @@ BrowserBridge.prototype.enableHttpThrottling = function(enable) { BrowserBridge.prototype.loadLogFile = function() { chrome.send('loadLogFile'); -} +}; + +BrowserBridge.prototype.refreshSystemLogs = function() { + chrome.send('refreshSystemLogs'); +}; + +BrowserBridge.prototype.getSystemLog = function(log_key, cellId) { + chrome.send('getSystemLog', [log_key, cellId]); +}; //------------------------------------------------------------------------------ // Messages received from the browser @@ -610,6 +633,10 @@ BrowserBridge.prototype.loadedLogFile = function(logFileContents) { } } +BrowserBridge.prototype.getSystemLogCallback = function(result) { + document.getElementById(result.cellId).textContent = result.log; +} + //------------------------------------------------------------------------------ /** diff --git a/chrome/browser/ui/webui/net_internals_ui.cc b/chrome/browser/ui/webui/net_internals_ui.cc index a802c77..090ea98 100644 --- a/chrome/browser/ui/webui/net_internals_ui.cc +++ b/chrome/browser/ui/webui/net_internals_ui.cc @@ -5,6 +5,7 @@ #include "chrome/browser/ui/webui/net_internals_ui.h" #include <algorithm> +#include <list> #include <string> #include <utility> #include <vector> @@ -61,6 +62,10 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" +#ifdef OS_CHROMEOS +#include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/cros/syslogs_library.h" +#endif #ifdef OS_WIN #include "chrome/browser/net/service_providers_win.h" #endif @@ -172,6 +177,10 @@ class NetInternalsMessageHandler // Javascript message handlers. void OnRendererReady(const ListValue* list); void OnEnableHttpThrottling(const ListValue* list); +#ifdef OS_CHROMEOS + void OnRefreshSystemLogs(const ListValue* list); + void OnGetSystemLog(const ListValue* list); +#endif // SelectFileDialog::Listener implementation virtual void FileSelected(const FilePath& path, int index, void* params); @@ -204,6 +213,61 @@ class NetInternalsMessageHandler const FilePath path_; }; +#ifdef OS_CHROMEOS + // Class that is used for getting network related ChromeOS logs. + // Logs are fetched from ChromeOS libcros on user request, and only when we + // don't yet have a copy of logs. If a copy is present, we send back data from + // it, else we save request and answer to it when we get logs from libcros. + // If needed, we also send request for system logs to libcros. + // Logs refresh has to be done explicitly, by deleting old logs and then + // loading them again. + class SystemLogsGetter { + public: + SystemLogsGetter(NetInternalsMessageHandler* handler, + chromeos::SyslogsLibrary* syslog_lib); + ~SystemLogsGetter(); + + // Deletes logs copy we currently have, and resets logs_requested and + // logs_received flags. + void DeleteSystemLogs(); + // Starts log fetching. If logs copy is present, requested logs are sent + // back. + // If syslogs load request hasn't been sent to libcros yet, we do that now, + // and postpone sending response. + // Request data is specified by args: + // $1 : key of the log we are interested in. + // $2 : string used to identify request. + void RequestSystemLog(const ListValue* args); + // Requests logs from libcros, but only if we don't have a copy. + void LoadSystemLogs(); + // Processes callback from libcros containing system logs. Postponed + // request responses are sent. + void OnSystemLogsLoaded(chromeos::LogDictionaryType* sys_info, + std::string* ignored_content); + + private: + // Struct we save postponed log request in. + struct SystemLogRequest { + std::string log_key; + std::string cell_id; + }; + + // Processes request. + void SendLogs(const SystemLogRequest& request); + + NetInternalsMessageHandler* handler_; + chromeos::SyslogsLibrary* syslogs_library_; + // List of postponed requests. + std::list<SystemLogRequest> requests_; + scoped_ptr<chromeos::LogDictionaryType> logs_; + bool logs_received_; + bool logs_requested_; + CancelableRequestConsumer consumer_; + // Libcros request handle. + CancelableRequestProvider::Handle syslogs_request_id_; + }; +#endif + // The pref member about whether HTTP throttling is enabled, which needs to // be accessed on the UI thread. BooleanPrefMember http_throttling_enabled_; @@ -215,6 +279,11 @@ class NetInternalsMessageHandler // This is the "real" message handler, which lives on the IO thread. scoped_refptr<IOThreadImpl> proxy_; +#ifdef OS_CHROMEOS + // Class that handles getting and filtering system logs. + scoped_ptr<SystemLogsGetter> syslogs_getter_; +#endif + // Used for loading log files. scoped_refptr<SelectFileDialog> select_log_file_dialog_; @@ -291,7 +360,6 @@ class NetInternalsMessageHandler::IOThreadImpl #ifdef OS_WIN void OnGetServiceProviders(const ListValue* list); #endif - void OnSetLogLevel(const ListValue* list); // ChromeNetLog::ThreadSafeObserver implementation: @@ -482,6 +550,10 @@ WebUIMessageHandler* NetInternalsMessageHandler::Attach(WebUI* web_ui) { proxy_ = new IOThreadImpl(this->AsWeakPtr(), g_browser_process->io_thread(), web_ui->GetProfile()->GetRequestContext()); +#ifdef OS_CHROMEOS + syslogs_getter_.reset(new SystemLogsGetter(this, + chromeos::CrosLibrary::Get()->GetSyslogsLibrary())); +#endif renderer_ready_io_callback_.reset( proxy_->CreateCallback(&IOThreadImpl::OnRendererReady)); @@ -582,7 +654,14 @@ void NetInternalsMessageHandler::RegisterMessages() { "getServiceProviders", proxy_->CreateCallback(&IOThreadImpl::OnGetServiceProviders)); #endif - +#ifdef OS_CHROMEOS + web_ui_->RegisterMessageCallback( + "refreshSystemLogs", + NewCallback(this, &NetInternalsMessageHandler::OnRefreshSystemLogs)); + web_ui_->RegisterMessageCallback( + "getSystemLog", + NewCallback(this, &NetInternalsMessageHandler::OnGetSystemLog)); +#endif web_ui_->RegisterMessageCallback( "setLogLevel", proxy_->CreateCallback(&IOThreadImpl::OnSetLogLevel)); @@ -660,6 +739,100 @@ void NetInternalsMessageHandler::ReadLogFileTask::Run() { new StringValue(file_contents)); } +#ifdef OS_CHROMEOS +//////////////////////////////////////////////////////////////////////////////// +// +// NetInternalsMessageHandler::SystemLogsGetter +// +//////////////////////////////////////////////////////////////////////////////// + +NetInternalsMessageHandler::SystemLogsGetter::SystemLogsGetter( + NetInternalsMessageHandler* handler, + chromeos::SyslogsLibrary* syslog_lib) + : handler_(handler), + syslogs_library_(syslog_lib), + logs_(NULL), + logs_received_(false), + logs_requested_(false) { + if (!syslogs_library_) + LOG(ERROR) << "System logs library not loaded"; +} + +NetInternalsMessageHandler::SystemLogsGetter::~SystemLogsGetter() { + DeleteSystemLogs(); +} + +void NetInternalsMessageHandler::SystemLogsGetter::DeleteSystemLogs() { + if (syslogs_library_ && logs_requested_ && !logs_received_) { + syslogs_library_->CancelRequest(syslogs_request_id_); + } + logs_requested_ = false; + logs_received_ = false; + logs_.reset(); +} + +void NetInternalsMessageHandler::SystemLogsGetter::RequestSystemLog( + const ListValue* args) { + if (!logs_requested_) { + DCHECK(!logs_received_); + LoadSystemLogs(); + } + SystemLogRequest log_request; + args->GetString(0, &log_request.log_key); + args->GetString(1, &log_request.cell_id); + + if (logs_received_) { + SendLogs(log_request); + } else { + requests_.push_back(log_request); + } +} + +void NetInternalsMessageHandler::SystemLogsGetter::LoadSystemLogs() { + if (logs_requested_ || !syslogs_library_) + return; + logs_requested_ = true; + syslogs_request_id_ = syslogs_library_->RequestSyslogs( + false, // compress logs. + chromeos::SyslogsLibrary::SYSLOGS_NETWORK, + &consumer_, + NewCallback( + this, + &NetInternalsMessageHandler::SystemLogsGetter::OnSystemLogsLoaded)); +} + +void NetInternalsMessageHandler::SystemLogsGetter::OnSystemLogsLoaded( + chromeos::LogDictionaryType* sys_info, std::string* ignored_content) { + DCHECK(!ignored_content); + logs_.reset(sys_info); + logs_received_ = true; + for (std::list<SystemLogRequest>::iterator request_it = requests_.begin(); + request_it != requests_.end(); + ++request_it) { + SendLogs(*request_it); + } + requests_.clear(); +} + +void NetInternalsMessageHandler::SystemLogsGetter::SendLogs( + const SystemLogRequest& request) { + scoped_ptr<DictionaryValue> result(new DictionaryValue()); + chromeos::LogDictionaryType::iterator log_it = logs_->find(request.log_key); + if (log_it != logs_->end()) { + if (!log_it->second.empty()) { + result->SetString("log", log_it->second); + } else { + result->SetString("log", "<no relevant lines found>"); + } + } else { + result->SetString("log", "<invalid log name>"); + } + result->SetString("cellId", request.cell_id); + + handler_->CallJavascriptFunction(L"g_browser.getSystemLogCallback", + result.get()); +} +#endif //////////////////////////////////////////////////////////////////////////////// // // NetInternalsMessageHandler::IOThreadImpl @@ -1322,6 +1495,19 @@ void NetInternalsMessageHandler::IOThreadImpl::OnGetServiceProviders( } #endif +#ifdef OS_CHROMEOS +void NetInternalsMessageHandler::OnRefreshSystemLogs(const ListValue* list) { + DCHECK(syslogs_getter_.get()); + syslogs_getter_->DeleteSystemLogs(); + syslogs_getter_->LoadSystemLogs(); +} + +void NetInternalsMessageHandler::OnGetSystemLog(const ListValue* list) { + DCHECK(syslogs_getter_.get()); + syslogs_getter_->RequestSystemLog(list); +} +#endif + void NetInternalsMessageHandler::IOThreadImpl::OnSetLogLevel( const ListValue* list) { int log_level; |