summaryrefslogtreecommitdiffstats
path: root/chrome/browser/metrics_service.cc
diff options
context:
space:
mode:
authorpetersont@google.com <petersont@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-04 21:59:45 +0000
committerpetersont@google.com <petersont@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-04 21:59:45 +0000
commit252873ef94051e50ea9cb3a4e8fa1e1d17aef384 (patch)
treeeab3695e37b973f7f29f93a411cfd9d700f61c99 /chrome/browser/metrics_service.cc
parent198ba17f199e64660ac7b0f54e0767201915f51f (diff)
downloadchromium_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.cc153
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,