@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 +13 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +117 -114
- package/package.json +1 -1
- package/src/index.ts +124 -120
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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
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
|
-
|
|
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
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
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
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
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
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
const
|
|
376
|
-
|
|
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
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
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
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
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
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
|
-
|
|
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
|
-
|
|
334
|
-
|
|
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
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
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
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
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
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
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
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
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
|
}
|