New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"bubbles" flag for monitoring of all IFRAMEs #86

Open
nicjansma opened this Issue Aug 11, 2017 · 7 comments

Comments

Projects
None yet
3 participants
@nicjansma
Copy link

nicjansma commented Aug 11, 2017

I'd like to discuss a method for registering a PerformanceObserver that would notify me of the observable entries from all (same-origin) frames on the page, from the root frame plus all (same-origin) descendants (children, grand-children, etc).

The motivation for this is that we'd like to be able to monitor the complete picture of events happening on the page (as an example, ResourceTiming entries), in every frame, without having to register a PerformanceObserver in all of those frames.

With today's PerformanceObserver, if we want to monitor all frames, at startup, we'll register PO for the root frame, then traverse the frame.frames tree to access all same-origin frames, registering POs there as well. Once we've done that, we'll have to translate events from any descendant frame's time-origin to the root frame's time origin.

After doing the above, what about new IFRAMEs that get added to the page dynamically? We'd either have to register a MutationObserver to listen in all of these frames just to be notified of any new frames (ugh! talk about observer effect!), or crawl the frame tree later (at beacon time) to see which ones didn't have a PO registered, and hope their buffers hadn't been filled up.

Instead, I'd love to get a bubbles: true flag (there's probably a better name) available during PO registration:

observer.observe({
  entryTypes: ["resource", "mark", "measure"],
  buffered: true,
  bubbles: true
});

If set, this would:

  • Notify me of any matching entries in any of my (same origin) descendant frames
  • Any new frames that are created anywhere in my tree would automatically be included
  • Translate the time-origin from any descendant entries to the registered frame's time-origin
  • Give me minimal frame attribution so I have a vague idea where it came from

(note, LongTasks already kind of does this, as it notifies you of entries happening in same- and cross-origin frames).

@igrigorik

This comment has been minimized.

Copy link
Member

igrigorik commented Aug 30, 2017

The use case is compelling and makes sense.

There are some implementation gotchas we need to think through...

  • How does the PO distinguish which frame — does it matter, in practice? — the entry is coming from? E.g. if you have an iframe fetching resources, and top-level frame is receiving notifications for it, how does it know that the RT entry belongs to the child frame?
    • Long Tasks API is already exposing events from different frames, is there a way to generalize LT behavior, or vice versa.. define a shared mechanism that LT should be using?
  • Would setting bubbles propagate up the tree only? E.g. a same-origin iframe registers a PO with bubbles, would we expect it to receive entries from the parent?

/cc @toddreifsteck @spanicker @tdresser

@tdresser

This comment has been minimized.

Copy link
Contributor

tdresser commented Sep 1, 2017

  • I think we do need to be able to distinguish frames. The current long tasks V2 explainer mentions, but doesn't clearly define containerType, containerSrc, containerId and containerName. Firming up our proposal there feels like a reasonable next step here.
  • If we want bidirectional propagation, I think bubbles is the wrong name. Perhaps global or crossFrame? I think bidirectional propagation is probably the simplest approach. Are there any cases where you'd want entries from your ancestors but not your children, or vice versa? I haven't come up with any.
@tdresser

This comment has been minimized.

Copy link
Contributor

tdresser commented Sep 1, 2017

Sorry, I was wrong about the first point. These fields are defined here.

Adding some subset of these to PerformanceEntry would be a plausible approach.

@nicjansma

This comment has been minimized.

Copy link

nicjansma commented Sep 4, 2017

How does the PO distinguish which frame — does it matter, in practice?

As a starting point, I like LongTasks's self|*-origin-* for "where" and containerType etc for "who".

Are there any cases where you'd want entries from your ancestors but not your children, or vice versa? I haven't come up with any.

Yeah it seems like getting notifications for everything up and down the chain would be helpful. As long as I can distinguish where it came from (i.e. LongTask's same-origin-ancestor vs same-origin-descendant), that should suffice.

global: true is nicely descriptive!

@igrigorik

This comment has been minimized.

Copy link
Member

igrigorik commented Sep 8, 2017

As a starting point, I like LongTasks's self|-origin- for "where" and containerType etc for "who".

Why just containerType and not also container{Src,Id,Name}. Did the latter prove to be less useful in context of Long Tasks API? If so, should we drop those there as well?

Are there any cases where you'd want entries from your ancestors but not your children, or vice versa? I haven't come up with any.

Yeah it seems like getting notifications for everything up and down the chain would be helpful. As long as I can distinguish where it came from (i.e. LongTask's same-origin-ancestor vs same-origin-descendant), that should suffice.

Nic, what's a concrete use case for this? Is it common for analytics to embedded inside a same-origin iframe, and then harvest data from parent frame? What about same-origin frames (e.g. other tabs), would we expect to show records from those too, same as LongTasks?

@nicjansma

This comment has been minimized.

Copy link

nicjansma commented Sep 8, 2017

Why just containerType and not also container{Src,Id,Name}

Oh, I want them all still! "containerType etc". I've found that each is used in different cases, i.e. some third parties only set the src while others will also set an id/name that is easier to associate with the third-party.

Is it common for analytics to embedded inside a same-origin iframe, and then harvest data from parent frame?

That's how Boomerang is loaded today, though we basically "break out" of the same-origin iframe and do all of our work (e.g. register the PerfObserver) in/to the root frame anyways.

What about same-origin frames (e.g. other tabs), would we expect to show records from those too, same as LongTasks?

I don't have a strong opinion here, since we (and I feel like other analytics scripts) would most likely register their PO in the root frame if possible (and would expect to see entries for all same-origin descendants).

@igrigorik

This comment has been minimized.

Copy link
Member

igrigorik commented Sep 8, 2017

Ok, so it sounds like we'd then want to lift the ~container attribute definitions "all the way" into PerformanceEntry..

PerformanceEntry {
    readonly attribute DOMString containerType;
    readonly attribute DOMString containerSrc;
    readonly attribute DOMString containerId;
    readonly attribute DOMString containerName;
}

I'm still a bit skeptical on the "global" bit. If we stick with "bubbles up", I think the use case you outlined at the start is fulfilled. Moving to "global" opens up another axis of complexity: we need to signal direction (descendant, ancestor, self, same-origin), and my intuition is that we don't want to enable Observers to collect entries across windows that share event loop -- e.g. multiple same-origin top-level tabs open by the user?

/cc @spanicker

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment