@getvision/adapter-hono 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @getvision/adapter-hono
2
2
 
3
+ ## 0.0.9
4
+
5
+ ### Patch Changes
6
+
7
+ - 22facf0: Implement Wide Events concept for logging
8
+
9
+ ## 0.0.8
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies [2635948]
14
+ - @getvision/core@0.0.8
15
+
3
16
  ## 0.0.7
4
17
 
5
18
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,iBAAiB,EAAE,MAAM,MAAM,CAAA;AACtD,OAAO,EACL,UAAU,EAOX,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EAAiB,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAM1F,UAAU,aAAa;IACrB,MAAM,EAAE,UAAU,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;CAChB;AAID;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAMhD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,qFAG5B;AAyID,wBAAgB,aAAa,CAAC,OAAO,GAAE,iBAAsB,GAAG,iBAAiB,CAwOhF;AAqGD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,iBAAiB,EAAE,CAAA;CAAE,QAGzF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,UAAU,GAAG,IAAI,CAErD;AAID,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,iBAAiB,EAAE,MAAM,MAAM,CAAA;AACtD,OAAO,EACL,UAAU,EAQX,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EAAiB,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAM1F,UAAU,aAAa;IACrB,MAAM,EAAE,UAAU,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;CAChB;AAID;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAMhD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,qFAG5B;AAyID,wBAAgB,aAAa,CAAC,OAAO,GAAE,iBAAsB,GAAG,iBAAiB,CA2OhF;AAqGD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,iBAAiB,EAAE,CAAA;CAAE,QAGzF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,UAAU,GAAG,IAAI,CAErD;AAID,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { VisionCore, generateZodTemplate, autoDetectPackageInfo, autoDetectIntegrations, detectDrizzle, startDrizzleStudio, stopDrizzleStudio, } from '@getvision/core';
1
+ import { VisionCore, generateZodTemplate, autoDetectPackageInfo, autoDetectIntegrations, detectDrizzle, startDrizzleStudio, stopDrizzleStudio, runInTraceContext, } from '@getvision/core';
2
2
  import { AsyncLocalStorage } from 'async_hooks';
3
3
  import { extractSchema } from './zod-validator';
4
4
  const visionContext = new AsyncLocalStorage();
