w3c / performance-timeline

Performance Timeline
https://w3c.github.io/performance-timeline/
Other
111 stars 27 forks source link

"bubbles" flag for monitoring of all IFRAMEs #86

Open nicjansma opened 7 years ago

nicjansma commented 7 years ago

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:

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

igrigorik commented 7 years ago

The use case is compelling and makes sense.

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

/cc @toddreifsteck @spanicker @tdresser

tdresser commented 7 years ago
tdresser commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 2 years ago

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 commented 1 year ago

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.