diff options
author | petersont@google.com <petersont@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-04 21:59:45 +0000 |
---|---|---|
committer | petersont@google.com <petersont@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-04 21:59:45 +0000 |
commit | 252873ef94051e50ea9cb3a4e8fa1e1d17aef384 (patch) | |
tree | eab3695e37b973f7f29f93a411cfd9d700f61c99 /chrome/browser/metrics_service.cc | |
parent | 198ba17f199e64660ac7b0f54e0767201915f51f (diff) | |
download | chromium_src-252873ef94051e50ea9cb3a4e8fa1e1d17aef384.zip chromium_src-252873ef94051e50ea9cb3a4e8fa1e1d17aef384.tar.gz chromium_src-252873ef94051e50ea9cb3a4e8fa1e1d17aef384.tar.bz2 |
Implemented xml parsing of UMA server response data.
Used libxml rather than scanf/the wrapper class XmlReader.
More data from the response are recorded to be used later to control the transmissions.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@341 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/metrics_service.cc')
-rw-r--r-- | chrome/browser/metrics_service.cc | 153 |
1 files changed, 111 insertions, 42 deletions
diff --git a/chrome/browser/metrics_service.cc b/chrome/browser/metrics_service.cc index d331803..5779063 100644 --- a/chrome/browser/metrics_service.cc +++ b/chrome/browser/metrics_service.cc @@ -201,6 +201,7 @@ #include "chrome/browser/template_url.h" #include "chrome/browser/template_url_model.h" #include "chrome/common/chrome_paths.h" +#include "chrome/common/libxml_utils.h" #include "chrome/common/pref_names.h" #include "chrome/common/pref_service.h" #include "googleurl/src/gurl.h" @@ -216,7 +217,11 @@ static const char kMetricsURL[] = static const char kMetricsType[] = "application/vnd.mozilla.metrics.bz2"; // The delay, in seconds, after startup before sending the first log message. -static const int kInitialLogDelay = 60; // one minute +static const int kInitialInterlogDuration = 60; // one minute + +// The default maximum number of events in a log uploaded to the UMA server. +// TODO(petersont): Honor the limit when the log is actually sent. +static const int kInitialEventLimit = 1000000; // When we have logs from previous Chrome sessions to send, how long should we // delay (in seconds) between each log transmission. @@ -345,7 +350,8 @@ MetricsService::MetricsService() log_sender_factory_(this), state_saver_factory_(this), logged_samples_(), - interlog_duration_(TimeDelta::FromSeconds(kInitialLogDelay)), + interlog_duration_(TimeDelta::FromSeconds(kInitialInterlogDuration)), + event_limit_(kInitialEventLimit), timer_pending_(false) { DCHECK(IsSingleThreaded()); InitializeMetricsState(); @@ -631,7 +637,7 @@ void MetricsService::StartRecording() { // that the main thread isn't blocked generating the list. g_browser_process->file_thread()->message_loop()->PostDelayedTask(FROM_HERE, new GetPluginListTask(MessageLoop::current()), - kInitialLogDelay * 1000 / 2); + kInitialInterlogDuration * 1000 / 2); } } @@ -1007,7 +1013,10 @@ void MetricsService::OnURLFetchComplete(const URLFetcher* source, // Confirm send so that we can move on. DLOG(INFO) << "METRICS RESPONSE CODE: " << response_code << " status=" << StatusToString(status); - if (response_code == 200) { // Success. + + if (response_code != 200) { + HandleBadResponseCode(); + } else { // Success. switch (state_) { case INITIAL_LOG_READY: state_ = SEND_OLD_INITIAL_LOGS; @@ -1032,58 +1041,118 @@ void MetricsService::OnURLFetchComplete(const URLFetcher* source, DCHECK(false); break; } - DLOG(INFO) << "METRICS RESPONSE DATA: " << data; DiscardPendingLog(); + + GetSettingsFromResponseData(data); + + // Override server specified interlog delay if there are unsent logs to + // transmit if (unsent_logs()) { DCHECK(state_ < SENDING_CURRENT_LOGS); interlog_duration_ = TimeDelta::FromSeconds(kUnsentLogDelay); - } else { - GetSuggestedInterlogTime(data); } - } else { - DLOG(INFO) << "METRICS: transmission attempt returned a failure code. " - "Verify network connectivity"; + } + + StartLogTransmissionTimer(); +} + +void MetricsService::HandleBadResponseCode() { + DLOG(INFO) << "METRICS: transmission attempt returned a failure code. " + "Verify network connectivity"; #ifndef NDEBUG - DLOG(INFO) << "Verify your metrics logs are formatted correctly." - " Verify server is active at " << kMetricsURL; + DLOG(INFO) << "Verify your metrics logs are formatted correctly." + " Verify server is active at " << kMetricsURL; #endif - if (!pending_log()) { - DLOG(INFO) << "METRICS: Recorder shutdown during log transmission."; - } else { - // Send progressively less frequently. - DCHECK(kBackoff > 1.0); - interlog_duration_ = TimeDelta::FromMicroseconds( - static_cast<int64>(kBackoff * interlog_duration_.InMicroseconds())); - - if (kMaxBackoff * TimeDelta::FromSeconds(kMinSecondsPerLog) < - interlog_duration_) - interlog_duration_ = kMaxBackoff * - TimeDelta::FromSeconds(kMinSecondsPerLog); - - DLOG(INFO) << "METRICS: transmission retry being scheduled in " << - interlog_duration_.InSeconds() << " seconds for " << - pending_log_text_; - } + if (!pending_log()) { + DLOG(INFO) << "METRICS: Recorder shutdown during log transmission."; + } else { + // Send progressively less frequently. + DCHECK(kBackoff > 1.0); + interlog_duration_ = TimeDelta::FromMicroseconds( + static_cast<int64>(kBackoff * interlog_duration_.InMicroseconds())); + + if (kMaxBackoff * TimeDelta::FromSeconds(kMinSecondsPerLog) < + interlog_duration_) + interlog_duration_ = kMaxBackoff * + TimeDelta::FromSeconds(kMinSecondsPerLog); + + DLOG(INFO) << "METRICS: transmission retry being scheduled in " << + interlog_duration_.InSeconds() << " seconds for " << + pending_log_text_; } - StartLogTransmissionTimer(); } -// TODO(JAR): Carfully parse XML, rather than hacking. -void MetricsService::GetSuggestedInterlogTime(const std::string& server_data) { - int interlog_seconds = kMinSecondsPerLog; - const char* prefix = "<upload interval=\""; - size_t seconds_indent = server_data.find(prefix); - if (std::string::npos != seconds_indent) { - int seconds; - int result = sscanf(server_data.c_str() + seconds_indent + strlen(prefix), - "%d", &seconds); - if (1 == result && seconds > kMinSuggestedSecondsPerLog) - interlog_seconds = seconds; +void MetricsService::GetSettingsFromResponseData(const std::string& data) { + // We assume that the file is structured as a block opened by <response> + // and that inside response, there is a block opened by tag <config> + // other tags are ignored for now except the content of <config>. + DLOG(INFO) << data; + int data_size = static_cast<int>(data.size()); + if (data_size < 0) { + DLOG(INFO) << "METRICS: server response data bad size " << + " aborting extraction of settings"; + return; + } + xmlDocPtr doc = xmlReadMemory(data.c_str(), data_size, + "", NULL, 0); + DCHECK(doc); + // if the document is malformed, we just use the settings that were there + if (!doc) + return; + + xmlNodePtr top_node = xmlDocGetRootElement(doc), config_node = NULL; + // Here, we find the config node by name. + for (xmlNodePtr p = top_node->children; p; p = p->next) { + if (xmlStrEqual(p->name, BAD_CAST "config")) { + config_node = p; + break; + } } - interlog_duration_ = TimeDelta::FromSeconds(interlog_seconds); + // If the server data is formatted wrong and there is no + // config node where we expect, we just drop out. + if (config_node != NULL) + GetSettingsFromConfigNode(config_node); + xmlFreeDoc(doc); } +void MetricsService::GetSettingsFromConfigNode(xmlNodePtr config_node) { + for (xmlNodePtr current_node = config_node->children; + current_node; + current_node = current_node->next) { + + // If the node is collectors list, we iterate through the children + // to get the types of collectors. + if (xmlStrEqual(current_node->name, BAD_CAST "collectors")) { + collectors_.clear(); + // Iterate through children and get the property "type". + for (xmlNodePtr sub_node = current_node->children; + sub_node; + sub_node = sub_node->next) { + if (xmlStrEqual(sub_node->name, BAD_CAST "collector")) { + xmlChar* type_value = xmlGetProp(sub_node, BAD_CAST "type"); + collectors_.insert(reinterpret_cast<char*>(type_value)); + } + } + continue; + } + // Search for other tags, limit and upload. Again if the server data + // does not contain those tags, the settings remain unchanged. + if (xmlStrEqual(current_node->name, BAD_CAST "limit")) { + xmlChar* event_limit_value = xmlGetProp(current_node, BAD_CAST "events"); + event_limit_ = atoi(reinterpret_cast<char*>(event_limit_value)); + continue; + } + if (xmlStrEqual(current_node->name, BAD_CAST "upload")) { + xmlChar* upload_interval_val = xmlGetProp(current_node, + BAD_CAST "interval"); + int upload_interval_sec = + atoi(reinterpret_cast<char*>(upload_interval_val)); + interlog_duration_ = TimeDelta::FromSeconds(upload_interval_sec); + continue; + } + } +} void MetricsService::LogWindowChange(NotificationType type, const NotificationSource& source, |