@pydantic/logfire-browser 0.16.3 → 0.17.0-alpha.0
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 +236 -3
- package/dist/browserMetrics-Bx5fHWgu.js +1 -0
- package/dist/browserMetrics-sqpejR9C.cjs +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +206 -4
- package/dist/index.d.ts +206 -4
- package/dist/index.js +1 -1
- package/package.json +20 -10
package/README.md
CHANGED
|
@@ -49,6 +49,235 @@ Do not use resource attributes for per-request values or sensitive user data.
|
|
|
49
49
|
First-class options such as `serviceName`, `serviceVersion`, and `environment`
|
|
50
50
|
take precedence over conflicting `resourceAttributes` keys.
|
|
51
51
|
|
|
52
|
+
## RUM session identity
|
|
53
|
+
|
|
54
|
+
Enable `rum.session` to add a browser session id to every span started by the
|
|
55
|
+
configured browser provider:
|
|
56
|
+
|
|
57
|
+
```js
|
|
58
|
+
import * as logfire from '@pydantic/logfire-browser'
|
|
59
|
+
|
|
60
|
+
logfire.configure({
|
|
61
|
+
traceUrl: '/client-traces',
|
|
62
|
+
serviceName: 'browser-app',
|
|
63
|
+
rum: { session: true },
|
|
64
|
+
})
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The SDK stores the session in `sessionStorage`, so it is scoped to the browser
|
|
68
|
+
tab and survives page reloads. Sessions rotate after 30 minutes of inactivity
|
|
69
|
+
or 4 hours of total duration by default. Spans get `session.id` and
|
|
70
|
+
`browser.session.id`; `session.id` is the OpenTelemetry semantic attribute and
|
|
71
|
+
`browser.session.id` is emitted for Logfire Platform compatibility.
|
|
72
|
+
|
|
73
|
+
By default, session-enabled spans also get `url.full` and `url.path` from the
|
|
74
|
+
current page URL. If your app has sensitive query strings or fragments, provide
|
|
75
|
+
a sanitizer or suppress URL attributes:
|
|
76
|
+
|
|
77
|
+
```js
|
|
78
|
+
logfire.configure({
|
|
79
|
+
traceUrl: '/client-traces',
|
|
80
|
+
serviceName: 'browser-app',
|
|
81
|
+
rum: {
|
|
82
|
+
session: {
|
|
83
|
+
urlAttributes: (url) => ({
|
|
84
|
+
full: `${url.origin}${url.pathname}`,
|
|
85
|
+
path: url.pathname,
|
|
86
|
+
}),
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
logfire.configure({
|
|
92
|
+
traceUrl: '/client-traces',
|
|
93
|
+
serviceName: 'browser-app',
|
|
94
|
+
rum: {
|
|
95
|
+
session: {
|
|
96
|
+
urlAttributes: false,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
})
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Use `getBrowserSessionId()` after `configure({ rum: { session: true } })` when
|
|
103
|
+
another browser integration needs the SDK-owned session id before the first
|
|
104
|
+
span is created.
|
|
105
|
+
|
|
106
|
+
## RUM Web Vitals
|
|
107
|
+
|
|
108
|
+
Enable `rum.webVitals` to report Core Web Vitals from real browser sessions:
|
|
109
|
+
|
|
110
|
+
```js
|
|
111
|
+
import * as logfire from '@pydantic/logfire-browser'
|
|
112
|
+
|
|
113
|
+
logfire.configure({
|
|
114
|
+
traceUrl: '/client-traces',
|
|
115
|
+
serviceName: 'browser-app',
|
|
116
|
+
rum: { webVitals: true },
|
|
117
|
+
})
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
The SDK dynamically loads `web-vitals/attribution` only when `rum.webVitals` is
|
|
121
|
+
enabled. It records LCP, INP, CLS, FCP, and TTFB as short spans named
|
|
122
|
+
`web_vital.lcp`, `web_vital.inp`, `web_vital.cls`, `web_vital.fcp`, and
|
|
123
|
+
`web_vital.ttfb`.
|
|
124
|
+
|
|
125
|
+
Each span includes base attributes such as `web_vital.name`,
|
|
126
|
+
`web_vital.value`, `web_vital.delta`, `web_vital.id`, `web_vital.rating`, and
|
|
127
|
+
`web_vital.navigation_type`. Attribution fields include values such as
|
|
128
|
+
`web_vital.lcp.target`, `web_vital.inp.target`, and
|
|
129
|
+
`web_vital.cls.largest_shift_target`.
|
|
130
|
+
|
|
131
|
+
`rum.webVitals` implies default `rum.session` behavior so Web Vital spans get
|
|
132
|
+
session and URL attributes. If you need to sanitize URLs, pass session options
|
|
133
|
+
alongside Web Vitals:
|
|
134
|
+
|
|
135
|
+
```js
|
|
136
|
+
logfire.configure({
|
|
137
|
+
traceUrl: '/client-traces',
|
|
138
|
+
serviceName: 'browser-app',
|
|
139
|
+
rum: {
|
|
140
|
+
session: {
|
|
141
|
+
urlAttributes: (url) => ({
|
|
142
|
+
full: `${url.origin}${url.pathname}`,
|
|
143
|
+
path: url.pathname,
|
|
144
|
+
}),
|
|
145
|
+
},
|
|
146
|
+
webVitals: {
|
|
147
|
+
reportAllChanges: true,
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
})
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
To emit native OpenTelemetry histogram metrics in parallel with those spans,
|
|
154
|
+
configure a browser-safe metrics proxy and opt Web Vitals into metrics:
|
|
155
|
+
|
|
156
|
+
```js
|
|
157
|
+
logfire.configure({
|
|
158
|
+
traceUrl: '/client-traces',
|
|
159
|
+
metrics: {
|
|
160
|
+
metricUrl: '/client-metrics',
|
|
161
|
+
},
|
|
162
|
+
serviceName: 'browser-app',
|
|
163
|
+
rum: {
|
|
164
|
+
webVitals: {
|
|
165
|
+
metrics: true,
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
})
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Metric export is disabled unless top-level `metrics.metricUrl` is configured,
|
|
172
|
+
and `rum.webVitals.metrics` requires that transport. The SDK uses a local
|
|
173
|
+
OpenTelemetry `MeterProvider`; it does not replace the application's global
|
|
174
|
+
meter provider.
|
|
175
|
+
|
|
176
|
+
Web Vitals metrics are histograms named
|
|
177
|
+
`logfire.browser.web_vital.lcp`, `logfire.browser.web_vital.inp`,
|
|
178
|
+
`logfire.browser.web_vital.cls`, `logfire.browser.web_vital.fcp`, and
|
|
179
|
+
`logfire.browser.web_vital.ttfb`. LCP, INP, FCP, and TTFB use unit `ms`; CLS
|
|
180
|
+
uses unit `1`.
|
|
181
|
+
|
|
182
|
+
Metric data point attributes are intentionally low-cardinality:
|
|
183
|
+
`web_vital.name` and `web_vital.rating` by default. They do not include
|
|
184
|
+
`session.id`, `browser.session.id`, `url.full`, `url.path`, Web Vital
|
|
185
|
+
ids/deltas, DOM selectors, attribution fields, or raw PerformanceEntry data. Use
|
|
186
|
+
spans for raw-sample drilldown, session/replay correlation, exact URL context,
|
|
187
|
+
and attribution selectors.
|
|
188
|
+
|
|
189
|
+
For modern single-page apps, these are standard document-level Web Vitals, not
|
|
190
|
+
route-level soft-navigation metrics. Span URL attributes describe the browser
|
|
191
|
+
URL when the callback fires; route-specific Core Web Vitals need separate route
|
|
192
|
+
or soft-navigation instrumentation. To add a route dimension to metrics, pass a
|
|
193
|
+
low-cardinality template such as `/products/:id` through
|
|
194
|
+
`rum.webVitals.metrics.attributes`.
|
|
195
|
+
|
|
196
|
+
## Session replay
|
|
197
|
+
|
|
198
|
+
Session replay is experimental while Logfire Platform replay ingest and playback
|
|
199
|
+
are still behind a feature flag. Keep replay behind your own application flag
|
|
200
|
+
and expect minor API, ingest, and UI behavior changes before general
|
|
201
|
+
availability.
|
|
202
|
+
|
|
203
|
+
Install the optional replay package and configure `sessionReplay` when you want
|
|
204
|
+
rrweb session recording:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
npm install @pydantic/logfire-session-replay
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
```js
|
|
211
|
+
import * as logfire from '@pydantic/logfire-browser'
|
|
212
|
+
|
|
213
|
+
logfire.configure({
|
|
214
|
+
traceUrl: '/logfire-proxy/v1/traces',
|
|
215
|
+
serviceName: 'browser-app',
|
|
216
|
+
sessionReplay: {
|
|
217
|
+
load: () => import('@pydantic/logfire-session-replay'),
|
|
218
|
+
replayUrl: '/logfire-proxy/v1/replay',
|
|
219
|
+
headers: async () => ({
|
|
220
|
+
'X-CSRF': await getCsrfToken(),
|
|
221
|
+
}),
|
|
222
|
+
maskAllInputs: true,
|
|
223
|
+
},
|
|
224
|
+
})
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
`sessionReplay` implies default browser session attributes. Replay chunks and
|
|
228
|
+
browser spans share `session.id` / `browser.session.id`, and spans started
|
|
229
|
+
while replay is active get `logfire.session_replay.active` and
|
|
230
|
+
`logfire.session_replay.mode`. The browser integration intentionally does not
|
|
231
|
+
poll active trace context into replay chunks.
|
|
232
|
+
|
|
233
|
+
Use a backend proxy for browser replay uploads. The proxy should authenticate
|
|
234
|
+
the browser request with your application session or CSRF mechanism and add the
|
|
235
|
+
Logfire write token server-side. Direct token configuration is available as an
|
|
236
|
+
advanced escape hatch:
|
|
237
|
+
|
|
238
|
+
```js
|
|
239
|
+
logfire.configure({
|
|
240
|
+
traceUrl: '/logfire-proxy/v1/traces',
|
|
241
|
+
serviceName: 'browser-app',
|
|
242
|
+
sessionReplay: {
|
|
243
|
+
load: () => import('@pydantic/logfire-session-replay'),
|
|
244
|
+
replayUrl: 'https://logfire-api.pydantic.dev/v1/replay',
|
|
245
|
+
token: '<write-token>',
|
|
246
|
+
},
|
|
247
|
+
})
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Do not use direct tokens in normal browser applications. Replay may capture
|
|
251
|
+
console, fetch/XHR, navigation, and DOM events. Keep the default input masking
|
|
252
|
+
enabled, use `blockSelector` or `maskTextSelector` for sensitive page regions,
|
|
253
|
+
and set `captureConsole`, `captureNetwork`, or `captureNavigation` to `false`
|
|
254
|
+
when those side channels are not appropriate.
|
|
255
|
+
|
|
256
|
+
When testing replay locally, browser privacy extensions or ad blockers may block
|
|
257
|
+
requests or dynamic imports whose URLs contain terms such as `session-replay`.
|
|
258
|
+
If replay fails to start with `ERR_BLOCKED_BY_CLIENT`, test in a clean profile
|
|
259
|
+
or disable the extension for the local app. Vite workspace examples may also
|
|
260
|
+
need to load rrweb's browser ESM build (`rrweb/dist/rrweb.js`) rather than its
|
|
261
|
+
CommonJS build when importing unpublished workspace output directly.
|
|
262
|
+
|
|
263
|
+
## Custom span processors
|
|
264
|
+
|
|
265
|
+
Use `spanProcessors` to register additional OpenTelemetry span processors with
|
|
266
|
+
the browser tracer provider:
|
|
267
|
+
|
|
268
|
+
```js
|
|
269
|
+
logfire.configure({
|
|
270
|
+
traceUrl: '/client-traces',
|
|
271
|
+
serviceName: 'browser-app',
|
|
272
|
+
spanProcessors: [customProcessor],
|
|
273
|
+
})
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Custom processors are advanced OpenTelemetry extension points. They are
|
|
277
|
+
registered before Logfire's built-in exporting processor and before Logfire
|
|
278
|
+
tail sampling, so use them for enrichment or integration hooks rather than
|
|
279
|
+
duplicate exporting unless that is intentional.
|
|
280
|
+
|
|
52
281
|
## Baggage span attributes
|
|
53
282
|
|
|
54
283
|
Use `baggage.spanAttributes` to copy selected active OpenTelemetry baggage
|
|
@@ -102,9 +331,13 @@ single-page app shells that replace the whole telemetry setup. Cleanup is
|
|
|
102
331
|
idempotent: repeated or concurrent calls share one promise and run the lifecycle
|
|
103
332
|
once in this order:
|
|
104
333
|
|
|
105
|
-
1.
|
|
106
|
-
2.
|
|
107
|
-
3.
|
|
334
|
+
1. await session replay startup and stop replay when enabled
|
|
335
|
+
2. unregister configured instrumentations
|
|
336
|
+
3. await Web Vitals startup and shutdown when enabled
|
|
337
|
+
4. force-flush and shut down metrics when configured
|
|
338
|
+
5. force-flush spans
|
|
339
|
+
6. shut down the tracer provider
|
|
340
|
+
7. clear SDK-owned browser session state
|
|
108
341
|
|
|
109
342
|
If any cleanup step fails, Logfire still attempts the later steps before
|
|
110
343
|
returning the first failure. Later calls return the same settled cleanup promise
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{diag as e}from"@opentelemetry/api";const t={CLS:{boundaries:[.01,.05,.1,.15,.25,.5,1],description:`Cumulative Layout Shift score recorded in browser sessions.`,name:`logfire.browser.web_vital.cls`,unit:`1`},FCP:{boundaries:[500,1e3,1500,1800,2500,3e3,4e3,6e3],description:`First Contentful Paint duration recorded in browser sessions.`,name:`logfire.browser.web_vital.fcp`,unit:`ms`},INP:{boundaries:[50,100,150,200,300,500,800,1e3,2e3],description:`Interaction to Next Paint duration recorded in browser sessions.`,name:`logfire.browser.web_vital.inp`,unit:`ms`},LCP:{boundaries:[500,1e3,1500,2e3,2500,3e3,3500,4e3,5e3,8e3,1e4],description:`Largest Contentful Paint duration recorded in browser sessions.`,name:`logfire.browser.web_vital.lcp`,unit:`ms`},TTFB:{boundaries:[100,300,500,800,1200,1800,2500,4e3],description:`Time to First Byte duration recorded in browser sessions.`,name:`logfire.browser.web_vital.ttfb`,unit:`ms`}},n=new Set([`browser.session.id`,`session.id`,`url.full`,`web_vital.delta`,`web_vital.id`,`web_vital.value`]),r={exportIntervalMillis:6e4,exportTimeoutMillis:1e4};function i(e){return e===`CLS`||e===`FCP`||e===`INP`||e===`LCP`||e===`TTFB`}function a(e){return n.has(e)||e.startsWith(`web_vital.cls.`)||e.startsWith(`web_vital.fcp.`)||e.startsWith(`web_vital.inp.`)||e.startsWith(`web_vital.lcp.`)||e.startsWith(`web_vital.ttfb.`)}function o(e,t,n){if(!a(t)){if(typeof n==`string`||typeof n==`boolean`){e[t]=n;return}typeof n==`number`&&Number.isFinite(n)&&(e[t]=n)}}function s(e,t){if(t!==void 0)for(let[n,r]of Object.entries(t))o(e,n,r)}function c(e){let t={};return o(t,`web_vital.name`,e.name),o(t,`web_vital.rating`,e.rating),t}function l(e){let n=e.getMeter(`logfire-browser-web-vitals`);return{CLS:n.createHistogram(t.CLS.name,{advice:{explicitBucketBoundaries:t.CLS.boundaries},description:t.CLS.description,unit:t.CLS.unit}),FCP:n.createHistogram(t.FCP.name,{advice:{explicitBucketBoundaries:t.FCP.boundaries},description:t.FCP.description,unit:t.FCP.unit}),INP:n.createHistogram(t.INP.name,{advice:{explicitBucketBoundaries:t.INP.boundaries},description:t.INP.description,unit:t.INP.unit}),LCP:n.createHistogram(t.LCP.name,{advice:{explicitBucketBoundaries:t.LCP.boundaries},description:t.LCP.description,unit:t.LCP.unit}),TTFB:n.createHistogram(t.TTFB.name,{advice:{explicitBucketBoundaries:t.TTFB.boundaries},description:t.TTFB.description,unit:t.TTFB.unit})}}function u(t,n={}){let r=!0;return{record(a){if(!(!r||!i(a.name)))try{let e=c(a);s(e,n.defaultAttributes?.(a)),n.attributes!==!1&&s(e,n.attributes?.(a)),t[a.name].record(a.value,e)}catch(t){e.error(`logfire-browser: failed to record Web Vital metric`,t)}},shutdown(){r=!1}}}async function d(e,t){let[{MeterProvider:n,PeriodicExportingMetricReader:i},{OTLPMetricExporter:a}]=await Promise.all([import(`@opentelemetry/sdk-metrics`),import(`@opentelemetry/exporter-metrics-otlp-http`)]),o=new a({...e.metricExporterConfig,headers:e.metricExporterHeaders===void 0?void 0:async()=>e.metricExporterHeaders?.()??{},url:e.metricUrl}),s=new n({readers:[new i({...r,...e.metricReaderConfig,exporter:o}),...e.metricReaders??[]],resource:t}),c=l(s),d;return{createWebVitalsMetricRecorder(e){return u(c,e)},async forceFlush(){if(d!==void 0)return d;await s.forceFlush()},async shutdown(){return d??=s.shutdown(),d}}}export{d as startBrowserMetrics};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
let e=require("@opentelemetry/api");const t={CLS:{boundaries:[.01,.05,.1,.15,.25,.5,1],description:`Cumulative Layout Shift score recorded in browser sessions.`,name:`logfire.browser.web_vital.cls`,unit:`1`},FCP:{boundaries:[500,1e3,1500,1800,2500,3e3,4e3,6e3],description:`First Contentful Paint duration recorded in browser sessions.`,name:`logfire.browser.web_vital.fcp`,unit:`ms`},INP:{boundaries:[50,100,150,200,300,500,800,1e3,2e3],description:`Interaction to Next Paint duration recorded in browser sessions.`,name:`logfire.browser.web_vital.inp`,unit:`ms`},LCP:{boundaries:[500,1e3,1500,2e3,2500,3e3,3500,4e3,5e3,8e3,1e4],description:`Largest Contentful Paint duration recorded in browser sessions.`,name:`logfire.browser.web_vital.lcp`,unit:`ms`},TTFB:{boundaries:[100,300,500,800,1200,1800,2500,4e3],description:`Time to First Byte duration recorded in browser sessions.`,name:`logfire.browser.web_vital.ttfb`,unit:`ms`}},n=new Set([`browser.session.id`,`session.id`,`url.full`,`web_vital.delta`,`web_vital.id`,`web_vital.value`]),r={exportIntervalMillis:6e4,exportTimeoutMillis:1e4};function i(e){return e===`CLS`||e===`FCP`||e===`INP`||e===`LCP`||e===`TTFB`}function a(e){return n.has(e)||e.startsWith(`web_vital.cls.`)||e.startsWith(`web_vital.fcp.`)||e.startsWith(`web_vital.inp.`)||e.startsWith(`web_vital.lcp.`)||e.startsWith(`web_vital.ttfb.`)}function o(e,t,n){if(!a(t)){if(typeof n==`string`||typeof n==`boolean`){e[t]=n;return}typeof n==`number`&&Number.isFinite(n)&&(e[t]=n)}}function s(e,t){if(t!==void 0)for(let[n,r]of Object.entries(t))o(e,n,r)}function c(e){let t={};return o(t,`web_vital.name`,e.name),o(t,`web_vital.rating`,e.rating),t}function l(e){let n=e.getMeter(`logfire-browser-web-vitals`);return{CLS:n.createHistogram(t.CLS.name,{advice:{explicitBucketBoundaries:t.CLS.boundaries},description:t.CLS.description,unit:t.CLS.unit}),FCP:n.createHistogram(t.FCP.name,{advice:{explicitBucketBoundaries:t.FCP.boundaries},description:t.FCP.description,unit:t.FCP.unit}),INP:n.createHistogram(t.INP.name,{advice:{explicitBucketBoundaries:t.INP.boundaries},description:t.INP.description,unit:t.INP.unit}),LCP:n.createHistogram(t.LCP.name,{advice:{explicitBucketBoundaries:t.LCP.boundaries},description:t.LCP.description,unit:t.LCP.unit}),TTFB:n.createHistogram(t.TTFB.name,{advice:{explicitBucketBoundaries:t.TTFB.boundaries},description:t.TTFB.description,unit:t.TTFB.unit})}}function u(t,n={}){let r=!0;return{record(a){if(!(!r||!i(a.name)))try{let e=c(a);s(e,n.defaultAttributes?.(a)),n.attributes!==!1&&s(e,n.attributes?.(a)),t[a.name].record(a.value,e)}catch(t){e.diag.error(`logfire-browser: failed to record Web Vital metric`,t)}},shutdown(){r=!1}}}async function d(e,t){let[{MeterProvider:n,PeriodicExportingMetricReader:i},{OTLPMetricExporter:a}]=await Promise.all([import(`@opentelemetry/sdk-metrics`),import(`@opentelemetry/exporter-metrics-otlp-http`)]),o=new a({...e.metricExporterConfig,headers:e.metricExporterHeaders===void 0?void 0:async()=>e.metricExporterHeaders?.()??{},url:e.metricUrl}),s=new n({readers:[new i({...r,...e.metricReaderConfig,exporter:o}),...e.metricReaders??[]],resource:t}),c=l(s),d;return{createWebVitalsMetricRecorder(e){return u(c,e)},async forceFlush(){if(d!==void 0)return d;await s.forceFlush()},async shutdown(){return d??=s.shutdown(),d}}}exports.startBrowserMetrics=d;
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});let e=require(`@opentelemetry/api`),t=require(`@opentelemetry/exporter-trace-otlp-http`),n=require(`@opentelemetry/instrumentation`),r=require(`@opentelemetry/resources`),i=require(`@opentelemetry/sdk-trace-web`),a=require(`@opentelemetry/semantic-conventions`),o=require(`@opentelemetry/semantic-conventions/incubating`),s=require(`logfire`),c=require(`@opentelemetry/core`);const l=`target_xpath`,u={1:`trace`,5:`debug`,9:`info`,10:`notice`,13:`warning`,17:`error`,21:`fatal`},d={debug:`#E3E3E3`,error:`#EA4335`,fatal:`#EA4335`,info:`#9EC1FB`,notice:`#A5D490`,"on-debug":`#636262`,"on-error":`#FFEDE9`,"on-fatal":`#FFEDE9`,"on-info":`#063175`,"on-notice":`#222222`,"on-trace":`#636262`,"on-warning":`#613A0D`,trace:`#E3E3E3`,warning:`#EFB77A`};var f=class{export(e,t){this.sendSpans(e,t)}async forceFlush(){return Promise.resolve()}async shutdown(){return this.sendSpans([]),this.forceFlush()}exportInfo(e){return{attributes:e.attributes,duration:(0,c.hrTimeToMicroseconds)(e.duration),events:e.events,id:e.spanContext().spanId,instrumentationScope:e.instrumentationScope,kind:e.kind,links:e.links,name:e.name,parentSpanContext:e.parentSpanContext,resource:{attributes:e.resource.attributes},status:e.status,timestamp:(0,c.hrTimeToMicroseconds)(e.startTime),traceId:e.spanContext().traceId,traceState:e.spanContext().traceState?.serialize()}}sendSpans(e,t){for(let t of e){let e=u[t.attributes[`logfire.level_num`]]??`info`,{attributes:n,name:r,...i}=this.exportInfo(t);console.log(`%cLogfire %c${e}`,`background-color: #E520E9; color: #FFFFFF`,`background-color: ${d[`on-${e}`]}; color: ${d[e]}`,r,n,i)}t&&t({code:c.ExportResultCode.SUCCESS})}},p=class{console;wrapped;constructor(e,t){t&&(this.console=new i.SimpleSpanProcessor(new f)),this.wrapped=e}async forceFlush(){return await this.console?.forceFlush(),this.wrapped.forceFlush()}onEnd(e){this.console?.onEnd(e),this.wrapped.onEnd(e)}onStart(e,t){if(o.ATTR_HTTP_URL in e.attributes){let t=new URL(e.attributes[o.ATTR_HTTP_URL]);Reflect.set(e,`name`,`${e.name} ${t.pathname}`)}if(l in e.attributes){let t=String(e.attributes.event_type??`unknown`),n=String(e.attributes[l]??``);Reflect.set(e,`name`,`${t} ${n}`)}this.console?.onStart(e,t),this.wrapped.onStart(e,t)}async shutdown(){return await this.console?.shutdown(),this.wrapped.shutdown()}};function m(){return{}}async function h(e,t){return{...typeof e==`function`?await e():e??{},...t()}}function g(c){c.diagLogLevel!==void 0&&e.diag.setLogger(new e.DiagConsoleLogger,c.diagLogLevel);let l={errorFingerprinting:c.errorFingerprinting??!1};c.baggage!==void 0&&(l.baggage=c.baggage),c.jsonSchema!==void 0&&(l.jsonSchema=c.jsonSchema),c.minLevel!==void 0&&(l.minLevel=c.minLevel),c.scrubbing!==void 0&&(l.scrubbing=c.scrubbing),(0,s.configureLogfireApi)(l);let u=(0,r.resourceFromAttributes)(c.resourceAttributes??{}).merge((0,r.resourceFromAttributes)({[o.ATTR_BROWSER_LANGUAGE]:navigator.language,[a.ATTR_SERVICE_NAME]:c.serviceName??`logfire-browser`,[a.ATTR_SERVICE_VERSION]:c.serviceVersion??`0.0.1`,[a.ATTR_TELEMETRY_SDK_LANGUAGE]:a.TELEMETRY_SDK_LANGUAGE_VALUE_WEBJS,[a.ATTR_TELEMETRY_SDK_NAME]:`logfire-browser`,...c.environment!==void 0&&c.environment!==``?{[o.ATTR_DEPLOYMENT_ENVIRONMENT_NAME]:c.environment}:{},[a.ATTR_TELEMETRY_SDK_VERSION]:`1.0.0`,...navigator.userAgentData?{[o.ATTR_BROWSER_BRANDS]:navigator.userAgentData.brands.map(e=>`${e.brand} ${e.version}`),[o.ATTR_BROWSER_MOBILE]:navigator.userAgentData.mobile,[o.ATTR_BROWSER_PLATFORM]:navigator.userAgentData.platform}:{[a.ATTR_USER_AGENT_ORIGINAL]:navigator.userAgent}}));e.diag.info(`logfire-browser: starting`);let d=c.sampling?.head,f=d!==void 0&&d<1?new i.ParentBasedSampler({root:new i.TraceIdRatioBasedSampler(d)}):void 0,g=new p(new i.BatchSpanProcessor(new t.OTLPTraceExporter({...c.traceExporterConfig,headers:async()=>h(c.traceExporterConfig?.headers,c.traceExporterHeaders??m),url:c.traceUrl}),c.batchSpanProcessorConfig),!!c.console);c.sampling?.tail&&(g=new s.TailSamplingProcessor(g,c.sampling.tail));let _=new i.WebTracerProvider({idGenerator:new s.ULIDGenerator,resource:u,...f?{sampler:f}:{},spanProcessors:[g]});_.register({contextManager:c.contextManager??new i.StackContextManager});let v=(0,n.registerInstrumentations)({instrumentations:c.instrumentations??[],tracerProvider:_}),y;return()=>(y??=(async()=>{let t,n=(n,r)=>{let i=r instanceof Error?r:Error(String(r));t??=i,e.diag.error(`logfire-browser: ${n} failed during shutdown`,i)},r=async(e,t)=>{try{await t()}catch(t){n(e,t)}};if(e.diag.info(`logfire-browser: shutting down`),await r(`instrumentation unregister`,v),await r(`force flush`,async()=>_.forceFlush()),await r(`tracer provider shutdown`,async()=>_.shutdown()),t!==void 0)throw Error(t.message,{cause:t});e.diag.info(`logfire-browser: shut down complete`)})(),y)}const _={configure:g,configureLogfireApi:s.configureLogfireApi,debug:s.debug,DiagLogLevel:e.DiagLogLevel,error:s.error,fatal:s.fatal,info:s.info,instrument:s.instrument,Level:s.Level,log:s.log,logfireApiConfig:s.logfireApiConfig,LogfireAttributeScrubber:s.LogfireAttributeScrubber,NoopAttributeScrubber:s.NoopAttributeScrubber,notice:s.notice,reportError:s.reportError,resolveBaseUrl:s.resolveBaseUrl,resolveSendToLogfire:s.resolveSendToLogfire,serializeAttributes:s.serializeAttributes,span:s.span,startPendingSpan:s.startPendingSpan,startSpan:s.startSpan,trace:s.trace,ULIDGenerator:s.ULIDGenerator,warning:s.warning,withSettings:s.withSettings,withTags:s.withTags};Object.defineProperty(exports,`DiagLogLevel`,{enumerable:!0,get:function(){return e.DiagLogLevel}}),exports.configure=g,exports.default=_,Object.keys(s).forEach(function(e){e!==`default`&&!Object.prototype.hasOwnProperty.call(exports,e)&&Object.defineProperty(exports,e,{enumerable:!0,get:function(){return s[e]}})});
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});let e=require("@opentelemetry/api"),t=require("@opentelemetry/exporter-trace-otlp-http"),n=require("@opentelemetry/instrumentation"),r=require("@opentelemetry/resources"),i=require("@opentelemetry/sdk-trace-web"),a=require("@opentelemetry/semantic-conventions"),o=require("@opentelemetry/semantic-conventions/incubating"),s=require("logfire"),c=require("@opentelemetry/core");function l(){let e=globalThis;try{let t=(e.location??e.window?.location)?.href;return t===void 0||t===``?void 0:new URL(t)}catch{return}}var u=class{replayState;sessionManager;constructor(e,t){this.sessionManager=e,this.replayState=t}async forceFlush(){return Promise.resolve()}onEnd(e){}onStart(e,t){let n=this.sessionManager.touch();e.setAttribute(`session.id`,n.id),e.setAttribute(`browser.session.id`,n.id);let r=this.replayState?.getState();r!==void 0&&(e.setAttribute(`logfire.session_replay.active`,r.active),e.setAttribute(`logfire.session_replay.mode`,r.mode));let i=l();if(i===void 0)return;let a;try{a=this.sessionManager.getUrlAttributes(i)}catch{return}a?.full!==void 0&&e.setAttribute(`url.full`,a.full),a?.path!==void 0&&e.setAttribute(`url.path`,a.path)}async shutdown(){return Promise.resolve()}};const d={idleTimeoutMs:30*6e4,maxDurationMs:240*6e4,storageKey:`lf_browser_session`};function f(){try{return globalThis.sessionStorage??null}catch{return null}}function p(){let e=globalThis.crypto;if(typeof e?.randomUUID==`function`)return e.randomUUID();if(typeof e?.getRandomValues==`function`){let t=new Uint8Array(16);return e.getRandomValues(t),Array.from(t,e=>e.toString(16).padStart(2,`0`)).join(``)}return`${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}-${Math.random().toString(36).slice(2)}`}function m(e){if(typeof e!=`object`||!e)return!1;let t=e;return typeof t.id==`string`&&t.id.length>0&&typeof t.startedAt==`number`&&Number.isFinite(t.startedAt)&&typeof t.lastActivityAt==`number`&&Number.isFinite(t.lastActivityAt)}var h=class{generateId;idleTimeoutMs;maxDurationMs;now;storage;storageKey;urlAttributes;memorySession;constructor(e={}){this.generateId=e.generateId??p,this.idleTimeoutMs=e.idleTimeoutMs??d.idleTimeoutMs,this.maxDurationMs=e.maxDurationMs??d.maxDurationMs,this.now=e.now??Date.now,this.storage=e.storage===void 0?f():e.storage,this.storageKey=e.storageKey??d.storageKey,this.urlAttributes=e.urlAttributes}getSession(){return this.getSessionAt(this.now())}peekSessionId(){return this.memorySession?.id}touch(){let e=this.now(),t={...this.getSessionAt(e),lastActivityAt:e};return this.writeSession(t),t}reset(){return this.createSession(this.now())}getUrlAttributes(e){if(this.urlAttributes!==!1)return typeof this.urlAttributes==`function`?this.urlAttributes(e):{full:e.href,path:e.pathname}}createSession(e){let t={id:this.generateId(),lastActivityAt:e,startedAt:e};return this.writeSession(t),t}getSessionAt(e){let t=this.readSession();return t!==void 0&&!this.isExpired(t,e)?t:this.createSession(e)}isExpired(e,t){return t-e.lastActivityAt>this.idleTimeoutMs||t-e.startedAt>this.maxDurationMs}readSession(){if(this.storage!==null)try{let e=this.storage.getItem(this.storageKey);if(e!==null){let t=JSON.parse(e);if(m(t))return this.memorySession=t,t}}catch{return this.memorySession}return this.memorySession}writeSession(e){if(this.memorySession=e,this.storage!==null)try{this.storage.setItem(this.storageKey,JSON.stringify(e))}catch{}}};let g;function _(e){if(e===void 0||e===!1){g=void 0;return}let t=new h(e===!0?{}:e);return g=t,t}function v(){return g?.touch().id}function y(e){g===e&&(g=void 0)}var b=class{replay;setReplay(e){this.replay=e}clear(){this.replay=void 0}getState(){let e=this.replay?.mode;if(!(this.replay?.recording!==!0||e!==`full`&&e!==`buffer`))return{active:!0,mode:e}}};async function x(t,n,r,i){try{if(n.touch(),n.peekSessionId()===void 0)throw Error(`logfire-browser: sessionReplay requires an active browser session id`);let e=await t.load(),a=S(t,n,i),o=C(e.startSessionReplay(a),r);return o.recording&&(o.mode===`full`||o.mode===`buffer`)&&r.setReplay(o),o}catch(n){r.clear(),e.diag.error(`logfire-browser: failed to start session replay; install @pydantic/logfire-session-replay and verify sessionReplay config`,n),t.onError?.(n);return}}function S(e,t,n){let r={getSessionId:()=>t.peekSessionId(),ignoreUrlPatterns:[...w(e.replayUrl,n),...e.ignoreUrlPatterns??[]],redactUrlPatterns:e.redactUrlPatterns??[],replayUrl:e.replayUrl};return e.headers!==void 0&&(r.headers=e.headers),e.token!==void 0&&(r.token=e.token),e.sessionSampleRate!==void 0&&(r.sessionSampleRate=e.sessionSampleRate),e.onErrorSampleRate!==void 0&&(r.onErrorSampleRate=e.onErrorSampleRate),e.maskAllInputs!==void 0&&(r.maskAllInputs=e.maskAllInputs),e.maskTextSelector!==void 0&&(r.maskTextSelector=e.maskTextSelector),e.blockSelector!==void 0&&(r.blockSelector=e.blockSelector),e.flushIntervalMs!==void 0&&(r.flushIntervalMs=e.flushIntervalMs),e.maxBufferBytes!==void 0&&(r.maxBufferBytes=e.maxBufferBytes),e.distinctId!==void 0&&(r.distinctId=e.distinctId),e.getDistinctId!==void 0&&(r.getDistinctId=e.getDistinctId),e.captureConsole!==void 0&&(r.captureConsole=e.captureConsole),e.captureNetwork!==void 0&&(r.captureNetwork=e.captureNetwork),e.captureNavigation!==void 0&&(r.captureNavigation=e.captureNavigation),e.onError!==void 0&&(r.onError=e.onError),e.fetchImpl!==void 0&&(r.fetchImpl=e.fetchImpl),r}function C(e,t){let n;return{get mode(){return e.mode},get recording(){return e.recording},flush:async()=>e.flush(),getSessionId:()=>e.getSessionId(),stop:async()=>(n??=(async()=>{try{await e.stop()}finally{t.clear()}})(),n)}}function w(e,t){return[t.traceUrl,t.metricUrl,e].flatMap(e=>{let t=T(e);return t===void 0?[]:[t]})}function T(e){if(e===void 0||e.length===0)return;let t=e.replace(/\/+$/u,``);return RegExp(`^${E(t)}(?:[/?#]|$)`,`u`)}function E(e){return e.replace(/[.*+?^${}()|[\]\\]/gu,`\\$&`)}let D,O;function k(e){let t=!1;return{async shutdown(){return t?Promise.resolve():(t=!0,e?.shutdown(),O===e&&(O=void 0),Promise.resolve())}}}function A(e,t,n){if(typeof n==`string`||typeof n==`boolean`){e[t]=n;return}typeof n==`number`&&Number.isFinite(n)&&(e[t]=n)}function j(e={}){let t={};return e.reportAllChanges!==void 0&&(t.reportAllChanges=e.reportAllChanges),e.generateTarget!==void 0&&(t.generateTarget=e.generateTarget),t}function M(e={}){return{...j(e),includeProcessedEventEntries:e.includeProcessedEventEntries??!1}}function N(e){let t={};return A(t,`web_vital.name`,e.name),A(t,`web_vital.value`,e.value),A(t,`web_vital.delta`,e.delta),A(t,`web_vital.id`,e.id),A(t,`web_vital.rating`,e.rating),A(t,`web_vital.navigation_type`,e.navigationType),t}function P(e){let t=N(e);switch(e.name){case`LCP`:{let{attribution:n}=e;A(t,`web_vital.lcp.target`,n.target),A(t,`web_vital.lcp.element`,n.target),A(t,`web_vital.lcp.url`,n.url),A(t,`web_vital.lcp.time_to_first_byte`,n.timeToFirstByte),A(t,`web_vital.lcp.resource_load_delay`,n.resourceLoadDelay),A(t,`web_vital.lcp.resource_load_duration`,n.resourceLoadDuration),A(t,`web_vital.lcp.element_render_delay`,n.elementRenderDelay);break}case`INP`:{let{attribution:n}=e;A(t,`web_vital.inp.target`,n.interactionTarget),A(t,`web_vital.inp.interaction_type`,n.interactionType),A(t,`web_vital.inp.interaction_time`,n.interactionTime),A(t,`web_vital.inp.input_delay`,n.inputDelay),A(t,`web_vital.inp.processing_duration`,n.processingDuration),A(t,`web_vital.inp.presentation_delay`,n.presentationDelay),A(t,`web_vital.inp.load_state`,n.loadState);break}case`CLS`:{let{attribution:n}=e;A(t,`web_vital.cls.largest_shift_target`,n.largestShiftTarget),A(t,`web_vital.cls.largest_shift_time`,n.largestShiftTime),A(t,`web_vital.cls.largest_shift_value`,n.largestShiftValue),A(t,`web_vital.cls.load_state`,n.loadState);break}case`FCP`:{let{attribution:n}=e;A(t,`web_vital.fcp.time_to_first_byte`,n.timeToFirstByte),A(t,`web_vital.fcp.first_byte_to_fcp`,n.firstByteToFCP),A(t,`web_vital.fcp.load_state`,n.loadState);break}case`TTFB`:{let{attribution:n}=e;A(t,`web_vital.ttfb.waiting_duration`,n.waitingDuration),A(t,`web_vital.ttfb.cache_duration`,n.cacheDuration),A(t,`web_vital.ttfb.dns_duration`,n.dnsDuration),A(t,`web_vital.ttfb.connection_duration`,n.connectionDuration),A(t,`web_vital.ttfb.request_duration`,n.requestDuration);break}default:break}return t}function F(t){try{let n=e.trace.getTracer(`logfire-web-vitals`).startSpan(`web_vital.${t.name.toLowerCase()}`);try{n.setAttributes(P(t))}finally{n.end()}}catch(t){e.diag.error(`logfire-browser: failed to report Web Vital`,t)}}function I(t,n){if(n!==void 0)try{n.record(t)}catch(t){e.diag.error(`logfire-browser: failed to report Web Vital metric`,t)}}function L(e,t){F(e),I(e,t)}function R(e,t={}){let n=j(t),r=e=>{L(e,O)};e.onLCP(r,n),e.onINP(r,M(t)),e.onCLS(r,n),e.onFCP(r,n),e.onTTFB(r,n)}async function z(t={}){return t.metricRecorder!==void 0&&(O=t.metricRecorder),D??=import(`web-vitals/attribution`).then(e=>{R(e,t)}).catch(t=>{e.diag.error(`logfire-browser: failed to start Web Vitals reporting`,t)}),await D,k(t.metricRecorder)}const B=`target_xpath`,V={1:`trace`,5:`debug`,9:`info`,10:`notice`,13:`warning`,17:`error`,21:`fatal`},H={debug:`#E3E3E3`,error:`#EA4335`,fatal:`#EA4335`,info:`#9EC1FB`,notice:`#A5D490`,"on-debug":`#636262`,"on-error":`#FFEDE9`,"on-fatal":`#FFEDE9`,"on-info":`#063175`,"on-notice":`#222222`,"on-trace":`#636262`,"on-warning":`#613A0D`,trace:`#E3E3E3`,warning:`#EFB77A`};var U=class{export(e,t){this.sendSpans(e,t)}async forceFlush(){return Promise.resolve()}async shutdown(){return this.sendSpans([]),this.forceFlush()}exportInfo(e){return{attributes:e.attributes,duration:(0,c.hrTimeToMicroseconds)(e.duration),events:e.events,id:e.spanContext().spanId,instrumentationScope:e.instrumentationScope,kind:e.kind,links:e.links,name:e.name,parentSpanContext:e.parentSpanContext,resource:{attributes:e.resource.attributes},status:e.status,timestamp:(0,c.hrTimeToMicroseconds)(e.startTime),traceId:e.spanContext().traceId,traceState:e.spanContext().traceState?.serialize()}}sendSpans(e,t){for(let t of e){let e=V[t.attributes[`logfire.level_num`]]??`info`,{attributes:n,name:r,...i}=this.exportInfo(t);console.log(`%cLogfire %c${e}`,`background-color: #E520E9; color: #FFFFFF`,`background-color: ${H[`on-${e}`]}; color: ${H[e]}`,r,n,i)}t&&t({code:c.ExportResultCode.SUCCESS})}},W=class{console;wrapped;constructor(e,t){t&&(this.console=new i.SimpleSpanProcessor(new U)),this.wrapped=e}async forceFlush(){return await this.console?.forceFlush(),this.wrapped.forceFlush()}onEnd(e){this.console?.onEnd(e),this.wrapped.onEnd(e)}onStart(e,t){if(o.ATTR_HTTP_URL in e.attributes){let t=new URL(e.attributes[o.ATTR_HTTP_URL]);Reflect.set(e,`name`,`${e.name} ${t.pathname}`)}if(B in e.attributes){let t=String(e.attributes.event_type??`unknown`),n=String(e.attributes[B]??``);Reflect.set(e,`name`,`${t} ${n}`)}this.console?.onStart(e,t),this.wrapped.onStart(e,t)}async shutdown(){return await this.console?.shutdown(),this.wrapped.shutdown()}};function G(){return{}}function K(e){if(!(e===void 0||e===!1))return e===!0?{}:e}function q(e){if(!(e===void 0||e===!1)){if(e.metricUrl===``)throw Error(`logfire-browser: metrics.metricUrl must be a non-empty browser-safe metrics proxy URL`);return e}}function J(e){if(!(e?.metrics===void 0||e.metrics===!1))return e.metrics===!0?{}:e.metrics}function Y(e){if(!(e===void 0||e===!1))return e}function X(e,t){let n=K(e?.webVitals),r=t!==void 0;if(n===void 0&&!r)return e?.session;if(e?.session===!1)throw Error(r?`logfire-browser: sessionReplay requires browser session attributes; remove rum.session: false or disable sessionReplay`:`logfire-browser: rum.webVitals requires browser session attributes; remove rum.session: false or disable rum.webVitals`);return e?.session??!0}async function Z(e,t){return{...typeof e==`function`?await e():e??{},...t()}}function Q(c){c.diagLogLevel!==void 0&&e.diag.setLogger(new e.DiagConsoleLogger,c.diagLogLevel);let l=K(c.rum?.webVitals),d=Y(c.sessionReplay),f=q(c.metrics),p=J(l);if(p!==void 0&&f===void 0)throw Error(`logfire-browser: rum.webVitals.metrics requires top-level metrics.metricUrl`);let m=X(c.rum,d),h={errorFingerprinting:c.errorFingerprinting??!1};c.baggage!==void 0&&(h.baggage=c.baggage),c.jsonSchema!==void 0&&(h.jsonSchema=c.jsonSchema),c.minLevel!==void 0&&(h.minLevel=c.minLevel),c.scrubbing!==void 0&&(h.scrubbing=c.scrubbing),(0,s.configureLogfireApi)(h);let g=(0,r.resourceFromAttributes)(c.resourceAttributes??{}).merge((0,r.resourceFromAttributes)({[o.ATTR_BROWSER_LANGUAGE]:navigator.language,[a.ATTR_SERVICE_NAME]:c.serviceName??`logfire-browser`,[a.ATTR_SERVICE_VERSION]:c.serviceVersion??`0.0.1`,[a.ATTR_TELEMETRY_SDK_LANGUAGE]:a.TELEMETRY_SDK_LANGUAGE_VALUE_WEBJS,[a.ATTR_TELEMETRY_SDK_NAME]:`logfire-browser`,...c.environment!==void 0&&c.environment!==``?{[o.ATTR_DEPLOYMENT_ENVIRONMENT_NAME]:c.environment}:{},[a.ATTR_TELEMETRY_SDK_VERSION]:`0.0.0`,...navigator.userAgentData?{[o.ATTR_BROWSER_BRANDS]:navigator.userAgentData.brands.map(e=>`${e.brand} ${e.version}`),[o.ATTR_BROWSER_MOBILE]:navigator.userAgentData.mobile,[o.ATTR_BROWSER_PLATFORM]:navigator.userAgentData.platform}:{[a.ATTR_USER_AGENT_ORIGINAL]:navigator.userAgent}}));e.diag.info(`logfire-browser: starting`);let v=c.sampling?.head,S=v!==void 0&&v<1?new i.ParentBasedSampler({root:new i.TraceIdRatioBasedSampler(v)}):void 0,C=new W(new i.BatchSpanProcessor(new t.OTLPTraceExporter({...c.traceExporterConfig,headers:async()=>Z(c.traceExporterConfig?.headers,c.traceExporterHeaders??G),url:c.traceUrl}),c.batchSpanProcessorConfig),!!c.console);c.sampling?.tail&&(C=new s.TailSamplingProcessor(C,c.sampling.tail));let w=_(m),T=new b,E=[];w!==void 0&&E.push(new u(w,T)),E.push(...c.spanProcessors??[],C);let D=new i.WebTracerProvider({idGenerator:new s.ULIDGenerator,resource:g,...S?{sampler:S}:{},spanProcessors:E});D.register({contextManager:c.contextManager??new i.StackContextManager});let O=(0,n.registerInstrumentations)({instrumentations:c.instrumentations??[],tracerProvider:D}),k=d===void 0||w===void 0?void 0:x(d,w,T,{metricUrl:f?.metricUrl,traceUrl:c.traceUrl}),A=f===void 0?void 0:Promise.resolve().then(()=>require("./browserMetrics-sqpejR9C.cjs")).then(async({startBrowserMetrics:e})=>e(f,g)).catch(t=>{e.diag.error(`logfire-browser: failed to start browser metrics`,t)}),j=l===void 0?void 0:p===void 0?z(l).catch(t=>{e.diag.error(`logfire-browser: failed to start Web Vitals reporting`,t)}):(async()=>{let e=await A;if(e===void 0)throw Error(`logfire-browser: failed to start Web Vitals metrics because browser metrics transport did not start`);return z({...l,metricRecorder:e.createWebVitalsMetricRecorder(p)})})().catch(t=>{e.diag.error(`logfire-browser: failed to start Web Vitals reporting`,t)}),M;return()=>(M??=(async()=>{let t,n=(n,r)=>{let i=r instanceof Error?r:Error(String(r));t??=i,e.diag.error(`logfire-browser: ${n} failed during shutdown`,i)},r=async(e,t)=>{try{await t()}catch(t){n(e,t)}};if(e.diag.info(`logfire-browser: shutting down`),k!==void 0&&(T.clear(),await r(`session replay shutdown`,async()=>{await(await k)?.stop()})),await r(`instrumentation unregister`,O),j!==void 0&&await r(`web vitals shutdown`,async()=>{await(await j)?.shutdown()}),A!==void 0&&(await r(`metric provider force flush`,async()=>{await(await A)?.forceFlush()}),await r(`metric provider shutdown`,async()=>{await(await A)?.shutdown()})),await r(`force flush`,async()=>D.forceFlush()),await r(`tracer provider shutdown`,async()=>D.shutdown()),w!==void 0&&await r(`browser session cleanup`,()=>{y(w)}),t!==void 0)throw Error(t.message,{cause:t});e.diag.info(`logfire-browser: shut down complete`)})(),M)}const $={configure:Q,configureLogfireApi:s.configureLogfireApi,debug:s.debug,DiagLogLevel:e.DiagLogLevel,error:s.error,fatal:s.fatal,getBrowserSessionId:v,info:s.info,instrument:s.instrument,Level:s.Level,log:s.log,logfireApiConfig:s.logfireApiConfig,LogfireAttributeScrubber:s.LogfireAttributeScrubber,NoopAttributeScrubber:s.NoopAttributeScrubber,notice:s.notice,reportError:s.reportError,resolveBaseUrl:s.resolveBaseUrl,resolveSendToLogfire:s.resolveSendToLogfire,serializeAttributes:s.serializeAttributes,span:s.span,startPendingSpan:s.startPendingSpan,startSpan:s.startSpan,trace:s.trace,ULIDGenerator:s.ULIDGenerator,warning:s.warning,withSettings:s.withSettings,withTags:s.withTags};Object.defineProperty(exports,"DiagLogLevel",{enumerable:!0,get:function(){return e.DiagLogLevel}}),exports.configure=Q,exports.default=$,exports.getBrowserSessionId=v,Object.keys(s).forEach(function(e){e!=="default"&&!Object.prototype.hasOwnProperty.call(exports,e)&&Object.defineProperty(exports,e,{enumerable:!0,get:function(){return s[e]}})});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,10 +1,188 @@
|
|
|
1
1
|
import { Attributes, ContextManager, DiagLogLevel, DiagLogLevel as DiagLogLevel$1 } from "@opentelemetry/api";
|
|
2
2
|
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
|
3
3
|
import { Instrumentation } from "@opentelemetry/instrumentation";
|
|
4
|
-
import { BufferConfig } from "@opentelemetry/sdk-trace-web";
|
|
5
|
-
import { BaggageOptions, JsonSchemaMode, Level, LogfireAttributeScrubber, MinLevel, NoopAttributeScrubber, SamplingOptions, ScrubbingOptions, ULIDGenerator, configureLogfireApi, debug, error, fatal, info, instrument, log, logfireApiConfig, notice, reportError, resolveBaseUrl, resolveSendToLogfire, serializeAttributes, span, startPendingSpan, startSpan, trace, warning, withSettings, withTags } from "logfire";
|
|
4
|
+
import { BufferConfig, SpanProcessor } from "@opentelemetry/sdk-trace-web";
|
|
5
|
+
import { BaggageOptions, JsonSchemaMode, Level, LogfireAttributeScrubber, MinLevel, NoopAttributeScrubber, SamplingOptions, ScrubbingOptions, ULIDGenerator, configureLogfireApi, debug, error, fatal, info, instrument, log, logfireApiConfig, notice, reportError, resolveBaseUrl, resolveSendToLogfire, serializeAttributes, span, startPendingSpan, startSpan, trace as trace$1, warning, withSettings, withTags } from "logfire";
|
|
6
|
+
import { OTLPMetricExporterOptions } from "@opentelemetry/exporter-metrics-otlp-http";
|
|
7
|
+
import { MetricReader, PeriodicExportingMetricReaderOptions } from "@opentelemetry/sdk-metrics";
|
|
8
|
+
import { MetricWithAttribution } from "web-vitals/attribution";
|
|
6
9
|
export * from "logfire";
|
|
7
10
|
|
|
11
|
+
//#region src/browserMetrics.d.ts
|
|
12
|
+
interface BrowserMetricsOptions {
|
|
13
|
+
/**
|
|
14
|
+
* Browser-safe OTLP metrics proxy URL, e.g. `/logfire-proxy/v1/metrics`.
|
|
15
|
+
*/
|
|
16
|
+
metricUrl: string;
|
|
17
|
+
/**
|
|
18
|
+
* Dynamic headers for the metric exporter. Browser apps should normally
|
|
19
|
+
* authenticate through their backend proxy, not with a Logfire write token in
|
|
20
|
+
* client code.
|
|
21
|
+
*/
|
|
22
|
+
metricExporterHeaders?: () => Record<string, string> | Promise<Record<string, string>>;
|
|
23
|
+
/**
|
|
24
|
+
* Additional OTLP metric exporter options. `url` and `headers` are owned by
|
|
25
|
+
* the browser Logfire metrics transport configuration.
|
|
26
|
+
*/
|
|
27
|
+
metricExporterConfig?: Omit<OTLPMetricExporterOptions, "url" | "headers">;
|
|
28
|
+
/**
|
|
29
|
+
* Periodic reader settings such as exportIntervalMillis and
|
|
30
|
+
* exportTimeoutMillis.
|
|
31
|
+
*/
|
|
32
|
+
metricReaderConfig?: Omit<PeriodicExportingMetricReaderOptions, "exporter">;
|
|
33
|
+
/**
|
|
34
|
+
* Advanced extension point for callers that already own a metric reader.
|
|
35
|
+
*/
|
|
36
|
+
metricReaders?: MetricReader[];
|
|
37
|
+
}
|
|
38
|
+
interface BrowserWebVitalsMetricOptions {
|
|
39
|
+
/**
|
|
40
|
+
* Add sanitized data point attributes. Keep this low-cardinality.
|
|
41
|
+
*/
|
|
42
|
+
attributes?: false | ((metric: MetricWithAttribution) => Attributes);
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/webVitals.d.ts
|
|
46
|
+
interface BrowserWebVitalsOptions {
|
|
47
|
+
/**
|
|
48
|
+
* Report metric changes instead of only final reportable values.
|
|
49
|
+
* Defaults to false.
|
|
50
|
+
*/
|
|
51
|
+
reportAllChanges?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Customize how DOM targets are stringified by `web-vitals/attribution`.
|
|
54
|
+
*/
|
|
55
|
+
generateTarget?: (element: Node | null) => string | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Whether INP attribution should include processed event entries internally.
|
|
58
|
+
* Defaults to false to reduce memory pressure; entries are not exported as
|
|
59
|
+
* span attributes either way.
|
|
60
|
+
*/
|
|
61
|
+
includeProcessedEventEntries?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Emit native OTel metrics in parallel with spans. Requires configured
|
|
64
|
+
* browser metrics transport.
|
|
65
|
+
*/
|
|
66
|
+
metrics?: boolean | BrowserWebVitalsMetricOptions;
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region src/browserSession.d.ts
|
|
70
|
+
interface BrowserSessionUrlAttributes {
|
|
71
|
+
full?: string;
|
|
72
|
+
path?: string;
|
|
73
|
+
}
|
|
74
|
+
interface BrowserSessionOptions {
|
|
75
|
+
/**
|
|
76
|
+
* Session inactivity timeout. Defaults to 30 minutes.
|
|
77
|
+
*/
|
|
78
|
+
idleTimeoutMs?: number;
|
|
79
|
+
/**
|
|
80
|
+
* Hard cap on one browser session. Defaults to 4 hours.
|
|
81
|
+
*/
|
|
82
|
+
maxDurationMs?: number;
|
|
83
|
+
/**
|
|
84
|
+
* Storage key for tests or advanced embedding. Defaults to
|
|
85
|
+
* `lf_browser_session`.
|
|
86
|
+
*/
|
|
87
|
+
storageKey?: string;
|
|
88
|
+
/**
|
|
89
|
+
* Controls URL attributes stamped on session/RUM spans. Defaults to emitting
|
|
90
|
+
* `url.full = window.location.href` and `url.path = window.location.pathname`.
|
|
91
|
+
* Set to false to suppress URL attributes, or return sanitized values.
|
|
92
|
+
*/
|
|
93
|
+
urlAttributes?: false | ((url: URL) => BrowserSessionUrlAttributes);
|
|
94
|
+
}
|
|
95
|
+
interface RUMOptions {
|
|
96
|
+
/**
|
|
97
|
+
* Enable browser session identity and session/page span attributes.
|
|
98
|
+
*/
|
|
99
|
+
session?: boolean | BrowserSessionOptions;
|
|
100
|
+
/**
|
|
101
|
+
* Enable browser Web Vitals reporting.
|
|
102
|
+
*/
|
|
103
|
+
webVitals?: boolean | BrowserWebVitalsOptions;
|
|
104
|
+
}
|
|
105
|
+
declare function getBrowserSessionId(): string | undefined;
|
|
106
|
+
//#endregion
|
|
107
|
+
//#region src/sessionReplay.d.ts
|
|
108
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
109
|
+
interface BrowserSessionReplayRuntime {
|
|
110
|
+
readonly recording: boolean;
|
|
111
|
+
readonly mode: "full" | "buffer" | "off";
|
|
112
|
+
getSessionId(): string;
|
|
113
|
+
flush(): Promise<void>;
|
|
114
|
+
stop(): Promise<void>;
|
|
115
|
+
}
|
|
116
|
+
interface BrowserSessionReplayPackageConfig {
|
|
117
|
+
replayUrl: string;
|
|
118
|
+
headers?: () => MaybePromise<Record<string, string>>;
|
|
119
|
+
token?: string | (() => MaybePromise<string>);
|
|
120
|
+
getSessionId?: () => string | undefined;
|
|
121
|
+
sessionSampleRate?: number;
|
|
122
|
+
onErrorSampleRate?: number;
|
|
123
|
+
maskAllInputs?: boolean;
|
|
124
|
+
maskTextSelector?: string;
|
|
125
|
+
blockSelector?: string;
|
|
126
|
+
flushIntervalMs?: number;
|
|
127
|
+
maxBufferBytes?: number;
|
|
128
|
+
distinctId?: string;
|
|
129
|
+
getDistinctId?: () => string | undefined;
|
|
130
|
+
captureConsole?: boolean;
|
|
131
|
+
captureNetwork?: boolean;
|
|
132
|
+
captureNavigation?: boolean;
|
|
133
|
+
ignoreUrlPatterns?: RegExp[];
|
|
134
|
+
redactUrlPatterns?: RegExp[];
|
|
135
|
+
onError?: (error: unknown) => void;
|
|
136
|
+
fetchImpl?: typeof fetch;
|
|
137
|
+
}
|
|
138
|
+
interface BrowserSessionReplayModule {
|
|
139
|
+
startSessionReplay(config: BrowserSessionReplayPackageConfig): BrowserSessionReplayRuntime;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Experimental browser session replay options.
|
|
143
|
+
*
|
|
144
|
+
* Logfire Platform replay ingest and playback are still feature-flagged, so
|
|
145
|
+
* keep browser replay rollout behind an application flag.
|
|
146
|
+
*/
|
|
147
|
+
interface BrowserSessionReplayOptions {
|
|
148
|
+
/**
|
|
149
|
+
* Loads @pydantic/logfire-session-replay. Applications that do not enable
|
|
150
|
+
* replay never need their bundler to resolve the optional peer.
|
|
151
|
+
*/
|
|
152
|
+
load: () => MaybePromise<BrowserSessionReplayModule>;
|
|
153
|
+
/**
|
|
154
|
+
* Replay upload endpoint. Browser apps should normally point this at a
|
|
155
|
+
* backend proxy.
|
|
156
|
+
*/
|
|
157
|
+
replayUrl: string;
|
|
158
|
+
/**
|
|
159
|
+
* Headers added to each replay upload, usually for authenticating to the
|
|
160
|
+
* caller's backend proxy.
|
|
161
|
+
*/
|
|
162
|
+
headers?: () => MaybePromise<Record<string, string>>;
|
|
163
|
+
/**
|
|
164
|
+
* Advanced direct-ingest escape hatch. Prefer replayUrl + headers through a
|
|
165
|
+
* backend proxy for browser applications.
|
|
166
|
+
*/
|
|
167
|
+
token?: string | (() => MaybePromise<string>);
|
|
168
|
+
sessionSampleRate?: number;
|
|
169
|
+
onErrorSampleRate?: number;
|
|
170
|
+
maskAllInputs?: boolean;
|
|
171
|
+
maskTextSelector?: string;
|
|
172
|
+
blockSelector?: string;
|
|
173
|
+
flushIntervalMs?: number;
|
|
174
|
+
maxBufferBytes?: number;
|
|
175
|
+
distinctId?: string;
|
|
176
|
+
getDistinctId?: () => string | undefined;
|
|
177
|
+
captureConsole?: boolean;
|
|
178
|
+
captureNetwork?: boolean;
|
|
179
|
+
captureNavigation?: boolean;
|
|
180
|
+
ignoreUrlPatterns?: RegExp[];
|
|
181
|
+
redactUrlPatterns?: RegExp[];
|
|
182
|
+
onError?: (error: unknown) => void;
|
|
183
|
+
fetchImpl?: typeof fetch;
|
|
184
|
+
}
|
|
185
|
+
//#endregion
|
|
8
186
|
//#region src/index.d.ts
|
|
9
187
|
type TraceExporterConfig = NonNullable<typeof OTLPTraceExporter extends (new (config: infer T) => unknown) ? T : never>;
|
|
10
188
|
interface LogfireConfigOptions {
|
|
@@ -56,6 +234,11 @@ interface LogfireConfigOptions {
|
|
|
56
234
|
*/
|
|
57
235
|
minLevel?: MinLevel | null;
|
|
58
236
|
/**
|
|
237
|
+
* Browser OpenTelemetry metrics transport options. Metrics are disabled
|
|
238
|
+
* unless this is configured.
|
|
239
|
+
*/
|
|
240
|
+
metrics?: false | BrowserMetricsOptions;
|
|
241
|
+
/**
|
|
59
242
|
* Sampling options for controlling which traces are exported.
|
|
60
243
|
* `head` sets a probabilistic sample rate (0.0-1.0) at trace creation time.
|
|
61
244
|
* `tail` provides a callback evaluated on every span to decide whether to keep the trace.
|
|
@@ -67,6 +250,24 @@ interface LogfireConfigOptions {
|
|
|
67
250
|
*/
|
|
68
251
|
sampling?: SamplingOptions;
|
|
69
252
|
/**
|
|
253
|
+
* Advanced OpenTelemetry span processors to register with the browser tracer provider.
|
|
254
|
+
*
|
|
255
|
+
* Processors are registered before Logfire's built-in exporting processor.
|
|
256
|
+
*/
|
|
257
|
+
spanProcessors?: SpanProcessor[];
|
|
258
|
+
/**
|
|
259
|
+
* Browser real-user monitoring options. RUM capture is opt-in.
|
|
260
|
+
*/
|
|
261
|
+
rum?: RUMOptions;
|
|
262
|
+
/**
|
|
263
|
+
* Experimental browser session replay options. Replay is disabled unless this
|
|
264
|
+
* is configured.
|
|
265
|
+
*
|
|
266
|
+
* Logfire Platform replay ingest and playback are still feature-flagged, so
|
|
267
|
+
* keep browser replay rollout behind an application flag.
|
|
268
|
+
*/
|
|
269
|
+
sessionReplay?: false | BrowserSessionReplayOptions;
|
|
270
|
+
/**
|
|
70
271
|
* Options for scrubbing sensitive data. Set to False to disable.
|
|
71
272
|
*/
|
|
72
273
|
scrubbing?: false | ScrubbingOptions;
|
|
@@ -112,6 +313,7 @@ declare const defaultExport: {
|
|
|
112
313
|
fatal: typeof fatal;
|
|
113
314
|
info: typeof info;
|
|
114
315
|
instrument: typeof instrument;
|
|
316
|
+
getBrowserSessionId: typeof getBrowserSessionId;
|
|
115
317
|
log: typeof log;
|
|
116
318
|
logfireApiConfig: typeof logfireApiConfig;
|
|
117
319
|
notice: typeof notice;
|
|
@@ -122,10 +324,10 @@ declare const defaultExport: {
|
|
|
122
324
|
span: typeof span;
|
|
123
325
|
startPendingSpan: typeof startPendingSpan;
|
|
124
326
|
startSpan: typeof startSpan;
|
|
125
|
-
trace: typeof trace;
|
|
327
|
+
trace: typeof trace$1;
|
|
126
328
|
warning: typeof warning;
|
|
127
329
|
withSettings: typeof withSettings;
|
|
128
330
|
withTags: typeof withTags;
|
|
129
331
|
};
|
|
130
332
|
//#endregion
|
|
131
|
-
export { DiagLogLevel, LogfireConfigOptions, configure, defaultExport as default };
|
|
333
|
+
export { type BrowserMetricsOptions, type BrowserSessionOptions, type BrowserSessionReplayOptions, type BrowserSessionUrlAttributes, type BrowserWebVitalsMetricOptions, type BrowserWebVitalsOptions, DiagLogLevel, LogfireConfigOptions, type RUMOptions, configure, defaultExport as default, getBrowserSessionId };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,188 @@
|
|
|
1
1
|
import { Attributes, ContextManager, DiagLogLevel, DiagLogLevel as DiagLogLevel$1 } from "@opentelemetry/api";
|
|
2
2
|
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
|
3
3
|
import { Instrumentation } from "@opentelemetry/instrumentation";
|
|
4
|
-
import { BufferConfig } from "@opentelemetry/sdk-trace-web";
|
|
5
|
-
import { BaggageOptions, JsonSchemaMode, Level, LogfireAttributeScrubber, MinLevel, NoopAttributeScrubber, SamplingOptions, ScrubbingOptions, ULIDGenerator, configureLogfireApi, debug, error, fatal, info, instrument, log, logfireApiConfig, notice, reportError, resolveBaseUrl, resolveSendToLogfire, serializeAttributes, span, startPendingSpan, startSpan, trace, warning, withSettings, withTags } from "logfire";
|
|
4
|
+
import { BufferConfig, SpanProcessor } from "@opentelemetry/sdk-trace-web";
|
|
5
|
+
import { BaggageOptions, JsonSchemaMode, Level, LogfireAttributeScrubber, MinLevel, NoopAttributeScrubber, SamplingOptions, ScrubbingOptions, ULIDGenerator, configureLogfireApi, debug, error, fatal, info, instrument, log, logfireApiConfig, notice, reportError, resolveBaseUrl, resolveSendToLogfire, serializeAttributes, span, startPendingSpan, startSpan, trace as trace$1, warning, withSettings, withTags } from "logfire";
|
|
6
|
+
import { OTLPMetricExporterOptions } from "@opentelemetry/exporter-metrics-otlp-http";
|
|
7
|
+
import { MetricReader, PeriodicExportingMetricReaderOptions } from "@opentelemetry/sdk-metrics";
|
|
8
|
+
import { MetricWithAttribution } from "web-vitals/attribution";
|
|
6
9
|
export * from "logfire";
|
|
7
10
|
|
|
11
|
+
//#region src/browserMetrics.d.ts
|
|
12
|
+
interface BrowserMetricsOptions {
|
|
13
|
+
/**
|
|
14
|
+
* Browser-safe OTLP metrics proxy URL, e.g. `/logfire-proxy/v1/metrics`.
|
|
15
|
+
*/
|
|
16
|
+
metricUrl: string;
|
|
17
|
+
/**
|
|
18
|
+
* Dynamic headers for the metric exporter. Browser apps should normally
|
|
19
|
+
* authenticate through their backend proxy, not with a Logfire write token in
|
|
20
|
+
* client code.
|
|
21
|
+
*/
|
|
22
|
+
metricExporterHeaders?: () => Record<string, string> | Promise<Record<string, string>>;
|
|
23
|
+
/**
|
|
24
|
+
* Additional OTLP metric exporter options. `url` and `headers` are owned by
|
|
25
|
+
* the browser Logfire metrics transport configuration.
|
|
26
|
+
*/
|
|
27
|
+
metricExporterConfig?: Omit<OTLPMetricExporterOptions, "url" | "headers">;
|
|
28
|
+
/**
|
|
29
|
+
* Periodic reader settings such as exportIntervalMillis and
|
|
30
|
+
* exportTimeoutMillis.
|
|
31
|
+
*/
|
|
32
|
+
metricReaderConfig?: Omit<PeriodicExportingMetricReaderOptions, "exporter">;
|
|
33
|
+
/**
|
|
34
|
+
* Advanced extension point for callers that already own a metric reader.
|
|
35
|
+
*/
|
|
36
|
+
metricReaders?: MetricReader[];
|
|
37
|
+
}
|
|
38
|
+
interface BrowserWebVitalsMetricOptions {
|
|
39
|
+
/**
|
|
40
|
+
* Add sanitized data point attributes. Keep this low-cardinality.
|
|
41
|
+
*/
|
|
42
|
+
attributes?: false | ((metric: MetricWithAttribution) => Attributes);
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/webVitals.d.ts
|
|
46
|
+
interface BrowserWebVitalsOptions {
|
|
47
|
+
/**
|
|
48
|
+
* Report metric changes instead of only final reportable values.
|
|
49
|
+
* Defaults to false.
|
|
50
|
+
*/
|
|
51
|
+
reportAllChanges?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Customize how DOM targets are stringified by `web-vitals/attribution`.
|
|
54
|
+
*/
|
|
55
|
+
generateTarget?: (element: Node | null) => string | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Whether INP attribution should include processed event entries internally.
|
|
58
|
+
* Defaults to false to reduce memory pressure; entries are not exported as
|
|
59
|
+
* span attributes either way.
|
|
60
|
+
*/
|
|
61
|
+
includeProcessedEventEntries?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Emit native OTel metrics in parallel with spans. Requires configured
|
|
64
|
+
* browser metrics transport.
|
|
65
|
+
*/
|
|
66
|
+
metrics?: boolean | BrowserWebVitalsMetricOptions;
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region src/browserSession.d.ts
|
|
70
|
+
interface BrowserSessionUrlAttributes {
|
|
71
|
+
full?: string;
|
|
72
|
+
path?: string;
|
|
73
|
+
}
|
|
74
|
+
interface BrowserSessionOptions {
|
|
75
|
+
/**
|
|
76
|
+
* Session inactivity timeout. Defaults to 30 minutes.
|
|
77
|
+
*/
|
|
78
|
+
idleTimeoutMs?: number;
|
|
79
|
+
/**
|
|
80
|
+
* Hard cap on one browser session. Defaults to 4 hours.
|
|
81
|
+
*/
|
|
82
|
+
maxDurationMs?: number;
|
|
83
|
+
/**
|
|
84
|
+
* Storage key for tests or advanced embedding. Defaults to
|
|
85
|
+
* `lf_browser_session`.
|
|
86
|
+
*/
|
|
87
|
+
storageKey?: string;
|
|
88
|
+
/**
|
|
89
|
+
* Controls URL attributes stamped on session/RUM spans. Defaults to emitting
|
|
90
|
+
* `url.full = window.location.href` and `url.path = window.location.pathname`.
|
|
91
|
+
* Set to false to suppress URL attributes, or return sanitized values.
|
|
92
|
+
*/
|
|
93
|
+
urlAttributes?: false | ((url: URL) => BrowserSessionUrlAttributes);
|
|
94
|
+
}
|
|
95
|
+
interface RUMOptions {
|
|
96
|
+
/**
|
|
97
|
+
* Enable browser session identity and session/page span attributes.
|
|
98
|
+
*/
|
|
99
|
+
session?: boolean | BrowserSessionOptions;
|
|
100
|
+
/**
|
|
101
|
+
* Enable browser Web Vitals reporting.
|
|
102
|
+
*/
|
|
103
|
+
webVitals?: boolean | BrowserWebVitalsOptions;
|
|
104
|
+
}
|
|
105
|
+
declare function getBrowserSessionId(): string | undefined;
|
|
106
|
+
//#endregion
|
|
107
|
+
//#region src/sessionReplay.d.ts
|
|
108
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
109
|
+
interface BrowserSessionReplayRuntime {
|
|
110
|
+
readonly recording: boolean;
|
|
111
|
+
readonly mode: "full" | "buffer" | "off";
|
|
112
|
+
getSessionId(): string;
|
|
113
|
+
flush(): Promise<void>;
|
|
114
|
+
stop(): Promise<void>;
|
|
115
|
+
}
|
|
116
|
+
interface BrowserSessionReplayPackageConfig {
|
|
117
|
+
replayUrl: string;
|
|
118
|
+
headers?: () => MaybePromise<Record<string, string>>;
|
|
119
|
+
token?: string | (() => MaybePromise<string>);
|
|
120
|
+
getSessionId?: () => string | undefined;
|
|
121
|
+
sessionSampleRate?: number;
|
|
122
|
+
onErrorSampleRate?: number;
|
|
123
|
+
maskAllInputs?: boolean;
|
|
124
|
+
maskTextSelector?: string;
|
|
125
|
+
blockSelector?: string;
|
|
126
|
+
flushIntervalMs?: number;
|
|
127
|
+
maxBufferBytes?: number;
|
|
128
|
+
distinctId?: string;
|
|
129
|
+
getDistinctId?: () => string | undefined;
|
|
130
|
+
captureConsole?: boolean;
|
|
131
|
+
captureNetwork?: boolean;
|
|
132
|
+
captureNavigation?: boolean;
|
|
133
|
+
ignoreUrlPatterns?: RegExp[];
|
|
134
|
+
redactUrlPatterns?: RegExp[];
|
|
135
|
+
onError?: (error: unknown) => void;
|
|
136
|
+
fetchImpl?: typeof fetch;
|
|
137
|
+
}
|
|
138
|
+
interface BrowserSessionReplayModule {
|
|
139
|
+
startSessionReplay(config: BrowserSessionReplayPackageConfig): BrowserSessionReplayRuntime;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Experimental browser session replay options.
|
|
143
|
+
*
|
|
144
|
+
* Logfire Platform replay ingest and playback are still feature-flagged, so
|
|
145
|
+
* keep browser replay rollout behind an application flag.
|
|
146
|
+
*/
|
|
147
|
+
interface BrowserSessionReplayOptions {
|
|
148
|
+
/**
|
|
149
|
+
* Loads @pydantic/logfire-session-replay. Applications that do not enable
|
|
150
|
+
* replay never need their bundler to resolve the optional peer.
|
|
151
|
+
*/
|
|
152
|
+
load: () => MaybePromise<BrowserSessionReplayModule>;
|
|
153
|
+
/**
|
|
154
|
+
* Replay upload endpoint. Browser apps should normally point this at a
|
|
155
|
+
* backend proxy.
|
|
156
|
+
*/
|
|
157
|
+
replayUrl: string;
|
|
158
|
+
/**
|
|
159
|
+
* Headers added to each replay upload, usually for authenticating to the
|
|
160
|
+
* caller's backend proxy.
|
|
161
|
+
*/
|
|
162
|
+
headers?: () => MaybePromise<Record<string, string>>;
|
|
163
|
+
/**
|
|
164
|
+
* Advanced direct-ingest escape hatch. Prefer replayUrl + headers through a
|
|
165
|
+
* backend proxy for browser applications.
|
|
166
|
+
*/
|
|
167
|
+
token?: string | (() => MaybePromise<string>);
|
|
168
|
+
sessionSampleRate?: number;
|
|
169
|
+
onErrorSampleRate?: number;
|
|
170
|
+
maskAllInputs?: boolean;
|
|
171
|
+
maskTextSelector?: string;
|
|
172
|
+
blockSelector?: string;
|
|
173
|
+
flushIntervalMs?: number;
|
|
174
|
+
maxBufferBytes?: number;
|
|
175
|
+
distinctId?: string;
|
|
176
|
+
getDistinctId?: () => string | undefined;
|
|
177
|
+
captureConsole?: boolean;
|
|
178
|
+
captureNetwork?: boolean;
|
|
179
|
+
captureNavigation?: boolean;
|
|
180
|
+
ignoreUrlPatterns?: RegExp[];
|
|
181
|
+
redactUrlPatterns?: RegExp[];
|
|
182
|
+
onError?: (error: unknown) => void;
|
|
183
|
+
fetchImpl?: typeof fetch;
|
|
184
|
+
}
|
|
185
|
+
//#endregion
|
|
8
186
|
//#region src/index.d.ts
|
|
9
187
|
type TraceExporterConfig = NonNullable<typeof OTLPTraceExporter extends (new (config: infer T) => unknown) ? T : never>;
|
|
10
188
|
interface LogfireConfigOptions {
|
|
@@ -56,6 +234,11 @@ interface LogfireConfigOptions {
|
|
|
56
234
|
*/
|
|
57
235
|
minLevel?: MinLevel | null;
|
|
58
236
|
/**
|
|
237
|
+
* Browser OpenTelemetry metrics transport options. Metrics are disabled
|
|
238
|
+
* unless this is configured.
|
|
239
|
+
*/
|
|
240
|
+
metrics?: false | BrowserMetricsOptions;
|
|
241
|
+
/**
|
|
59
242
|
* Sampling options for controlling which traces are exported.
|
|
60
243
|
* `head` sets a probabilistic sample rate (0.0-1.0) at trace creation time.
|
|
61
244
|
* `tail` provides a callback evaluated on every span to decide whether to keep the trace.
|
|
@@ -67,6 +250,24 @@ interface LogfireConfigOptions {
|
|
|
67
250
|
*/
|
|
68
251
|
sampling?: SamplingOptions;
|
|
69
252
|
/**
|
|
253
|
+
* Advanced OpenTelemetry span processors to register with the browser tracer provider.
|
|
254
|
+
*
|
|
255
|
+
* Processors are registered before Logfire's built-in exporting processor.
|
|
256
|
+
*/
|
|
257
|
+
spanProcessors?: SpanProcessor[];
|
|
258
|
+
/**
|
|
259
|
+
* Browser real-user monitoring options. RUM capture is opt-in.
|
|
260
|
+
*/
|
|
261
|
+
rum?: RUMOptions;
|
|
262
|
+
/**
|
|
263
|
+
* Experimental browser session replay options. Replay is disabled unless this
|
|
264
|
+
* is configured.
|
|
265
|
+
*
|
|
266
|
+
* Logfire Platform replay ingest and playback are still feature-flagged, so
|
|
267
|
+
* keep browser replay rollout behind an application flag.
|
|
268
|
+
*/
|
|
269
|
+
sessionReplay?: false | BrowserSessionReplayOptions;
|
|
270
|
+
/**
|
|
70
271
|
* Options for scrubbing sensitive data. Set to False to disable.
|
|
71
272
|
*/
|
|
72
273
|
scrubbing?: false | ScrubbingOptions;
|
|
@@ -112,6 +313,7 @@ declare const defaultExport: {
|
|
|
112
313
|
fatal: typeof fatal;
|
|
113
314
|
info: typeof info;
|
|
114
315
|
instrument: typeof instrument;
|
|
316
|
+
getBrowserSessionId: typeof getBrowserSessionId;
|
|
115
317
|
log: typeof log;
|
|
116
318
|
logfireApiConfig: typeof logfireApiConfig;
|
|
117
319
|
notice: typeof notice;
|
|
@@ -122,10 +324,10 @@ declare const defaultExport: {
|
|
|
122
324
|
span: typeof span;
|
|
123
325
|
startPendingSpan: typeof startPendingSpan;
|
|
124
326
|
startSpan: typeof startSpan;
|
|
125
|
-
trace: typeof trace;
|
|
327
|
+
trace: typeof trace$1;
|
|
126
328
|
warning: typeof warning;
|
|
127
329
|
withSettings: typeof withSettings;
|
|
128
330
|
withTags: typeof withTags;
|
|
129
331
|
};
|
|
130
332
|
//#endregion
|
|
131
|
-
export { DiagLogLevel, LogfireConfigOptions, configure, defaultExport as default };
|
|
333
|
+
export { type BrowserMetricsOptions, type BrowserSessionOptions, type BrowserSessionReplayOptions, type BrowserSessionUrlAttributes, type BrowserWebVitalsMetricOptions, type BrowserWebVitalsOptions, DiagLogLevel, LogfireConfigOptions, type RUMOptions, configure, defaultExport as default, getBrowserSessionId };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DiagConsoleLogger as e,DiagLogLevel as t,DiagLogLevel as n,diag as r}from"@opentelemetry/api";import{OTLPTraceExporter as i}from"@opentelemetry/exporter-trace-otlp-http";import{registerInstrumentations as a}from"@opentelemetry/instrumentation";import{resourceFromAttributes as o}from"@opentelemetry/resources";import{BatchSpanProcessor as s,ParentBasedSampler as c,SimpleSpanProcessor as l,StackContextManager as u,TraceIdRatioBasedSampler as d,WebTracerProvider as f}from"@opentelemetry/sdk-trace-web";import{ATTR_SERVICE_NAME as p,ATTR_SERVICE_VERSION as m,ATTR_TELEMETRY_SDK_LANGUAGE as h,ATTR_TELEMETRY_SDK_NAME as g,ATTR_TELEMETRY_SDK_VERSION as _,ATTR_USER_AGENT_ORIGINAL as ee,TELEMETRY_SDK_LANGUAGE_VALUE_WEBJS as te}from"@opentelemetry/semantic-conventions";import{ATTR_BROWSER_BRANDS as v,ATTR_BROWSER_LANGUAGE as y,ATTR_BROWSER_MOBILE as b,ATTR_BROWSER_PLATFORM as x,ATTR_DEPLOYMENT_ENVIRONMENT_NAME as S,ATTR_HTTP_URL as C}from"@opentelemetry/semantic-conventions/incubating";import{Level as w,LogfireAttributeScrubber as T,NoopAttributeScrubber as E,TailSamplingProcessor as D,ULIDGenerator as O,configureLogfireApi as k,debug as A,error as j,fatal as M,info as N,instrument as P,log as F,logfireApiConfig as I,notice as L,reportError as ne,resolveBaseUrl as R,resolveSendToLogfire as z,serializeAttributes as B,span as V,startPendingSpan as H,startSpan as U,trace as W,warning as G,withSettings as K,withTags as q}from"logfire";import{ExportResultCode as J,hrTimeToMicroseconds as Y}from"@opentelemetry/core";export*from"logfire";const X=`target_xpath`,Z={1:`trace`,5:`debug`,9:`info`,10:`notice`,13:`warning`,17:`error`,21:`fatal`},Q={debug:`#E3E3E3`,error:`#EA4335`,fatal:`#EA4335`,info:`#9EC1FB`,notice:`#A5D490`,"on-debug":`#636262`,"on-error":`#FFEDE9`,"on-fatal":`#FFEDE9`,"on-info":`#063175`,"on-notice":`#222222`,"on-trace":`#636262`,"on-warning":`#613A0D`,trace:`#E3E3E3`,warning:`#EFB77A`};var re=class{export(e,t){this.sendSpans(e,t)}async forceFlush(){return Promise.resolve()}async shutdown(){return this.sendSpans([]),this.forceFlush()}exportInfo(e){return{attributes:e.attributes,duration:Y(e.duration),events:e.events,id:e.spanContext().spanId,instrumentationScope:e.instrumentationScope,kind:e.kind,links:e.links,name:e.name,parentSpanContext:e.parentSpanContext,resource:{attributes:e.resource.attributes},status:e.status,timestamp:Y(e.startTime),traceId:e.spanContext().traceId,traceState:e.spanContext().traceState?.serialize()}}sendSpans(e,t){for(let t of e){let e=Z[t.attributes[`logfire.level_num`]]??`info`,{attributes:n,name:r,...i}=this.exportInfo(t);console.log(`%cLogfire %c${e}`,`background-color: #E520E9; color: #FFFFFF`,`background-color: ${Q[`on-${e}`]}; color: ${Q[e]}`,r,n,i)}t&&t({code:J.SUCCESS})}},ie=class{console;wrapped;constructor(e,t){t&&(this.console=new l(new re)),this.wrapped=e}async forceFlush(){return await this.console?.forceFlush(),this.wrapped.forceFlush()}onEnd(e){this.console?.onEnd(e),this.wrapped.onEnd(e)}onStart(e,t){if(C in e.attributes){let t=new URL(e.attributes[C]);Reflect.set(e,`name`,`${e.name} ${t.pathname}`)}if(X in e.attributes){let t=String(e.attributes.event_type??`unknown`),n=String(e.attributes[X]??``);Reflect.set(e,`name`,`${t} ${n}`)}this.console?.onStart(e,t),this.wrapped.onStart(e,t)}async shutdown(){return await this.console?.shutdown(),this.wrapped.shutdown()}};function ae(){return{}}async function oe(e,t){return{...typeof e==`function`?await e():e??{},...t()}}function $(t){t.diagLogLevel!==void 0&&r.setLogger(new e,t.diagLogLevel);let n={errorFingerprinting:t.errorFingerprinting??!1};t.baggage!==void 0&&(n.baggage=t.baggage),t.jsonSchema!==void 0&&(n.jsonSchema=t.jsonSchema),t.minLevel!==void 0&&(n.minLevel=t.minLevel),t.scrubbing!==void 0&&(n.scrubbing=t.scrubbing),k(n);let l=o(t.resourceAttributes??{}).merge(o({[y]:navigator.language,[p]:t.serviceName??`logfire-browser`,[m]:t.serviceVersion??`0.0.1`,[h]:te,[g]:`logfire-browser`,...t.environment!==void 0&&t.environment!==``?{[S]:t.environment}:{},[_]:`1.0.0`,...navigator.userAgentData?{[v]:navigator.userAgentData.brands.map(e=>`${e.brand} ${e.version}`),[b]:navigator.userAgentData.mobile,[x]:navigator.userAgentData.platform}:{[ee]:navigator.userAgent}}));r.info(`logfire-browser: starting`);let C=t.sampling?.head,w=C!==void 0&&C<1?new c({root:new d(C)}):void 0,T=new ie(new s(new i({...t.traceExporterConfig,headers:async()=>oe(t.traceExporterConfig?.headers,t.traceExporterHeaders??ae),url:t.traceUrl}),t.batchSpanProcessorConfig),!!t.console);t.sampling?.tail&&(T=new D(T,t.sampling.tail));let E=new f({idGenerator:new O,resource:l,...w?{sampler:w}:{},spanProcessors:[T]});E.register({contextManager:t.contextManager??new u});let A=a({instrumentations:t.instrumentations??[],tracerProvider:E}),j;return()=>(j??=(async()=>{let e,t=(t,n)=>{let i=n instanceof Error?n:Error(String(n));e??=i,r.error(`logfire-browser: ${t} failed during shutdown`,i)},n=async(e,n)=>{try{await n()}catch(n){t(e,n)}};if(r.info(`logfire-browser: shutting down`),await n(`instrumentation unregister`,A),await n(`force flush`,async()=>E.forceFlush()),await n(`tracer provider shutdown`,async()=>E.shutdown()),e!==void 0)throw Error(e.message,{cause:e});r.info(`logfire-browser: shut down complete`)})(),j)}const se={configure:$,configureLogfireApi:k,debug:A,DiagLogLevel:n,error:j,fatal:M,info:N,instrument:P,Level:w,log:F,logfireApiConfig:I,LogfireAttributeScrubber:T,NoopAttributeScrubber:E,notice:L,reportError:ne,resolveBaseUrl:R,resolveSendToLogfire:z,serializeAttributes:B,span:V,startPendingSpan:H,startSpan:U,trace:W,ULIDGenerator:O,warning:G,withSettings:K,withTags:q};export{t as DiagLogLevel,$ as configure,se as default};
|
|
1
|
+
import{DiagConsoleLogger as e,DiagLogLevel as t,DiagLogLevel as n,diag as r,trace as i}from"@opentelemetry/api";import{OTLPTraceExporter as a}from"@opentelemetry/exporter-trace-otlp-http";import{registerInstrumentations as o}from"@opentelemetry/instrumentation";import{resourceFromAttributes as s}from"@opentelemetry/resources";import{BatchSpanProcessor as ee,ParentBasedSampler as te,SimpleSpanProcessor as c,StackContextManager as l,TraceIdRatioBasedSampler as ne,WebTracerProvider as re}from"@opentelemetry/sdk-trace-web";import{ATTR_SERVICE_NAME as ie,ATTR_SERVICE_VERSION as ae,ATTR_TELEMETRY_SDK_LANGUAGE as oe,ATTR_TELEMETRY_SDK_NAME as se,ATTR_TELEMETRY_SDK_VERSION as ce,ATTR_USER_AGENT_ORIGINAL as u,TELEMETRY_SDK_LANGUAGE_VALUE_WEBJS as d}from"@opentelemetry/semantic-conventions";import{ATTR_BROWSER_BRANDS as f,ATTR_BROWSER_LANGUAGE as le,ATTR_BROWSER_MOBILE as ue,ATTR_BROWSER_PLATFORM as de,ATTR_DEPLOYMENT_ENVIRONMENT_NAME as fe,ATTR_HTTP_URL as p}from"@opentelemetry/semantic-conventions/incubating";import{Level as m,LogfireAttributeScrubber as h,NoopAttributeScrubber as g,TailSamplingProcessor as pe,ULIDGenerator as _,configureLogfireApi as v,debug as y,error as b,fatal as x,info as S,instrument as C,log as w,logfireApiConfig as T,notice as E,reportError as D,resolveBaseUrl as O,resolveSendToLogfire as k,serializeAttributes as A,span as j,startPendingSpan as M,startSpan as N,trace as P,warning as F,withSettings as I,withTags as L}from"logfire";import{ExportResultCode as R,hrTimeToMicroseconds as z}from"@opentelemetry/core";export*from"logfire";function B(){let e=globalThis;try{let t=(e.location??e.window?.location)?.href;return t===void 0||t===``?void 0:new URL(t)}catch{return}}var me=class{replayState;sessionManager;constructor(e,t){this.sessionManager=e,this.replayState=t}async forceFlush(){return Promise.resolve()}onEnd(e){}onStart(e,t){let n=this.sessionManager.touch();e.setAttribute(`session.id`,n.id),e.setAttribute(`browser.session.id`,n.id);let r=this.replayState?.getState();r!==void 0&&(e.setAttribute(`logfire.session_replay.active`,r.active),e.setAttribute(`logfire.session_replay.mode`,r.mode));let i=B();if(i===void 0)return;let a;try{a=this.sessionManager.getUrlAttributes(i)}catch{return}a?.full!==void 0&&e.setAttribute(`url.full`,a.full),a?.path!==void 0&&e.setAttribute(`url.path`,a.path)}async shutdown(){return Promise.resolve()}};const V={idleTimeoutMs:30*6e4,maxDurationMs:240*6e4,storageKey:`lf_browser_session`};function he(){try{return globalThis.sessionStorage??null}catch{return null}}function ge(){let e=globalThis.crypto;if(typeof e?.randomUUID==`function`)return e.randomUUID();if(typeof e?.getRandomValues==`function`){let t=new Uint8Array(16);return e.getRandomValues(t),Array.from(t,e=>e.toString(16).padStart(2,`0`)).join(``)}return`${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}-${Math.random().toString(36).slice(2)}`}function _e(e){if(typeof e!=`object`||!e)return!1;let t=e;return typeof t.id==`string`&&t.id.length>0&&typeof t.startedAt==`number`&&Number.isFinite(t.startedAt)&&typeof t.lastActivityAt==`number`&&Number.isFinite(t.lastActivityAt)}var ve=class{generateId;idleTimeoutMs;maxDurationMs;now;storage;storageKey;urlAttributes;memorySession;constructor(e={}){this.generateId=e.generateId??ge,this.idleTimeoutMs=e.idleTimeoutMs??V.idleTimeoutMs,this.maxDurationMs=e.maxDurationMs??V.maxDurationMs,this.now=e.now??Date.now,this.storage=e.storage===void 0?he():e.storage,this.storageKey=e.storageKey??V.storageKey,this.urlAttributes=e.urlAttributes}getSession(){return this.getSessionAt(this.now())}peekSessionId(){return this.memorySession?.id}touch(){let e=this.now(),t={...this.getSessionAt(e),lastActivityAt:e};return this.writeSession(t),t}reset(){return this.createSession(this.now())}getUrlAttributes(e){if(this.urlAttributes!==!1)return typeof this.urlAttributes==`function`?this.urlAttributes(e):{full:e.href,path:e.pathname}}createSession(e){let t={id:this.generateId(),lastActivityAt:e,startedAt:e};return this.writeSession(t),t}getSessionAt(e){let t=this.readSession();return t!==void 0&&!this.isExpired(t,e)?t:this.createSession(e)}isExpired(e,t){return t-e.lastActivityAt>this.idleTimeoutMs||t-e.startedAt>this.maxDurationMs}readSession(){if(this.storage!==null)try{let e=this.storage.getItem(this.storageKey);if(e!==null){let t=JSON.parse(e);if(_e(t))return this.memorySession=t,t}}catch{return this.memorySession}return this.memorySession}writeSession(e){if(this.memorySession=e,this.storage!==null)try{this.storage.setItem(this.storageKey,JSON.stringify(e))}catch{}}};let H;function ye(e){if(e===void 0||e===!1){H=void 0;return}let t=new ve(e===!0?{}:e);return H=t,t}function U(){return H?.touch().id}function be(e){H===e&&(H=void 0)}var xe=class{replay;setReplay(e){this.replay=e}clear(){this.replay=void 0}getState(){let e=this.replay?.mode;if(!(this.replay?.recording!==!0||e!==`full`&&e!==`buffer`))return{active:!0,mode:e}}};async function Se(e,t,n,i){try{if(t.touch(),t.peekSessionId()===void 0)throw Error(`logfire-browser: sessionReplay requires an active browser session id`);let r=await e.load(),a=Ce(e,t,i),o=we(r.startSessionReplay(a),n);return o.recording&&(o.mode===`full`||o.mode===`buffer`)&&n.setReplay(o),o}catch(t){n.clear(),r.error(`logfire-browser: failed to start session replay; install @pydantic/logfire-session-replay and verify sessionReplay config`,t),e.onError?.(t);return}}function Ce(e,t,n){let r={getSessionId:()=>t.peekSessionId(),ignoreUrlPatterns:[...Te(e.replayUrl,n),...e.ignoreUrlPatterns??[]],redactUrlPatterns:e.redactUrlPatterns??[],replayUrl:e.replayUrl};return e.headers!==void 0&&(r.headers=e.headers),e.token!==void 0&&(r.token=e.token),e.sessionSampleRate!==void 0&&(r.sessionSampleRate=e.sessionSampleRate),e.onErrorSampleRate!==void 0&&(r.onErrorSampleRate=e.onErrorSampleRate),e.maskAllInputs!==void 0&&(r.maskAllInputs=e.maskAllInputs),e.maskTextSelector!==void 0&&(r.maskTextSelector=e.maskTextSelector),e.blockSelector!==void 0&&(r.blockSelector=e.blockSelector),e.flushIntervalMs!==void 0&&(r.flushIntervalMs=e.flushIntervalMs),e.maxBufferBytes!==void 0&&(r.maxBufferBytes=e.maxBufferBytes),e.distinctId!==void 0&&(r.distinctId=e.distinctId),e.getDistinctId!==void 0&&(r.getDistinctId=e.getDistinctId),e.captureConsole!==void 0&&(r.captureConsole=e.captureConsole),e.captureNetwork!==void 0&&(r.captureNetwork=e.captureNetwork),e.captureNavigation!==void 0&&(r.captureNavigation=e.captureNavigation),e.onError!==void 0&&(r.onError=e.onError),e.fetchImpl!==void 0&&(r.fetchImpl=e.fetchImpl),r}function we(e,t){let n;return{get mode(){return e.mode},get recording(){return e.recording},flush:async()=>e.flush(),getSessionId:()=>e.getSessionId(),stop:async()=>(n??=(async()=>{try{await e.stop()}finally{t.clear()}})(),n)}}function Te(e,t){return[t.traceUrl,t.metricUrl,e].flatMap(e=>{let t=Ee(e);return t===void 0?[]:[t]})}function Ee(e){if(e===void 0||e.length===0)return;let t=e.replace(/\/+$/u,``);return RegExp(`^${De(t)}(?:[/?#]|$)`,`u`)}function De(e){return e.replace(/[.*+?^${}()|[\]\\]/gu,`\\$&`)}let W,G;function Oe(e){let t=!1;return{async shutdown(){return t?Promise.resolve():(t=!0,e?.shutdown(),G===e&&(G=void 0),Promise.resolve())}}}function K(e,t,n){if(typeof n==`string`||typeof n==`boolean`){e[t]=n;return}typeof n==`number`&&Number.isFinite(n)&&(e[t]=n)}function q(e={}){let t={};return e.reportAllChanges!==void 0&&(t.reportAllChanges=e.reportAllChanges),e.generateTarget!==void 0&&(t.generateTarget=e.generateTarget),t}function ke(e={}){return{...q(e),includeProcessedEventEntries:e.includeProcessedEventEntries??!1}}function Ae(e){let t={};return K(t,`web_vital.name`,e.name),K(t,`web_vital.value`,e.value),K(t,`web_vital.delta`,e.delta),K(t,`web_vital.id`,e.id),K(t,`web_vital.rating`,e.rating),K(t,`web_vital.navigation_type`,e.navigationType),t}function je(e){let t=Ae(e);switch(e.name){case`LCP`:{let{attribution:n}=e;K(t,`web_vital.lcp.target`,n.target),K(t,`web_vital.lcp.element`,n.target),K(t,`web_vital.lcp.url`,n.url),K(t,`web_vital.lcp.time_to_first_byte`,n.timeToFirstByte),K(t,`web_vital.lcp.resource_load_delay`,n.resourceLoadDelay),K(t,`web_vital.lcp.resource_load_duration`,n.resourceLoadDuration),K(t,`web_vital.lcp.element_render_delay`,n.elementRenderDelay);break}case`INP`:{let{attribution:n}=e;K(t,`web_vital.inp.target`,n.interactionTarget),K(t,`web_vital.inp.interaction_type`,n.interactionType),K(t,`web_vital.inp.interaction_time`,n.interactionTime),K(t,`web_vital.inp.input_delay`,n.inputDelay),K(t,`web_vital.inp.processing_duration`,n.processingDuration),K(t,`web_vital.inp.presentation_delay`,n.presentationDelay),K(t,`web_vital.inp.load_state`,n.loadState);break}case`CLS`:{let{attribution:n}=e;K(t,`web_vital.cls.largest_shift_target`,n.largestShiftTarget),K(t,`web_vital.cls.largest_shift_time`,n.largestShiftTime),K(t,`web_vital.cls.largest_shift_value`,n.largestShiftValue),K(t,`web_vital.cls.load_state`,n.loadState);break}case`FCP`:{let{attribution:n}=e;K(t,`web_vital.fcp.time_to_first_byte`,n.timeToFirstByte),K(t,`web_vital.fcp.first_byte_to_fcp`,n.firstByteToFCP),K(t,`web_vital.fcp.load_state`,n.loadState);break}case`TTFB`:{let{attribution:n}=e;K(t,`web_vital.ttfb.waiting_duration`,n.waitingDuration),K(t,`web_vital.ttfb.cache_duration`,n.cacheDuration),K(t,`web_vital.ttfb.dns_duration`,n.dnsDuration),K(t,`web_vital.ttfb.connection_duration`,n.connectionDuration),K(t,`web_vital.ttfb.request_duration`,n.requestDuration);break}default:break}return t}function Me(e){try{let t=i.getTracer(`logfire-web-vitals`).startSpan(`web_vital.${e.name.toLowerCase()}`);try{t.setAttributes(je(e))}finally{t.end()}}catch(e){r.error(`logfire-browser: failed to report Web Vital`,e)}}function Ne(e,t){if(t!==void 0)try{t.record(e)}catch(e){r.error(`logfire-browser: failed to report Web Vital metric`,e)}}function Pe(e,t){Me(e),Ne(e,t)}function Fe(e,t={}){let n=q(t),r=e=>{Pe(e,G)};e.onLCP(r,n),e.onINP(r,ke(t)),e.onCLS(r,n),e.onFCP(r,n),e.onTTFB(r,n)}async function J(e={}){return e.metricRecorder!==void 0&&(G=e.metricRecorder),W??=import(`web-vitals/attribution`).then(t=>{Fe(t,e)}).catch(e=>{r.error(`logfire-browser: failed to start Web Vitals reporting`,e)}),await W,Oe(e.metricRecorder)}const Y=`target_xpath`,Ie={1:`trace`,5:`debug`,9:`info`,10:`notice`,13:`warning`,17:`error`,21:`fatal`},X={debug:`#E3E3E3`,error:`#EA4335`,fatal:`#EA4335`,info:`#9EC1FB`,notice:`#A5D490`,"on-debug":`#636262`,"on-error":`#FFEDE9`,"on-fatal":`#FFEDE9`,"on-info":`#063175`,"on-notice":`#222222`,"on-trace":`#636262`,"on-warning":`#613A0D`,trace:`#E3E3E3`,warning:`#EFB77A`};var Le=class{export(e,t){this.sendSpans(e,t)}async forceFlush(){return Promise.resolve()}async shutdown(){return this.sendSpans([]),this.forceFlush()}exportInfo(e){return{attributes:e.attributes,duration:z(e.duration),events:e.events,id:e.spanContext().spanId,instrumentationScope:e.instrumentationScope,kind:e.kind,links:e.links,name:e.name,parentSpanContext:e.parentSpanContext,resource:{attributes:e.resource.attributes},status:e.status,timestamp:z(e.startTime),traceId:e.spanContext().traceId,traceState:e.spanContext().traceState?.serialize()}}sendSpans(e,t){for(let t of e){let e=Ie[t.attributes[`logfire.level_num`]]??`info`,{attributes:n,name:r,...i}=this.exportInfo(t);console.log(`%cLogfire %c${e}`,`background-color: #E520E9; color: #FFFFFF`,`background-color: ${X[`on-${e}`]}; color: ${X[e]}`,r,n,i)}t&&t({code:R.SUCCESS})}},Re=class{console;wrapped;constructor(e,t){t&&(this.console=new c(new Le)),this.wrapped=e}async forceFlush(){return await this.console?.forceFlush(),this.wrapped.forceFlush()}onEnd(e){this.console?.onEnd(e),this.wrapped.onEnd(e)}onStart(e,t){if(p in e.attributes){let t=new URL(e.attributes[p]);Reflect.set(e,`name`,`${e.name} ${t.pathname}`)}if(Y in e.attributes){let t=String(e.attributes.event_type??`unknown`),n=String(e.attributes[Y]??``);Reflect.set(e,`name`,`${t} ${n}`)}this.console?.onStart(e,t),this.wrapped.onStart(e,t)}async shutdown(){return await this.console?.shutdown(),this.wrapped.shutdown()}};function ze(){return{}}function Z(e){if(!(e===void 0||e===!1))return e===!0?{}:e}function Be(e){if(!(e===void 0||e===!1)){if(e.metricUrl===``)throw Error(`logfire-browser: metrics.metricUrl must be a non-empty browser-safe metrics proxy URL`);return e}}function Ve(e){if(!(e?.metrics===void 0||e.metrics===!1))return e.metrics===!0?{}:e.metrics}function Q(e){if(!(e===void 0||e===!1))return e}function He(e,t){let n=Z(e?.webVitals),r=t!==void 0;if(n===void 0&&!r)return e?.session;if(e?.session===!1)throw Error(r?`logfire-browser: sessionReplay requires browser session attributes; remove rum.session: false or disable sessionReplay`:`logfire-browser: rum.webVitals requires browser session attributes; remove rum.session: false or disable rum.webVitals`);return e?.session??!0}async function Ue(e,t){return{...typeof e==`function`?await e():e??{},...t()}}function $(t){t.diagLogLevel!==void 0&&r.setLogger(new e,t.diagLogLevel);let n=Z(t.rum?.webVitals),i=Q(t.sessionReplay),c=Be(t.metrics),p=Ve(n);if(p!==void 0&&c===void 0)throw Error(`logfire-browser: rum.webVitals.metrics requires top-level metrics.metricUrl`);let m=He(t.rum,i),h={errorFingerprinting:t.errorFingerprinting??!1};t.baggage!==void 0&&(h.baggage=t.baggage),t.jsonSchema!==void 0&&(h.jsonSchema=t.jsonSchema),t.minLevel!==void 0&&(h.minLevel=t.minLevel),t.scrubbing!==void 0&&(h.scrubbing=t.scrubbing),v(h);let g=s(t.resourceAttributes??{}).merge(s({[le]:navigator.language,[ie]:t.serviceName??`logfire-browser`,[ae]:t.serviceVersion??`0.0.1`,[oe]:d,[se]:`logfire-browser`,...t.environment!==void 0&&t.environment!==``?{[fe]:t.environment}:{},[ce]:`0.0.0`,...navigator.userAgentData?{[f]:navigator.userAgentData.brands.map(e=>`${e.brand} ${e.version}`),[ue]:navigator.userAgentData.mobile,[de]:navigator.userAgentData.platform}:{[u]:navigator.userAgent}}));r.info(`logfire-browser: starting`);let y=t.sampling?.head,b=y!==void 0&&y<1?new te({root:new ne(y)}):void 0,x=new Re(new ee(new a({...t.traceExporterConfig,headers:async()=>Ue(t.traceExporterConfig?.headers,t.traceExporterHeaders??ze),url:t.traceUrl}),t.batchSpanProcessorConfig),!!t.console);t.sampling?.tail&&(x=new pe(x,t.sampling.tail));let S=ye(m),C=new xe,w=[];S!==void 0&&w.push(new me(S,C)),w.push(...t.spanProcessors??[],x);let T=new re({idGenerator:new _,resource:g,...b?{sampler:b}:{},spanProcessors:w});T.register({contextManager:t.contextManager??new l});let E=o({instrumentations:t.instrumentations??[],tracerProvider:T}),D=i===void 0||S===void 0?void 0:Se(i,S,C,{metricUrl:c?.metricUrl,traceUrl:t.traceUrl}),O=c===void 0?void 0:import(`./browserMetrics-Bx5fHWgu.js`).then(async({startBrowserMetrics:e})=>e(c,g)).catch(e=>{r.error(`logfire-browser: failed to start browser metrics`,e)}),k=n===void 0?void 0:p===void 0?J(n).catch(e=>{r.error(`logfire-browser: failed to start Web Vitals reporting`,e)}):(async()=>{let e=await O;if(e===void 0)throw Error(`logfire-browser: failed to start Web Vitals metrics because browser metrics transport did not start`);return J({...n,metricRecorder:e.createWebVitalsMetricRecorder(p)})})().catch(e=>{r.error(`logfire-browser: failed to start Web Vitals reporting`,e)}),A;return()=>(A??=(async()=>{let e,t=(t,n)=>{let i=n instanceof Error?n:Error(String(n));e??=i,r.error(`logfire-browser: ${t} failed during shutdown`,i)},n=async(e,n)=>{try{await n()}catch(n){t(e,n)}};if(r.info(`logfire-browser: shutting down`),D!==void 0&&(C.clear(),await n(`session replay shutdown`,async()=>{await(await D)?.stop()})),await n(`instrumentation unregister`,E),k!==void 0&&await n(`web vitals shutdown`,async()=>{await(await k)?.shutdown()}),O!==void 0&&(await n(`metric provider force flush`,async()=>{await(await O)?.forceFlush()}),await n(`metric provider shutdown`,async()=>{await(await O)?.shutdown()})),await n(`force flush`,async()=>T.forceFlush()),await n(`tracer provider shutdown`,async()=>T.shutdown()),S!==void 0&&await n(`browser session cleanup`,()=>{be(S)}),e!==void 0)throw Error(e.message,{cause:e});r.info(`logfire-browser: shut down complete`)})(),A)}const We={configure:$,configureLogfireApi:v,debug:y,DiagLogLevel:n,error:b,fatal:x,getBrowserSessionId:U,info:S,instrument:C,Level:m,log:w,logfireApiConfig:T,LogfireAttributeScrubber:h,NoopAttributeScrubber:g,notice:E,reportError:D,resolveBaseUrl:O,resolveSendToLogfire:k,serializeAttributes:A,span:j,startPendingSpan:M,startSpan:N,trace:P,ULIDGenerator:_,warning:F,withSettings:I,withTags:L};export{t as DiagLogLevel,$ as configure,We as default,U as getBrowserSessionId};
|
package/package.json
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"stats",
|
|
26
26
|
"monitoring"
|
|
27
27
|
],
|
|
28
|
-
"version": "0.
|
|
28
|
+
"version": "0.17.0-alpha.0",
|
|
29
29
|
"type": "module",
|
|
30
30
|
"main": "./dist/index.cjs",
|
|
31
31
|
"module": "./dist/index.js",
|
|
@@ -44,20 +44,30 @@
|
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@opentelemetry/api": "^1.9.1",
|
|
47
|
-
"@opentelemetry/core": "^2.
|
|
48
|
-
"@opentelemetry/exporter-
|
|
49
|
-
"@opentelemetry/
|
|
50
|
-
"@opentelemetry/
|
|
51
|
-
"
|
|
47
|
+
"@opentelemetry/core": "^2.8.0",
|
|
48
|
+
"@opentelemetry/exporter-metrics-otlp-http": ">=0.219.0 <0.300.0",
|
|
49
|
+
"@opentelemetry/exporter-trace-otlp-http": ">=0.219.0 <0.300.0",
|
|
50
|
+
"@opentelemetry/instrumentation": ">=0.219.0 <0.300.0",
|
|
51
|
+
"@opentelemetry/resources": "^2.8.0",
|
|
52
|
+
"@opentelemetry/sdk-metrics": "^2.8.0",
|
|
53
|
+
"web-vitals": "^5.3.0",
|
|
54
|
+
"logfire": "0.20.1"
|
|
52
55
|
},
|
|
53
56
|
"peerDependencies": {
|
|
54
|
-
"@opentelemetry/sdk-trace-web": "^2.
|
|
55
|
-
"@opentelemetry/semantic-conventions": "^1.41.1"
|
|
57
|
+
"@opentelemetry/sdk-trace-web": "^2.8.0",
|
|
58
|
+
"@opentelemetry/semantic-conventions": "^1.41.1",
|
|
59
|
+
"@pydantic/logfire-session-replay": "0.1.0-alpha.0"
|
|
60
|
+
},
|
|
61
|
+
"peerDependenciesMeta": {
|
|
62
|
+
"@pydantic/logfire-session-replay": {
|
|
63
|
+
"optional": true
|
|
64
|
+
}
|
|
56
65
|
},
|
|
57
66
|
"devDependencies": {
|
|
58
|
-
"@opentelemetry/sdk-trace-web": "^2.
|
|
67
|
+
"@opentelemetry/sdk-trace-web": "^2.8.0",
|
|
59
68
|
"@opentelemetry/semantic-conventions": "^1.41.1",
|
|
60
|
-
"user-agent-data-types": "^0.4.2"
|
|
69
|
+
"user-agent-data-types": "^0.4.2",
|
|
70
|
+
"@pydantic/logfire-session-replay": "0.1.0-alpha.0"
|
|
61
71
|
},
|
|
62
72
|
"files": [
|
|
63
73
|
"dist",
|