mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 20:05:49 +00:00
fixes bug 328125 "Add support for dynamic configuration and throttling" r=bryner
This commit is contained in:
parent
649032f434
commit
dd7ffaf0ca
@ -1,3 +1,3 @@
|
||||
pref("metrics.upload.interval", 86400000); // 24 hrs in msec
|
||||
pref("metrics.upload.enable", false);
|
||||
pref("metrics.upload.uri", "");
|
||||
pref("metrics.event-count", 0);
|
||||
|
@ -63,10 +63,11 @@ REQUIRES = xpcom \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
nsMetricsService.cpp \
|
||||
nsLoadCollector.cpp \
|
||||
nsWindowCollector.cpp \
|
||||
nsMetricsConfig.cpp \
|
||||
nsMetricsModule.cpp \
|
||||
nsMetricsService.cpp \
|
||||
nsWindowCollector.cpp \
|
||||
$(NULL)
|
||||
|
||||
SHARED_LIBRARY_LIBS += $(DIST)/lib/$(LIB_PREFIX)bz2.$(LIB_SUFFIX)
|
||||
|
@ -161,7 +161,7 @@ static PRBool GetMemUsage(MemUsage *result)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static nsLoadCollector *gLoadCollector = nsnull;
|
||||
static nsLoadCollector *sLoadCollector = nsnull;
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsLoadCollector,
|
||||
nsIWebProgressListener, nsISupportsWeakReference)
|
||||
@ -320,15 +320,16 @@ nsLoadCollector::OnSecurityChange(nsIWebProgress *webProgress,
|
||||
/* static */ nsresult
|
||||
nsLoadCollector::Startup()
|
||||
{
|
||||
NS_ASSERTION(!gLoadCollector, "nsLoadCollector::Startup called twice");
|
||||
if (sLoadCollector)
|
||||
return NS_OK;
|
||||
|
||||
gLoadCollector = new nsLoadCollector();
|
||||
NS_ENSURE_TRUE(gLoadCollector, NS_ERROR_OUT_OF_MEMORY);
|
||||
NS_ADDREF(gLoadCollector);
|
||||
sLoadCollector = new nsLoadCollector();
|
||||
NS_ENSURE_TRUE(sLoadCollector, NS_ERROR_OUT_OF_MEMORY);
|
||||
NS_ADDREF(sLoadCollector);
|
||||
|
||||
nsresult rv = gLoadCollector->Init();
|
||||
nsresult rv = sLoadCollector->Init();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_RELEASE(gLoadCollector);
|
||||
NS_RELEASE(sLoadCollector);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -338,19 +339,11 @@ nsLoadCollector::Startup()
|
||||
/* static */ void
|
||||
nsLoadCollector::Shutdown()
|
||||
{
|
||||
// See comments in nsWindowCollector::Shutdown about why we don't
|
||||
// null out gLoadCollector here.
|
||||
gLoadCollector->Release();
|
||||
NS_RELEASE(sLoadCollector);
|
||||
|
||||
GetMemUsage_Shutdown();
|
||||
}
|
||||
|
||||
nsLoadCollector::~nsLoadCollector()
|
||||
{
|
||||
NS_ASSERTION(gLoadCollector == this, "two load collectors created?");
|
||||
gLoadCollector = nsnull;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsLoadCollector::Init()
|
||||
{
|
||||
|
@ -82,7 +82,7 @@ class nsLoadCollector : public nsIWebProgressListener,
|
||||
static void Shutdown();
|
||||
|
||||
private:
|
||||
~nsLoadCollector();
|
||||
~nsLoadCollector() {}
|
||||
|
||||
// Object initialization, to be called by Startup()
|
||||
nsresult Init();
|
||||
|
216
extensions/metrics/src/nsMetricsConfig.cpp
Normal file
216
extensions/metrics/src/nsMetricsConfig.cpp
Normal file
@ -0,0 +1,216 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the Metrics extension.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Google Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsMetricsService.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDOMParser.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIDOM3Node.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
#define NS_DEFAULT_UPLOAD_INTERVAL 3600 // 1 hour
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static const nsAutoString
|
||||
MakeKey(const nsAString &eventNS, const nsAString &eventName)
|
||||
{
|
||||
// Since eventName must be a valid XML NCName, we can use ':' to separate
|
||||
// eventName from eventNS when formulating our hash key.
|
||||
NS_ASSERTION(eventName.FindChar(':') == kNotFound, "Not a valid NCName");
|
||||
|
||||
return nsAutoString(eventName + NS_LITERAL_STRING(":") + eventNS);
|
||||
}
|
||||
|
||||
// This method leaves the result value unchanged if a parsing error occurs.
|
||||
static void
|
||||
ReadIntegerAttr(nsIDOMElement *elem, const nsAString &attrName, PRInt32 *result)
|
||||
{
|
||||
nsAutoString attrValue;
|
||||
elem->GetAttribute(attrName, attrValue);
|
||||
|
||||
PRInt32 errcode;
|
||||
PRInt32 parsedVal = attrValue.ToInteger(&errcode);
|
||||
|
||||
if (NS_SUCCEEDED(errcode))
|
||||
*result = parsedVal;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsMetricsConfig::nsMetricsConfig()
|
||||
: mEventLimit(0),
|
||||
mUploadInterval(NS_DEFAULT_UPLOAD_INTERVAL)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsMetricsConfig::Reset()
|
||||
{
|
||||
mEventSet.Clear();
|
||||
mEventLimit = 0;
|
||||
mUploadInterval = NS_DEFAULT_UPLOAD_INTERVAL;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMetricsConfig::Load(nsIFile *file)
|
||||
{
|
||||
// The given file references a XML file with the following structure:
|
||||
//
|
||||
// <config xmlns="http://www.mozilla.org/metrics"
|
||||
// xmlns:foo="http://foo.com/metrics">
|
||||
// <collectors>
|
||||
// <collector type="ui"/>
|
||||
// <collector type="load"/>
|
||||
// <collector type="window"/>
|
||||
// <collector type="foo:mystat"/>
|
||||
// </collectors>
|
||||
// <limit events="200"/>
|
||||
// <upload interval="600"/>
|
||||
// </config>
|
||||
|
||||
PRInt64 fileSize;
|
||||
nsresult rv = file->GetFileSize(&fileSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_STATE(fileSize <= PR_INT32_MAX);
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
NS_NewLocalFileInputStream(getter_AddRefs(stream), file);
|
||||
NS_ENSURE_STATE(stream);
|
||||
|
||||
nsCOMPtr<nsIDOMParser> parser = do_CreateInstance(NS_DOMPARSER_CONTRACTID);
|
||||
NS_ENSURE_STATE(parser);
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> doc;
|
||||
parser->ParseFromStream(stream, nsnull, fileSize, "application/xml",
|
||||
getter_AddRefs(doc));
|
||||
NS_ENSURE_STATE(doc);
|
||||
|
||||
// At this point, we can clear our old configuration.
|
||||
Reset();
|
||||
|
||||
// Now, walk the DOM. All config elements are optional, and we ignore stuff
|
||||
// that we don't understand.
|
||||
nsCOMPtr<nsIDOMElement> elem;
|
||||
doc->GetDocumentElement(getter_AddRefs(elem));
|
||||
if (!elem)
|
||||
return NS_OK;
|
||||
|
||||
ForEachChildElement(elem, &nsMetricsConfig::ProcessToplevelElement);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsMetricsConfig::ForEachChildElement(nsIDOMElement *elem,
|
||||
ForEachChildElementCallback callback)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> node, next;
|
||||
elem->GetFirstChild(getter_AddRefs(node));
|
||||
while (node) {
|
||||
nsCOMPtr<nsIDOMElement> childElem = do_QueryInterface(node);
|
||||
if (childElem) {
|
||||
// Skip elements that are not in our namespace
|
||||
nsAutoString namespaceURI;
|
||||
childElem->GetNamespaceURI(namespaceURI);
|
||||
if (namespaceURI.EqualsLiteral(NS_METRICS_NAMESPACE))
|
||||
(this->*callback)(childElem);
|
||||
}
|
||||
node->GetNextSibling(getter_AddRefs(next));
|
||||
node.swap(next);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsMetricsConfig::ProcessToplevelElement(nsIDOMElement *elem)
|
||||
{
|
||||
// Process a top-level element
|
||||
|
||||
nsAutoString name;
|
||||
elem->GetLocalName(name);
|
||||
if (name.EqualsLiteral("collectors")) {
|
||||
// Enumerate <collector> elements
|
||||
ForEachChildElement(elem, &nsMetricsConfig::ProcessCollectorElement);
|
||||
} else if (name.EqualsLiteral("limit")) {
|
||||
ReadIntegerAttr(elem, NS_LITERAL_STRING("events"), &mEventLimit);
|
||||
} else if (name.EqualsLiteral("upload")) {
|
||||
ReadIntegerAttr(elem, NS_LITERAL_STRING("interval"), &mUploadInterval);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsMetricsConfig::ProcessCollectorElement(nsIDOMElement *elem)
|
||||
{
|
||||
nsAutoString value;
|
||||
|
||||
// Make sure we are dealing with a <collector> element.
|
||||
elem->GetLocalName(value);
|
||||
if (!value.EqualsLiteral("collector"))
|
||||
return;
|
||||
value.Truncate();
|
||||
|
||||
elem->GetAttribute(NS_LITERAL_STRING("type"), value);
|
||||
if (value.IsEmpty())
|
||||
return;
|
||||
|
||||
// Get the namespace URI specified by any prefix of value.
|
||||
nsCOMPtr<nsIDOM3Node> node = do_QueryInterface(elem);
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
// Check to see if this value references a specific namespace.
|
||||
PRInt32 colon = value.FindChar(':');
|
||||
|
||||
nsAutoString namespaceURI;
|
||||
if (colon == kNotFound) {
|
||||
node->LookupNamespaceURI(EmptyString(), namespaceURI);
|
||||
// value is the EventName
|
||||
} else {
|
||||
// value is NamespacePrefix + ":" + EventName
|
||||
node->LookupNamespaceURI(StringHead(value, colon), namespaceURI);
|
||||
value.Cut(0, colon + 1);
|
||||
}
|
||||
|
||||
mEventSet.PutEntry(MakeKey(namespaceURI, value));
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsMetricsConfig::IsEventEnabled(const nsAString &eventNS,
|
||||
const nsAString &eventName)
|
||||
{
|
||||
return mEventSet.GetEntry(MakeKey(eventNS, eventName)) != nsnull;
|
||||
}
|
111
extensions/metrics/src/nsMetricsConfig.h
Normal file
111
extensions/metrics/src/nsMetricsConfig.h
Normal file
@ -0,0 +1,111 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the Metrics extension.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Google Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsMetricsConfig_h__
|
||||
#define nsMetricsConfig_h__
|
||||
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
||||
class nsIDOMElement;
|
||||
|
||||
class nsMetricsConfig
|
||||
{
|
||||
public:
|
||||
nsMetricsConfig();
|
||||
~nsMetricsConfig() {}
|
||||
|
||||
/**
|
||||
* This method must be called before using an instance of this class.
|
||||
*/
|
||||
PRBool Init() {
|
||||
return mEventSet.Init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the default configuration.
|
||||
*/
|
||||
void Reset();
|
||||
|
||||
/**
|
||||
* Load the metrics configuration from disk.
|
||||
*/
|
||||
nsresult Load(nsIFile *file);
|
||||
|
||||
/**
|
||||
* Call this method to determine if the given event type is enabled for
|
||||
* collection.
|
||||
*/
|
||||
PRBool IsEventEnabled(const nsAString &eventNS, const nsAString &eventName);
|
||||
|
||||
/**
|
||||
* Get the limit on the number of events that should be collected.
|
||||
*/
|
||||
PRInt32 EventLimit() {
|
||||
return mEventLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the upload interval (measured in seconds).
|
||||
*/
|
||||
PRInt32 UploadInterval() {
|
||||
return mUploadInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the upload interval (measured in seconds).
|
||||
*/
|
||||
void SetUploadInterval(PRInt32 uploadInterval) {
|
||||
mUploadInterval = uploadInterval;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef void (nsMetricsConfig::*ForEachChildElementCallback)(nsIDOMElement *);
|
||||
|
||||
// Run a callback method for each child element of the given element.
|
||||
void ForEachChildElement(nsIDOMElement *elem, ForEachChildElementCallback cb);
|
||||
|
||||
void ProcessToplevelElement(nsIDOMElement *elem);
|
||||
void ProcessCollectorElement(nsIDOMElement *elem);
|
||||
|
||||
nsTHashtable<nsStringHashKey> mEventSet;
|
||||
PRInt32 mEventLimit;
|
||||
PRInt32 mUploadInterval;
|
||||
};
|
||||
|
||||
#endif // nsMetricsConfig_h__
|
@ -58,7 +58,9 @@
|
||||
#include "nsIDOMSerializer.h"
|
||||
#include "nsMultiplexInputStream.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsVariant.h"
|
||||
#include "prtime.h"
|
||||
#include "bzlib.h"
|
||||
#include "nsIClassInfoImpl.h"
|
||||
|
||||
@ -72,6 +74,8 @@
|
||||
// Flush the event log whenever its size exceeds this number of events.
|
||||
#define NS_EVENTLOG_FLUSH_POINT 64
|
||||
|
||||
#define NS_SECONDS_PER_DAY (60 * 60 * 24)
|
||||
|
||||
nsMetricsService* nsMetricsService::sMetricsService = nsnull;
|
||||
#ifdef PR_LOGGING
|
||||
PRLogModuleInfo *gMetricsLog;
|
||||
@ -93,6 +97,14 @@ nsMetricsService::LogEvent(const nsAString &eventNS,
|
||||
if (mSuspendCount != 0) // Ignore events while suspended
|
||||
return NS_OK;
|
||||
|
||||
// Restrict the number of events logged
|
||||
if (mEventCount >= mConfig.EventLimit())
|
||||
return NS_OK;
|
||||
|
||||
// Restrict the types of events logged
|
||||
if (!mConfig.IsEventEnabled(eventNS, eventName))
|
||||
return NS_OK;
|
||||
|
||||
// Create a DOM element for the event and append it to our document.
|
||||
nsCOMPtr<nsIDOMElement> eventElement;
|
||||
nsresult rv = mDocument->CreateElementNS(eventNS, eventName,
|
||||
@ -166,7 +178,8 @@ nsMetricsService::LogEvent(const nsAString &eventNS,
|
||||
rv = mRoot->AppendChild(eventElement, getter_AddRefs(outChild));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (++mEventCount > NS_EVENTLOG_FLUSH_POINT)
|
||||
// Flush event log to disk if it has grown too large
|
||||
if ((++mEventCount % NS_EVENTLOG_FLUSH_POINT) == 0)
|
||||
Flush();
|
||||
return NS_OK;
|
||||
}
|
||||
@ -205,6 +218,12 @@ nsMetricsService::Flush()
|
||||
PR_Close(fd);
|
||||
NS_ENSURE_STATE(succeeded);
|
||||
|
||||
// Write current event count to prefs
|
||||
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
NS_ENSURE_STATE(prefs);
|
||||
rv = prefs->SetIntPref("metrics.event-count", mEventCount);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Create a new mRoot
|
||||
rv = CreateRoot();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -231,8 +250,10 @@ nsMetricsService::Upload()
|
||||
// original data file, and allow new events to be logged to a new file.
|
||||
nsCOMPtr<nsILocalFile> dataFile;
|
||||
GetDataFile(&dataFile);
|
||||
if (dataFile)
|
||||
dataFile->Remove(PR_FALSE);
|
||||
if (dataFile) {
|
||||
if (NS_FAILED(dataFile->Remove(PR_FALSE)))
|
||||
NS_WARNING("failed to remove data file");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -273,6 +294,13 @@ nsMetricsService::NewChannel(nsIURI *uri, nsIChannel **result)
|
||||
NS_IMETHODIMP
|
||||
nsMetricsService::OnStartRequest(nsIRequest *request, nsISupports *context)
|
||||
{
|
||||
NS_ENSURE_STATE(!mConfigOutputStream);
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
GetConfigFile(getter_AddRefs(file));
|
||||
|
||||
NS_NewLocalFileOutputStream(getter_AddRefs(mConfigOutputStream), file,
|
||||
PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -280,9 +308,49 @@ NS_IMETHODIMP
|
||||
nsMetricsService::OnStopRequest(nsIRequest *request, nsISupports *context,
|
||||
nsresult status)
|
||||
{
|
||||
nsCOMPtr<nsILocalFile> uploadFile = do_QueryInterface(context);
|
||||
if (uploadFile)
|
||||
uploadFile->Remove(PR_FALSE);
|
||||
if (mConfigOutputStream) {
|
||||
mConfigOutputStream->Close();
|
||||
mConfigOutputStream = 0;
|
||||
}
|
||||
|
||||
// Load configuration file:
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
GetConfigFile(getter_AddRefs(file));
|
||||
|
||||
if (NS_SUCCEEDED(status))
|
||||
status = mConfig.Load(file);
|
||||
|
||||
if (NS_FAILED(status)) {
|
||||
// Upon failure, dial back the upload interval
|
||||
PRInt32 interval = mConfig.UploadInterval();
|
||||
mConfig.Reset();
|
||||
|
||||
interval <<= 2;
|
||||
if (interval > NS_SECONDS_PER_DAY)
|
||||
interval = NS_SECONDS_PER_DAY;
|
||||
mConfig.SetUploadInterval(interval);
|
||||
|
||||
if (NS_FAILED(file->Remove(PR_FALSE)))
|
||||
NS_WARNING("failed to remove config file");
|
||||
}
|
||||
|
||||
// Apply possibly new upload interval:
|
||||
RegisterUploadTimer();
|
||||
|
||||
// Shutdown collectors that are no longer enabled. For now, this only
|
||||
// applies to the load collector since the window collector may be needed by
|
||||
// other collectors.
|
||||
//
|
||||
// TODO(darin): Come up with a better solution for this. A broadcast
|
||||
// notification to the collectors might be ideal.
|
||||
//
|
||||
if (mConfig.IsEventEnabled(NS_LITERAL_STRING(NS_METRICS_NAMESPACE),
|
||||
NS_LITERAL_STRING("load"))) {
|
||||
nsLoadCollector::Startup();
|
||||
} else {
|
||||
nsLoadCollector::Shutdown();
|
||||
}
|
||||
|
||||
mUploading = PR_FALSE;
|
||||
return NS_OK;
|
||||
@ -293,8 +361,9 @@ nsMetricsService::OnDataAvailable(nsIRequest *request, nsISupports *context,
|
||||
nsIInputStream *stream, PRUint32 offset,
|
||||
PRUint32 count)
|
||||
{
|
||||
// We don't expect to receive any data from an upload.
|
||||
return NS_ERROR_ABORT;
|
||||
PRUint32 n;
|
||||
return stream->ReadSegments(NS_CopySegmentToStream, mConfigOutputStream,
|
||||
count, &n);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -306,15 +375,7 @@ nsMetricsService::Observe(nsISupports *subject, const char *topic,
|
||||
nsLoadCollector::Shutdown();
|
||||
nsWindowCollector::Shutdown();
|
||||
} else if (strcmp(topic, "profile-after-change") == 0) {
|
||||
PRInt32 interval = 86400000; // 24 hours
|
||||
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
if (prefs)
|
||||
prefs->GetIntPref("metrics.upload.interval", &interval);
|
||||
|
||||
nsCOMPtr<nsIUpdateTimerManager> mgr =
|
||||
do_GetService("@mozilla.org/updates/timer-manager;1");
|
||||
if (mgr)
|
||||
mgr->RegisterTimer(NS_LITERAL_STRING("metrics-upload"), this, interval);
|
||||
RegisterUploadTimer();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -367,6 +428,18 @@ nsMetricsService::Init()
|
||||
|
||||
nsresult rv;
|
||||
|
||||
// Initialize configuration.
|
||||
NS_ENSURE_STATE(mConfig.Init());
|
||||
nsCOMPtr<nsIFile> file;
|
||||
GetConfigFile(getter_AddRefs(file));
|
||||
if (file)
|
||||
mConfig.Load(file);
|
||||
|
||||
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
NS_ENSURE_STATE(prefs);
|
||||
rv = prefs->GetIntPref("metrics.event-count", &mEventCount);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Create an XML document to serve as the owner document for elements.
|
||||
mDocument = do_CreateInstance("@mozilla.org/xml/xml-document;1");
|
||||
NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
|
||||
@ -464,7 +537,8 @@ nsMetricsService::UploadData()
|
||||
// NOTE: nsIUploadChannel requires a buffered stream to upload...
|
||||
|
||||
nsCOMPtr<nsIInputStream> fileStream;
|
||||
NS_NewLocalFileInputStream(getter_AddRefs(fileStream), file);
|
||||
NS_NewLocalFileInputStream(getter_AddRefs(fileStream), file, -1, -1,
|
||||
nsIFileInputStream::DELETE_ON_CLOSE);
|
||||
NS_ENSURE_STATE(fileStream);
|
||||
|
||||
PRUint32 streamLen;
|
||||
@ -497,7 +571,7 @@ nsMetricsService::UploadData()
|
||||
rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = channel->AsyncOpen(this, file);
|
||||
rv = channel->AsyncOpen(this, nsnull);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
@ -592,7 +666,7 @@ nsMetricsService::OpenCompleteXMLStream(nsILocalFile *dataFile,
|
||||
// footer.
|
||||
static const char METRICS_XML_HEAD[] =
|
||||
"<?xml version=\"1.0\"?>\n"
|
||||
"<log xmlns=\"http://www.mozilla.org/metrics\">\n";
|
||||
"<log xmlns=\"" NS_METRICS_NAMESPACE "\">\n";
|
||||
static const char METRICS_XML_TAIL[] = "</log>";
|
||||
|
||||
nsCOMPtr<nsIInputStream> fileStream;
|
||||
@ -625,6 +699,28 @@ nsMetricsService::OpenCompleteXMLStream(nsILocalFile *dataFile,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsMetricsService::RegisterUploadTimer()
|
||||
{
|
||||
nsCOMPtr<nsIUpdateTimerManager> mgr =
|
||||
do_GetService("@mozilla.org/updates/timer-manager;1");
|
||||
if (mgr)
|
||||
mgr->RegisterTimer(NS_LITERAL_STRING("metrics-upload"), this,
|
||||
mConfig.UploadInterval() * PR_MSEC_PER_SEC);
|
||||
}
|
||||
|
||||
void
|
||||
nsMetricsService::GetConfigFile(nsIFile **result)
|
||||
{
|
||||
nsCOMPtr<nsIFile> file;
|
||||
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(file));
|
||||
if (file)
|
||||
file->AppendNative(NS_LITERAL_CSTRING("metrics-config.xml"));
|
||||
|
||||
*result = nsnull;
|
||||
file.swap(*result);
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
nsMetricsUtils::PutUint16(nsIWritablePropertyBag *bag,
|
||||
const nsAString &propertyName,
|
||||
|
@ -41,8 +41,10 @@
|
||||
|
||||
#include "nsIMetricsService.h"
|
||||
#include "nsMetricsModule.h"
|
||||
#include "nsMetricsConfig.h"
|
||||
#include "nsIAboutModule.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsILocalFile.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsITimer.h"
|
||||
@ -132,10 +134,21 @@ private:
|
||||
nsresult OpenCompleteXMLStream(nsILocalFile *dataFile,
|
||||
nsIInputStream **result);
|
||||
|
||||
// Hook ourselves up to the timer manager.
|
||||
void RegisterUploadTimer();
|
||||
|
||||
// A reference to the local file containing our current configuration
|
||||
void GetConfigFile(nsIFile **result);
|
||||
|
||||
private:
|
||||
// Pointer to the metrics service singleton
|
||||
static nsMetricsService* sMetricsService;
|
||||
|
||||
nsMetricsConfig mConfig;
|
||||
|
||||
// This output stream is non-null when we are downloading the config file.
|
||||
nsCOMPtr<nsIOutputStream> mConfigOutputStream;
|
||||
|
||||
// XML document containing events to be flushed.
|
||||
nsCOMPtr<nsIDOMDocument> mDocument;
|
||||
// Root element of the XML document
|
||||
|
Loading…
Reference in New Issue
Block a user