@@ -255,127 +255,130 @@ export function visionAdapter(options = {}) {
255
255
  const trace = vision.createTrace(c.req.method, c.req.path);
256
256
  // Run request in AsyncLocalStorage context
257
257
  return visionContext.run({ vision, traceId: trace.id }, async () => {
258
- // Also add to Hono context for compatibility
259
- c.set('vision', vision);
260
- c.set('traceId', trace.id);
261
- // Start main span
262
- const tracer = vision.getTracer();
263
- const span = tracer.startSpan('http.request', trace.id);
264
- // Add request attributes
265
- tracer.setAttribute(span.id, 'http.method', c.req.method);
266
- tracer.setAttribute(span.id, 'http.path', c.req.path);
267
- tracer.setAttribute(span.id, 'http.url', c.req.url);
268
- // Add query params if any
269
- const url = new URL(c.req.url);
270
- if (url.search) {
271
- tracer.setAttribute(span.id, 'http.query', url.search);
272
- }
273
- // Capture request metadata (headers, query, body if json)
274
- try {
275
- const rawReq = c.req.raw;
276
- const headers = {};
277
- rawReq.headers.forEach((v, k) => { headers[k] = v; });
278
- const urlObj = new URL(c.req.url);
279
- const query = {};
280
- urlObj.searchParams.forEach((v, k) => { query[k] = v; });
281
- let body = undefined;
282
- const ct = headers['content-type'] || headers['Content-Type'];
283
- if (ct && ct.includes('application/json')) {
284
- try {
285
- body = await rawReq.clone().json();
286
- }
287
- catch { }
258
+ // Also set core trace context for ConsoleInterceptor
259
+ return runInTraceContext(trace.id, async () => {
260
+ // Also add to Hono context for compatibility
261
+ c.set('vision', vision);
262
+ c.set('traceId', trace.id);
263
+ // Start main span
264
+ const tracer = vision.getTracer();
265
+ const span = tracer.startSpan('http.request', trace.id);
266
+ // Add request attributes
267
+ tracer.setAttribute(span.id, 'http.method', c.req.method);
268
+ tracer.setAttribute(span.id, 'http.path', c.req.path);
269
+ tracer.setAttribute(span.id, 'http.url', c.req.url);
270
+ // Add query params if any
271
+ const url = new URL(c.req.url);
272
+ if (url.search) {
273
+ tracer.setAttribute(span.id, 'http.query', url.search);
288
274
  }
289
- const sessionId = headers['x-vision-session'];
290
- if (sessionId) {
291
- tracer.setAttribute(span.id, 'session.id', sessionId);
292
- trace.metadata = { ...(trace.metadata || {}), sessionId };
293
- }
294
- const requestMeta = {
295
- method: c.req.method,
296
- url: urlObj.pathname + (urlObj.search || ''),
297
- headers,
298
- query: Object.keys(query).length ? query : undefined,
299
- body,
300
- };
301
- tracer.setAttribute(span.id, 'http.request', requestMeta);
302
- // Also mirror to trace-level metadata for convenience
303
- trace.metadata = { ...(trace.metadata || {}), request: requestMeta };
304
- // Emit start log (if enabled)
305
- if (logging) {
306
- const { endpoint, handler } = resolveEndpointTemplate(c.req.method, c.req.path);
307
- const params = extractParams(endpoint, c.req.path);
308
- const parts = [
309
- `method=${c.req.method}`,
310
- `endpoint=${endpoint}`,
311
- `service=${handler}`,
312
- ];
313
- if (params)
314
- parts.push(`params=${JSON.stringify(params)}`);
315
- if (Object.keys(query).length)
316
- parts.push(`query=${JSON.stringify(query)}`);
317
- if (trace.metadata?.sessionId)
318
- parts.push(`sessionId=${trace.metadata.sessionId}`);
319
- parts.push(`traceId=${trace.id}`);
320
- console.info(`INF starting request ${parts.join(' ')}`);
321
- }
322
- // Execute request
323
- await next();
324
- // Add response attributes
325
- tracer.setAttribute(span.id, 'http.status_code', c.res.status);
326
- const resHeaders = {};
327
- c.res.headers?.forEach((v, k) => { resHeaders[k] = v; });
328
- let respBody = undefined;
329
- const resCt = c.res.headers?.get('content-type') || '';
275
+ // Capture request metadata (headers, query, body if json)
330
276
  try {
331
- const clone = c.res.clone();
332
- if (resCt.includes('application/json')) {
333
- const txt = await clone.text();
334
- if (txt && txt.length <= 65536) {
335
- try {
336
- respBody = JSON.parse(txt);
337
- }
338
- catch {
339
- respBody = txt;
277
+ const rawReq = c.req.raw;
278
+ const headers = {};
279
+ rawReq.headers.forEach((v, k) => { headers[k] = v; });
280
+ const urlObj = new URL(c.req.url);
281
+ const query = {};
282
+ urlObj.searchParams.forEach((v, k) => { query[k] = v; });
283
+ let body = undefined;
284
+ const ct = headers['content-type'] || headers['Content-Type'];
285
+ if (ct && ct.includes('application/json')) {
286
+ try {
287
+ body = await rawReq.clone().json();
288
+ }
289
+ catch { }
290
+ }
291
+ const sessionId = headers['x-vision-session'];
292
+ if (sessionId) {
293
+ tracer.setAttribute(span.id, 'session.id', sessionId);
294
+ trace.metadata = { ...(trace.metadata || {}), sessionId };
295
+ }
296
+ const requestMeta = {
297
+ method: c.req.method,
298
+ url: urlObj.pathname + (urlObj.search || ''),
299
+ headers,
300
+ query: Object.keys(query).length ? query : undefined,
301
+ body,
302
+ };
303
+ tracer.setAttribute(span.id, 'http.request', requestMeta);
304
+ // Also mirror to trace-level metadata for convenience
305
+ trace.metadata = { ...(trace.metadata || {}), request: requestMeta };
306
+ // Emit start log (if enabled)
307
+ if (logging) {
308
+ const { endpoint, handler } = resolveEndpointTemplate(c.req.method, c.req.path);
309
+ const params = extractParams(endpoint, c.req.path);
310
+ const parts = [
311
+ `method=${c.req.method}`,
312
+ `endpoint=${endpoint}`,
313
+ `service=${handler}`,
314
+ ];
315
+ if (params)
316
+ parts.push(`params=${JSON.stringify(params)}`);
317
+ if (Object.keys(query).length)
318
+ parts.push(`query=${JSON.stringify(query)}`);
319
+ if (trace.metadata?.sessionId)
320
+ parts.push(`sessionId=${trace.metadata.sessionId}`);
321
+ parts.push(`traceId=${trace.id}`);
322
+ console.info(`INF starting request ${parts.join(' ')}`);
323
+ }
324
+ // Execute request
325
+ await next();
326
+ // Add response attributes
327
+ tracer.setAttribute(span.id, 'http.status_code', c.res.status);
328
+ const resHeaders = {};
329
+ c.res.headers?.forEach((v, k) => { resHeaders[k] = v; });
330
+ let respBody = undefined;
331
+ const resCt = c.res.headers?.get('content-type') || '';
332
+ try {
333
+ const clone = c.res.clone();
334
+ if (resCt.includes('application/json')) {
335
+ const txt = await clone.text();
336
+ if (txt && txt.length <= 65536) {
337
+ try {
338
+ respBody = JSON.parse(txt);
339
+ }
340
+ catch {
341
+ respBody = txt;
342
+ }
340
343
  }
341
344
  }
342
345
  }
346
+ catch { }
347
+ const responseMeta = {
348
+ status: c.res.status,
349
+ headers: Object.keys(resHeaders).length ? resHeaders : undefined,
350
+ body: respBody,
351
+ };
352
+ tracer.setAttribute(span.id, 'http.response', responseMeta);
353
+ trace.metadata = { ...(trace.metadata || {}), response: responseMeta };
343
354
  }
344
- catch { }
345
- const responseMeta = {
346
- status: c.res.status,
347
- headers: Object.keys(resHeaders).length ? resHeaders : undefined,
348
- body: respBody,
349
- };
350
- tracer.setAttribute(span.id, 'http.response', responseMeta);
351
- trace.metadata = { ...(trace.metadata || {}), response: responseMeta };
352
- }
353
- catch (error) {
354
- // Track error
355
- tracer.addEvent(span.id, 'error', {
356
- message: error instanceof Error ? error.message : 'Unknown error',
357
- stack: error instanceof Error ? error.stack : undefined,
358
- });
359
- tracer.setAttribute(span.id, 'error', true);
360
- throw error;
361
- }
362
- finally {
363
- // End span and add it to trace
364
- const completedSpan = tracer.endSpan(span.id);
365
- if (completedSpan) {
366
- vision.getTraceStore().addSpan(trace.id, completedSpan);
355
+ catch (error) {
356
+ // Track error
357
+ tracer.addEvent(span.id, 'error', {
358
+ message: error instanceof Error ? error.message : 'Unknown error',
359
+ stack: error instanceof Error ? error.stack : undefined,
360
+ });
361
+ tracer.setAttribute(span.id, 'error', true);
362
+ throw error;
367
363
  }
368
- // Complete trace
369
- const duration = Date.now() - startTime;
370
- vision.completeTrace(trace.id, c.res.status, duration);
371
- // Add trace ID to response headers so client can correlate metrics
372
- c.header('X-Vision-Trace-Id', trace.id);
373
- // Emit completion log (if enabled)
374
- if (logging) {
375
- const { endpoint } = resolveEndpointTemplate(c.req.method, c.req.path);
376
- console.info(`INF request completed code=${c.res.status} duration=${duration}ms method=${c.req.method} endpoint=${endpoint} traceId=${trace.id}`);
364
+ finally {
365
+ // End span and add it to trace
366
+ const completedSpan = tracer.endSpan(span.id);
367
+ if (completedSpan) {
368
+ vision.getTraceStore().addSpan(trace.id, completedSpan);
369
+ }
370
+ // Complete trace
371
+ const duration = Date.now() - startTime;
372
+ vision.completeTrace(trace.id, c.res.status, duration);
373
+ // Add trace ID to response headers so client can correlate metrics
374
+ c.header('X-Vision-Trace-Id', trace.id);
375
+ // Emit completion log (if enabled)
376
+ if (logging) {
377
+ const { endpoint } = resolveEndpointTemplate(c.req.method, c.req.path);
378
+ console.info(`INF request completed code=${c.res.status} duration=${duration}ms method=${c.req.method} endpoint=${endpoint} traceId=${trace.id}`);
379
+ }
377
380
  }
378
- }
381
+ }); // Close runInTraceContext
379
382
  }); // Close visionContext.run()
380
383
  };
381
384
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getvision/adapter-hono",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./src/index.ts"
package/src/index.ts CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  detectDrizzle,
8
8
  startDrizzleStudio,
9
9
  stopDrizzleStudio,
10
+ runInTraceContext,
10
11
  } from '@getvision/core'
11
12
  import type { RouteMetadata, VisionHonoOptions, ServiceDefinition } from '@getvision/core'
12
13
  import { existsSync } from 'fs'
@@ -298,135 +299,138 @@ export function visionAdapter(options: VisionHonoOptions = {}): MiddlewareHandle
298
299
 
299
300
  // Run request in AsyncLocalStorage context
300
301
  return visionContext.run({ vision, traceId: trace.id }, async () => {
301
- // Also add to Hono context for compatibility
302
- c.set('vision', vision)
303
- c.set('traceId', trace.id)
304
-
305
- // Start main span
306
- const tracer = vision.getTracer()
307
- const span = tracer.startSpan('http.request', trace.id)
308
-
309
- // Add request attributes
310
- tracer.setAttribute(span.id, 'http.method', c.req.method)
311
- tracer.setAttribute(span.id, 'http.path', c.req.path)
312
- tracer.setAttribute(span.id, 'http.url', c.req.url)
302
+ // Also set core trace context for ConsoleInterceptor
303
+ return runInTraceContext(trace.id, async () => {
304
+ // Also add to Hono context for compatibility
305
+ c.set('vision', vision)
306
+ c.set('traceId', trace.id)
307
+
308
+ // Start main span
309
+ const tracer = vision.getTracer()
310
+ const span = tracer.startSpan('http.request', trace.id)
313
311
 
314
- // Add query params if any
315
- const url = new URL(c.req.url)
316
- if (url.search) {
317
- tracer.setAttribute(span.id, 'http.query', url.search)
318
- }
312
+ // Add request attributes
313
+ tracer.setAttribute(span.id, 'http.method', c.req.method)
314
+ tracer.setAttribute(span.id, 'http.path', c.req.path)
315
+ tracer.setAttribute(span.id, 'http.url', c.req.url)
316
+
317
+ // Add query params if any
318
+ const url = new URL(c.req.url)
319
+ if (url.search) {
320
+ tracer.setAttribute(span.id, 'http.query', url.search)
321
+ }
319
322
 
320
- // Capture request metadata (headers, query, body if json)
321
- try {
322
- const rawReq = c.req.raw
323
- const headers: Record<string, string> = {}
324
- rawReq.headers.forEach((v, k) => { headers[k] = v })
325
- const urlObj = new URL(c.req.url)
326
- const query: Record<string, string> = {}
327
- urlObj.searchParams.forEach((v, k) => { query[k] = v })
328
-
329
- let body: unknown = undefined
330
- const ct = headers['content-type'] || headers['Content-Type']
331
- if (ct && ct.includes('application/json')) {
323
+ // Capture request metadata (headers, query, body if json)
332
324
  try {
333
- body = await rawReq.clone().json()
334
- } catch {}
335
- }
325
+ const rawReq = c.req.raw
326
+ const headers: Record<string, string> = {}
327
+ rawReq.headers.forEach((v, k) => { headers[k] = v })
328
+ const urlObj = new URL(c.req.url)
329
+ const query: Record<string, string> = {}
330
+ urlObj.searchParams.forEach((v, k) => { query[k] = v })
331
+
332
+ let body: unknown = undefined
333
+ const ct = headers['content-type'] || headers['Content-Type']
334
+ if (ct && ct.includes('application/json')) {
335
+ try {
336
+ body = await rawReq.clone().json()
337
+ } catch {}
338
+ }
336
339
 
337
- const sessionId = headers['x-vision-session']
338
- if (sessionId) {
339
- tracer.setAttribute(span.id, 'session.id', sessionId)
340
- trace.metadata = { ...(trace.metadata || {}), sessionId }
341
- }
340
+ const sessionId = headers['x-vision-session']
341
+ if (sessionId) {
342
+ tracer.setAttribute(span.id, 'session.id', sessionId)
343
+ trace.metadata = { ...(trace.metadata || {}), sessionId }
344
+ }
342
345
 
343
- const requestMeta = {
344
- method: c.req.method,
345
- url: urlObj.pathname + (urlObj.search || ''),
346
- headers,
347
- query: Object.keys(query).length ? query : undefined,
348
- body,
349
- }
350
- tracer.setAttribute(span.id, 'http.request', requestMeta)
351
- // Also mirror to trace-level metadata for convenience
352
- trace.metadata = { ...(trace.metadata || {}), request: requestMeta }
353
-
354
- // Emit start log (if enabled)
355
- if (logging) {
356
- const { endpoint, handler } = resolveEndpointTemplate(c.req.method, c.req.path)
357
- const params = extractParams(endpoint, c.req.path)
358
- const parts = [
359
- `method=${c.req.method}`,
360
- `endpoint=${endpoint}`,
361
- `service=${handler}`,
362
- ]
363
- if (params) parts.push(`params=${JSON.stringify(params)}`)
364
- if (Object.keys(query).length) parts.push(`query=${JSON.stringify(query)}`)
365
- if ((trace.metadata as any)?.sessionId) parts.push(`sessionId=${(trace.metadata as any).sessionId}`)
366
- parts.push(`traceId=${trace.id}`)
367
- console.info(`INF starting request ${parts.join(' ')}`)
368
- }
346
+ const requestMeta = {
347
+ method: c.req.method,
348
+ url: urlObj.pathname + (urlObj.search || ''),
349
+ headers,
350
+ query: Object.keys(query).length ? query : undefined,
351
+ body,
352
+ }
353
+ tracer.setAttribute(span.id, 'http.request', requestMeta)
354
+ // Also mirror to trace-level metadata for convenience
355
+ trace.metadata = { ...(trace.metadata || {}), request: requestMeta }
356
+
357
+ // Emit start log (if enabled)
358
+ if (logging) {
359
+ const { endpoint, handler } = resolveEndpointTemplate(c.req.method, c.req.path)
360
+ const params = extractParams(endpoint, c.req.path)
361
+ const parts = [
362
+ `method=${c.req.method}`,
363
+ `endpoint=${endpoint}`,
364
+ `service=${handler}`,
365
+ ]
366
+ if (params) parts.push(`params=${JSON.stringify(params)}`)
367
+ if (Object.keys(query).length) parts.push(`query=${JSON.stringify(query)}`)
368
+ if ((trace.metadata as any)?.sessionId) parts.push(`sessionId=${(trace.metadata as any).sessionId}`)
369
+ parts.push(`traceId=${trace.id}`)
370
+ console.info(`INF starting request ${parts.join(' ')}`)
371
+ }
369
372
 
370
- // Execute request
371
- await next()
372
-
373
- // Add response attributes
374
- tracer.setAttribute(span.id, 'http.status_code', c.res.status)
375
- const resHeaders: Record<string, string> = {}
376
- c.res.headers?.forEach((v, k) => { resHeaders[k] = v as unknown as string })
373
+ // Execute request
374
+ await next()
375
+
376
+ // Add response attributes
377
+ tracer.setAttribute(span.id, 'http.status_code', c.res.status)
378
+ const resHeaders: Record<string, string> = {}
379
+ c.res.headers?.forEach((v, k) => { resHeaders[k] = v as unknown as string })
380
+
381
+ let respBody: unknown = undefined
382
+ const resCt = c.res.headers?.get('content-type') || ''
383
+ try {
384
+ const clone = c.res.clone()
385
+ if (resCt.includes('application/json')) {
386
+ const txt = await clone.text()
387
+ if (txt && txt.length <= 65536) {
388
+ try { respBody = JSON.parse(txt) } catch { respBody = txt }
389
+ }
390
+ }
391
+ } catch {}
377
392
 
378
- let respBody: unknown = undefined
379
- const resCt = c.res.headers?.get('content-type') || ''
380
- try {
381
- const clone = c.res.clone()
382
- if (resCt.includes('application/json')) {
383
- const txt = await clone.text()
384
- if (txt && txt.length <= 65536) {
385
- try { respBody = JSON.parse(txt) } catch { respBody = txt }
393
+ const responseMeta = {
394
+ status: c.res.status,
395
+ headers: Object.keys(resHeaders).length ? resHeaders : undefined,
396
+ body: respBody,
397
+ }
398
+ tracer.setAttribute(span.id, 'http.response', responseMeta)
399
+ trace.metadata = { ...(trace.metadata || {}), response: responseMeta }
400
+
401
+ } catch (error) {
402
+ // Track error
403
+ tracer.addEvent(span.id, 'error', {
404
+ message: error instanceof Error ? error.message : 'Unknown error',
405
+ stack: error instanceof Error ? error.stack : undefined,
406
+ })
407
+
408
+ tracer.setAttribute(span.id, 'error', true)
409
+ throw error
410
+
411
+ } finally {
412
+ // End span and add it to trace
413
+ const completedSpan = tracer.endSpan(span.id)
414
+ if (completedSpan) {
415
+ vision.getTraceStore().addSpan(trace.id, completedSpan)
386
416
  }
387
- }
388
- } catch {}
389
417
 
390
- const responseMeta = {
391
- status: c.res.status,
392
- headers: Object.keys(resHeaders).length ? resHeaders : undefined,
393
- body: respBody,
394
- }
395
- tracer.setAttribute(span.id, 'http.response', responseMeta)
396
- trace.metadata = { ...(trace.metadata || {}), response: responseMeta }
397
-
398
- } catch (error) {
399
- // Track error
400
- tracer.addEvent(span.id, 'error', {
401
- message: error instanceof Error ? error.message : 'Unknown error',
402
- stack: error instanceof Error ? error.stack : undefined,
403
- })
404
-
405
- tracer.setAttribute(span.id, 'error', true)
406
- throw error
407
-
408
- } finally {
409
- // End span and add it to trace
410
- const completedSpan = tracer.endSpan(span.id)
411
- if (completedSpan) {
412
- vision.getTraceStore().addSpan(trace.id, completedSpan)
413
- }
414
-
415
- // Complete trace
416
- const duration = Date.now() - startTime
417
- vision.completeTrace(trace.id, c.res.status, duration)
418
-
419
- // Add trace ID to response headers so client can correlate metrics
420
- c.header('X-Vision-Trace-Id', trace.id)
421
-
422
- // Emit completion log (if enabled)
423
- if (logging) {
424
- const { endpoint } = resolveEndpointTemplate(c.req.method, c.req.path)
425
- console.info(
426
- `INF request completed code=${c.res.status} duration=${duration}ms method=${c.req.method} endpoint=${endpoint} traceId=${trace.id}`
427
- )
428
- }
429
- }
418
+ // Complete trace
419
+ const duration = Date.now() - startTime
420
+ vision.completeTrace(trace.id, c.res.status, duration)
421
+
422
+ // Add trace ID to response headers so client can correlate metrics
423
+ c.header('X-Vision-Trace-Id', trace.id)
424
+
425
+ // Emit completion log (if enabled)
426
+ if (logging) {
427
+ const { endpoint } = resolveEndpointTemplate(c.req.method, c.req.path)
428
+ console.info(
429
+ `INF request completed code=${c.res.status} duration=${duration}ms method=${c.req.method} endpoint=${endpoint} traceId=${trace.id}`
430
+ )
431
+ }
432
+ }
433
+ }) // Close runInTraceContext
430
434
  }) // Close visionContext.run()
431
435
  }
432
436
  }