Add logging for command events in the UI (bug 328069). As part of this change, we're adding an onAttach() notification to nsIMetricsCollector, so that re-enabling a disabled collector can work properly. Patch by Marria Nazif <marria@gmail.com>, r=me.

This commit is contained in:
bryner%brianryner.com 2006-04-26 04:16:38 +00:00
Родитель 1ba05c16c5
Коммит a99dd6b675
10 изменённых файлов: 397 добавлений и 124 удалений

Просмотреть файл

@ -47,9 +47,16 @@
* is instantiated (using getSerivce). The collector is responsible for
* calling nsIMetricsService::logEvent() when it has something to log.
*/
[scriptable, uuid(b6cba4ad-363a-4780-90fa-9d7cc8115854)]
[scriptable, uuid(9c6bd2a8-784a-4003-9534-faf45b4de64c)]
interface nsIMetricsCollector : nsISupports
{
/**
* Notification that this collector should be enabled. The collector
* should register itself for observer and event notifications as
* necessary.
*/
void onAttach();
/**
* Notification that this collector is no longer enabled. The collector
* should unregister itself from observer and event notifications so that

Просмотреть файл

@ -83,6 +83,7 @@ CPPSRCS = \
nsMetricsService.cpp \
nsProfileCollector.cpp \
nsWindowCollector.cpp \
nsUICommandCollector.cpp \
nsStringUtils.cpp \
$(NULL)

Просмотреть файл

@ -355,7 +355,12 @@ nsresult
nsLoadCollector::Init()
{
NS_ENSURE_TRUE(mRequestMap.Init(32), NS_ERROR_OUT_OF_MEMORY);
return NS_OK;
}
NS_IMETHODIMP
nsLoadCollector::OnAttach()
{
// Attach the LoadCollector as a global web progress listener
nsCOMPtr<nsIWebProgress> progress =
do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
@ -371,6 +376,10 @@ nsLoadCollector::Init()
NS_IMETHODIMP
nsLoadCollector::OnDetach()
{
// Clear the request map so we start fresh next time we're attached
mRequestMap.Clear();
// Remove the progress listener
nsCOMPtr<nsIWebProgress> progress =
do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
NS_ENSURE_STATE(progress);

Просмотреть файл

@ -1,120 +0,0 @@
/* -*- 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 "nsMetricsModule.h"
#include "nsMetricsService.h"
#include "nsLoadCollector.h"
#include "nsWindowCollector.h"
#include "nsProfileCollector.h"
#include "nsIGenericFactory.h"
#include "nsICategoryManager.h"
#include "nsServiceManagerUtils.h"
#include "nsCOMPtr.h"
#include "nsXPCOMCID.h"
#ifndef MOZILLA_1_8_BRANCH
#include "nsIClassInfoImpl.h"
#endif
NS_DECL_CLASSINFO(nsMetricsService)
#define COLLECTOR_CONTRACTID(type) \
"@mozilla.org/metrics/collector;1?name=" type ":" NS_METRICS_NAMESPACE
static NS_METHOD
nsMetricsServiceRegisterSelf(nsIComponentManager *compMgr,
nsIFile *path,
const char *loaderStr,
const char *type,
const nsModuleComponentInfo *info)
{
nsCOMPtr<nsICategoryManager> cat =
do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
NS_ENSURE_STATE(cat);
cat->AddCategoryEntry("app-startup",
NS_METRICSSERVICE_CLASSNAME,
"service," NS_METRICSSERVICE_CONTRACTID,
PR_TRUE, PR_TRUE, nsnull);
return NS_OK;
}
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsLoadCollector, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsWindowCollector, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsProfileCollector)
static const nsModuleComponentInfo components[] = {
{
NS_METRICSSERVICE_CLASSNAME,
NS_METRICSSERVICE_CID,
NS_METRICSSERVICE_CONTRACTID,
nsMetricsService::Create,
nsMetricsServiceRegisterSelf,
NULL,
NULL,
NS_CI_INTERFACE_GETTER_NAME(nsMetricsService),
NULL,
&NS_CLASSINFO_NAME(nsMetricsService),
nsIClassInfo::MAIN_THREAD_ONLY | nsIClassInfo::SINGLETON
},
{
NS_METRICSSERVICE_CLASSNAME,
NS_METRICSSERVICE_CID,
NS_ABOUT_MODULE_CONTRACTID_PREFIX "metrics",
nsMetricsService::Create
},
{
NS_LOADCOLLECTOR_CLASSNAME,
NS_LOADCOLLECTOR_CID,
COLLECTOR_CONTRACTID("document"),
nsLoadCollectorConstructor
},
{
NS_WINDOWCOLLECTOR_CLASSNAME,
NS_WINDOWCOLLECTOR_CID,
COLLECTOR_CONTRACTID("window"),
nsWindowCollectorConstructor
},
{
NS_PROFILECOLLECTOR_CLASSNAME,
NS_PROFILECOLLECTOR_CID,
COLLECTOR_CONTRACTID("profile"),
nsProfileCollectorConstructor
}
};
NS_IMPL_NSGETMODULE(metrics, components)

Просмотреть файл

@ -747,6 +747,7 @@ nsMetricsService::EnableCollectors()
if (coll) {
MS_LOG(("Created collector %s", contractID.get()));
mCollectorMap.Put(name, coll);
coll->OnAttach();
} else {
MS_LOG(("Couldn't instantiate collector %s", contractID.get()));
}

Просмотреть файл

@ -111,6 +111,12 @@ nsProfileCollector::~nsProfileCollector()
NS_IMPL_ISUPPORTS1(nsProfileCollector, nsIMetricsCollector)
NS_IMETHODIMP
nsProfileCollector::OnAttach()
{
return NS_OK;
}
NS_IMETHODIMP
nsProfileCollector::OnDetach()
{

Просмотреть файл

@ -0,0 +1,298 @@
/* -*- 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):
* Marria Nazif <marria@gmail.com>
*
* 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 "nsUICommandCollector.h"
#include "nsMetricsService.h"
#include "nsServiceManagerUtils.h"
#include "nsIObserverService.h"
#include "nsIDOMEventTarget.h"
#include "nsIDOMEvent.h"
#include "nsIDOMNSEvent.h"
#include "nsIDOMElement.h"
#include "nsIDOMDocument.h"
#include "nsIDOMDocumentView.h"
#include "nsIDOMAbstractView.h"
#include "nsIDOMWindow.h"
#include "nsDataHashtable.h"
NS_IMPL_ISUPPORTS3(nsUICommandCollector, nsIObserver, nsIDOMEventListener,
nsIMetricsCollector)
/* static */
PLDHashOperator PR_CALLBACK nsUICommandCollector::RemoveCommandEventListener(
const void* key, PRUint32 windowID, void* userArg)
{
const nsIDOMWindow* window = NS_STATIC_CAST(const nsIDOMWindow*, key);
nsIDOMWindow* window2 = NS_CONST_CAST(nsIDOMWindow*, window);
nsCOMPtr<nsIDOMEventTarget> windowTarget = do_QueryInterface(window2);
if (!windowTarget) {
MS_LOG(("Error casting domeventtarget"));
return PL_DHASH_NEXT;
}
nsIDOMEventListener* listener = NS_STATIC_CAST(nsIDOMEventListener*,
userArg);
if (!listener) {
MS_LOG(("no event listener in userArg"));
return PL_DHASH_NEXT;
}
nsresult rv = windowTarget->RemoveEventListener(NS_LITERAL_STRING("command"),
listener, PR_TRUE);
if (NS_FAILED(rv)) {
MS_LOG(("Warning: Removing event listener failed"));
}
return PL_DHASH_NEXT;
}
nsUICommandCollector::nsUICommandCollector()
{
}
nsUICommandCollector::~nsUICommandCollector()
{
}
// nsIMetricsCollector
NS_IMETHODIMP
nsUICommandCollector::OnAttach()
{
nsresult rv;
nsCOMPtr<nsIObserverService> obsSvc =
do_GetService("@mozilla.org/observer-service;1");
NS_ENSURE_STATE(obsSvc);
// Listen for newly opened windows, so that we can attach a command event
// listener to each window
rv = obsSvc->AddObserver(this, "domwindowopened", PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsUICommandCollector::OnDetach()
{
nsresult rv;
nsCOMPtr<nsIObserverService> obsSvc =
do_GetService("@mozilla.org/observer-service;1");
NS_ENSURE_STATE(obsSvc);
// Remove our observer for open windows
rv = obsSvc->RemoveObserver(this, "domwindowopened");
NS_ENSURE_SUCCESS(rv, rv);
// Also iterate through all windows and try to remove command event
// listeners. It is possible that we never attached one to some
// of the windows (if we were detached and then attached) so
// continue on even if it fails
nsMetricsService *ms = nsMetricsService::get();
NS_ENSURE_STATE(ms);
ms->WindowMap().EnumerateRead(RemoveCommandEventListener,
NS_STATIC_CAST(nsIDOMEventListener*, this));
return NS_OK;
}
NS_IMETHODIMP
nsUICommandCollector::OnNewLog()
{
return NS_OK;
}
// nsIObserver
NS_IMETHODIMP
nsUICommandCollector::Observe(nsISupports *subject,
const char *topic,
const PRUnichar *data)
{
if (strcmp(topic, "domwindowopened") == 0) {
// Attach a capturing command listener to the window.
// Use capturing instead of bubbling so that we still record
// the event even if propogation is canceled for some reason.
nsCOMPtr<nsIDOMEventTarget> window = do_QueryInterface(subject);
NS_ENSURE_STATE(window);
nsresult rv = window->AddEventListener(NS_LITERAL_STRING("command"),
this,
PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
// nsIDomEventListener
NS_IMETHODIMP
nsUICommandCollector::HandleEvent(nsIDOMEvent* event)
{
// First check that this is an event type that we expect
nsString type;
nsresult rv = event->GetType(type);
NS_ENSURE_SUCCESS(rv, rv);
if (!type.Equals(NS_LITERAL_STRING("command"))) {
MS_LOG(("UICommandCollector: Unexpected event type %s received",
NS_ConvertUTF16toUTF8(type).get()));
return NS_ERROR_UNEXPECTED;
}
// Get the Original Target id - this is the target after text node
// retargeting. If this id is blank it means the target is anonymous
// content.
nsCOMPtr<nsIDOMNSEvent> nsEvent = do_QueryInterface(event);
NS_ENSURE_STATE(nsEvent);
nsCOMPtr<nsIDOMEventTarget> original_target;
nsEvent->GetOriginalTarget(getter_AddRefs(original_target));
NS_ENSURE_STATE(original_target);
nsCOMPtr<nsIDOMElement> origElement(do_QueryInterface(original_target));
nsString orig_id;
nsString orig_anon;
if (origElement) {
origElement->GetAttribute(NS_LITERAL_STRING("id"), orig_id);
origElement->GetAttribute(NS_LITERAL_STRING("anonid"), orig_anon);
}
// Get the target id - this is the target after all retargeting.
// In the case of anonymous content, the original target ID will
// be blank and the target ID will be set.
nsCOMPtr<nsIDOMEventTarget> target;
event->GetTarget(getter_AddRefs(target));
nsString tar_id;
nsCOMPtr<nsIDOMElement> tarElement(do_QueryInterface(target));
if (tarElement) {
tarElement->GetAttribute(NS_LITERAL_STRING("id"), tar_id);
}
MS_LOG(("Original Target Id: %s, Target Id: %s, Anonid: %s",
NS_ConvertUTF16toUTF8(orig_id).get(),
NS_ConvertUTF16toUTF8(tar_id).get(),
NS_ConvertUTF16toUTF8(orig_anon).get()));
// If the Target Id is empty, return without logging and print an error
if (tar_id.IsEmpty()) {
MS_LOG(("Warning: skipping logging because of empty target ID"));
return NS_OK;
}
// If the Original ID (target after text node retargeting) is empty,
// then assume we are dealing with anonymous content. In that case,
// return without logging and print an error if the anonid is empty.
PRBool logAnonId = PR_FALSE;
if (orig_id.IsEmpty()) {
logAnonId = PR_TRUE;
if (orig_anon.IsEmpty()) {
MS_LOG(("Warning: skipping logging because of empty anonid"));
return NS_OK;
}
}
// Get the window that this target is in, so that we can log the event
// with the appropriate window id.
nsCOMPtr<nsIDOMNode> targetNode = do_QueryInterface(target);
if (!targetNode) {
MS_LOG(("Warning: skipping logging because target is not a node"));
return NS_OK;
}
nsCOMPtr<nsIDOMDocument> ownerDoc;
targetNode->GetOwnerDocument(getter_AddRefs(ownerDoc));
NS_ENSURE_STATE(ownerDoc);
nsCOMPtr<nsIDOMDocumentView> docView = do_QueryInterface(ownerDoc);
NS_ENSURE_STATE(docView);
nsCOMPtr<nsIDOMAbstractView> absView;
docView->GetDefaultView(getter_AddRefs(absView));
NS_ENSURE_STATE(absView);
nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(absView);
NS_ENSURE_STATE(window);
// Fill a property bag with what we want to log
nsCOMPtr<nsIWritablePropertyBag2> properties;
nsMetricsUtils::NewPropertyBag(getter_AddRefs(properties));
NS_ENSURE_STATE(properties);
rv = properties->SetPropertyAsUint32(NS_LITERAL_STRING("window"),
nsMetricsService::GetWindowID(window));
NS_ENSURE_SUCCESS(rv, rv);
rv = properties->SetPropertyAsAString(NS_LITERAL_STRING("action"),
type);
NS_ENSURE_SUCCESS(rv, rv);
// Get the metrics service now so we can use it to hash the ids below
nsMetricsService *ms = nsMetricsService::get();
NS_ENSURE_STATE(ms);
// Log the Target Id which will be the same as the Original Target Id
// unless the target is anonymous content
nsCString hashedTarId;
rv = ms->Hash(tar_id, hashedTarId);
NS_ENSURE_SUCCESS(rv, rv);
rv = properties->SetPropertyAsACString(NS_LITERAL_STRING("targetidhash"),
hashedTarId);
NS_ENSURE_SUCCESS(rv, rv);
if (logAnonId) {
nsCString hashedAnonId;
rv = ms->Hash(orig_anon, hashedAnonId);
NS_ENSURE_SUCCESS(rv, rv);
rv = properties->SetPropertyAsACString(
NS_LITERAL_STRING("targetanonidhash"), hashedAnonId);
NS_ENSURE_SUCCESS(rv, rv);
}
// Actually log it
rv = ms->LogEvent(NS_LITERAL_STRING("uielement"), properties);
NS_ENSURE_SUCCESS(rv, rv);
MS_LOG(("Successfully logged UI Event"));
return NS_OK;
}

Просмотреть файл

@ -0,0 +1,72 @@
/* -*- 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):
* Marria Nazif <marria@gmail.com>
*
* 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 nsUICommandCollector_h_
#define nsUICommandCollector_h_
#include "nsIObserver.h"
#include "nsIDOMEventListener.h"
#include "nsIMetricsCollector.h"
#include "nsDataHashtable.h"
class nsUICommandCollector : public nsIObserver,
public nsIDOMEventListener,
public nsIMetricsCollector
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSIDOMEVENTLISTENER
NS_DECL_NSIMETRICSCOLLECTOR
static PLDHashOperator PR_CALLBACK RemoveCommandEventListener(
const void* key, PRUint32 windowID, void* userArg);
nsUICommandCollector();
private:
~nsUICommandCollector();
};
#define NS_UICOMMANDCOLLECTOR_CLASSNAME "UI Command Collector"
#define NS_UICOMMANDCOLLECTOR_CID \
{ 0xcc2fedc9, 0x8b2e, 0x4e2c, {0x97, 0x07, 0xe2, 0xe5, 0x6b, 0xeb, 0x01, 0x85}}
#endif // nsUICommandCollector_h_

Просмотреть файл

@ -60,8 +60,8 @@ nsWindowCollector::~nsWindowCollector()
NS_IMPL_ISUPPORTS2(nsWindowCollector, nsIMetricsCollector, nsIObserver)
nsresult
nsWindowCollector::Init()
NS_IMETHODIMP
nsWindowCollector::OnAttach()
{
nsCOMPtr<nsIObserverService> obsSvc =
do_GetService("@mozilla.org/observer-service;1");

Просмотреть файл

@ -88,7 +88,6 @@ class nsWindowCollector : public nsIMetricsCollector,
NS_DECL_NSIOBSERVER
nsWindowCollector();
nsresult Init();
private:
~nsWindowCollector();