-
Notifications
You must be signed in to change notification settings - Fork 20
/
index.html
343 lines (258 loc) · 18.4 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
<!DOCTYPE html>
<head>
<title>Server Timing</title>
<meta charset='utf-8'>
<meta name="color-scheme" content="light dark">
<script src='https://www.w3.org/Tools/respec/respec-w3c' async class='remove'></script>
<script class='remove'>
var respecConfig = {
shortName: "server-timing",
specStatus: "ED",
edDraftURI: "https://w3c.github.io/server-timing/",
editors: [{
name: "Charles Vazac",
mailto: "[email protected]",
company: "Akamai",
companyURL: "https://www.akamai.com/",
w3cid: "77116"
}, {
name: "Ilya Grigorik",
url: "https://www.igvita.com/",
company: "Google",
companyURL: "https://www.google.com/",
w3cid: "56102"
}],
group:"webperf",
wg: "Web Performance Working Group",
wgURI: "https://www.w3.org/webperf/",
wgPublicList: "public-web-perf",
subjectPrefix: "[server-timing]",
license: 'w3c-software-doc',
format: "markdown",
xref: ["webidl", "fetch", "secure-contexts", "html", "hr-time", "infra"],
github: "https://github.com/w3c/server-timing/",
otherLinks: [{
key: 'Mailing list',
data: [{
value: '[email protected]',
href: 'https://lists.w3.org/Archives/Public/public-web-perf/'
}]
},{
key: 'Implementation',
data: [{
value: 'Test Suite',
href: 'http://w3c-test.org/server-timing/'
}, {
value: 'Test Suite repository',
href: 'https://github.com/web-platform-tests/wpt/tree/master/server-timing'
}]
}],
wgPatentURI: "https://www.w3.org/2004/01/pp-impl/45211/status"
};
</script>
</head>
<section id='abstract'>
This specification enables a server to communicate performance metrics about the request-response cycle to the user agent. It also standardizes a JavaScript interface to enable applications to collect, process, and act on these metrics to optimize application delivery.
</section>
<section id='sotd'>
</section>
<section class='informative'>
## Introduction
Accurately measuring performance characteristics of web applications is an important aspect of making web applications faster. [[NAVIGATION-TIMING]] and [[RESOURCE-TIMING]] provide detailed request timing information for the document and its resources, which include time when the request was initiated, and various milestones to negotiate the connection and receive the response. However, while the user agent can observe the timing data of the request it has no insight into how or why certain stages of the request-response cycle have taken as much time as they have - e.g., how the request was routed, where the time was spent on the server, and so on.
This specification introduces {{PerformanceServerTiming}} interface, which enables the server to communicate performance metrics about the request-response cycle to the user agent, and a JavaScript interface to enable applications to collect, process, and act on these metrics to optimize application delivery.
</section>
<section id='conformance'></section>
<section>
### The `Server-Timing` Header Field
The <dfn>Server-Timing header field</dfn> is used to communicate one or more metrics and descriptions for the given request-response cycle. The ABNF (Augmented Backus-Naur Form) [[RFC5234]] syntax for the [=Server-Timing header field=] is as follows:
```ABNF
Server-Timing = #server-timing-metric
server-timing-metric = metric-name *( OWS ";" OWS server-timing-param )
metric-name = token
server-timing-param = server-timing-param-name OWS "=" OWS server-timing-param-value
server-timing-param-name = token
server-timing-param-value = token / quoted-string
```
See [[RFC7230]] for definitions of `#`, `*`, `OWS`, `token`, and `quoted-string`.
A response MAY have multiple server-timing-metric entries with the same metric-name, and the user agent MUST process and expose all such entries.
The user agent MAY surface provided metrics in any order - i.e. the order of metrics in the HTTP header field is not significant.
This header field is defined with an extensible syntax to allow for future parameters. A user agent that does not recognize particular server-timing-param-name in the Server-Timing header field of a response MUST ignore those tokens and continue processing instead of signaling an error.
To avoid any possible ambiguity, individual `server-timing-param-name`s SHOULD NOT appear multiple times within a `server-timing-metric`. If any `server-timing-param-name` is specified more than once, only the first instance is to be considered, even if the `server-timing-param` is incomplete or invalid. All subsequent occurrences MUST be ignored without signaling an error or otherwise altering the processing of the `server-timing-metric`. This is the only case in which the ordering of parameters within a `server-timing-metric` is considered to be significant.
User agents MUST ignore extraneous characters found after a `server-timing-param-value` but before the next `server-timing-param` and before the end of the current `server-timing-metric`.
User agents MUST ignore extraneous characters found after a `metric-name` but before the first `server-timing-param` and before the next `server-timing-metric`.
<p data-link-for="PerformanceServerTiming">
This specification establishes the server-timing-params for server-timing-param-names "dur" for {{duration}} and "desc" for {{description}}, both optional.
</p>
<div class="note">
- To minimize the HTTP overhead the provided names and descriptions should be kept as short as possible - e.g. use abbreviations and omit optional values where possible.
- Because there can be no guarantee of clock synchronization between client, server, and intermediaries, it is impossible to map a meaningful `startTime` onto the clients timeline. For that reason, any `startTime` attribution is purposely omitted from this specification. If the developers want to establish a relationship between multiple entries, they can do so by communicating custom data via metric names and/or descriptions.
- The server and/or any relevant intermediaries are in full control of which metrics are communicated to the user agent and when. For example, access to some metrics may be restricted due to privacy or security reasons - see <a href="#privacy-and-security"></a> section.
</div>
To <dfn>parse a server-timing header field</dfn> given a string |field|:
1. Let |position| be a [=string/position variable=], initially pointing at the start of |field|.
1. Let |name| be the result of [=collecting a sequence of code points=] from |field| that are not equal to U+003B (;), given |position|.
1. [=Strip leading and trailing ASCII whitespace=] from |name|.
1. If |name| is an empty string, return null.
1. Let |metric| be a new {{PerformanceServerTiming}} whose <a data-for="PerformanceServerTiming">metric name</a> is |name|.
1. Let |params| be an empty <a>ordered map</a>.
1. While |position| is not at the end of |field|:
1. Advance |position| by 1.
1. Let |paramName| be the result of [=collecting a sequence of code points=] from |field| that are not equal to U+003D (=), given |position|.
1. [=Strip leading and trailing ASCII whitespace=] from |paramName|.
1. If |paramName| is an empty string or |params|[|paramName|] [=map/exists=], [=iteration/continue=].
1. Advance |position| by 1.
1. Let |paramValue| be an empty string.
1. [=Skip ASCII whitespace=] within |field| given |position|.
1. If the [=code point=] at |position| within |field| is U+0022 ("), then:
1. Set |paramValue| to the result of [=collecting an HTTP quoted string=] from |field| given |position| with the <i>extract-value flag</i> set.
1. [=Collect a sequence of code points=] from |field| that are not equal to U+003B (;), given |position|. The result is not used.
1. Otherwise:
1. Let |rawParamValue| be the result of [=collecting a sequence of code points=] from |field| that are not equal to U+003B (;), given |position|.
1. Let |paramValue| be the result of [=strip leading and trailing ASCII whitespace|stripping=] |rawParamValue|.
1. [=map/set|Set=] |metric|'s <a data-for="PerformanceServerTiming">params</a> to |params|.
1. Return |metric|.
</section>
<section data-dfn-for="PerformanceServerTiming" data-link-for="PerformanceServerTiming">
## The <dfn>PerformanceServerTiming</dfn> Interface
``` webidl
[Exposed=(Window,Worker)]
interface PerformanceServerTiming {
readonly attribute DOMString name;
readonly attribute DOMHighResTimeStamp duration;
readonly attribute DOMString description;
[Default] object toJSON();
};
```
When <dfn class="export" data-dfn-for="PerformanceServerTiming">toJSON</dfn> is called, run [[WEBIDL]]'s [=default toJSON steps=].
### <dfn>name</dfn> attribute
The <a>name</a> getter steps are to return <a>this</a>'s <a data-for="PerformanceServerTiming">metric name</a>.
### <dfn>duration</dfn> attribute
The <a>duration</a> getter steps are to do the following:
1. If <a>this</a>'s <a data-for="PerformanceServerTiming">params</a>[<code>"dur"</code>] does not [=map/exists|exist=], return 0.
1. Let |dur| be the result of parsing <a>this</a>'s <a data-for="PerformanceServerTiming">params</a>[<code>"dur"</code>] using the [=rules for parsing floating-point number values=].
1. If |dur| is an error, return 0; Otherwise return |dur|.
<p class="note">
Since <a>duration</a> is a {{DOMHighResTimeStamp}}, it usually represents a [=duration=] in
milliseconds. Since this is not enforcable in practice, <a>duration</a> can represent any unit
of time, and having it represent a [=duration=] in milliseconds is a recommendation.
</p>
### <dfn>description</dfn> attribute
The <a>description</a> getter steps are to return <a>this</a>'s <a data-for="PerformanceServerTiming">params</a>[<code>"desc"</code>] if it [=map/exists=], otherwise the empty string.
A {{PerformanceServerTiming}} has an associated string <dfn>metric name</dfn>, initially set to the empty string.
A {{PerformanceServerTiming}} has an associated <a>ordered map</a> <dfn>params</dfn>, initially empty.
</section>
<!-- TODO: How do extend and cross-reference the interface? -->
<section data-dfn-for="PerformanceResourceTiming" data-link-for="PerformanceResourceTiming">
### Extension to the {{PerformanceResourceTiming}} interface
The {{PerformanceResourceTiming}} interface, which this specification partially extends, is defined in [[RESOURCE-TIMING]].
``` webidl
[Exposed=(Window,Worker)]
partial interface PerformanceResourceTiming {
readonly attribute FrozenArray<PerformanceServerTiming> serverTiming;
};
```
### <code>serverTiming</code> attribute
The <dfn>serverTiming</dfn> getter steps are the following:
1. Let |entries| be a new [=list=].
1. [=list/iterate|For each=] |field| in <a>this</a>'s <a data-cite="RESOURCE-TIMING#dfn-timing-info">timing info</a>'s [=fetch timing info/server-timing headers=]:
1. Let |metric| be the result of [=parse a server-timing header field|parsing=] |field|.
1. If |metric| is not null, [=list/append=] |metric| to |entries|.
1. Return |entries|.
</section>
<section class='informative'>
## Privacy and Security
The interfaces defined in this specification expose potentially sensitive application and infrastructure information to any web page that has included a resource that advertises server timing metrics. For this reason the access to `PerformanceServerTiming` interface is restricted by the [=same origin=] policy by default. Resource providers can explicitly allow server timing information to be available by adding the `Timing-Allow-Origin` HTTP response header, as defined in [[RESOURCE-TIMING]], that specifies the domains that may be allowed to access the server metrics, but the user agent MAY keep the [=same origin=] policy restriction.
In addition to using the `Timing-Allow-Origin` HTTP response header, the server can also use relevant logic to control which metrics are returned, when, and to whom - e.g. the server may only provide certain metrics to correctly authenticated users and nothing at all to all others.
</section>
<section>
## IANA Considerations
The permanent message header field registry should be updated with the following registrations ([[RFC3864]]):
### Server-Timing Header Field
<dl>
<dt>Header field name</dt>
<dd>Server-Timing</dd>
<dt>Applicable protocol</dt>
<dd>http</dd>
<dt>Status</dt>
<dd>standard</dd>
<dt>Author/Change controller</dt>
<dd>W3C</dd>
<dt>Specification document</dt>
<dd>This specification (See [=Server-Timing Header Field=])</dd>
</dl>
</section>
<section class='appendix informative'>
## Examples
<pre class="example http">
> GET /resource HTTP/1.1
> Host: example.com
<br>
< HTTP/1.1 200 OK
< Server-Timing: miss, db;dur=53, app;dur=47.2
< Server-Timing: customView, dc;desc=atl
< Server-Timing: cache;desc="Cache Read";dur=23.2
< Trailer: Server-Timing
< (... snip response body ...)
< Server-Timing: total;dur=123.4
</pre>
<table class="parameters">
<thead>
<tr>
<th>Name</th>
<th>Duration</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr><td>miss</td><td></td><td></td></tr>
<tr><td>db</td><td>53</td><td></td></tr>
<tr><td>app</td><td>47.2</td><td></td></tr>
<tr><td>customView</td><td></td><td></td></tr>
<tr><td>dc</td><td></td><td>atl</td></tr>
<tr><td>cache</td><td>23.2</td><td>Cache Read</td></tr>
<tr><td>total</td><td>123.4</td><td></td></tr>
</tbody>
</table>
<p>The above header fields communicate six distinct metrics that illustrate all the possible ways for the server to communicate data to the user agent: metric name only, metric with value, metric with value and description, and metric with description. For example, the above metrics may indicate that for `example.com/resource.jpg` fetch:</p>
<ol>
<li>There was a cache miss.</li>
<li>The request was routed through the "atl" datacenter ("dc").</li>
<li>The database ("db") time was 53 ms.</li>
<li>A cache read took 23.2 ms.</li>
<li>The application server ("app") took 47.2ms to process "customView" template or function.</li>
<li>The total time for the request-response cycle on the server was 123.4ms, which is recorded at the end of the response and delivered via a trailer field.</li>
</ol>
<p>The application can collect, process, and act on the provided metrics via the provided JavaScript interface:</p>
<pre class="example js">
// serverTiming entries can live on 'navigation' and 'resource' entries
for (const entryType of ['navigation', 'resource']) {
for (const {name: url, serverTiming} of performance.getEntriesByType(entryType)) {
// iterate over the serverTiming array
for (const {name, duration, description} of serverTiming) {
// we only care about "slow" ones
if (duration > 200) {
console.info('Slow server-timing entry =',
JSON.stringify({url, entryType, name, duration, description}, null, 2))
}
}
}
}
</pre>
</section>
<section class='appendix informative'>
## Use cases
### Server timing in developer tools
Server processing time can be a significant fraction of the total request time. For example, a dynamic response may require one or more database queries, cache lookups, API calls, time to process relevant data and render the response, and so on. Similarly, even a static response can be delayed due to overloaded servers, slow caches, or other reasons.
Today, the user agent developer tools are able to show when the request was initiated, and when the first and last bytes of the response were received. However, there is no visibility into where or how the time was spent on the server, which means that the developer is unable to quickly diagnose if there is a performance bottleneck on the server, and if so, in which component. Today, to answer this question, the developer is required to use different techniques: check the server logs, embed performance data within the response (if possible), use external tools, and so on. This makes identifying and diagnosing performance bottlenecks hard, and in many cases impractical.
Server Timing defines a standard mechanism that enables the server to communicate relevant performance metrics to the client and allows the client to surface them directly in the developer tools - e.g. the requests can be annotated with server sent metrics to provide insight into where or how the time was spent while generating the response.
### Server timing for automated analytics
In addition to surfacing server sent performance metrics in the developer tools, a standard JavaScript interface enables analytics tools to automatically collect, process, beacon, and aggregate these metrics for operational and performance analysis.
### Measuring request routing performance
Server Timing enables origin servers to communicate performance metrics about where or how time is spent while processing the request. However, the same request and response may also be routed through one or more multiple proxies (e.g. cache servers, load balancers, and so on), each of which may introduce own delays and may want to provide performance metrics into where or how the time is spent.
For example, a CDN edge node may want to report which data center was being used, if the resource was available in cache, and how long it took to retrieve the response from cache or from the origin server. Further, the same process may be repeated by other proxies, thus allowing full end-to-end visibility into how the request was routed and where the time was spent.
Similarly, when a Service Worker is active, some or all of the navigation and resource requests may be routed through it. Effectively, an active Service Worker is a local proxy that is able to reroute requests, serve cached responses, synthesize responses, and more. As a result, Server Timing enables Service Worker to report custom performance metrics about how the request was processed: whether it was fetched from a server or served from local cache, duration of relevant the processing steps, and so on.
</section>
<section class='appendix informative'>
## Acknowledgments
This document reuses text from the [[NAVIGATION-TIMING]], [[RESOURCE-TIMING]], [[PERFORMANCE-TIMELINE-2]], and [[RFC6797]] specifications as permitted by the licenses of those specifications.
</section>