@pydantic/logfire-browser 0.15.2 → 0.16.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 CHANGED
@@ -49,6 +49,99 @@ 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
+ ## Baggage span attributes
53
+
54
+ Use `baggage.spanAttributes` to copy selected active OpenTelemetry baggage
55
+ values onto Logfire manual spans and logs:
56
+
57
+ ```js
58
+ import * as logfire from '@pydantic/logfire-browser'
59
+
60
+ logfire.configure({
61
+ traceUrl: '/client-traces',
62
+ serviceName: 'browser-app',
63
+ baggage: {
64
+ spanAttributes: ['tenant', 'region'],
65
+ },
66
+ })
67
+ ```
68
+
69
+ Projection is disabled by default and allowlisted. Configured baggage key
70
+ `tenant` is emitted as `baggage.tenant`. Explicit span attributes win on
71
+ conflict, missing keys are ignored, and values are truncated to 1000
72
+ characters. Do not store secrets, credentials, session cookies, raw emails, or
73
+ other sensitive user data in baggage because baggage propagates across service
74
+ boundaries.
75
+
76
+ ## Minimum level filtering
77
+
78
+ Use `minLevel` to suppress low-severity manual Logfire telemetry before spans
79
+ are created:
80
+
81
+ ```js
82
+ import * as logfire from '@pydantic/logfire-browser'
83
+
84
+ logfire.configure({
85
+ traceUrl: '/client-traces',
86
+ serviceName: 'browser-app',
87
+ minLevel: 'warning',
88
+ })
89
+ ```
90
+
91
+ Browser configuration does not read Logfire environment variables. Pass
92
+ `minLevel` in code, or pass `minLevel: null` to clear a previous setting. Log
93
+ helpers and `reportError()` are filtered by their level. Duration-style APIs
94
+ such as `span()`, `startSpan()`, `startPendingSpan()`, and `instrument()` are
95
+ filtered only when the call or scoped client sets an explicit level.
96
+
97
+ ## Runtime lifecycle
98
+
99
+ `configure()` returns an async cleanup function. Call it when your application is
100
+ tearing down the configured browser provider, such as in tests, previews, or
101
+ single-page app shells that replace the whole telemetry setup. Cleanup is
102
+ idempotent: repeated or concurrent calls share one promise and run the lifecycle
103
+ once in this order:
104
+
105
+ 1. unregister configured instrumentations
106
+ 2. force-flush spans
107
+ 3. shut down the tracer provider
108
+
109
+ If any cleanup step fails, Logfire still attempts the later steps before
110
+ returning the first failure. Later calls return the same settled cleanup promise
111
+ rather than starting another cleanup cycle.
112
+
113
+ Browser pages also get OpenTelemetry's built-in batch-processor auto-flush on
114
+ document hide. The underlying batch span processor calls `forceFlush()` when the
115
+ document becomes hidden or emits `pagehide`, which helps export spans during
116
+ navigation away from the page. You can disable that OpenTelemetry behavior with
117
+ `batchSpanProcessorConfig.disableAutoFlushOnDocumentHide`, but doing so means
118
+ only explicit cleanup or normal batch timing will flush spans.
119
+
120
+ ## Pending spans
121
+
122
+ Browser `configure()` does not install automatic pending-span processing.
123
+ Browser apps often produce many short-lived fetch and interaction spans, so
124
+ automatic pending spans can significantly increase span volume, network
125
+ pressure, and ingestion cost in a user-facing environment.
126
+
127
+ For long-running browser operations where an immediate placeholder is useful,
128
+ call `startPendingSpan()` explicitly:
129
+
130
+ ```js
131
+ import * as logfire from '@pydantic/logfire-browser'
132
+
133
+ const span = logfire.startPendingSpan('Load dashboard', { route: '/dashboard' })
134
+ try {
135
+ await loadDashboard()
136
+ } finally {
137
+ span.end()
138
+ }
139
+ ```
140
+
141
+ Manual pending spans still add one placeholder span for each call. Node.js
142
+ applications get automatic pending spans from `@pydantic/logfire-node`; Browser
143
+ keeps this behavior explicit.
144
+
52
145
  ## Contributing
53
146
 
54
147
  See [CONTRIBUTING.md](https://github.com/pydantic/logfire-js/blob/main/CONTRIBUTING.md) for development instructions.
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.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:_});return async()=>{e.diag.info(`logfire-browser: shutting down`),v(),await _.forceFlush(),await _.shutdown(),e.diag.info(`logfire-browser: shut down complete`)}}const _={configure:g,configureLogfireApi:s.configureLogfireApi,debug:s.debug,DiagLogLevel:e.DiagLogLevel,error:s.error,fatal:s.fatal,info:s.info,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,startSpan:s.startSpan,trace:s.trace,ULIDGenerator:s.ULIDGenerator,warning:s.warning};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`);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]}})});
package/dist/index.d.cts CHANGED
@@ -2,7 +2,7 @@ import { Attributes, ContextManager, DiagLogLevel, DiagLogLevel as DiagLogLevel$
2
2
  import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
3
3
  import { Instrumentation } from "@opentelemetry/instrumentation";
4
4
  import { BufferConfig } from "@opentelemetry/sdk-trace-web";
5
- import { Level, LogfireAttributeScrubber, NoopAttributeScrubber, SamplingOptions, ScrubbingOptions, ULIDGenerator, configureLogfireApi, debug, error, fatal, info, log, logfireApiConfig, notice, reportError, resolveBaseUrl, resolveSendToLogfire, serializeAttributes, span, startSpan, trace, warning } from "logfire";
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";
6
6
  export * from "logfire";
7
7
 
8
8
  //#region src/index.d.ts
@@ -13,6 +13,10 @@ interface LogfireConfigOptions {
13
13
  */
14
14
  batchSpanProcessorConfig?: BufferConfig;
15
15
  /**
16
+ * Active OpenTelemetry baggage keys to copy to Logfire manual spans/logs as span attributes.
17
+ */
18
+ baggage?: BaggageOptions;
19
+ /**
16
20
  * Whether to log the spans to the console in addition to sending them to the Logfire API.
17
21
  */
18
22
  console?: boolean;
@@ -35,10 +39,23 @@ interface LogfireConfigOptions {
35
39
  */
36
40
  errorFingerprinting?: boolean;
37
41
  /**
42
+ * Controls JSON schema metadata for serialized object/array attributes.
43
+ *
44
+ * Defaults to 'rich'. Use 'basic' for legacy broad schemas, or false to omit schema metadata.
45
+ */
46
+ jsonSchema?: JsonSchemaMode;
47
+ /**
38
48
  * The instrumentations to register - a common one [is the fetch instrumentation](https://www.npmjs.com/package/@opentelemetry/instrumentation-fetch).
39
49
  */
40
50
  instrumentations?: (Instrumentation | Instrumentation[])[];
41
51
  /**
52
+ * Minimum Logfire level to emit for manual log-like spans.
53
+ *
54
+ * Accepts lowercase level names (trace, debug, info, notice, warning, error, fatal)
55
+ * or numeric values from `logfire.Level`. Set to null to disable a previously configured minimum.
56
+ */
57
+ minLevel?: MinLevel | null;
58
+ /**
42
59
  * Sampling options for controlling which traces are exported.
43
60
  * `head` sets a probabilistic sample rate (0.0-1.0) at trace creation time.
44
61
  * `tail` provides a callback evaluated on every span to decide whether to keep the trace.
@@ -94,6 +111,7 @@ declare const defaultExport: {
94
111
  error: typeof error;
95
112
  fatal: typeof fatal;
96
113
  info: typeof info;
114
+ instrument: typeof instrument;
97
115
  log: typeof log;
98
116
  logfireApiConfig: typeof logfireApiConfig;
99
117
  notice: typeof notice;
@@ -102,9 +120,12 @@ declare const defaultExport: {
102
120
  resolveSendToLogfire: typeof resolveSendToLogfire;
103
121
  serializeAttributes: typeof serializeAttributes;
104
122
  span: typeof span;
123
+ startPendingSpan: typeof startPendingSpan;
105
124
  startSpan: typeof startSpan;
106
125
  trace: typeof trace;
107
126
  warning: typeof warning;
127
+ withSettings: typeof withSettings;
128
+ withTags: typeof withTags;
108
129
  };
109
130
  //#endregion
110
131
  export { DiagLogLevel, LogfireConfigOptions, configure, defaultExport as default };
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import { Attributes, ContextManager, DiagLogLevel, DiagLogLevel as DiagLogLevel$
2
2
  import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
3
3
  import { Instrumentation } from "@opentelemetry/instrumentation";
4
4
  import { BufferConfig } from "@opentelemetry/sdk-trace-web";
5
- import { Level, LogfireAttributeScrubber, NoopAttributeScrubber, SamplingOptions, ScrubbingOptions, ULIDGenerator, configureLogfireApi, debug, error, fatal, info, log, logfireApiConfig, notice, reportError, resolveBaseUrl, resolveSendToLogfire, serializeAttributes, span, startSpan, trace, warning } from "logfire";
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";
6
6
  export * from "logfire";
7
7
 
8
8
  //#region src/index.d.ts
@@ -13,6 +13,10 @@ interface LogfireConfigOptions {
13
13
  */
14
14
  batchSpanProcessorConfig?: BufferConfig;
15
15
  /**
16
+ * Active OpenTelemetry baggage keys to copy to Logfire manual spans/logs as span attributes.
17
+ */
18
+ baggage?: BaggageOptions;
19
+ /**
16
20
  * Whether to log the spans to the console in addition to sending them to the Logfire API.
17
21
  */
18
22
  console?: boolean;
@@ -35,10 +39,23 @@ interface LogfireConfigOptions {
35
39
  */
36
40
  errorFingerprinting?: boolean;
37
41
  /**
42
+ * Controls JSON schema metadata for serialized object/array attributes.
43
+ *
44
+ * Defaults to 'rich'. Use 'basic' for legacy broad schemas, or false to omit schema metadata.
45
+ */
46
+ jsonSchema?: JsonSchemaMode;
47
+ /**
38
48
  * The instrumentations to register - a common one [is the fetch instrumentation](https://www.npmjs.com/package/@opentelemetry/instrumentation-fetch).
39
49
  */
40
50
  instrumentations?: (Instrumentation | Instrumentation[])[];
41
51
  /**
52
+ * Minimum Logfire level to emit for manual log-like spans.
53
+ *
54
+ * Accepts lowercase level names (trace, debug, info, notice, warning, error, fatal)
55
+ * or numeric values from `logfire.Level`. Set to null to disable a previously configured minimum.
56
+ */
57
+ minLevel?: MinLevel | null;
58
+ /**
42
59
  * Sampling options for controlling which traces are exported.
43
60
  * `head` sets a probabilistic sample rate (0.0-1.0) at trace creation time.
44
61
  * `tail` provides a callback evaluated on every span to decide whether to keep the trace.
@@ -94,6 +111,7 @@ declare const defaultExport: {
94
111
  error: typeof error;
95
112
  fatal: typeof fatal;
96
113
  info: typeof info;
114
+ instrument: typeof instrument;
97
115
  log: typeof log;
98
116
  logfireApiConfig: typeof logfireApiConfig;
99
117
  notice: typeof notice;
@@ -102,9 +120,12 @@ declare const defaultExport: {
102
120
  resolveSendToLogfire: typeof resolveSendToLogfire;
103
121
  serializeAttributes: typeof serializeAttributes;
104
122
  span: typeof span;
123
+ startPendingSpan: typeof startPendingSpan;
105
124
  startSpan: typeof startSpan;
106
125
  trace: typeof trace;
107
126
  warning: typeof warning;
127
+ withSettings: typeof withSettings;
128
+ withTags: typeof withTags;
108
129
  };
109
130
  //#endregion
110
131
  export { DiagLogLevel, LogfireConfigOptions, configure, defaultExport as default };
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 v,TELEMETRY_SDK_LANGUAGE_VALUE_WEBJS as ee}from"@opentelemetry/semantic-conventions";import{ATTR_BROWSER_BRANDS as y,ATTR_BROWSER_LANGUAGE as b,ATTR_BROWSER_MOBILE as x,ATTR_BROWSER_PLATFORM as S,ATTR_DEPLOYMENT_ENVIRONMENT_NAME as C,ATTR_HTTP_URL as w}from"@opentelemetry/semantic-conventions/incubating";import{Level as T,LogfireAttributeScrubber as E,NoopAttributeScrubber as D,TailSamplingProcessor as O,ULIDGenerator as k,configureLogfireApi as A,debug as j,error as M,fatal as N,info as te,log as P,logfireApiConfig as F,notice as I,reportError as L,resolveBaseUrl as R,resolveSendToLogfire as z,serializeAttributes as B,span as V,startSpan as H,trace as U,warning as W}from"logfire";import{ExportResultCode as G,hrTimeToMicroseconds as K}from"@opentelemetry/core";export*from"logfire";const q=`target_xpath`,J={1:`trace`,5:`debug`,9:`info`,10:`notice`,13:`warning`,17:`error`,21:`fatal`},Y={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 X=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:K(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:K(e.startTime),traceId:e.spanContext().traceId,traceState:e.spanContext().traceState?.serialize()}}sendSpans(e,t){for(let t of e){let e=J[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: ${Y[`on-${e}`]}; color: ${Y[e]}`,r,n,i)}t&&t({code:G.SUCCESS})}},Z=class{console;wrapped;constructor(e,t){t&&(this.console=new l(new X)),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(w in e.attributes){let t=new URL(e.attributes[w]);Reflect.set(e,`name`,`${e.name} ${t.pathname}`)}if(q in e.attributes){let t=String(e.attributes.event_type??`unknown`),n=String(e.attributes[q]??``);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 Q(){return{}}async function ne(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.scrubbing!==void 0&&(n.scrubbing=t.scrubbing),A(n);let l=o(t.resourceAttributes??{}).merge(o({[b]:navigator.language,[p]:t.serviceName??`logfire-browser`,[m]:t.serviceVersion??`0.0.1`,[h]:ee,[g]:`logfire-browser`,...t.environment!==void 0&&t.environment!==``?{[C]:t.environment}:{},[_]:`1.0.0`,...navigator.userAgentData?{[y]:navigator.userAgentData.brands.map(e=>`${e.brand} ${e.version}`),[x]:navigator.userAgentData.mobile,[S]:navigator.userAgentData.platform}:{[v]:navigator.userAgent}}));r.info(`logfire-browser: starting`);let w=t.sampling?.head,T=w!==void 0&&w<1?new c({root:new d(w)}):void 0,E=new Z(new s(new i({...t.traceExporterConfig,headers:async()=>ne(t.traceExporterConfig?.headers,t.traceExporterHeaders??Q),url:t.traceUrl}),t.batchSpanProcessorConfig),!!t.console);t.sampling?.tail&&(E=new O(E,t.sampling.tail));let D=new f({idGenerator:new k,resource:l,...T?{sampler:T}:{},spanProcessors:[E]});D.register({contextManager:t.contextManager??new u});let j=a({instrumentations:t.instrumentations??[],tracerProvider:D});return async()=>{r.info(`logfire-browser: shutting down`),j(),await D.forceFlush(),await D.shutdown(),r.info(`logfire-browser: shut down complete`)}}const re={configure:$,configureLogfireApi:A,debug:j,DiagLogLevel:n,error:M,fatal:N,info:te,Level:T,log:P,logfireApiConfig:F,LogfireAttributeScrubber:E,NoopAttributeScrubber:D,notice:I,reportError:L,resolveBaseUrl:R,resolveSendToLogfire:z,serializeAttributes:B,span:V,startSpan:H,trace:U,ULIDGenerator:k,warning:W};export{t as DiagLogLevel,$ as configure,re as default};
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};
package/package.json CHANGED
@@ -25,7 +25,7 @@
25
25
  "stats",
26
26
  "monitoring"
27
27
  ],
28
- "version": "0.15.2",
28
+ "version": "0.16.0",
29
29
  "type": "module",
30
30
  "main": "./dist/index.cjs",
31
31
  "module": "./dist/index.js",
@@ -48,7 +48,7 @@
48
48
  "@opentelemetry/exporter-trace-otlp-http": ">=0.217.0 <0.300.0",
49
49
  "@opentelemetry/instrumentation": ">=0.217.0 <0.300.0",
50
50
  "@opentelemetry/resources": "^2.7.1",
51
- "logfire": "0.15.2"
51
+ "logfire": "0.17.0"
52
52
  },
53
53
  "peerDependencies": {
54
54
  "@opentelemetry/sdk-trace-web": "^2.7.1",