collect data about UI (click / keyboard nav) events

RESOLVED FIXED in mozilla1.8.1

Status

RESOLVED FIXED
13 years ago
8 years ago

People

(Reporter: bryner, Assigned: marria)

Tracking

unspecified
mozilla1.8.1
Dependency tree / graph

Firefox Tracking Flags

(Not tracked)

Details

Attachments

(1 attachment, 7 obsolete attachments)

(Reporter)

Description

13 years ago
 
QA Contact: nobody → metrics
(Assignee)

Updated

13 years ago
Assignee: nobody → marria
(Assignee)

Updated

13 years ago
Status: NEW → ASSIGNED
(Reporter)

Updated

13 years ago
Depends on: 331290
(Assignee)

Comment 1

13 years ago
Created attachment 217505 [details] [diff] [review]
checkpointing ui event patch
(Assignee)

Comment 2

13 years ago
Created attachment 217506 [details]
checkpoing nsUICommandCollector.cpp

no cvs access, so adding files to bug
(Assignee)

Updated

13 years ago
Attachment #217506 - Attachment description: checkpoing UI collector → checkpoing nsUICommandCollector.cpp
(Assignee)

Comment 3

13 years ago
Created attachment 217507 [details]
checkpointing nsUICommandCollector.h
(Assignee)

Comment 4

13 years ago
Created attachment 217508 [details]
checkpointing jar.mn
(Assignee)

Comment 5

13 years ago
Created attachment 217509 [details]
checkpointing metrics/content/nsUICommandWhitelist
(Reporter)

Comment 6

13 years ago
Comment on attachment 217506 [details]
checkpoing nsUICommandCollector.cpp

A few comments on the parts of this that don't pertain to whitelisting (since that will be replaced by hashing):

>NS_IMETHODIMP
>nsUICommandCollector::Observe(nsISupports *subject,
>                              const char *topic,
>                              const PRUnichar *data)
>{
>  nsCOMPtr<nsIDOMEventTarget> window;
>
>  if (strcmp(topic, "toplevel-window-ready") == 0) {
>    // Attach a capturing command listener to the window
>    window = do_QueryInterface(subject);

Move the declaration of "window" into this scope.

>    NS_ENSURE_STATE(window);
>
>    nsresult rv = window->AddEventListener(NS_LITERAL_STRING("command"),
>                                           this,
>                                           PR_TRUE);
>    NS_ENSURE_SUCCESS(rv, rv);
>    
>    return rv;

Just fall through to the return NS_OK.

>  }
>
>  return NS_OK;
>}
>


>NS_IMETHODIMP
>nsUICommandCollector::HandleEvent(nsIDOMEvent* aEvent)
>{
>  // First check that this is an event type that we expect
>  nsAutoString type;
>  nsresult rv = aEvent->GetType(type);
>  if (type != NS_LITERAL_STRING("command")) {
>
>#ifdef PR_LOGGING
>    MS_LOG(("UICommandCollector: Unexpected event type %s received",
>            type.get()));

This probably doesn't work, you need to convert the string to UTF-8 before it can be logged.

>  // 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(aEvent, &rv);
>  NS_ENSURE_SUCCESS(rv, rv);

This is ok, though I'd probably just do NS_ENSURE_STATE(nsEvent), which is equivalent to NS_ENSURE_TRUE(nsEvent, NS_ERROR_UNEXPECTED).  Same applies to some other places where you're really just interested in whether the result is null.

>  // Get the target id - this is the target after all retargeting.
>  // We only really use this if the original target is anonymous content.
>  // In that case, since anonymous content doesn't have an id, we identify
>  // the target by that target id + the anonid of the anonymous content
>  nsCOMPtr<nsIDOMEvent> domEvent = do_QueryInterface(nsEvent, &rv);
>  NS_ENSURE_SUCCESS(rv, rv);

You can just use aEvent here, can't you?

>  // 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, &rv);
>  NS_ENSURE_SUCCESS(rv, rv);

It's theoretically possible that the event target is not a node.  In particular, this could happen if the target of the event was 'document' or 'window'.  If that happens, I'm not sure this method should really return "failure" (remember that's equivalent to throwing)... unusual extensions could do something like this.

>  // Actually log it
>  nsMetricsService *ms = nsMetricsService::get();
>  NS_ENSURE_STATE(ms);
>  rv = ms->LogEvent(NS_LITERAL_STRING("ui"), properties);
>

I'd check for success here, then your logging statement actually indicates success.

>#ifdef PR_LOGGING
>  MS_LOG(("Successfully logged UI Event"));
>#endif
>
>  return rv;

And then just change this to return NS_OK.
(Reporter)

Comment 7

13 years ago
(In reply to comment #6)
> It's theoretically possible that the event target is not a node.  In
> particular, this could happen if the target of the event was 'document' or
> 'window'.  If that happens, I'm not sure this method should really return
> "failure" (remember that's equivalent to throwing)... unusual extensions could
> do something like this.

Small correction: 'document' is a DOMNode.  'window' isn't.
(Assignee)

Comment 8

13 years ago
Created attachment 219617 [details] [diff] [review]
updated UI collector

Updated per bryner's comments.  Also ripped out whitelisting, in favor of hashing target IDs.  Also updated to build as a standalone extension.
Attachment #217505 - Attachment is obsolete: true
Attachment #217506 - Attachment is obsolete: true
Attachment #217507 - Attachment is obsolete: true
Attachment #217508 - Attachment is obsolete: true
Attachment #217509 - Attachment is obsolete: true
Attachment #219617 - Flags: first-review?
(Assignee)

Updated

13 years ago
Attachment #219617 - Flags: first-review? → first-review?(bryner)
(Reporter)

Comment 9

13 years ago
Comment on attachment 219617 [details] [diff] [review]
updated UI collector

>--- /dev/null	1 Jan 1970 00:00:00 -0000
>+++ src/nsUICommandCollector.cpp	24 Apr 2006 18:15:43 -0000
>+nsresult
>+nsUICommandCollector::Init()
>+{
>+  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);
>+
>+}

You need to return NS_OK at the end of the function.

>+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

You might want to say briefly why it's capturing and not bubbling.

>+NS_IMETHODIMP
>+nsUICommandCollector::HandleEvent(nsIDOMEvent* aEvent)
>+{
>+  // First check that this is an event type that we expect
>+  nsString type;
>+  nsresult rv = aEvent->GetType(type);

Either don't assign to rv, or check the result for failure (it doesn't matter too much which one).

>+  if (!type.Equals(NS_LITERAL_STRING("command"))) {
>+
>+#ifdef PR_LOGGING
>+    MS_LOG(("UICommandCollector: Unexpected event type %s received",
>+            NS_ConvertUTF16toUTF8(type.get())));

The macro argument is a little backwards.  You want:

NS_ConvertUTF16toUTF8(type).get()

because you want the final result to be a const char*.  It's kind of unfortunate that what you have compiles.  Also, you don't need to #ifdef it -- MS_LOG() is defined to empty if PR_LOGGING is turned off.  Same comment applies to other MS_LOG usage.

>+  // First try looking up the Original Target ID in our whitelist.  In some
>+  // cases this id might be empty (i.e. for anonymous content).  In that
>+  // case, fall back on looking for the Target ID in
>+  // our whitelist.  If we don't find that an ID is in our whitelist, return
>+  // without logging anything.

This comment needs to be updated.

>+  // Fill a property bag with what we want to log
>+  nsRefPtr<nsIWritablePropertyBag2> properties;

It doesn't _really_ matter, but all of the other collectors use nsCOMPtr for this, can you change it to be consistent?  Remove #include "nsAutoPtr.h" when you make this change.

>+  } else {
>+   nsCString hashedOrigId;
>+   nsresult rv = ms->Hash(orig_id, hashedOrigId);
>+   NS_ENSURE_SUCCESS(rv, rv);

So, I'm a little confused about why you use separate variables and separate codepaths for logging the "id" based on whether we're logging "anonid".  Can't you just always log the id the same way, and then also log the anonid if you need to?

>+  // Actually log it
>+  rv = ms->LogEvent(NS_LITERAL_STRING("ui"), properties);

The event name should be uielement.
Attachment #219617 - Flags: first-review?(bryner) → first-review-
(Assignee)

Comment 10

13 years ago
(In reply to comment #9)

> 
> >+  } else {
> >+   nsCString hashedOrigId;
> >+   nsresult rv = ms->Hash(orig_id, hashedOrigId);
> >+   NS_ENSURE_SUCCESS(rv, rv);
> 
> So, I'm a little confused about why you use separate variables and separate
> codepaths for logging the "id" based on whether we're logging "anonid".  Can't
> you just always log the id the same way, and then also log the anonid if you
> need to?

Actually the kind of id we log is different depending on whether we're logging anonid or not.  First we try to log the _Original_ Target ID (target after text retargeting only) - if that is empty we log the Target ID (target after all retargeting) plus the anonid.  In that second case we need the target ID to distinguish between the same anonid used under different targets.  I've updated the comments to make this more clear.  (Note that I'm copying Original Target and Target terminology from the API :-))

> >+  // Actually log it
> >+  rv = ms->LogEvent(NS_LITERAL_STRING("ui"), properties);
> 
> The event name should be uielement.
> 

updated id to be targetidhash and anonid to be targetanonidhash as well


I have updated the patch according to all of your other comments
(Assignee)

Comment 11

13 years ago
Created attachment 219690 [details] [diff] [review]
updated patch
Attachment #219617 - Attachment is obsolete: true
Attachment #219690 - Flags: first-review?
(Assignee)

Updated

13 years ago
Attachment #219690 - Flags: first-review? → first-review?(bryner)
(Reporter)

Comment 12

13 years ago
Comment on attachment 219690 [details] [diff] [review]
updated patch

cancelling review based on some changes we talked about offline
Attachment #219690 - Flags: first-review?(bryner)
(Assignee)

Comment 13

13 years ago
Created attachment 219815 [details] [diff] [review]
updated patch

Updated to only ever log target id, since original target id = target id for content that is not anonymous.  Also added OnAttach, as per offline discussion.
Attachment #219690 - Attachment is obsolete: true
Attachment #219815 - Flags: first-review?
(Assignee)

Updated

13 years ago
Attachment #219815 - Flags: first-review? → first-review?(bryner)
(Reporter)

Comment 14

13 years ago
Comment on attachment 219815 [details] [diff] [review]
updated patch

>--- public/nsIMetricsCollector.idl	25 Apr 2006 04:01:07 -0000	1.1.2.2
>+++ public/nsIMetricsCollector.idl	25 Apr 2006 23:56:13 -0000
>@@ -44,20 +44,27 @@
>  * collector "foo" in namespace "http://www.mozilla.org/metrics",
>  * the contract id
>  * "@mozilla.org/metrics/collector;1?name=http://www.mozilla.org/metrics:foo"
>  * 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)]
> interface nsIMetricsCollector : nsISupports
> {
>   /**
>+   * Notification that this collector should be enabled.  The collector
>+   * should register itself for observer and event notifications as
>+   * necessary.
>+   */
>+  void onAttach();
>+

You should change the uuid of the interface whenever you add/remove/change a method.

>--- src/nsMetricsService.cpp	25 Apr 2006 04:02:37 -0000	1.4.2.20
>+++ src/nsMetricsService.cpp	25 Apr 2006 23:56:14 -0000
>@@ -740,20 +740,21 @@ nsMetricsService::EnableCollectors()
>   for (i = 0; i < enabledCollectors.Length(); ++i) {
>     const nsString &name = enabledCollectors[i];
>     if (!mCollectorMap.GetWeak(name)) {
>       nsCString contractID("@mozilla.org/metrics/collector;1?name=");
>       contractID.Append(NS_ConvertUTF16toUTF8(name));
> 
>       nsCOMPtr<nsIMetricsCollector> coll = do_GetService(contractID.get());
>       if (coll) {
>         MS_LOG(("Created collector %s", contractID.get()));
>         mCollectorMap.Put(name, coll);
>+        coll->OnAttach();

It seems like we should call OnAttach before we put the collector into the hash table, and not insert it if OnAttach failed.

nsUICommandCollector.cpp:

>+/* static */
>+PLDHashOperator PR_CALLBACK nsUICommandCollector::RemoveCommandEventListener(
>+const void* aKey, PRUint32 windowID, void* aUserArg)
>+{
>+  const nsIDOMWindow* window = NS_STATIC_CAST(const nsIDOMWindow*, aKey);
>+  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*,
>+                                                 aUserArg);
>+  if (!listener) {

The cast can't really fail... it would probably be cleaner to just null check aUserArg at the start.

>+  nsresult rv = windowTarget->RemoveEventListener(NS_LITERAL_STRING("command"),
>+                                                  listener, PR_TRUE);
>+  if (!NS_SUCCEEDED(rv)) {

if (NS_FAILED(rv))

Looks good otherwise.
Attachment #219815 - Flags: first-review?(bryner) → first-review+
(Reporter)

Comment 15

13 years ago
(In reply to comment #14)
> It seems like we should call OnAttach before we put the collector into the hash
> table, and not insert it if OnAttach failed.

Actually, I changed my mind on this.  For consistency, with onDetach/onNewLog, we should just treat this as a notification, not a chance for the collector to cancel itself.
(Reporter)

Comment 16

13 years ago
Ok, checked in on trunk and branch.

I fixed a few other small things I should have caught in the review, hope that's ok.  Here's a list:

- removed now-unused nsUICommandCollector::sInstance
- removed unused Init() declarations from nsUICommandCollector.h and nsWindowCollector.h
- removed unneeded #include nsBaseHashtable.h in nsUICommandCollector.h
- changed argument names to uniformly not be prefixed with "a" for consistency with the rest of the extension
- got rid of the temporary "windows" variable in nsUICommandCollector::OnDetach, it's more readable to just call ms->WindowMap().EnumerateRead(...)
Status: ASSIGNED → RESOLVED
Last Resolved: 13 years ago
Resolution: --- → FIXED
(Reporter)

Updated

13 years ago
Depends on: 336696
(Reporter)

Updated

13 years ago
No longer blocks: 328064

Updated

8 years ago
Component: Data Collection/Metrics → Data Collection/Metrics
Flags: first-review-
Flags: first-review+
Product: Toolkit → Toolkit Graveyard
You need to log in before you can comment on or make changes to this bug.