@pydantic/logfire-browser 0.16.4 → 0.17.0-alpha.1

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 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. unregister configured instrumentations
106
- 2. force-flush spans
107
- 3. shut down the tracer provider
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.16.4",
28
+ "version": "0.17.0-alpha.1",
29
29
  "type": "module",
30
30
  "main": "./dist/index.cjs",
31
31
  "module": "./dist/index.js",
@@ -45,19 +45,29 @@
45
45
  "dependencies": {
46
46
  "@opentelemetry/api": "^1.9.1",
47
47
  "@opentelemetry/core": "^2.8.0",
48
+ "@opentelemetry/exporter-metrics-otlp-http": ">=0.219.0 <0.300.0",
48
49
  "@opentelemetry/exporter-trace-otlp-http": ">=0.219.0 <0.300.0",
49
50
  "@opentelemetry/instrumentation": ">=0.219.0 <0.300.0",
50
51
  "@opentelemetry/resources": "^2.8.0",
52
+ "@opentelemetry/sdk-metrics": "^2.8.0",
53
+ "web-vitals": "^5.3.0",
51
54
  "logfire": "0.20.1"
52
55
  },
53
56
  "peerDependencies": {
54
57
  "@opentelemetry/sdk-trace-web": "^2.8.0",
55
- "@opentelemetry/semantic-conventions": "^1.41.1"
58
+ "@opentelemetry/semantic-conventions": "^1.41.1",
59
+ "@pydantic/logfire-session-replay": "0.1.0-alpha.1"
60
+ },
61
+ "peerDependenciesMeta": {
62
+ "@pydantic/logfire-session-replay": {
63
+ "optional": true
64
+ }
56
65
  },
57
66
  "devDependencies": {
58
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.1"
61
71
  },
62
72
  "files": [
63
73
  "dist",