Skip to content

Commit 879bddc

Browse files
committed
Replace tracing with OpenTelemetry
1 parent 67fc6fa commit 879bddc

File tree

8 files changed

+95
-251
lines changed

8 files changed

+95
-251
lines changed

Dockerfile

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM denoland/deno:alpine-1.30.1
1+
FROM denoland/deno:alpine-1.31.1
22
RUN apk add --no-cache graphviz
33
ADD fonts/ /usr/share/fonts/truetype/
44

@@ -7,4 +7,4 @@ ADD deps.ts .
77
RUN deno check deps.ts
88
ADD . .
99
RUN deno check server.ts
10-
ENTRYPOINT ["deno","run","--allow-env","--allow-net","--allow-run=deno,dot","--allow-read=.","server.ts"]
10+
ENTRYPOINT ["deno","run","--allow-sys=hostname","--allow-env","--allow-net","--allow-run=deno,dot","--allow-read=.","server.ts"]

deps.ts

+2
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,5 @@ export type {
1818
ModuleGraphJson,
1919
ModuleJson,
2020
} from "https://deno.land/x/[email protected]/lib/types.d.ts";
21+
22+
export { trace, context, type Context } from "npm:@opentelemetry/api";

feat/dependencies-of/api.ts

+32-17
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@ import {
44
readableStreamFromIterable,
55
SubProcess,
66
type SubprocessErrorData,
7+
trace,
8+
context,
9+
Context,
710
} from "../../deps.ts";
8-
import { getTraceContext } from "../../gcp-tracing.ts";
911

1012
import { templateHtml, makeErrorResponse, HtmlHeaders } from '../../lib/request-handling.ts';
1113
import { findModuleSlug, resolveModuleUrl } from "../../lib/resolve.ts";
1214
import { computeGraph, renderGraph } from "./compute.ts";
1315

16+
const tracer = trace.getTracer('dependencies-of-api');
17+
1418
export async function *handleRequest(req: Request, modSlug: string, args: URLSearchParams) {
1519
if (modSlug == '') {
1620
const url = args.get('url');
@@ -78,20 +82,15 @@ const hideLoadMsg = `<style type="text/css">#graph-waiting { display: none; }</s
7882

7983
async function serveHtmlGraphPage(req: Request, modUrl: string, modSlug: string, args: URLSearchParams) {
8084
args.set('font', 'Archivo Narrow');
81-
const ctx = getTraceContext()!;
8285

8386
// Render the basic page first, so we can error more cleanly if that fails
8487
let pageHtml = '';
8588
try {
86-
pageHtml = await ctx.enterSpan({
87-
spanKind: 'INTERNAL',
88-
displayName: {value: 'Render page HTML'},
89-
startTime: new Date().toISOString(),
90-
}, () => templateHtml('feat/dependencies-of/public.html', {
89+
pageHtml = await templateHtml('feat/dependencies-of/public.html', {
9190
module_slug: entities.encode(modSlug),
9291
module_url: entities.encode(modUrl),
9392
export_prefix: entities.encode(`${req.url}${req.url.includes('?') ? '&' : '?'}format=`),
94-
}));
93+
});
9594
} catch (err) {
9695
return makeErrorResponse(err);
9796
}
@@ -149,28 +148,44 @@ async function serveHtmlGraphPage(req: Request, modUrl: string, modSlug: string,
149148
});
150149

151150
// Return the body in two parts, with a comment in between
152-
return new Response(readableStreamFromIterable((async function*() {
151+
152+
async function* bodyGenerator() {
153153
try {
154154
const encoder = new TextEncoder();
155155
yield encoder.encode(pageHtml);
156156

157157
yield encoder.encode("\n<!-- now waiting for graph ... ");
158158
const d0 = Date.now();
159-
const graphText = await ctx.enterSpan({
160-
spanKind: "INTERNAL",
161-
startTime: new Date().toISOString(),
162-
displayName: {value: "Wait for graph text"},
163-
}, async () => hideLoadMsg + await graphPromise);
159+
const span = tracer.startSpan('Wait for graph text');
160+
const graphText = hideLoadMsg + await graphPromise.finally(() => span.end());
164161
const millis = Date.now() - d0;
165162
yield encoder.encode(`completed in ${millis}ms -->\n\n`);
166163

167164
yield encoder.encode(graphText);
168-
169-
ctx.spans[0].endTime = new Date().toISOString(); // TODO: ugh
170165
} catch (err) {
171166
console.error(err)
172167
}
173-
}())), {
168+
}
169+
170+
const bodyIterable = asyncGeneratorWithContext(context.active(), bodyGenerator);
171+
return new Response(readableStreamFromIterable(bodyIterable), {
174172
headers: HtmlHeaders,
175173
});
176174
}
175+
176+
async function* asyncGeneratorWithContext<T, TReturn, TNext>(
177+
operationContext: Context,
178+
operation: () => AsyncGenerator<T, TReturn, TNext>,
179+
): AsyncGenerator<T, TReturn, TNext> {
180+
const generator = context.with(operationContext, operation)
181+
const next = context.bind(operationContext, generator.next.bind(generator))
182+
183+
let result: IteratorResult<T, TReturn> = await next()
184+
185+
while (!result.done) {
186+
const nextParam = yield result.value
187+
result = await next(nextParam)
188+
}
189+
190+
return result.value
191+
}

feat/dependencies-of/compute.ts

+24-22
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,53 @@
1-
import { ModuleGraphJson, SubProcess } from "../../deps.ts";
2-
import { getTraceContext } from "../../gcp-tracing.ts";
1+
import { ModuleGraphJson, SubProcess, trace } from "../../deps.ts";
32
import { computeDependencies } from "../../lib/module-map.ts";
43

4+
const tracer = trace.getTracer('dependencies-of-compute');
5+
56
export async function computeGraph(
67
modUrl: string,
78
args: URLSearchParams,
89
format?: string,
910
) {
1011
if (format) args.set('format', format);
1112

12-
const ctx = getTraceContext()!;
13+
const dlSpan = tracer.startSpan('deno info --json', {
14+
attributes: {
15+
'module_url': modUrl,
16+
},
17+
});
1318

14-
const downloadData = await ctx.enterSpan({
15-
displayName: {value: 'deno info --json'},
16-
startTime: new Date().toISOString(),
17-
spanKind: "INTERNAL",
18-
}, async () => JSON.parse(await new SubProcess('download', {
19+
const downloadData = JSON.parse(await new SubProcess('download', {
1920
cmd: ["deno", "info", "--json", "--", modUrl],
2021
env: { "NO_COLOR": "yas" },
2122
stdin: 'null',
2223
errorPrefix: /^error: /,
23-
}).captureAllTextOutput()) as ModuleGraphJson);
24-
25-
return await ctx.enterSpan({
26-
spanKind: 'INTERNAL',
27-
displayName: {value: 'Compute graph'},
28-
startTime: new Date().toISOString(),
29-
}, async () => computeDependencies(downloadData, args));
24+
}).captureAllTextOutput().finally(() => dlSpan.end())) as ModuleGraphJson;
25+
26+
const computeSpan = tracer.startSpan('Compute graph');
27+
try {
28+
return computeDependencies(downloadData, args);
29+
} finally {
30+
computeSpan.end();
31+
}
3032
}
3133

3234
export async function renderGraph(modUrl: string, dotArgs: string[], args: URLSearchParams) {
33-
const ctx = getTraceContext()!;
35+
return tracer.startActiveSpan('Compute + Render Graph', span =>
36+
renderGraphInner(modUrl, dotArgs, args).finally(() => span.end()));
37+
}
38+
async function renderGraphInner(modUrl: string, dotArgs: string[], args: URLSearchParams) {
3439
const dotText = await computeGraph(modUrl, args, 'dot');
3540

41+
const span = tracer.startSpan('graphviz');
42+
3643
const dotProc = new SubProcess('render', {
3744
cmd: ["dot", ...dotArgs],
3845
stdin: 'piped',
3946
errorPrefix: /^Error: /,
4047
});
4148
await dotProc.writeInputText(dotText);
4249

43-
ctx.enterSpan({
44-
spanKind: 'INTERNAL',
45-
displayName: {value: 'graphviz'},
46-
startTime: new Date().toISOString(),
47-
sameProcessAsParentSpan: false,
48-
}, () => dotProc.status());
50+
dotProc.status().finally(() => span.end());
4951

5052
return dotProc;
5153
}

gcp-tracing.ts

-190
This file was deleted.

0 commit comments

Comments
 (0)