From d3584d81e645a2d0c881a3451f041bf5ddfceee6 Mon Sep 17 00:00:00 2001 From: vanstinator Date: Fri, 15 Mar 2024 16:58:01 -0400 Subject: [PATCH 1/2] feat: start adding support to cf pages --- src/instrumentation/fetch.ts | 2 +- src/instrumentation/page.ts | 89 ++++++++++++++++++++++++++++++++++++ src/sdk.ts | 14 +++++- 3 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 src/instrumentation/page.ts diff --git a/src/instrumentation/fetch.ts b/src/instrumentation/fetch.ts index 3f0f268..3abf5c8 100644 --- a/src/instrumentation/fetch.ts +++ b/src/instrumentation/fetch.ts @@ -111,7 +111,7 @@ export function getParentContextFromHeaders(headers: Headers): Context { }) } -function getParentContextFromRequest(request: Request) { +export function getParentContextFromRequest(request: Request) { const workerConfig = getActiveConfig() const acceptTraceContext = typeof workerConfig.handlers.fetch.acceptTraceContext === 'function' diff --git a/src/instrumentation/page.ts b/src/instrumentation/page.ts new file mode 100644 index 0000000..8bf938b --- /dev/null +++ b/src/instrumentation/page.ts @@ -0,0 +1,89 @@ +import { ReadableSpan } from '@opentelemetry/sdk-trace-base' +import { Initialiser, setConfig } from '../config' +import { exportSpans, proxyExecutionContext } from './common' +// import { instrumentEnv } from "./env" +import { Exception, SpanKind, SpanOptions, SpanStatusCode, context as api_context, trace } from '@opentelemetry/api' +import { wrap } from '../wrap' +import { + gatherIncomingCfAttributes, + gatherRequestAttributes, + gatherResponseAttributes, + getParentContextFromRequest, +} from './fetch' + +type PageHandlerArgs = Parameters + +let cold_start = true +export function executePageHandler(pagesFn: PagesFunction, [request]: PageHandlerArgs): Promise { + const spanContext = getParentContextFromRequest(request.request) + + const tracer = trace.getTracer('pagesHandler') + const attributes = { + ['faas.trigger']: 'http', + ['faas.coldstart']: cold_start, + ['faas.invocation_id']: request.request.headers.get('cf-ray') ?? undefined, + } + cold_start = false + Object.assign(attributes, gatherRequestAttributes(request.request)) + Object.assign(attributes, gatherIncomingCfAttributes(request.request)) + const options: SpanOptions = { + attributes, + kind: SpanKind.SERVER, + } + + console.log(request.data) + + const promise = tracer.startActiveSpan( + `${request.request.method} ${request.functionPath}`, + options, + spanContext, + async (span) => { + const readable = span as unknown as ReadableSpan + try { + const response: Response = await pagesFn(request) + span.setAttributes(gatherResponseAttributes(response)) + if (readable.attributes['http.route']) { + span.updateName(`${request.request.method} ${readable.attributes['http.route']}`) + } + span.end() + + return response + } catch (error) { + if (readable.attributes['http.route']) { + span.updateName(`${request.request.method} ${readable.attributes['http.route']}`) + } + span.recordException(error as Exception) + span.setStatus({ code: SpanStatusCode.ERROR }) + span.end() + throw error + } + }, + ) + return promise +} + +export function createPageHandler< + E = unknown, + P extends string = any, + D extends Record = Record, +>(pageFn: PagesFunction, initialiser: Initialiser): PagesFunction { + const pagesHandler: ProxyHandler = { + apply: async (target, _thisArg, argArray: Parameters): Promise => { + const [orig_ctx] = argArray + const config = initialiser(orig_ctx.env as Record, orig_ctx.request) + // const env = instrumentEnv(orig_ctx.env as Record) + const { ctx, tracker } = proxyExecutionContext(orig_ctx) + const context = setConfig(config) + + try { + const args: PageHandlerArgs = [ctx] as PageHandlerArgs + return await api_context.with(context, executePageHandler, undefined, target, args) + } catch (error) { + throw error + } finally { + orig_ctx.waitUntil(exportSpans(tracker)) + } + }, + } + return wrap(pageFn, pagesHandler) +} diff --git a/src/sdk.ts b/src/sdk.ts index baaa937..fcf089e 100644 --- a/src/sdk.ts +++ b/src/sdk.ts @@ -144,7 +144,7 @@ function parseConfig(supplied: TraceConfig): ResolvedTraceConfig { } } -function createInitialiser(config: ConfigurationOption): Initialiser { +export function createInitialiser(config: ConfigurationOption): Initialiser { if (typeof config === 'function') { return (env, trigger) => { const conf = parseConfig(config(env, trigger)) @@ -160,6 +160,18 @@ function createInitialiser(config: ConfigurationOption): Initialiser { } } +export function instrumentPage< + E = unknown, + P extends string = any, + D extends Record = Record, +>(handler: PagesFunction, config: ConfigurationOption): PagesFunction { + const initialiser = createInitialiser(config) + + handler = createPageHandler(handler, initialiser) + + return handler +} + export function instrument( handler: ExportedHandler, config: ConfigurationOption, From ecb458379adaae603008b466d0af77b1ec3d12ba Mon Sep 17 00:00:00 2001 From: vanstinator Date: Wed, 17 Apr 2024 09:17:47 -0400 Subject: [PATCH 2/2] small cleanup --- src/instrumentation/page.ts | 4 ---- src/sdk.ts | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/instrumentation/page.ts b/src/instrumentation/page.ts index 8bf938b..7b9a686 100644 --- a/src/instrumentation/page.ts +++ b/src/instrumentation/page.ts @@ -1,7 +1,6 @@ import { ReadableSpan } from '@opentelemetry/sdk-trace-base' import { Initialiser, setConfig } from '../config' import { exportSpans, proxyExecutionContext } from './common' -// import { instrumentEnv } from "./env" import { Exception, SpanKind, SpanOptions, SpanStatusCode, context as api_context, trace } from '@opentelemetry/api' import { wrap } from '../wrap' import { @@ -31,8 +30,6 @@ export function executePageHandler(pagesFn: PagesFunction, [request]: PageHandle kind: SpanKind.SERVER, } - console.log(request.data) - const promise = tracer.startActiveSpan( `${request.request.method} ${request.functionPath}`, options, @@ -71,7 +68,6 @@ export function createPageHandler< apply: async (target, _thisArg, argArray: Parameters): Promise => { const [orig_ctx] = argArray const config = initialiser(orig_ctx.env as Record, orig_ctx.request) - // const env = instrumentEnv(orig_ctx.env as Record) const { ctx, tracker } = proxyExecutionContext(orig_ctx) const context = setConfig(config) diff --git a/src/sdk.ts b/src/sdk.ts index fcf089e..51a1cf7 100644 --- a/src/sdk.ts +++ b/src/sdk.ts @@ -144,7 +144,7 @@ function parseConfig(supplied: TraceConfig): ResolvedTraceConfig { } } -export function createInitialiser(config: ConfigurationOption): Initialiser { +function createInitialiser(config: ConfigurationOption): Initialiser { if (typeof config === 'function') { return (env, trigger) => { const conf = parseConfig(config(env, trigger))