@geekmidas/telescope 10.0.0-alpha.14 → 10.0.0-alpha.141
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/README.md +14 -14
- package/dist/{MetricsAggregator-BxBLQUPj.d.cts → MetricsAggregator-BJdIvfEv.d.mts} +2 -2
- package/dist/MetricsAggregator-BJdIvfEv.d.mts.map +1 -0
- package/dist/{MetricsAggregator-j9wmZ0K_.d.mts → MetricsAggregator-CnC3oT5q.d.cts} +2 -2
- package/dist/MetricsAggregator-CnC3oT5q.d.cts.map +1 -0
- package/dist/{Telescope-BcrWTaar.d.mts → Telescope-BVfDvVvY.d.mts} +3 -3
- package/dist/{Telescope-BcrWTaar.d.mts.map → Telescope-BVfDvVvY.d.mts.map} +1 -1
- package/dist/{Telescope-DnCMZT7V.d.cts → Telescope-DeqSHfuB.d.cts} +3 -3
- package/dist/{Telescope-DnCMZT7V.d.cts.map → Telescope-DeqSHfuB.d.cts.map} +1 -1
- package/dist/Telescope.d.cts +1 -1
- package/dist/Telescope.d.mts +1 -1
- package/dist/adapters/lambda.d.cts +1 -1
- package/dist/adapters/lambda.d.cts.map +1 -1
- package/dist/adapters/lambda.d.mts +1 -1
- package/dist/adapters/lambda.d.mts.map +1 -1
- package/dist/adapters/middy.d.cts +1 -1
- package/dist/adapters/middy.d.mts +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.mts +3 -3
- package/dist/instrumentation/hono.cjs +47 -7
- package/dist/instrumentation/hono.cjs.map +1 -1
- package/dist/instrumentation/hono.d.cts +19 -0
- package/dist/instrumentation/hono.d.cts.map +1 -1
- package/dist/instrumentation/hono.d.mts +19 -0
- package/dist/instrumentation/hono.d.mts.map +1 -1
- package/dist/instrumentation/hono.mjs +48 -8
- package/dist/instrumentation/hono.mjs.map +1 -1
- package/dist/instrumentation/http.cjs +29 -4
- package/dist/instrumentation/http.cjs.map +1 -1
- package/dist/instrumentation/http.d.cts +18 -2
- package/dist/instrumentation/http.d.cts.map +1 -1
- package/dist/instrumentation/http.d.mts +18 -2
- package/dist/instrumentation/http.d.mts.map +1 -1
- package/dist/instrumentation/http.mjs +30 -6
- package/dist/instrumentation/http.mjs.map +1 -1
- package/dist/instrumentation/index.cjs +9 -0
- package/dist/instrumentation/index.d.cts +5 -3
- package/dist/instrumentation/index.d.mts +5 -3
- package/dist/instrumentation/index.mjs +5 -3
- package/dist/instrumentation/middleware.cjs +4 -2
- package/dist/instrumentation/middleware.cjs.map +1 -1
- package/dist/instrumentation/middleware.d.cts +13 -0
- package/dist/instrumentation/middleware.d.cts.map +1 -1
- package/dist/instrumentation/middleware.d.mts +13 -0
- package/dist/instrumentation/middleware.d.mts.map +1 -1
- package/dist/instrumentation/middleware.mjs +5 -3
- package/dist/instrumentation/middleware.mjs.map +1 -1
- package/dist/instrumentation/otel.d.cts.map +1 -1
- package/dist/instrumentation/otel.d.mts.map +1 -1
- package/dist/instrumentation/sampler.cjs +54 -0
- package/dist/instrumentation/sampler.cjs.map +1 -0
- package/dist/instrumentation/sampler.d.cts +38 -0
- package/dist/instrumentation/sampler.d.cts.map +1 -0
- package/dist/instrumentation/sampler.d.mts +38 -0
- package/dist/instrumentation/sampler.d.mts.map +1 -0
- package/dist/instrumentation/sampler.mjs +52 -0
- package/dist/instrumentation/sampler.mjs.map +1 -0
- package/dist/instrumentation/setup.cjs +63 -21
- package/dist/instrumentation/setup.cjs.map +1 -1
- package/dist/instrumentation/setup.d.cts +59 -3
- package/dist/instrumentation/setup.d.cts.map +1 -1
- package/dist/instrumentation/setup.d.mts +59 -3
- package/dist/instrumentation/setup.d.mts.map +1 -1
- package/dist/instrumentation/setup.mjs +64 -23
- package/dist/instrumentation/setup.mjs.map +1 -1
- package/dist/instrumentation/trust.cjs +116 -0
- package/dist/instrumentation/trust.cjs.map +1 -0
- package/dist/instrumentation/trust.d.cts +59 -0
- package/dist/instrumentation/trust.d.cts.map +1 -0
- package/dist/instrumentation/trust.d.mts +59 -0
- package/dist/instrumentation/trust.d.mts.map +1 -0
- package/dist/instrumentation/trust.mjs +113 -0
- package/dist/instrumentation/trust.mjs.map +1 -0
- package/dist/logger/console.d.cts +1 -1
- package/dist/logger/console.d.cts.map +1 -1
- package/dist/logger/console.d.mts +1 -1
- package/dist/logger/console.d.mts.map +1 -1
- package/dist/logger/pino.d.cts +1 -1
- package/dist/logger/pino.d.mts +1 -1
- package/dist/metrics/MetricsAggregator.d.cts +1 -1
- package/dist/metrics/MetricsAggregator.d.mts +1 -1
- package/dist/metrics/index.d.cts +1 -1
- package/dist/metrics/index.d.mts +1 -1
- package/dist/metrics/storage/InMemoryMetricsStorage.d.cts.map +1 -1
- package/dist/metrics/storage/InMemoryMetricsStorage.d.mts.map +1 -1
- package/dist/otlp/index.d.cts +1 -1
- package/dist/otlp/index.d.mts +1 -1
- package/dist/otlp/receiver.d.cts +2 -2
- package/dist/otlp/receiver.d.cts.map +1 -1
- package/dist/otlp/receiver.d.mts +2 -2
- package/dist/otlp/receiver.d.mts.map +1 -1
- package/dist/otlp/transformer.d.cts +1 -1
- package/dist/otlp/transformer.d.mts +1 -1
- package/dist/redact.d.cts +1 -1
- package/dist/redact.d.mts +1 -1
- package/dist/server/hono.cjs +11 -23
- package/dist/server/hono.cjs.map +1 -1
- package/dist/server/hono.d.cts +11 -3
- package/dist/server/hono.d.cts.map +1 -1
- package/dist/server/hono.d.mts +11 -3
- package/dist/server/hono.d.mts.map +1 -1
- package/dist/server/hono.mjs +11 -23
- package/dist/server/hono.mjs.map +1 -1
- package/dist/storage/kysely.d.cts +1 -1
- package/dist/storage/kysely.d.cts.map +1 -1
- package/dist/storage/kysely.d.mts +1 -1
- package/dist/storage/kysely.d.mts.map +1 -1
- package/dist/storage/memory.d.cts +1 -1
- package/dist/storage/memory.d.cts.map +1 -1
- package/dist/storage/memory.d.mts +1 -1
- package/dist/storage/memory.d.mts.map +1 -1
- package/dist/{transformer-DlESim6Q.d.cts → transformer-BtqjAs0b.d.cts} +2 -2
- package/dist/{transformer-BBBXCjHP.d.mts.map → transformer-BtqjAs0b.d.cts.map} +1 -1
- package/dist/{transformer-BBBXCjHP.d.mts → transformer-DI6t8-YA.d.mts} +2 -2
- package/dist/{transformer-DlESim6Q.d.cts.map → transformer-DI6t8-YA.d.mts.map} +1 -1
- package/dist/{types-a9Vistj1.d.cts → types-BVujq4zd.d.cts} +2 -2
- package/dist/{types-a9Vistj1.d.cts.map → types-BVujq4zd.d.cts.map} +1 -1
- package/dist/{types-a9Vistj1.d.mts → types-BVujq4zd.d.mts} +2 -2
- package/dist/{types-a9Vistj1.d.mts.map → types-BVujq4zd.d.mts.map} +1 -1
- package/dist/types.d.cts +1 -1
- package/dist/types.d.mts +1 -1
- package/package.json +7 -5
- package/dist/MetricsAggregator-BxBLQUPj.d.cts.map +0 -1
- package/dist/MetricsAggregator-j9wmZ0K_.d.mts.map +0 -1
- package/dist/ui-assets.cjs +0 -32
- package/dist/ui-assets.cjs.map +0 -1
- package/dist/ui-assets.d.cts +0 -11
- package/dist/ui-assets.d.cts.map +0 -1
- package/dist/ui-assets.d.mts +0 -11
- package/dist/ui-assets.d.mts.map +0 -1
- package/dist/ui-assets.mjs +0 -29
- package/dist/ui-assets.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @geekmidas/telescope
|
|
2
2
|
|
|
3
|
-
Laravel Telescope-style debugging and monitoring for web applications. Capture
|
|
3
|
+
Laravel Telescope-style debugging and monitoring for web applications. Capture HTTP requests, exceptions and logs, and read them back as a JSON API with a WebSocket feed. Headless: there is no dashboard — build whatever UI you want on the JSON.
|
|
4
4
|
|
|
5
5
|
**Framework-agnostic core** with adapters for Hono, AWS Lambda, and more.
|
|
6
6
|
|
|
@@ -17,7 +17,7 @@ pnpm add @geekmidas/telescope
|
|
|
17
17
|
```typescript
|
|
18
18
|
import { Hono } from 'hono';
|
|
19
19
|
import { Telescope, InMemoryStorage } from '@geekmidas/telescope';
|
|
20
|
-
import {
|
|
20
|
+
import { createApi, createMiddleware } from '@geekmidas/telescope/server/hono';
|
|
21
21
|
|
|
22
22
|
const telescope = new Telescope({
|
|
23
23
|
storage: new InMemoryStorage(),
|
|
@@ -28,8 +28,8 @@ const app = new Hono();
|
|
|
28
28
|
// Add middleware to capture requests
|
|
29
29
|
app.use('*', createMiddleware(telescope));
|
|
30
30
|
|
|
31
|
-
// Mount the
|
|
32
|
-
app.route('/__telescope',
|
|
31
|
+
// Mount the JSON API
|
|
32
|
+
app.route('/__telescope', createApi(telescope));
|
|
33
33
|
|
|
34
34
|
// Your routes
|
|
35
35
|
app.get('/users', (c) => c.json({ users: [] }));
|
|
@@ -37,7 +37,7 @@ app.get('/users', (c) => c.json({ users: [] }));
|
|
|
37
37
|
export default app;
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
Read the data at `http://localhost:3000/__telescope/api/requests` (and `/api/exceptions`, `/api/logs`, …).
|
|
41
41
|
|
|
42
42
|
### Framework-Agnostic Core
|
|
43
43
|
|
|
@@ -80,7 +80,7 @@ try {
|
|
|
80
80
|
- **Request Recording**: Capture HTTP requests with headers, body, query params, and response
|
|
81
81
|
- **Exception Tracking**: Record exceptions with stack traces and source context
|
|
82
82
|
- **Log Aggregation**: Collect application logs with context
|
|
83
|
-
- **Real-time Updates**: WebSocket
|
|
83
|
+
- **Real-time Updates**: a WebSocket feed of new entries
|
|
84
84
|
- **Storage Agnostic**: Use in-memory for dev, database for production
|
|
85
85
|
- **Hono Integration**: First-class middleware and route mounting
|
|
86
86
|
- **Lambda Integration**: Wrapper and Middy middleware for AWS Lambda with auto-flush
|
|
@@ -95,7 +95,7 @@ const telescope = new Telescope({
|
|
|
95
95
|
// Optional: Enable/disable telescope (default: true)
|
|
96
96
|
enabled: true,
|
|
97
97
|
|
|
98
|
-
// Optional:
|
|
98
|
+
// Optional: where the JSON API is mounted (default: '/__telescope')
|
|
99
99
|
path: '/__telescope',
|
|
100
100
|
|
|
101
101
|
// Optional: Record request/response bodies (default: true)
|
|
@@ -344,7 +344,7 @@ telescope.destroy();
|
|
|
344
344
|
Import from `@geekmidas/telescope/server/hono`:
|
|
345
345
|
|
|
346
346
|
```typescript
|
|
347
|
-
import {
|
|
347
|
+
import { createApi, createMiddleware, setupWebSocket, getRequestId } from '@geekmidas/telescope/server/hono';
|
|
348
348
|
```
|
|
349
349
|
|
|
350
350
|
#### `createMiddleware(telescope)`
|
|
@@ -355,12 +355,12 @@ Returns Hono middleware that captures requests and responses.
|
|
|
355
355
|
app.use('*', createMiddleware(telescope));
|
|
356
356
|
```
|
|
357
357
|
|
|
358
|
-
#### `
|
|
358
|
+
#### `createApi(telescope)`
|
|
359
359
|
|
|
360
|
-
Returns a Hono app
|
|
360
|
+
Returns a Hono app serving the JSON API under `/api`.
|
|
361
361
|
|
|
362
362
|
```typescript
|
|
363
|
-
app.route('/__telescope',
|
|
363
|
+
app.route('/__telescope', createApi(telescope));
|
|
364
364
|
```
|
|
365
365
|
|
|
366
366
|
#### `setupWebSocket(app, telescope, upgradeWebSocket)`
|
|
@@ -371,7 +371,7 @@ Set up WebSocket routes for real-time updates.
|
|
|
371
371
|
import { createNodeWebSocket } from '@hono/node-ws';
|
|
372
372
|
|
|
373
373
|
const { upgradeWebSocket } = createNodeWebSocket({ app });
|
|
374
|
-
setupWebSocket(
|
|
374
|
+
setupWebSocket(createApi(telescope), telescope, upgradeWebSocket);
|
|
375
375
|
```
|
|
376
376
|
|
|
377
377
|
#### `getRequestId(c)`
|
|
@@ -542,9 +542,9 @@ const requestLogger = logger.withRequestId('req-abc123');
|
|
|
542
542
|
requestLogger.info('Processing request');
|
|
543
543
|
```
|
|
544
544
|
|
|
545
|
-
##
|
|
545
|
+
## JSON API
|
|
546
546
|
|
|
547
|
-
|
|
547
|
+
`createApi` serves a read API at the path it is mounted on:
|
|
548
548
|
|
|
549
549
|
| Endpoint | Description |
|
|
550
550
|
|----------|-------------|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { f as RequestEntry, g as StatusDistribution, n as EndpointDetails, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions } from "./types-
|
|
1
|
+
import { f as RequestEntry, g as StatusDistribution, n as EndpointDetails, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions } from "./types-BVujq4zd.mjs";
|
|
2
2
|
//#region src/metrics/MetricsAggregator.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Configuration for MetricsAggregator
|
|
@@ -55,4 +55,4 @@ declare class MetricsAggregator {
|
|
|
55
55
|
}
|
|
56
56
|
//#endregion
|
|
57
57
|
export { MetricsAggregatorOptions as n, MetricsAggregator as t };
|
|
58
|
-
//# sourceMappingURL=MetricsAggregator-
|
|
58
|
+
//# sourceMappingURL=MetricsAggregator-BJdIvfEv.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MetricsAggregator-BJdIvfEv.d.mts","names":[],"sources":["../src/metrics/MetricsAggregator.ts"],"mappings":";;;;;UAgBiB;;EAEhB;;EAEA;;EAEA;;cAwBY;UACJ;UACA;UACA;UAEA;EAGR,YAAY,UAAS;;;;EAOrB,OAAO,OAAO;;;;EAiBd,WAAW,UAAS,sBAA2B;;;;EAwD/C,mBAAmB,UAAS,sBAA2B;;;;EAiCvD,sBAAsB,UAAS,sBAA2B;;;;EAwB1D,mBACC,gBACA,cACA,UAAS,sBACP;;;;EAyEH;UAUQ;UAMA;UAuCA;UAuCA;UAsDA;UAmBA;UAgBA;UAMA;UAcA;UAqDA;UAiBA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { f as RequestEntry, g as StatusDistribution, n as EndpointDetails, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions } from "./types-
|
|
1
|
+
import { f as RequestEntry, g as StatusDistribution, n as EndpointDetails, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions } from "./types-BVujq4zd.cjs";
|
|
2
2
|
//#region src/metrics/MetricsAggregator.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Configuration for MetricsAggregator
|
|
@@ -55,4 +55,4 @@ declare class MetricsAggregator {
|
|
|
55
55
|
}
|
|
56
56
|
//#endregion
|
|
57
57
|
export { MetricsAggregatorOptions as n, MetricsAggregator as t };
|
|
58
|
-
//# sourceMappingURL=MetricsAggregator-
|
|
58
|
+
//# sourceMappingURL=MetricsAggregator-CnC3oT5q.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MetricsAggregator-CnC3oT5q.d.cts","names":[],"sources":["../src/metrics/MetricsAggregator.ts"],"mappings":";;;;;UAgBiB;;EAEhB;;EAEA;;EAEA;;cAwBY;UACJ;UACA;UACA;UAEA;EAGR,YAAY,UAAS;;;;EAOrB,OAAO,OAAO;;;;EAiBd,WAAW,UAAS,sBAA2B;;;;EAwD/C,mBAAmB,UAAS,sBAA2B;;;;EAiCvD,sBAAsB,UAAS,sBAA2B;;;;EAwB1D,mBACC,gBACA,cACA,UAAS,sBACP;;;;EAyEH;UAUQ;UAMA;UAuCA;UAuCA;UAsDA;UAmBA;UAgBA;UAMA;UAcA;UAqDA;UAiBA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { _ as TelescopeEvent, a as LogEntry, c as MetricsSnapshot, f as RequestEntry, g as StatusDistribution, i as ExceptionEntry, n as EndpointDetails, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions, u as QueryOptions, x as TelescopeStats, y as TelescopeOptions } from "./types-
|
|
2
|
-
import { n as MetricsAggregatorOptions } from "./MetricsAggregator-
|
|
1
|
+
import { _ as TelescopeEvent, a as LogEntry, c as MetricsSnapshot, f as RequestEntry, g as StatusDistribution, i as ExceptionEntry, n as EndpointDetails, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions, u as QueryOptions, x as TelescopeStats, y as TelescopeOptions } from "./types-BVujq4zd.mjs";
|
|
2
|
+
import { n as MetricsAggregatorOptions } from "./MetricsAggregator-BJdIvfEv.mjs";
|
|
3
3
|
//#region src/Telescope.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Framework-agnostic Telescope class for debugging and monitoring applications.
|
|
@@ -166,4 +166,4 @@ declare class Telescope {
|
|
|
166
166
|
}
|
|
167
167
|
//#endregion
|
|
168
168
|
export { Telescope as t };
|
|
169
|
-
//# sourceMappingURL=Telescope-
|
|
169
|
+
//# sourceMappingURL=Telescope-BVfDvVvY.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Telescope-
|
|
1
|
+
{"version":3,"file":"Telescope-BVfDvVvY.d.mts","names":["_$__types0.TelescopeStats"],"sources":["../src/Telescope.ts"],"mappings":";;;;;;;cA4Ba;UACJ;UACA;UACA;UACA;UACA;UACA;UACA;EAER,YACC,SAAS;IAAqB,UAAU;;;;;EAuBnC,cACL,OAAO,KAAK,oCACV;;;;UA+BW;;;;;;;;;;;EAsBR,IACL,SAAS;IACR;IACA;IACA,UAAU;IACV;OAEC;;;;EAsBG,MACL,iBACA,UAAU,yBACV,qBACE;;;;EAOG,KACL,iBACA,UAAU,yBACV,qBACE;;;;EAOG,KACL,iBACA,UAAU,yBACV,qBACE;;;;EAOG,MACL,iBACA,UAAU,yBACV,qBACE;UAIW;;;;EA4BR,UAAU,OAAO,OAAO,qBAAqB;;;;EA8B7C,YAAY,UAAU,eAAe,QAAQ;;;;EAO7C,WAAW,aAAa,QAAQ;;;;EAOhC,cAAc,UAAU,eAAe,QAAQ;;;;EAO/C,aAAa,aAAa,QAAQ;;;;EAOlC,QAAQ,UAAU,eAAe,QAAQ;;;;EAOzC,YAAQ,QAPyBA;;;;EAkBvC,WAAW,UAAU,sBAAsB;;;;EAO3C,mBAAmB,UAAU,sBAAsB;;;;EAOnD,mBACC,gBACA,cACA,UAAU,sBACR;;;;EAOH,sBAAsB,UAAU,sBAAsB;;;;EAOtD;;;;EAOA,sBAAsB;;;;;;;EAuBtB,sBAAsB;;;;EAoBtB;;;;EAcA,YAAY,IAAI;;;;EAYhB,eAAe,IAAI;;;;EAOnB,UAAU,OAAO;;;;EAkBX,MAAM,WAAW,OAAO;;;;EAO9B;;;;MAeI;;;;MAOA;;;;MAOA;;;;MAOA;;;;EAOJ,aAAa;UAqBL;UAeA;UA2CM"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { _ as TelescopeEvent, a as LogEntry, c as MetricsSnapshot, f as RequestEntry, g as StatusDistribution, i as ExceptionEntry, n as EndpointDetails, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions, u as QueryOptions, x as TelescopeStats, y as TelescopeOptions } from "./types-
|
|
2
|
-
import { n as MetricsAggregatorOptions } from "./MetricsAggregator-
|
|
1
|
+
import { _ as TelescopeEvent, a as LogEntry, c as MetricsSnapshot, f as RequestEntry, g as StatusDistribution, i as ExceptionEntry, n as EndpointDetails, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions, u as QueryOptions, x as TelescopeStats, y as TelescopeOptions } from "./types-BVujq4zd.cjs";
|
|
2
|
+
import { n as MetricsAggregatorOptions } from "./MetricsAggregator-CnC3oT5q.cjs";
|
|
3
3
|
//#region src/Telescope.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Framework-agnostic Telescope class for debugging and monitoring applications.
|
|
@@ -166,4 +166,4 @@ declare class Telescope {
|
|
|
166
166
|
}
|
|
167
167
|
//#endregion
|
|
168
168
|
export { Telescope as t };
|
|
169
|
-
//# sourceMappingURL=Telescope-
|
|
169
|
+
//# sourceMappingURL=Telescope-DeqSHfuB.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Telescope-
|
|
1
|
+
{"version":3,"file":"Telescope-DeqSHfuB.d.cts","names":["_$__types0.TelescopeStats"],"sources":["../src/Telescope.ts"],"mappings":";;;;;;;cA4Ba;UACJ;UACA;UACA;UACA;UACA;UACA;UACA;EAER,YACC,SAAS;IAAqB,UAAU;;;;;EAuBnC,cACL,OAAO,KAAK,oCACV;;;;UA+BW;;;;;;;;;;;EAsBR,IACL,SAAS;IACR;IACA;IACA,UAAU;IACV;OAEC;;;;EAsBG,MACL,iBACA,UAAU,yBACV,qBACE;;;;EAOG,KACL,iBACA,UAAU,yBACV,qBACE;;;;EAOG,KACL,iBACA,UAAU,yBACV,qBACE;;;;EAOG,MACL,iBACA,UAAU,yBACV,qBACE;UAIW;;;;EA4BR,UAAU,OAAO,OAAO,qBAAqB;;;;EA8B7C,YAAY,UAAU,eAAe,QAAQ;;;;EAO7C,WAAW,aAAa,QAAQ;;;;EAOhC,cAAc,UAAU,eAAe,QAAQ;;;;EAO/C,aAAa,aAAa,QAAQ;;;;EAOlC,QAAQ,UAAU,eAAe,QAAQ;;;;EAOzC,YAAQ,QAPyBA;;;;EAkBvC,WAAW,UAAU,sBAAsB;;;;EAO3C,mBAAmB,UAAU,sBAAsB;;;;EAOnD,mBACC,gBACA,cACA,UAAU,sBACR;;;;EAOH,sBAAsB,UAAU,sBAAsB;;;;EAOtD;;;;EAOA,sBAAsB;;;;;;;EAuBtB,sBAAsB;;;;EAoBtB;;;;EAcA,YAAY,IAAI;;;;EAYhB,eAAe,IAAI;;;;EAOnB,UAAU,OAAO;;;;EAkBX,MAAM,WAAW,OAAO;;;;EAO9B;;;;MAeI;;;;MAOA;;;;MAOA;;;;MAOA;;;;EAOJ,aAAa;UAqBL;UAeA;UA2CM"}
|
package/dist/Telescope.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as Telescope } from "./Telescope-
|
|
1
|
+
import { t as Telescope } from "./Telescope-DeqSHfuB.cjs";
|
|
2
2
|
export { Telescope };
|
package/dist/Telescope.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as Telescope } from "./Telescope-
|
|
1
|
+
import { t as Telescope } from "./Telescope-BVfDvVvY.mjs";
|
|
2
2
|
export { Telescope };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as Telescope } from "../Telescope-
|
|
1
|
+
import { t as Telescope } from "../Telescope-DeqSHfuB.cjs";
|
|
2
2
|
import { AdapterRequestContext, AdapterResponseContext, LambdaAdapterConfig, TelescopeAdapter } from "./types.cjs";
|
|
3
3
|
import { TelescopeMiddlewareOptions, createTelescopeHandler, telescopeMiddleware } from "./middy.cjs";
|
|
4
4
|
import { Context } from "aws-lambda";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lambda.d.cts","names":["LambdaContext"],"sources":["../../src/adapters/lambda.ts"],"mappings":";;;;;;;;iBAqBiB;EAChB;EACA;EACA;EACA;EACA;EACA;GACC;;;;;wBAMc,yBAAyB;;;;wBAiBzB,+BACf,iBACA,SAASA;EAET;EACA;EACA;EACA;EACA;EACA;;;;;;qBAmCY,yBAAyB,iBAAiB;WAC7C,QAAQ;WACR,WAAW;UACZ;
|
|
1
|
+
{"version":3,"file":"lambda.d.cts","names":["LambdaContext"],"sources":["../../src/adapters/lambda.ts"],"mappings":";;;;;;;;iBAqBiB;EAChB;EACA;EACA;EACA;EACA;EACA;GACC;;;;;wBAMc,yBAAyB;;;;wBAiBzB,+BACf,iBACA,SAASA;EAET;EACA;EACA;EACA;EACA;EACA;;;;;;qBAmCY,yBAAyB,iBAAiB;WAC7C,QAAQ;WACR,WAAW;UACZ;EAER,YAAY,WAAW,WAAW,SAAQ,QAAQ;EAK5C,WAAW;EAOX,aAAa;;;;EAOnB,sBAAsB,iBAAiB;;;;EAiFvC,uBACC,mBACA,oBACE;;;;EAiCG,SAAS;;;;EAOf,yBAAyB;;;;;;;;;;;;;;;;;wBAoBV,kBAAkB,QAAQ,SACzC,WAAW,WACX,UAAU,OAAO,QAAQ,SAASA,YAAkB,QAAQ,UAC5D,UAAS,QAAQ,wBACd,OAAO,QAAQ,SAASA,YAAkB,QAAQ"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as Telescope } from "../Telescope-
|
|
1
|
+
import { t as Telescope } from "../Telescope-BVfDvVvY.mjs";
|
|
2
2
|
import { AdapterRequestContext, AdapterResponseContext, LambdaAdapterConfig, TelescopeAdapter } from "./types.mjs";
|
|
3
3
|
import { TelescopeMiddlewareOptions, createTelescopeHandler, telescopeMiddleware } from "./middy.mjs";
|
|
4
4
|
import { Context } from "aws-lambda";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lambda.d.mts","names":["LambdaContext"],"sources":["../../src/adapters/lambda.ts"],"mappings":";;;;;;;;iBAqBiB;EAChB;EACA;EACA;EACA;EACA;EACA;GACC;;;;;wBAMc,yBAAyB;;;;wBAiBzB,+BACf,iBACA,SAASA;EAET;EACA;EACA;EACA;EACA;EACA;;;;;;qBAmCY,yBAAyB,iBAAiB;WAC7C,QAAQ;WACR,WAAW;UACZ;
|
|
1
|
+
{"version":3,"file":"lambda.d.mts","names":["LambdaContext"],"sources":["../../src/adapters/lambda.ts"],"mappings":";;;;;;;;iBAqBiB;EAChB;EACA;EACA;EACA;EACA;EACA;GACC;;;;;wBAMc,yBAAyB;;;;wBAiBzB,+BACf,iBACA,SAASA;EAET;EACA;EACA;EACA;EACA;EACA;;;;;;qBAmCY,yBAAyB,iBAAiB;WAC7C,QAAQ;WACR,WAAW;UACZ;EAER,YAAY,WAAW,WAAW,SAAQ,QAAQ;EAK5C,WAAW;EAOX,aAAa;;;;EAOnB,sBAAsB,iBAAiB;;;;EAiFvC,uBACC,mBACA,oBACE;;;;EAiCG,SAAS;;;;EAOf,yBAAyB;;;;;;;;;;;;;;;;;wBAoBV,kBAAkB,QAAQ,SACzC,WAAW,WACX,UAAU,OAAO,QAAQ,SAASA,YAAkB,QAAQ,UAC5D,UAAS,QAAQ,wBACd,OAAO,QAAQ,SAASA,YAAkB,QAAQ"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as Telescope } from "../Telescope-
|
|
1
|
+
import { t as Telescope } from "../Telescope-DeqSHfuB.cjs";
|
|
2
2
|
import { APIGatewayProxyEvent, APIGatewayProxyEventV2, Context } from "aws-lambda";
|
|
3
3
|
import { MiddlewareObj } from "@middy/core";
|
|
4
4
|
//#region src/adapters/middy.d.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as Telescope } from "../Telescope-
|
|
1
|
+
import { t as Telescope } from "../Telescope-BVfDvVvY.mjs";
|
|
2
2
|
import { APIGatewayProxyEvent, APIGatewayProxyEventV2, Context } from "aws-lambda";
|
|
3
3
|
import { MiddlewareObj } from "@middy/core";
|
|
4
4
|
//#region src/adapters/middy.d.ts
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as TimeRange, S as TelescopeStorage, _ as TelescopeEvent, a as LogEntry, d as RequestContext, f as RequestEntry, g as StatusDistribution, h as StackFrame, i as ExceptionEntry, l as NormalizedTelescopeOptions, m as SourceContext, o as MetricsBucket, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions, t as EndpointBucket, u as QueryOptions, v as TelescopeEventType, w as TimeSeriesPoint, x as TelescopeStats, y as TelescopeOptions } from "./types-
|
|
2
|
-
import { n as MetricsAggregatorOptions, t as MetricsAggregator } from "./MetricsAggregator-
|
|
3
|
-
import { t as Telescope } from "./Telescope-
|
|
1
|
+
import { C as TimeRange, S as TelescopeStorage, _ as TelescopeEvent, a as LogEntry, d as RequestContext, f as RequestEntry, g as StatusDistribution, h as StackFrame, i as ExceptionEntry, l as NormalizedTelescopeOptions, m as SourceContext, o as MetricsBucket, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions, t as EndpointBucket, u as QueryOptions, v as TelescopeEventType, w as TimeSeriesPoint, x as TelescopeStats, y as TelescopeOptions } from "./types-BVujq4zd.cjs";
|
|
2
|
+
import { n as MetricsAggregatorOptions, t as MetricsAggregator } from "./MetricsAggregator-CnC3oT5q.cjs";
|
|
3
|
+
import { t as Telescope } from "./Telescope-DeqSHfuB.cjs";
|
|
4
4
|
import { InMemoryStorage, InMemoryStorageOptions } from "./storage/memory.cjs";
|
|
5
5
|
export { type EndpointBucket, type EndpointMetrics, type ExceptionEntry, InMemoryStorage, type InMemoryStorageOptions, type LogEntry, MetricsAggregator, type MetricsAggregatorOptions, type MetricsBucket, type MetricsQueryOptions, type NormalizedTelescopeOptions, type QueryOptions, type RequestContext, type RequestEntry, type RequestMetrics, type SourceContext, type StackFrame, type StatusDistribution, Telescope, type TelescopeEvent, type TelescopeEventType, type TelescopeOptions, type TelescopeStats, type TelescopeStorage, type TimeRange, type TimeSeriesPoint };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as TimeRange, S as TelescopeStorage, _ as TelescopeEvent, a as LogEntry, d as RequestContext, f as RequestEntry, g as StatusDistribution, h as StackFrame, i as ExceptionEntry, l as NormalizedTelescopeOptions, m as SourceContext, o as MetricsBucket, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions, t as EndpointBucket, u as QueryOptions, v as TelescopeEventType, w as TimeSeriesPoint, x as TelescopeStats, y as TelescopeOptions } from "./types-
|
|
2
|
-
import { n as MetricsAggregatorOptions, t as MetricsAggregator } from "./MetricsAggregator-
|
|
3
|
-
import { t as Telescope } from "./Telescope-
|
|
1
|
+
import { C as TimeRange, S as TelescopeStorage, _ as TelescopeEvent, a as LogEntry, d as RequestContext, f as RequestEntry, g as StatusDistribution, h as StackFrame, i as ExceptionEntry, l as NormalizedTelescopeOptions, m as SourceContext, o as MetricsBucket, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions, t as EndpointBucket, u as QueryOptions, v as TelescopeEventType, w as TimeSeriesPoint, x as TelescopeStats, y as TelescopeOptions } from "./types-BVujq4zd.mjs";
|
|
2
|
+
import { n as MetricsAggregatorOptions, t as MetricsAggregator } from "./MetricsAggregator-BJdIvfEv.mjs";
|
|
3
|
+
import { t as Telescope } from "./Telescope-BVfDvVvY.mjs";
|
|
4
4
|
import { InMemoryStorage, InMemoryStorageOptions } from "./storage/memory.mjs";
|
|
5
5
|
export { type EndpointBucket, type EndpointMetrics, type ExceptionEntry, InMemoryStorage, type InMemoryStorageOptions, type LogEntry, MetricsAggregator, type MetricsAggregatorOptions, type MetricsBucket, type MetricsQueryOptions, type NormalizedTelescopeOptions, type QueryOptions, type RequestContext, type RequestEntry, type RequestMetrics, type SourceContext, type StackFrame, type StatusDistribution, Telescope, type TelescopeEvent, type TelescopeEventType, type TelescopeOptions, type TelescopeStats, type TelescopeStorage, type TimeRange, type TimeSeriesPoint };
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_instrumentation_http = require("./http.cjs");
|
|
3
|
+
const require_instrumentation_trust = require("./trust.cjs");
|
|
3
4
|
let _opentelemetry_api = require("@opentelemetry/api");
|
|
5
|
+
let hono_route = require("hono/route");
|
|
4
6
|
//#region src/instrumentation/hono.ts
|
|
5
7
|
const SPAN_KEY = "telemetry.span";
|
|
6
8
|
const CONTEXT_KEY = "telemetry.context";
|
|
@@ -35,9 +37,9 @@ function honoTelemetryMiddleware(options = {}) {
|
|
|
35
37
|
c.req.raw.headers.forEach((value, key) => {
|
|
36
38
|
headers[key] = value;
|
|
37
39
|
});
|
|
38
|
-
const parentContext = require_instrumentation_http.
|
|
40
|
+
const { parent: parentContext, links } = require_instrumentation_http.incomingTraceContext(headers, isTrustedCaller(c, options));
|
|
39
41
|
const attrs = buildHonoSpanAttributes(c, options);
|
|
40
|
-
const span = require_instrumentation_http.createHttpServerSpan(attrs, parentContext);
|
|
42
|
+
const span = require_instrumentation_http.createHttpServerSpan(attrs, parentContext, links);
|
|
41
43
|
const spanContext = _opentelemetry_api.trace.setSpan(parentContext, span);
|
|
42
44
|
c.set(SPAN_KEY, span);
|
|
43
45
|
c.set(CONTEXT_KEY, spanContext);
|
|
@@ -49,31 +51,69 @@ function honoTelemetryMiddleware(options = {}) {
|
|
|
49
51
|
await _opentelemetry_api.context.with(spanContext, async () => {
|
|
50
52
|
await next();
|
|
51
53
|
});
|
|
54
|
+
nameAfterRoute(c, span);
|
|
52
55
|
const statusCode = c.res.status;
|
|
53
56
|
if (options.recordResponseBody) try {
|
|
54
57
|
const body = await c.res.clone().text();
|
|
55
58
|
if (body) span.setAttribute("http.response.body", body.length > 4096 ? `${body.slice(0, 4096)}...` : body);
|
|
56
59
|
} catch {}
|
|
57
|
-
require_instrumentation_http.endHttpSpan(span, { statusCode });
|
|
60
|
+
require_instrumentation_http.endHttpSpan(span, { statusCode }, c.error);
|
|
58
61
|
} catch (error) {
|
|
62
|
+
nameAfterRoute(c, span);
|
|
59
63
|
require_instrumentation_http.endHttpSpan(span, { statusCode: 500 }, error instanceof Error ? error : new Error(String(error)));
|
|
60
64
|
throw error;
|
|
61
65
|
}
|
|
62
66
|
};
|
|
63
67
|
}
|
|
64
68
|
/**
|
|
69
|
+
* Whether this request's `traceparent` is continued: from one of the API's
|
|
70
|
+
* own origins, or from an internal caller.
|
|
71
|
+
*/
|
|
72
|
+
function isTrustedCaller(c, options) {
|
|
73
|
+
const origin = c.req.header("origin");
|
|
74
|
+
if (origin) {
|
|
75
|
+
const trusted = typeof options.trustedOrigins === "function" ? options.trustedOrigins() : options.trustedOrigins;
|
|
76
|
+
return require_instrumentation_trust.isTrustedOrigin(origin, trusted);
|
|
77
|
+
}
|
|
78
|
+
const internal = options.internalCallers ?? true;
|
|
79
|
+
if (typeof internal === "function") return internal(c);
|
|
80
|
+
if (!internal) return false;
|
|
81
|
+
return require_instrumentation_trust.isInternalCaller({
|
|
82
|
+
headers: c.req.raw.headers,
|
|
83
|
+
remoteAddress: remoteAddressOf(c)
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/** The TCP peer's address under `@hono/node-server`, or undefined. */
|
|
87
|
+
function remoteAddressOf(c) {
|
|
88
|
+
return c.env?.incoming?.socket?.remoteAddress;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The route the request matched, once the handler has run — `/users/:id`,
|
|
92
|
+
* never `/users/42` — or undefined when only middleware ran (a 404).
|
|
93
|
+
*
|
|
94
|
+
* Read after `next()`: before it, the route is this middleware's own `*`.
|
|
95
|
+
*/
|
|
96
|
+
function matchedRoute(c) {
|
|
97
|
+
const path = (0, hono_route.routePath)(c);
|
|
98
|
+
return path && !path.includes("*") ? path : void 0;
|
|
99
|
+
}
|
|
100
|
+
/** `GET /users/:id`, or the bare method when no route matched. */
|
|
101
|
+
function nameAfterRoute(c, span) {
|
|
102
|
+
const route = matchedRoute(c);
|
|
103
|
+
if (route) {
|
|
104
|
+
span.setAttribute("http.route", route);
|
|
105
|
+
span.updateName(`${c.req.method} ${route}`);
|
|
106
|
+
} else span.updateName(c.req.method);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
65
109
|
* Build span attributes from Hono context
|
|
66
110
|
*/
|
|
67
111
|
function buildHonoSpanAttributes(c, options) {
|
|
68
112
|
const req = c.req;
|
|
69
113
|
const url = new URL(req.url);
|
|
70
|
-
const routePath = c.req.routePath;
|
|
71
|
-
const route = routePath && routePath !== "*" && !routePath.includes("/*") ? routePath : url.pathname;
|
|
72
114
|
const attrs = {
|
|
73
115
|
method: req.method,
|
|
74
|
-
url: req.url,
|
|
75
116
|
path: url.pathname,
|
|
76
|
-
route,
|
|
77
117
|
host: url.host,
|
|
78
118
|
scheme: url.protocol.replace(":", ""),
|
|
79
119
|
userAgent: req.header("user-agent"),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hono.cjs","names":["extractTraceContext","createHttpServerSpan","trace","context"],"sources":["../../src/instrumentation/hono.ts"],"sourcesContent":["import { context, type Span, trace } from '@opentelemetry/api';\n/**\n * OpenTelemetry instrumentation middleware for Hono\n *\n * This middleware automatically creates spans for HTTP requests,\n * extracts trace context from incoming headers, and records\n * request/response metadata as span attributes.\n */\nimport type { Context, MiddlewareHandler } from 'hono';\nimport {\n\tcreateHttpServerSpan,\n\tendHttpSpan,\n\textractTraceContext,\n\ttype HttpSpanAttributes,\n} from './http';\n\n/**\n * Options for the Hono telemetry middleware\n */\nexport interface HonoTelemetryMiddlewareOptions {\n\t/**\n\t * Whether to record request body as span attribute\n\t * @default false\n\t */\n\trecordBody?: boolean;\n\n\t/**\n\t * Whether to record response body as span attribute\n\t * @default false\n\t */\n\trecordResponseBody?: boolean;\n\n\t/**\n\t * Custom function to extract user ID from context\n\t */\n\tgetUserId?: (c: Context) => string | undefined;\n\n\t/**\n\t * Paths to skip tracing (supports wildcards)\n\t */\n\tignorePaths?: string[];\n\n\t/**\n\t * Whether to skip tracing for this request\n\t */\n\tshouldSkip?: (c: Context) => boolean;\n}\n\n// Key for storing span on context\nconst SPAN_KEY = 'telemetry.span';\nconst CONTEXT_KEY = 'telemetry.context';\n\n/**\n * Get the current span from Hono context\n */\nexport function getSpanFromContext(c: Context): Span | undefined {\n\treturn c.get(SPAN_KEY);\n}\n\n/**\n * Get the current trace context from Hono context\n */\nexport function getTraceContextFromHono(c: Context): any {\n\treturn c.get(CONTEXT_KEY);\n}\n\n/**\n * Create a telemetry middleware for Hono applications\n *\n * @example\n * ```typescript\n * import { honoTelemetryMiddleware } from '@geekmidas/telescope/instrumentation';\n *\n * const app = new Hono();\n * app.use('*', honoTelemetryMiddleware());\n * ```\n */\nexport function honoTelemetryMiddleware(\n\toptions: HonoTelemetryMiddlewareOptions = {},\n): MiddlewareHandler {\n\treturn async (c, next) => {\n\t\t// Check if path should be ignored\n\t\tif (\n\t\t\toptions.ignorePaths &&\n\t\t\tshouldIgnorePath(c.req.path, options.ignorePaths)\n\t\t) {\n\t\t\treturn next();\n\t\t}\n\n\t\t// Skip if custom skip function returns true\n\t\tif (options.shouldSkip?.(c)) {\n\t\t\treturn next();\n\t\t}\n\n\t\t// Extract trace context from headers\n\t\tconst headers: Record<string, string | string[] | undefined> = {};\n\t\tc.req.raw.headers.forEach((value, key) => {\n\t\t\theaders[key] = value;\n\t\t});\n\t\tconst parentContext = extractTraceContext(headers);\n\n\t\t// Build span attributes from request\n\t\tconst attrs = buildHonoSpanAttributes(c, options);\n\n\t\t// Create the span\n\t\tconst span = createHttpServerSpan(attrs, parentContext);\n\t\tconst spanContext = trace.setSpan(parentContext, span);\n\n\t\t// Store span and context on Hono context\n\t\tc.set(SPAN_KEY, span);\n\t\tc.set(CONTEXT_KEY, spanContext);\n\n\t\t// Record body if requested\n\t\tif (options.recordBody) {\n\t\t\ttry {\n\t\t\t\tconst body = await c.req.text();\n\t\t\t\tif (body) {\n\t\t\t\t\tspan.setAttribute(\n\t\t\t\t\t\t'http.request.body',\n\t\t\t\t\t\tbody.length > 4096 ? `${body.slice(0, 4096)}...` : body,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Body may have already been consumed\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\t// Execute the rest of the middleware chain within span context\n\t\t\tawait context.with(spanContext, async () => {\n\t\t\t\tawait next();\n\t\t\t});\n\n\t\t\t// Record response\n\t\t\tconst statusCode = c.res.status;\n\n\t\t\tif (options.recordResponseBody) {\n\t\t\t\ttry {\n\t\t\t\t\tconst body = await c.res.clone().text();\n\t\t\t\t\tif (body) {\n\t\t\t\t\t\tspan.setAttribute(\n\t\t\t\t\t\t\t'http.response.body',\n\t\t\t\t\t\t\tbody.length > 4096 ? `${body.slice(0, 4096)}...` : body,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Response body may not be available\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tendHttpSpan(span, { statusCode });\n\t\t} catch (error) {\n\t\t\tendHttpSpan(\n\t\t\t\tspan,\n\t\t\t\t{ statusCode: 500 },\n\t\t\t\terror instanceof Error ? error : new Error(String(error)),\n\t\t\t);\n\t\t\tthrow error;\n\t\t}\n\t};\n}\n\n/**\n * Build span attributes from Hono context\n */\nfunction buildHonoSpanAttributes(\n\tc: Context,\n\toptions: HonoTelemetryMiddlewareOptions,\n): HttpSpanAttributes {\n\tconst req = c.req;\n\tconst url = new URL(req.url);\n\n\t// Use actual path for route unless it's a specific route pattern\n\tconst routePath = c.req.routePath;\n\tconst route =\n\t\troutePath && routePath !== '*' && !routePath.includes('/*')\n\t\t\t? routePath\n\t\t\t: url.pathname;\n\n\tconst attrs: HttpSpanAttributes = {\n\t\tmethod: req.method,\n\t\turl: req.url,\n\t\tpath: url.pathname,\n\t\troute,\n\t\thost: url.host,\n\t\tscheme: url.protocol.replace(':', '') as 'http' | 'https',\n\t\tuserAgent: req.header('user-agent'),\n\t\tclientIp: getClientIp(c),\n\t\trequestId: req.header('x-request-id') || req.header('x-amzn-requestid'),\n\t};\n\n\t// Add user metadata if extractor provided\n\tif (options.getUserId) {\n\t\tconst userId = options.getUserId(c);\n\t\tif (userId) {\n\t\t\tattrs.user = { userId };\n\t\t}\n\t}\n\n\treturn attrs;\n}\n\n/**\n * Extract client IP from Hono context\n */\nfunction getClientIp(c: Context): string | undefined {\n\t// Try various headers in order of preference\n\tconst xForwardedFor = c.req.header('x-forwarded-for');\n\tif (xForwardedFor) {\n\t\tconst first = xForwardedFor.split(',')[0];\n\t\treturn first?.trim();\n\t}\n\n\tconst xRealIp = c.req.header('x-real-ip');\n\tif (xRealIp) {\n\t\treturn xRealIp;\n\t}\n\n\t// Try CF-Connecting-IP (Cloudflare)\n\tconst cfConnectingIp = c.req.header('cf-connecting-ip');\n\tif (cfConnectingIp) {\n\t\treturn cfConnectingIp;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Check if path should be ignored\n */\nfunction shouldIgnorePath(path: string, ignorePaths: string[]): boolean {\n\tfor (const pattern of ignorePaths) {\n\t\tif (pattern.endsWith('*')) {\n\t\t\t// Wildcard match\n\t\t\tconst prefix = pattern.slice(0, -1);\n\t\t\tif (path.startsWith(prefix)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} else if (path === pattern) {\n\t\t\t// Exact match\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * Run a function within the span context from Hono context\n *\n * @example\n * ```typescript\n * app.get('/api/users', async (c) => {\n * return withHonoSpanContext(c, async () => {\n * // Any spans created here will be children of the request span\n * const users = await fetchUsers();\n * return c.json(users);\n * });\n * });\n * ```\n */\nexport async function withHonoSpanContext<T>(\n\tc: Context,\n\tfn: () => Promise<T>,\n): Promise<T> {\n\tconst ctx = getTraceContextFromHono(c);\n\tif (!ctx) {\n\t\treturn fn();\n\t}\n\treturn context.with(ctx, fn);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hono.cjs","names":["incomingTraceContext","createHttpServerSpan","trace","context","isTrustedOrigin","isInternalCaller","routePath"],"sources":["../../src/instrumentation/hono.ts"],"sourcesContent":["import { context, type Span, trace } from '@opentelemetry/api';\n/**\n * OpenTelemetry instrumentation middleware for Hono\n *\n * This middleware automatically creates spans for HTTP requests,\n * extracts trace context from incoming headers, and records\n * request/response metadata as span attributes.\n */\nimport type { Context, MiddlewareHandler } from 'hono';\nimport { routePath } from 'hono/route';\nimport {\n\tcreateHttpServerSpan,\n\tendHttpSpan,\n\ttype HttpSpanAttributes,\n\tincomingTraceContext,\n} from './http';\nimport { isInternalCaller, isTrustedOrigin } from './trust';\n\n/**\n * Options for the Hono telemetry middleware\n */\nexport interface HonoTelemetryMiddlewareOptions {\n\t/**\n\t * Whether to record request body as span attribute\n\t * @default false\n\t */\n\trecordBody?: boolean;\n\n\t/**\n\t * Whether to record response body as span attribute\n\t * @default false\n\t */\n\trecordResponseBody?: boolean;\n\n\t/**\n\t * Custom function to extract user ID from context\n\t */\n\tgetUserId?: (c: Context) => string | undefined;\n\n\t/**\n\t * Paths to skip tracing (supports wildcards)\n\t */\n\tignorePaths?: string[];\n\n\t/**\n\t * Whether to skip tracing for this request\n\t */\n\tshouldSkip?: (c: Context) => boolean;\n\n\t/**\n\t * The origins whose `traceparent` is continued: the API's own sites, the\n\t * same list its CORS allows. A request from any other origin starts a new\n\t * trace linked to the one it claimed.\n\t *\n\t * A function is read on each request, for a server that learns its origins\n\t * only once the app has loaded its configuration.\n\t */\n\ttrustedOrigins?: readonly string[] | (() => readonly string[] | undefined);\n\n\t/**\n\t * Whether a request with no `Origin` from an internal caller continues its\n\t * `traceparent` — another service on the private network (see `./trust`):\n\t * no `Origin`, no proxy's forwarding header, and a loopback or private\n\t * peer address, read from `@hono/node-server`'s socket.\n\t *\n\t * `false` trusts no caller without an origin; a function decides itself.\n\t * @default true\n\t */\n\tinternalCallers?: boolean | ((c: Context) => boolean);\n}\n\n// Key for storing span on context\nconst SPAN_KEY = 'telemetry.span';\nconst CONTEXT_KEY = 'telemetry.context';\n\n/**\n * Get the current span from Hono context\n */\nexport function getSpanFromContext(c: Context): Span | undefined {\n\treturn c.get(SPAN_KEY);\n}\n\n/**\n * Get the current trace context from Hono context\n */\nexport function getTraceContextFromHono(c: Context): any {\n\treturn c.get(CONTEXT_KEY);\n}\n\n/**\n * Create a telemetry middleware for Hono applications\n *\n * @example\n * ```typescript\n * import { honoTelemetryMiddleware } from '@geekmidas/telescope/instrumentation';\n *\n * const app = new Hono();\n * app.use('*', honoTelemetryMiddleware());\n * ```\n */\nexport function honoTelemetryMiddleware(\n\toptions: HonoTelemetryMiddlewareOptions = {},\n): MiddlewareHandler {\n\treturn async (c, next) => {\n\t\t// Check if path should be ignored\n\t\tif (\n\t\t\toptions.ignorePaths &&\n\t\t\tshouldIgnorePath(c.req.path, options.ignorePaths)\n\t\t) {\n\t\t\treturn next();\n\t\t}\n\n\t\t// Skip if custom skip function returns true\n\t\tif (options.shouldSkip?.(c)) {\n\t\t\treturn next();\n\t\t}\n\n\t\t// Extract trace context from headers\n\t\tconst headers: Record<string, string | string[] | undefined> = {};\n\t\tc.req.raw.headers.forEach((value, key) => {\n\t\t\theaders[key] = value;\n\t\t});\n\t\t// Continued only from a trusted caller; anyone else gets a new trace\n\t\t// that links to the one they claimed.\n\t\tconst { parent: parentContext, links } = incomingTraceContext(\n\t\t\theaders,\n\t\t\tisTrustedCaller(c, options),\n\t\t);\n\n\t\t// Build span attributes from request\n\t\tconst attrs = buildHonoSpanAttributes(c, options);\n\n\t\t// Create the span\n\t\tconst span = createHttpServerSpan(attrs, parentContext, links);\n\t\tconst spanContext = trace.setSpan(parentContext, span);\n\n\t\t// Store span and context on Hono context\n\t\tc.set(SPAN_KEY, span);\n\t\tc.set(CONTEXT_KEY, spanContext);\n\n\t\t// Record body if requested\n\t\tif (options.recordBody) {\n\t\t\ttry {\n\t\t\t\tconst body = await c.req.text();\n\t\t\t\tif (body) {\n\t\t\t\t\tspan.setAttribute(\n\t\t\t\t\t\t'http.request.body',\n\t\t\t\t\t\tbody.length > 4096 ? `${body.slice(0, 4096)}...` : body,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Body may have already been consumed\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\t// Execute the rest of the middleware chain within span context, so\n\t\t\t// the handler's logs and outbound spans nest under this one.\n\t\t\tawait context.with(spanContext, async () => {\n\t\t\t\tawait next();\n\t\t\t});\n\n\t\t\tnameAfterRoute(c, span);\n\n\t\t\t// Record response\n\t\t\tconst statusCode = c.res.status;\n\n\t\t\tif (options.recordResponseBody) {\n\t\t\t\ttry {\n\t\t\t\t\tconst body = await c.res.clone().text();\n\t\t\t\t\tif (body) {\n\t\t\t\t\t\tspan.setAttribute(\n\t\t\t\t\t\t\t'http.response.body',\n\t\t\t\t\t\t\tbody.length > 4096 ? `${body.slice(0, 4096)}...` : body,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Response body may not be available\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Hono hands a thrown error to `onError` and sets `c.error`\n\t\t\t// rather than rethrowing, so that is where it is found.\n\t\t\tendHttpSpan(span, { statusCode }, c.error);\n\t\t} catch (error) {\n\t\t\tnameAfterRoute(c, span);\n\t\t\tendHttpSpan(\n\t\t\t\tspan,\n\t\t\t\t{ statusCode: 500 },\n\t\t\t\terror instanceof Error ? error : new Error(String(error)),\n\t\t\t);\n\t\t\tthrow error;\n\t\t}\n\t};\n}\n\n/**\n * Whether this request's `traceparent` is continued: from one of the API's\n * own origins, or from an internal caller.\n */\nfunction isTrustedCaller(\n\tc: Context,\n\toptions: HonoTelemetryMiddlewareOptions,\n): boolean {\n\tconst origin = c.req.header('origin');\n\tif (origin) {\n\t\tconst trusted =\n\t\t\ttypeof options.trustedOrigins === 'function'\n\t\t\t\t? options.trustedOrigins()\n\t\t\t\t: options.trustedOrigins;\n\t\treturn isTrustedOrigin(origin, trusted);\n\t}\n\n\tconst internal = options.internalCallers ?? true;\n\tif (typeof internal === 'function') return internal(c);\n\tif (!internal) return false;\n\treturn isInternalCaller({\n\t\theaders: c.req.raw.headers,\n\t\tremoteAddress: remoteAddressOf(c),\n\t});\n}\n\n/** The TCP peer's address under `@hono/node-server`, or undefined. */\nfunction remoteAddressOf(c: Context): string | undefined {\n\tconst env = c.env as\n\t\t| { incoming?: { socket?: { remoteAddress?: string } } }\n\t\t| undefined;\n\treturn env?.incoming?.socket?.remoteAddress;\n}\n\n/**\n * The route the request matched, once the handler has run — `/users/:id`,\n * never `/users/42` — or undefined when only middleware ran (a 404).\n *\n * Read after `next()`: before it, the route is this middleware's own `*`.\n */\nfunction matchedRoute(c: Context): string | undefined {\n\tconst path = routePath(c);\n\treturn path && !path.includes('*') ? path : undefined;\n}\n\n/** `GET /users/:id`, or the bare method when no route matched. */\nfunction nameAfterRoute(c: Context, span: Span): void {\n\tconst route = matchedRoute(c);\n\tif (route) {\n\t\tspan.setAttribute('http.route', route);\n\t\tspan.updateName(`${c.req.method} ${route}`);\n\t} else {\n\t\tspan.updateName(c.req.method);\n\t}\n}\n\n/**\n * Build span attributes from Hono context\n */\nfunction buildHonoSpanAttributes(\n\tc: Context,\n\toptions: HonoTelemetryMiddlewareOptions,\n): HttpSpanAttributes {\n\tconst req = c.req;\n\tconst url = new URL(req.url);\n\n\t// No `url.full`: a query string can carry a token, and the span would\n\t// keep it. The route is named once the handler has run.\n\tconst attrs: HttpSpanAttributes = {\n\t\tmethod: req.method,\n\t\tpath: url.pathname,\n\t\thost: url.host,\n\t\tscheme: url.protocol.replace(':', '') as 'http' | 'https',\n\t\tuserAgent: req.header('user-agent'),\n\t\tclientIp: getClientIp(c),\n\t\trequestId: req.header('x-request-id') || req.header('x-amzn-requestid'),\n\t};\n\n\t// Add user metadata if extractor provided\n\tif (options.getUserId) {\n\t\tconst userId = options.getUserId(c);\n\t\tif (userId) {\n\t\t\tattrs.user = { userId };\n\t\t}\n\t}\n\n\treturn attrs;\n}\n\n/**\n * Extract client IP from Hono context\n */\nfunction getClientIp(c: Context): string | undefined {\n\t// Try various headers in order of preference\n\tconst xForwardedFor = c.req.header('x-forwarded-for');\n\tif (xForwardedFor) {\n\t\tconst first = xForwardedFor.split(',')[0];\n\t\treturn first?.trim();\n\t}\n\n\tconst xRealIp = c.req.header('x-real-ip');\n\tif (xRealIp) {\n\t\treturn xRealIp;\n\t}\n\n\t// Try CF-Connecting-IP (Cloudflare)\n\tconst cfConnectingIp = c.req.header('cf-connecting-ip');\n\tif (cfConnectingIp) {\n\t\treturn cfConnectingIp;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Check if path should be ignored\n */\nfunction shouldIgnorePath(path: string, ignorePaths: string[]): boolean {\n\tfor (const pattern of ignorePaths) {\n\t\tif (pattern.endsWith('*')) {\n\t\t\t// Wildcard match\n\t\t\tconst prefix = pattern.slice(0, -1);\n\t\t\tif (path.startsWith(prefix)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} else if (path === pattern) {\n\t\t\t// Exact match\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * Run a function within the span context from Hono context\n *\n * @example\n * ```typescript\n * app.get('/api/users', async (c) => {\n * return withHonoSpanContext(c, async () => {\n * // Any spans created here will be children of the request span\n * const users = await fetchUsers();\n * return c.json(users);\n * });\n * });\n * ```\n */\nexport async function withHonoSpanContext<T>(\n\tc: Context,\n\tfn: () => Promise<T>,\n): Promise<T> {\n\tconst ctx = getTraceContextFromHono(c);\n\tif (!ctx) {\n\t\treturn fn();\n\t}\n\treturn context.with(ctx, fn);\n}\n"],"mappings":";;;;;;AAwEA,MAAM,WAAW;AACjB,MAAM,cAAc;;;;AAKpB,SAAgB,mBAAmB,GAA8B;CAChE,OAAO,EAAE,IAAI,QAAQ;AACtB;;;;AAKA,SAAgB,wBAAwB,GAAiB;CACxD,OAAO,EAAE,IAAI,WAAW;AACzB;;;;;;;;;;;;AAaA,SAAgB,wBACf,UAA0C,CAAC,GACvB;CACpB,OAAO,OAAO,GAAG,SAAS;EAEzB,IACC,QAAQ,eACR,iBAAiB,EAAE,IAAI,MAAM,QAAQ,WAAW,GAEhD,OAAO,KAAK;EAIb,IAAI,QAAQ,aAAa,CAAC,GACzB,OAAO,KAAK;EAIb,MAAM,UAAyD,CAAC;EAChE,EAAE,IAAI,IAAI,QAAQ,SAAS,OAAO,QAAQ;GACzC,QAAQ,OAAO;EAChB,CAAC;EAGD,MAAM,EAAE,QAAQ,eAAe,UAAUA,6BAAAA,qBACxC,SACA,gBAAgB,GAAG,OAAO,CAC3B;EAGA,MAAM,QAAQ,wBAAwB,GAAG,OAAO;EAGhD,MAAM,OAAOC,6BAAAA,qBAAqB,OAAO,eAAe,KAAK;EAC7D,MAAM,cAAcC,mBAAAA,MAAM,QAAQ,eAAe,IAAI;EAGrD,EAAE,IAAI,UAAU,IAAI;EACpB,EAAE,IAAI,aAAa,WAAW;EAG9B,IAAI,QAAQ,YACX,IAAI;GACH,MAAM,OAAO,MAAM,EAAE,IAAI,KAAK;GAC9B,IAAI,MACH,KAAK,aACJ,qBACA,KAAK,SAAS,OAAO,GAAG,KAAK,MAAM,GAAG,IAAI,EAAE,OAAO,IACpD;EAEF,QAAQ,CAER;EAGD,IAAI;GAGH,MAAMC,mBAAAA,QAAQ,KAAK,aAAa,YAAY;IAC3C,MAAM,KAAK;GACZ,CAAC;GAED,eAAe,GAAG,IAAI;GAGtB,MAAM,aAAa,EAAE,IAAI;GAEzB,IAAI,QAAQ,oBACX,IAAI;IACH,MAAM,OAAO,MAAM,EAAE,IAAI,MAAM,CAAC,CAAC,KAAK;IACtC,IAAI,MACH,KAAK,aACJ,sBACA,KAAK,SAAS,OAAO,GAAG,KAAK,MAAM,GAAG,IAAI,EAAE,OAAO,IACpD;GAEF,QAAQ,CAER;GAKD,6BAAA,YAAY,MAAM,EAAE,WAAW,GAAG,EAAE,KAAK;EAC1C,SAAS,OAAO;GACf,eAAe,GAAG,IAAI;GACtB,6BAAA,YACC,MACA,EAAE,YAAY,IAAI,GAClB,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CACzD;GACA,MAAM;EACP;CACD;AACD;;;;;AAMA,SAAS,gBACR,GACA,SACU;CACV,MAAM,SAAS,EAAE,IAAI,OAAO,QAAQ;CACpC,IAAI,QAAQ;EACX,MAAM,UACL,OAAO,QAAQ,mBAAmB,aAC/B,QAAQ,eAAe,IACvB,QAAQ;EACZ,OAAOC,8BAAAA,gBAAgB,QAAQ,OAAO;CACvC;CAEA,MAAM,WAAW,QAAQ,mBAAmB;CAC5C,IAAI,OAAO,aAAa,YAAY,OAAO,SAAS,CAAC;CACrD,IAAI,CAAC,UAAU,OAAO;CACtB,OAAOC,8BAAAA,iBAAiB;EACvB,SAAS,EAAE,IAAI,IAAI;EACnB,eAAe,gBAAgB,CAAC;CACjC,CAAC;AACF;;AAGA,SAAS,gBAAgB,GAAgC;CAIxD,OAHY,EAAE,KAGF,UAAU,QAAQ;AAC/B;;;;;;;AAQA,SAAS,aAAa,GAAgC;CACrD,MAAM,QAAA,GAAOC,WAAAA,UAAAA,CAAU,CAAC;CACxB,OAAO,QAAQ,CAAC,KAAK,SAAS,GAAG,IAAI,OAAO,KAAA;AAC7C;;AAGA,SAAS,eAAe,GAAY,MAAkB;CACrD,MAAM,QAAQ,aAAa,CAAC;CAC5B,IAAI,OAAO;EACV,KAAK,aAAa,cAAc,KAAK;EACrC,KAAK,WAAW,GAAG,EAAE,IAAI,OAAO,GAAG,OAAO;CAC3C,OACC,KAAK,WAAW,EAAE,IAAI,MAAM;AAE9B;;;;AAKA,SAAS,wBACR,GACA,SACqB;CACrB,MAAM,MAAM,EAAE;CACd,MAAM,MAAM,IAAI,IAAI,IAAI,GAAG;CAI3B,MAAM,QAA4B;EACjC,QAAQ,IAAI;EACZ,MAAM,IAAI;EACV,MAAM,IAAI;EACV,QAAQ,IAAI,SAAS,QAAQ,KAAK,EAAE;EACpC,WAAW,IAAI,OAAO,YAAY;EAClC,UAAU,YAAY,CAAC;EACvB,WAAW,IAAI,OAAO,cAAc,KAAK,IAAI,OAAO,kBAAkB;CACvE;CAGA,IAAI,QAAQ,WAAW;EACtB,MAAM,SAAS,QAAQ,UAAU,CAAC;EAClC,IAAI,QACH,MAAM,OAAO,EAAE,OAAO;CAExB;CAEA,OAAO;AACR;;;;AAKA,SAAS,YAAY,GAAgC;CAEpD,MAAM,gBAAgB,EAAE,IAAI,OAAO,iBAAiB;CACpD,IAAI,eAEH,OADc,cAAc,MAAM,GAAG,CAAC,CAAC,EAC3B,EAAE,KAAK;CAGpB,MAAM,UAAU,EAAE,IAAI,OAAO,WAAW;CACxC,IAAI,SACH,OAAO;CAIR,MAAM,iBAAiB,EAAE,IAAI,OAAO,kBAAkB;CACtD,IAAI,gBACH,OAAO;AAIT;;;;AAKA,SAAS,iBAAiB,MAAc,aAAgC;CACvE,KAAK,MAAM,WAAW,aACrB,IAAI,QAAQ,SAAS,GAAG,GAAG;EAE1B,MAAM,SAAS,QAAQ,MAAM,GAAG,EAAE;EAClC,IAAI,KAAK,WAAW,MAAM,GACzB,OAAO;CAET,OAAO,IAAI,SAAS,SAEnB,OAAO;CAGT,OAAO;AACR;;;;;;;;;;;;;;;AAgBA,eAAsB,oBACrB,GACA,IACa;CACb,MAAM,MAAM,wBAAwB,CAAC;CACrC,IAAI,CAAC,KACJ,OAAO,GAAG;CAEX,OAAOH,mBAAAA,QAAQ,KAAK,KAAK,EAAE;AAC5B"}
|
|
@@ -27,6 +27,25 @@ export interface HonoTelemetryMiddlewareOptions {
|
|
|
27
27
|
* Whether to skip tracing for this request
|
|
28
28
|
*/
|
|
29
29
|
shouldSkip?: (c: Context) => boolean;
|
|
30
|
+
/**
|
|
31
|
+
* The origins whose `traceparent` is continued: the API's own sites, the
|
|
32
|
+
* same list its CORS allows. A request from any other origin starts a new
|
|
33
|
+
* trace linked to the one it claimed.
|
|
34
|
+
*
|
|
35
|
+
* A function is read on each request, for a server that learns its origins
|
|
36
|
+
* only once the app has loaded its configuration.
|
|
37
|
+
*/
|
|
38
|
+
trustedOrigins?: readonly string[] | (() => readonly string[] | undefined);
|
|
39
|
+
/**
|
|
40
|
+
* Whether a request with no `Origin` from an internal caller continues its
|
|
41
|
+
* `traceparent` — another service on the private network (see `./trust`):
|
|
42
|
+
* no `Origin`, no proxy's forwarding header, and a loopback or private
|
|
43
|
+
* peer address, read from `@hono/node-server`'s socket.
|
|
44
|
+
*
|
|
45
|
+
* `false` trusts no caller without an origin; a function decides itself.
|
|
46
|
+
* @default true
|
|
47
|
+
*/
|
|
48
|
+
internalCallers?: boolean | ((c: Context) => boolean);
|
|
30
49
|
}
|
|
31
50
|
/**
|
|
32
51
|
* Get the current span from Hono context
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hono.d.cts","names":[],"sources":["../../src/instrumentation/hono.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"hono.d.cts","names":[],"sources":["../../src/instrumentation/hono.ts"],"mappings":";;;;;;iBAqBiB;;;;;EAKhB;;;;;EAMA;;;;EAKA,aAAa,GAAG;;;;EAKhB;;;;EAKA,cAAc,GAAG;;;;;;;;;EAUjB;;;;;;;;;;EAWA,8BAA8B,GAAG;;;;;wBAUlB,mBAAmB,GAAG,UAAU;;;;wBAOhC,wBAAwB,GAAG;;;;;;;;;;;;wBAe3B,wBACf,UAAS,iCACP;;;;;;;;;;;;;;;wBAiPmB,oBAAoB,GACzC,GAAG,SACH,UAAU,QAAQ,KAChB,QAAQ"}
|
|
@@ -27,6 +27,25 @@ export interface HonoTelemetryMiddlewareOptions {
|
|
|
27
27
|
* Whether to skip tracing for this request
|
|
28
28
|
*/
|
|
29
29
|
shouldSkip?: (c: Context$1) => boolean;
|
|
30
|
+
/**
|
|
31
|
+
* The origins whose `traceparent` is continued: the API's own sites, the
|
|
32
|
+
* same list its CORS allows. A request from any other origin starts a new
|
|
33
|
+
* trace linked to the one it claimed.
|
|
34
|
+
*
|
|
35
|
+
* A function is read on each request, for a server that learns its origins
|
|
36
|
+
* only once the app has loaded its configuration.
|
|
37
|
+
*/
|
|
38
|
+
trustedOrigins?: readonly string[] | (() => readonly string[] | undefined);
|
|
39
|
+
/**
|
|
40
|
+
* Whether a request with no `Origin` from an internal caller continues its
|
|
41
|
+
* `traceparent` — another service on the private network (see `./trust`):
|
|
42
|
+
* no `Origin`, no proxy's forwarding header, and a loopback or private
|
|
43
|
+
* peer address, read from `@hono/node-server`'s socket.
|
|
44
|
+
*
|
|
45
|
+
* `false` trusts no caller without an origin; a function decides itself.
|
|
46
|
+
* @default true
|
|
47
|
+
*/
|
|
48
|
+
internalCallers?: boolean | ((c: Context$1) => boolean);
|
|
30
49
|
}
|
|
31
50
|
/**
|
|
32
51
|
* Get the current span from Hono context
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hono.d.mts","names":["Context"],"sources":["../../src/instrumentation/hono.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"hono.d.mts","names":["Context"],"sources":["../../src/instrumentation/hono.ts"],"mappings":";;;;;;iBAqBiB;;;;;EAKhB;;;;;EAMA;;;;EAKA,aAAa,GAAGA;;;;EAKhB;;;;EAKA,cAAc,GAAGA;;;;;;;;;EAUjB;;;;;;;;;;EAWA,8BAA8B,GAAGA;;;;;wBAUlB,mBAAmB,GAAGA,YAAU;;;;wBAOhC,wBAAwB,GAAGA;;;;;;;;;;;;wBAe3B,wBACf,UAAS,iCACP;;;;;;;;;;;;;;;wBAiPmB,oBAAoB,GACzC,GAAGA,WACH,UAAU,QAAQ,KAChB,QAAQ"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { createHttpServerSpan, endHttpSpan,
|
|
1
|
+
import { createHttpServerSpan, endHttpSpan, incomingTraceContext } from "./http.mjs";
|
|
2
|
+
import { isInternalCaller, isTrustedOrigin } from "./trust.mjs";
|
|
2
3
|
import { context, trace } from "@opentelemetry/api";
|
|
4
|
+
import { routePath } from "hono/route";
|
|
3
5
|
//#region src/instrumentation/hono.ts
|
|
4
6
|
const SPAN_KEY = "telemetry.span";
|
|
5
7
|
const CONTEXT_KEY = "telemetry.context";
|
|
@@ -34,9 +36,9 @@ function honoTelemetryMiddleware(options = {}) {
|
|
|
34
36
|
c.req.raw.headers.forEach((value, key) => {
|
|
35
37
|
headers[key] = value;
|
|
36
38
|
});
|
|
37
|
-
const parentContext =
|
|
39
|
+
const { parent: parentContext, links } = incomingTraceContext(headers, isTrustedCaller(c, options));
|
|
38
40
|
const attrs = buildHonoSpanAttributes(c, options);
|
|
39
|
-
const span = createHttpServerSpan(attrs, parentContext);
|
|
41
|
+
const span = createHttpServerSpan(attrs, parentContext, links);
|
|
40
42
|
const spanContext = trace.setSpan(parentContext, span);
|
|
41
43
|
c.set(SPAN_KEY, span);
|
|
42
44
|
c.set(CONTEXT_KEY, spanContext);
|
|
@@ -48,31 +50,69 @@ function honoTelemetryMiddleware(options = {}) {
|
|
|
48
50
|
await context.with(spanContext, async () => {
|
|
49
51
|
await next();
|
|
50
52
|
});
|
|
53
|
+
nameAfterRoute(c, span);
|
|
51
54
|
const statusCode = c.res.status;
|
|
52
55
|
if (options.recordResponseBody) try {
|
|
53
56
|
const body = await c.res.clone().text();
|
|
54
57
|
if (body) span.setAttribute("http.response.body", body.length > 4096 ? `${body.slice(0, 4096)}...` : body);
|
|
55
58
|
} catch {}
|
|
56
|
-
endHttpSpan(span, { statusCode });
|
|
59
|
+
endHttpSpan(span, { statusCode }, c.error);
|
|
57
60
|
} catch (error) {
|
|
61
|
+
nameAfterRoute(c, span);
|
|
58
62
|
endHttpSpan(span, { statusCode: 500 }, error instanceof Error ? error : new Error(String(error)));
|
|
59
63
|
throw error;
|
|
60
64
|
}
|
|
61
65
|
};
|
|
62
66
|
}
|
|
63
67
|
/**
|
|
68
|
+
* Whether this request's `traceparent` is continued: from one of the API's
|
|
69
|
+
* own origins, or from an internal caller.
|
|
70
|
+
*/
|
|
71
|
+
function isTrustedCaller(c, options) {
|
|
72
|
+
const origin = c.req.header("origin");
|
|
73
|
+
if (origin) {
|
|
74
|
+
const trusted = typeof options.trustedOrigins === "function" ? options.trustedOrigins() : options.trustedOrigins;
|
|
75
|
+
return isTrustedOrigin(origin, trusted);
|
|
76
|
+
}
|
|
77
|
+
const internal = options.internalCallers ?? true;
|
|
78
|
+
if (typeof internal === "function") return internal(c);
|
|
79
|
+
if (!internal) return false;
|
|
80
|
+
return isInternalCaller({
|
|
81
|
+
headers: c.req.raw.headers,
|
|
82
|
+
remoteAddress: remoteAddressOf(c)
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/** The TCP peer's address under `@hono/node-server`, or undefined. */
|
|
86
|
+
function remoteAddressOf(c) {
|
|
87
|
+
return c.env?.incoming?.socket?.remoteAddress;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The route the request matched, once the handler has run — `/users/:id`,
|
|
91
|
+
* never `/users/42` — or undefined when only middleware ran (a 404).
|
|
92
|
+
*
|
|
93
|
+
* Read after `next()`: before it, the route is this middleware's own `*`.
|
|
94
|
+
*/
|
|
95
|
+
function matchedRoute(c) {
|
|
96
|
+
const path = routePath(c);
|
|
97
|
+
return path && !path.includes("*") ? path : void 0;
|
|
98
|
+
}
|
|
99
|
+
/** `GET /users/:id`, or the bare method when no route matched. */
|
|
100
|
+
function nameAfterRoute(c, span) {
|
|
101
|
+
const route = matchedRoute(c);
|
|
102
|
+
if (route) {
|
|
103
|
+
span.setAttribute("http.route", route);
|
|
104
|
+
span.updateName(`${c.req.method} ${route}`);
|
|
105
|
+
} else span.updateName(c.req.method);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
64
108
|
* Build span attributes from Hono context
|
|
65
109
|
*/
|
|
66
110
|
function buildHonoSpanAttributes(c, options) {
|
|
67
111
|
const req = c.req;
|
|
68
112
|
const url = new URL(req.url);
|
|
69
|
-
const routePath = c.req.routePath;
|
|
70
|
-
const route = routePath && routePath !== "*" && !routePath.includes("/*") ? routePath : url.pathname;
|
|
71
113
|
const attrs = {
|
|
72
114
|
method: req.method,
|
|
73
|
-
url: req.url,
|
|
74
115
|
path: url.pathname,
|
|
75
|
-
route,
|
|
76
116
|
host: url.host,
|
|
77
117
|
scheme: url.protocol.replace(":", ""),
|
|
78
118
|
userAgent: req.header("user-agent"),
|