Skip to content
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 · 9 comments
Open

"bubbles" flag for monitoring of all IFRAMEs #86

nicjansma opened this issue Aug 11, 2017 · 9 comments
Milestone

Comments

@nicjansma
Copy link

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
Copy link
Member

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
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
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
Copy link
Author

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
Copy link
Member

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
Copy link
Author

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
Copy link
Member

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

@clelland
Copy link
Contributor

My current proposal for this is outlined in this doc, and adds an "includeFrames" flag for the caller of getEntries methods, as well as on the PerformanceObserver init dict. There's also an opt-in mechanism so that cross-origin frames can be included as well, through document policy.

Spec change for review at #202

@noamr
Copy link
Contributor

noamr commented Feb 20, 2023

I just went through the documents and proposals around this, and I feel like we're missing a big piece which is workers (mainly service workers, but not only). Those could have their own entries, which would not be included in the iframe timeline, thus giving a partial picture when relying on this to understand the impact of a particular 3rd party.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants