From 8c2a6aa23609175a268fb12775f86704f2836094 Mon Sep 17 00:00:00 2001 From: Daniel Lamando Date: Wed, 18 Dec 2024 13:21:36 +0100 Subject: [PATCH] ci: Test on Deno v2 (#8) * ci: Test on Deno v2 * Update typescript signatures for Deno 2 * Remove dead Deno APIs: run, metrics, resources https://docs.deno.com/runtime/reference/migration_guide/ * Deno.run() is replaced by new Deno.Command() * Deno.metrics() is gone * Deno.resources() is gone * Continue being ok on deno v1 --- .github/workflows/deno-ci.yml | 5 ++- demo.ts | 3 +- instrumentation/auto.ts | 2 - instrumentation/deno-command.ts | 4 +- instrumentation/deno-kv.ts | 21 ++++++---- instrumentation/deno-run.ts | 72 --------------------------------- instrumentation/deno-runtime.ts | 48 ---------------------- instrumentation/http-server.ts | 3 +- mod.ts | 1 - otel-platform/detectors.ts | 2 +- 10 files changed, 24 insertions(+), 137 deletions(-) delete mode 100644 instrumentation/deno-run.ts diff --git a/.github/workflows/deno-ci.yml b/.github/workflows/deno-ci.yml index d5b16a2..49f0d21 100644 --- a/.github/workflows/deno-ci.yml +++ b/.github/workflows/deno-ci.yml @@ -17,6 +17,7 @@ jobs: - v1.37 - v1.39 - v1.43 + - v2.0 - canary fail-fast: false # run each branch to completion @@ -25,14 +26,14 @@ jobs: uses: actions/checkout@v4 - name: Use Deno ${{ matrix.deno-version }} - uses: denoland/setup-deno@v1 + uses: denoland/setup-deno@v2 with: deno-version: ${{ matrix.deno-version }} # "https" cache: code from the Internet # External sources won't change much so we use less precise keys - name: Cache https:// - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/deno/deps/https key: deno-https/v1-${{ github.sha }} diff --git a/demo.ts b/demo.ts index 4465c75..d0f0336 100755 --- a/demo.ts +++ b/demo.ts @@ -69,7 +69,8 @@ async function handler(req: Request): Promise { stderr: 'inherit', }).output(); return new Response('No failure happened??'); - } catch (err) { + } catch (thrown: unknown) { + const err = thrown as Error; return new Response(`Failed as expected.\n${err.message}`); } } diff --git a/instrumentation/auto.ts b/instrumentation/auto.ts index 3ab86c6..1a37da3 100644 --- a/instrumentation/auto.ts +++ b/instrumentation/auto.ts @@ -2,7 +2,6 @@ import { InstrumentationBase } from "../opentelemetry/instrumentation.js"; import { DenoCommandInstrumentation } from "./deno-command.ts"; import { DenoKvInstrumentation } from "./deno-kv.ts"; -import { DenoRunInstrumentation } from "./deno-run.ts"; import { DenoRuntimeInstrumentation } from "./deno-runtime.ts"; import { FetchInstrumentation } from "./fetch.ts"; @@ -14,7 +13,6 @@ export function getDenoAutoInstrumentations() { // Rough check to exclude Deno Deploy, which doesn't have subprocesses etc. if (Deno.version?.deno) { instrs.push(new DenoCommandInstrumentation()); - instrs.push(new DenoRunInstrumentation()); instrs.push(new DenoRuntimeInstrumentation()); } diff --git a/instrumentation/deno-command.ts b/instrumentation/deno-command.ts index 14f6be1..004ccfa 100644 --- a/instrumentation/deno-command.ts +++ b/instrumentation/deno-command.ts @@ -91,7 +91,7 @@ export class DenoCommandInstrumentation extends InstrumentationBase { throw err; } } - outputSync(): Deno.CommandOutput { + override outputSync(): Deno.CommandOutput { const span = this._span ??= plugin.tracer.startSpan(this._spanName, this._attributes); try { const output = super.outputSync(); @@ -105,7 +105,7 @@ export class DenoCommandInstrumentation extends InstrumentationBase { throw err; } } - spawn(): Deno.ChildProcess { + override spawn(): Deno.ChildProcess { const span = this._span ??= plugin.tracer.startSpan(this._spanName, this._attributes); try { const process = super.spawn(); diff --git a/instrumentation/deno-kv.ts b/instrumentation/deno-kv.ts index 38d2e09..f62b62b 100644 --- a/instrumentation/deno-kv.ts +++ b/instrumentation/deno-kv.ts @@ -69,7 +69,8 @@ export class DenoKvInstrumentation extends InstrumentationBase { }); span.end(); return result; - } catch (err) { + } catch (thrown: unknown) { + const err = thrown as Error; span.recordException(err); span.end(); throw err; @@ -107,7 +108,8 @@ export class DenoKvInstrumentation extends InstrumentationBase { }); span.end(); return result; - } catch (err) { + } catch (thrown: unknown) { + const err = thrown as Error; span.recordException(err); span.end(); throw err; @@ -145,7 +147,8 @@ export class DenoKvInstrumentation extends InstrumentationBase { const result = original.call(this, selector, opts); listSpans.set(result, {span, docCount: 0}); return result; - } catch (err) { + } catch (thrown: unknown) { + const err = thrown as Error; span.recordException(err); span.end(); throw err; @@ -179,7 +182,8 @@ export class DenoKvInstrumentation extends InstrumentationBase { }); span.end(); return result; - } catch (err) { + } catch (thrown: unknown) { + const err = thrown as Error; span.recordException(err); span.end(); throw err; @@ -209,7 +213,8 @@ export class DenoKvInstrumentation extends InstrumentationBase { const result = await original.call(this, key); span.end(); return result; - } catch (err) { + } catch (thrown: unknown) { + const err = thrown as Error; span.recordException(err); span.end(); throw err; @@ -238,7 +243,8 @@ export class DenoKvInstrumentation extends InstrumentationBase { const result = await original.call(this); span.end(); return result; - } catch (err) { + } catch (thrown: unknown) { + const err = thrown as Error; span.recordException(err); span.end(); throw err; @@ -260,7 +266,8 @@ export class DenoKvInstrumentation extends InstrumentationBase { const result = await original.call(this); ref.span.end(); return result; - } catch (err) { + } catch (thrown: unknown) { + const err = thrown as Error; ref.span.recordException(err); ref.span.end(); throw err; diff --git a/instrumentation/deno-run.ts b/instrumentation/deno-run.ts deleted file mode 100644 index d55c424..0000000 --- a/instrumentation/deno-run.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { - isWrapped, - InstrumentationBase, - type InstrumentationConfig, -} from "../opentelemetry/instrumentation.js"; - -export class DenoRunInstrumentation extends InstrumentationBase { - readonly component: string = 'subprocess'; - moduleName = this.component; - - constructor(config?: InstrumentationConfig) { - super('subprocess', '0.1.0', config); - } - - init(): void {} - - /** - * Patches the constructor of fetch - */ - private _patchConstructor(): (original: typeof Deno.run) => typeof Deno.run { - return original => { - const plugin = this; - return function patchConstructor( - this: typeof Deno, - opt: Parameters[0] - ): Deno.Process { - - const span = plugin.tracer.startSpan(`${opt.cmd[0]}`, { - attributes: { - 'exec.argv': opt.cmd.map(x => x.toString()), - 'component': plugin.moduleName, - }, - }); - - try { - const proc = original(opt); - proc.status().then(status => { - span.setAttribute('exec.exit_code', status.code); - if (status.signal) { - span.setAttribute('exec.signal', status.signal); - } - }).finally(() => { - span.end(); - }); - return proc; - } catch (err) { - span.recordException(err); - throw err; - } - - }; - }; - } - - /** - * implements enable function - */ - override enable(): void { - if (isWrapped(Deno.run)) { - this._unwrap(Deno, 'run'); - this._diag.debug('removing previous patch for constructor'); - } - this._wrap(Deno, 'run', this._patchConstructor()); - } - - /** - * implements unpatch function - */ - override disable(): void { - this._unwrap(Deno, 'run'); - } -} diff --git a/instrumentation/deno-runtime.ts b/instrumentation/deno-runtime.ts index d4e4f80..46bafb4 100644 --- a/instrumentation/deno-runtime.ts +++ b/instrumentation/deno-runtime.ts @@ -1,10 +1,7 @@ import { type Attributes, - type BatchObservableResult, - type ObservableCounter, type ObservableGauge, type ObservableResult, - type ObservableUpDownCounter, ValueType, } from "../opentelemetry/api.js"; import { @@ -21,23 +18,11 @@ export class DenoRuntimeInstrumentation extends InstrumentationBase { } metrics!: { - openResources: ObservableUpDownCounter; memoryUsage: ObservableGauge; - dispatchedCtr: ObservableCounter; - inflightCtr: ObservableUpDownCounter; }; protected init() {} - private gatherOpenResources = (x: ObservableResult) => { - for (const entry of Object - .values(Deno.resources()) - .reduce>((acc,x) => (acc.set(x, 1 + (acc.get(x) ?? 0)), acc), new Map()) - ) { - x.observe(entry[1], { 'deno.resource.type': entry[0] }); - } - } - private gatherMemoryUsage = (x: ObservableResult) => { const usage = Deno.memoryUsage(); x.observe(usage.rss, {"deno.memory.type": "rss"}); @@ -46,51 +31,18 @@ export class DenoRuntimeInstrumentation extends InstrumentationBase { x.observe(usage.external, {"deno.memory.type": "external"}); } - private gatherOps = (x: BatchObservableResult) => { - for (const [op, data] of Object.entries(Deno.metrics().ops)) { - if (data.opsDispatched == 0) continue; - x.observe(this.metrics.dispatchedCtr, data.opsDispatched, { "deno.op": op }); - x.observe(this.metrics.inflightCtr, data.opsDispatched - data.opsCompleted, { "deno.op": op }); - } - } - enable() { this.metrics ??= { - openResources: this.meter - .createObservableUpDownCounter("deno.open_resources", { - valueType: ValueType.INT, - description: "Number of open resources of a particular type.", - }), memoryUsage: this.meter .createObservableGauge("deno.memory_usage", { valueType: ValueType.INT, }), - dispatchedCtr: this.meter - .createObservableCounter("deno.ops_dispatched", { - valueType: ValueType.INT, - description: "Total number of Deno op invocations.", - }), - inflightCtr: this.meter - .createObservableUpDownCounter("deno.ops_inflight", { - valueType: ValueType.INT, - description: "Number of currently-inflight Deno ops.", - }), }; - this.metrics.openResources.addCallback(this.gatherOpenResources); this.metrics.memoryUsage.addCallback(this.gatherMemoryUsage); - this.meter.addBatchObservableCallback(this.gatherOps, [ - this.metrics.dispatchedCtr, - this.metrics.inflightCtr, - ]); } disable() { - this.metrics.openResources.removeCallback(this.gatherOpenResources); this.metrics.memoryUsage.removeCallback(this.gatherMemoryUsage); - this.meter.removeBatchObservableCallback(this.gatherOps, [ - this.metrics.dispatchedCtr, - this.metrics.inflightCtr, - ]); } } diff --git a/instrumentation/http-server.ts b/instrumentation/http-server.ts index e808e41..f5f9c22 100644 --- a/instrumentation/http-server.ts +++ b/instrumentation/http-server.ts @@ -117,7 +117,8 @@ export function httpTracer(inner: Deno.ServeHandler, opts?: { return new Response(respSnoop.newBody, resp); - } catch (err) { + } catch (thrown: unknown) { + const err = thrown as Error; serverSpan.recordException(err); serverSpan.setStatus({ code: SpanStatusCode.ERROR, diff --git a/mod.ts b/mod.ts index 5376728..ce5fe53 100644 --- a/mod.ts +++ b/mod.ts @@ -3,7 +3,6 @@ export { logs } from './opentelemetry/api-logs.js'; export { Resource } from "./opentelemetry/resources.js"; export { httpTracer } from './instrumentation/http-server.ts'; -export { DenoRunInstrumentation } from './instrumentation/deno-run.ts'; export { FetchInstrumentation } from './instrumentation/fetch.ts'; export { DenoRuntimeInstrumentation } from './instrumentation/deno-runtime.ts'; export { getDenoAutoInstrumentations } from './instrumentation/auto.ts'; diff --git a/otel-platform/detectors.ts b/otel-platform/detectors.ts index e326992..3fa391f 100644 --- a/otel-platform/detectors.ts +++ b/otel-platform/detectors.ts @@ -71,7 +71,7 @@ const processResource = new Resource({ }); export class DenoProcessDetector implements DetectorSync { detect() { - // deno deploy currently lacks querySync, but can read + //@ts-ignore deno deploy currently lacks querySync, but can take the action const canRead = (Deno.permissions.querySync?.({name: 'read'}).state == 'granted') ?? true; if (!canRead) return processResource;