Skip to content

Commit cab3e37

Browse files
authored
Improve asset-worker tracing and add tracing into router-worker (#7887)
* Add more spans into asset-worker fetch handling * Add tracing observability into router-worker
1 parent a7965c7 commit cab3e37

File tree

7 files changed

+123
-32
lines changed

7 files changed

+123
-32
lines changed

.changeset/nice-mice-mix.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@cloudflare/workers-shared": patch
3+
---
4+
5+
chore: add more observability into asset-worker for the Workers team to better insight into how requests are handled.

.changeset/plenty-guests-look.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@cloudflare/workers-shared": patch
3+
---
4+
5+
chore: add tracing into router-worker so the Workers team can have a better insight into into how requests are handled.

packages/workers-shared/asset-worker/src/handler.ts

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,30 @@ export const handleRequest = async (
2727
const intent = await getIntent(decodedPathname, configuration, exists);
2828

2929
if (!intent) {
30-
return new NotFoundResponse();
30+
return env.JAEGER.enterSpan("no_intent", (span) => {
31+
span.setTags({
32+
decodedPathname,
33+
configuration: JSON.stringify(configuration),
34+
status: 404,
35+
});
36+
37+
return new NotFoundResponse();
38+
});
3139
}
3240

3341
// if there was a POST etc. to a route without an asset
3442
// this should be passed onto a user worker if one exists
3543
// so prioritise returning a 404 over 405?
3644
const method = request.method.toUpperCase();
3745
if (!["GET", "HEAD"].includes(method)) {
38-
return new MethodNotAllowedResponse();
46+
return env.JAEGER.enterSpan("method_not_allowed", (span) => {
47+
span.setTags({
48+
method,
49+
status: 405,
50+
});
51+
52+
return new MethodNotAllowedResponse();
53+
});
3954
}
4055

4156
const decodedDestination = intent.redirect ?? decodedPathname;
@@ -47,11 +62,29 @@ export const handleRequest = async (
4762
* We combine this with other redirects (e.g. for html_handling) to avoid multiple redirects.
4863
*/
4964
if ((encodedDestination !== pathname && intent.asset) || intent.redirect) {
50-
return new TemporaryRedirectResponse(encodedDestination + search);
65+
return env.JAEGER.enterSpan("redirect", (span) => {
66+
span.setTags({
67+
originalPath: pathname,
68+
location:
69+
encodedDestination !== pathname
70+
? encodedDestination
71+
: intent.redirect ?? "<unknown>",
72+
status: 307,
73+
});
74+
75+
return new TemporaryRedirectResponse(encodedDestination + search);
76+
});
5177
}
5278

5379
if (!intent.asset) {
54-
return new InternalServerErrorResponse(new Error("Unknown action"));
80+
return env.JAEGER.enterSpan("unknown_action", (span) => {
81+
span.setTags({
82+
pathname,
83+
status: 500,
84+
});
85+
86+
return new InternalServerErrorResponse(new Error("Unknown action"));
87+
});
5588
}
5689

5790
const asset = await env.JAEGER.enterSpan("getByETag", async (span) => {
@@ -70,16 +103,31 @@ export const handleRequest = async (
70103
const weakETag = `W/${strongETag}`;
71104
const ifNoneMatch = request.headers.get("If-None-Match") || "";
72105
if ([weakETag, strongETag].includes(ifNoneMatch)) {
73-
return new NotModifiedResponse(null, { headers });
74-
}
106+
return env.JAEGER.enterSpan("matched_etag", (span) => {
107+
span.setTags({
108+
matchedEtag: ifNoneMatch,
109+
status: 304,
110+
});
75111

76-
const body = method === "HEAD" ? null : asset.readableStream;
77-
switch (intent.asset.status) {
78-
case 404:
79-
return new NotFoundResponse(body, { headers });
80-
case 200:
81-
return new OkResponse(body, { headers });
112+
return new NotModifiedResponse(null, { headers });
113+
});
82114
}
115+
116+
return env.JAEGER.enterSpan("response", (span) => {
117+
span.setTags({
118+
etag: intent.asset.eTag,
119+
status: intent.asset.status,
120+
head: method === "HEAD",
121+
});
122+
123+
const body = method === "HEAD" ? null : asset.readableStream;
124+
switch (intent.asset.status) {
125+
case 404:
126+
return new NotFoundResponse(body, { headers });
127+
case 200:
128+
return new OkResponse(body, { headers });
129+
}
130+
});
83131
};
84132

85133
type Intent =
@@ -90,6 +138,7 @@ type Intent =
90138
| { asset: null; redirect: string }
91139
| null;
92140

141+
// TODO: Trace this
93142
export const getIntent = async (
94143
pathname: string,
95144
configuration: Required<AssetConfig>,

packages/workers-shared/asset-worker/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { WorkerEntrypoint } from "cloudflare:workers";
22
import { PerformanceTimer } from "../../utils/performance";
33
import { setupSentry } from "../../utils/sentry";
4+
import { mockJaegerBinding } from "../../utils/tracing";
45
import { Analytics } from "./analytics";
56
import { AssetsManifest } from "./assets-manifest";
67
import { applyConfigurationDefaults } from "./configuration";
78
import { decodePath, getIntent, handleRequest } from "./handler";
89
import { InternalServerErrorResponse } from "./responses";
910
import { getAssetWithMetadataFromKV } from "./utils/kv";
10-
import { mockJaegerBinding } from "./utils/mocks";
1111
import type {
1212
AssetWorkerConfig,
1313
ColoMetadata,
@@ -164,6 +164,7 @@ export default class extends WorkerEntrypoint<Env> {
164164
}
165165
}
166166

167+
// TODO: Trace unstable methods
167168
async unstable_canFetch(request: Request): Promise<boolean> {
168169
const url = new URL(request.url);
169170
const decodedPathname = decodePath(url.pathname);

packages/workers-shared/asset-worker/tests/handler.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { vi } from "vitest";
2+
import { mockJaegerBinding } from "../../utils/tracing";
23
import { applyConfigurationDefaults } from "../src/configuration";
34
import { handleRequest } from "../src/handler";
4-
import { mockJaegerBinding } from "../src/utils/mocks";
55
import type { AssetConfig } from "../../utils/types";
66

77
describe("[Asset Worker] `handleRequest`", () => {
@@ -222,7 +222,7 @@ describe("[Asset Worker] `handleRequest`", () => {
222222
const response2 = await handleRequest(
223223
new Request("https://example.com/%A0%A0"),
224224
// @ts-expect-error Empty config default to using mocked jaeger
225-
{},
225+
mockEnv,
226226
configuration,
227227
exists,
228228
getByEtag

packages/workers-shared/router-worker/src/index.ts

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
import { PerformanceTimer } from "../../utils/performance";
22
import { setupSentry } from "../../utils/sentry";
3+
import { mockJaegerBinding } from "../../utils/tracing";
34
import { Analytics, DISPATCH_TYPE } from "./analytics";
45
import type AssetWorker from "../../asset-worker/src/index";
5-
import type { RoutingConfig, UnsafePerformanceTimer } from "../../utils/types";
6+
import type {
7+
JaegerTracing,
8+
RoutingConfig,
9+
UnsafePerformanceTimer,
10+
} from "../../utils/types";
611
import type { ColoMetadata, Environment, ReadyAnalytics } from "./types";
712

813
interface Env {
@@ -16,6 +21,7 @@ interface Env {
1621
COLO_METADATA: ColoMetadata;
1722
UNSAFE_PERFORMANCE: UnsafePerformanceTimer;
1823
VERSION_METADATA: WorkerVersionMetadata;
24+
JAEGER: JaegerTracing;
1925

2026
SENTRY_ACCESS_CLIENT_ID: string;
2127
SENTRY_ACCESS_CLIENT_SECRET: string;
@@ -29,6 +35,10 @@ export default {
2935
const startTimeMs = performance.now();
3036

3137
try {
38+
if (!env.JAEGER) {
39+
env.JAEGER = mockJaegerBinding();
40+
}
41+
3242
sentry = setupSentry(
3343
request,
3444
ctx,
@@ -63,27 +73,48 @@ export default {
6373
// User's configuration indicates they want user-Worker to run ahead of any
6474
// assets. Do not provide any fallback logic.
6575
if (env.CONFIG.invoke_user_worker_ahead_of_assets) {
66-
if (!env.CONFIG.has_user_worker) {
67-
throw new Error(
68-
"Fetch for user worker without having a user worker binding"
69-
);
70-
}
71-
return env.USER_WORKER.fetch(maybeSecondRequest);
76+
return env.JAEGER.enterSpan("invoke_user_worker_first", async () => {
77+
if (!env.CONFIG.has_user_worker) {
78+
throw new Error(
79+
"Fetch for user worker without having a user worker binding"
80+
);
81+
}
82+
return env.USER_WORKER.fetch(maybeSecondRequest);
83+
});
7284
}
7385

7486
// Otherwise, we try to first fetch assets, falling back to user-Worker.
7587
if (env.CONFIG.has_user_worker) {
76-
if (await env.ASSET_WORKER.unstable_canFetch(request)) {
77-
analytics.setData({ dispatchtype: DISPATCH_TYPE.ASSETS });
78-
return env.ASSET_WORKER.fetch(maybeSecondRequest);
79-
} else {
80-
analytics.setData({ dispatchtype: DISPATCH_TYPE.WORKER });
81-
return env.USER_WORKER.fetch(maybeSecondRequest);
82-
}
88+
return env.JAEGER.enterSpan("has_user_worker", async (span) => {
89+
if (await env.ASSET_WORKER.unstable_canFetch(request)) {
90+
span.setTags({
91+
asset: true,
92+
dispatchType: DISPATCH_TYPE.ASSETS,
93+
});
94+
95+
analytics.setData({ dispatchtype: DISPATCH_TYPE.ASSETS });
96+
return env.ASSET_WORKER.fetch(maybeSecondRequest);
97+
} else {
98+
span.setTags({
99+
asset: false,
100+
dispatchType: DISPATCH_TYPE.WORKER,
101+
});
102+
103+
analytics.setData({ dispatchtype: DISPATCH_TYPE.WORKER });
104+
return env.USER_WORKER.fetch(maybeSecondRequest);
105+
}
106+
});
83107
}
84108

85-
analytics.setData({ dispatchtype: DISPATCH_TYPE.ASSETS });
86-
return env.ASSET_WORKER.fetch(request);
109+
return env.JAEGER.enterSpan("assets_only", async (span) => {
110+
span.setTags({
111+
asset: true,
112+
dispatchType: DISPATCH_TYPE.ASSETS,
113+
});
114+
115+
analytics.setData({ dispatchtype: DISPATCH_TYPE.ASSETS });
116+
return env.ASSET_WORKER.fetch(request);
117+
});
87118
} catch (err) {
88119
if (err instanceof Error) {
89120
analytics.setData({ error: err.message });

packages/workers-shared/asset-worker/src/utils/mocks.ts renamed to packages/workers-shared/utils/tracing.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { JaegerTracing, Span } from "../../../utils/types";
1+
import type { JaegerTracing, Span } from "./types";
22

33
export function mockJaegerBindingSpan(): Span {
44
return {

0 commit comments

Comments
 (0)