@sentry/effect 10.50.0-alpha.0 → 10.51.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
@@ -6,11 +6,16 @@
6
6
 
7
7
  > NOTICE: This package is in alpha state and may be subject to breaking changes.
8
8
 
9
+ `@sentry/effect` supports both Effect v3 and Effect v4 (beta). The integration
10
+ auto-detects the installed Effect version at runtime, but the layer composition
11
+ APIs differ between the two major versions, so the setup code is slightly
12
+ different.
13
+
9
14
  ## Getting Started
10
15
 
11
16
  This SDK does not have docs yet. Stay tuned.
12
17
 
13
- ## Usage
18
+ ## Usage with Effect v3
14
19
 
15
20
  ```typescript
16
21
  import * as Sentry from '@sentry/effect/server';
@@ -33,16 +38,45 @@ const MainLive = HttpLive.pipe(Layer.provide(SentryLive));
33
38
  MainLive.pipe(Layer.launch, NodeRuntime.runMain);
34
39
  ```
35
40
 
36
- The `effectLayer` function initializes Sentry. To enable Effect instrumentation, compose with:
41
+ ## Usage with Effect v4
37
42
 
38
- - `Layer.setTracer(Sentry.SentryEffectTracer)` - Effect spans traced as Sentry spans
39
- - `Logger.replace(Logger.defaultLogger, Sentry.SentryEffectLogger)` - Effect logs forwarded to Sentry
40
- - `Sentry.SentryEffectMetricsLayer` - Effect metrics sent to Sentry
43
+ Effect v4 reorganized the `Tracer` and `Logger` layer APIs, so the wiring looks
44
+ slightly different. The `effectLayer`, `SentryEffectTracer`,
45
+ `SentryEffectLogger`, and `SentryEffectMetricsLayer` exports themselves are the
46
+ same.
41
47
 
42
- ## Links
48
+ ```typescript
49
+ import * as Sentry from '@sentry/effect/server';
50
+ import { NodeHttpServer, NodeRuntime } from '@effect/platform-node';
51
+ import * as Layer from 'effect/Layer';
52
+ import * as Logger from 'effect/Logger';
53
+ import * as Tracer from 'effect/Tracer';
54
+ import { HttpRouter } from 'effect/unstable/http';
55
+ import { createServer } from 'http';
56
+ import { Routes } from './Routes.js';
57
+
58
+ const SentryLive = Layer.mergeAll(
59
+ Sentry.effectLayer({
60
+ dsn: '__DSN__',
61
+ tracesSampleRate: 1.0,
62
+ enableLogs: true,
63
+ }),
64
+ Layer.succeed(Tracer.Tracer, Sentry.SentryEffectTracer),
65
+ Logger.layer([Sentry.SentryEffectLogger]),
66
+ Sentry.SentryEffectMetricsLayer,
67
+ );
43
68
 
44
- <!-- - [Official SDK Docs](https://docs.sentry.io/platforms/javascript/guides/effect/) -->
69
+ const HttpLive = HttpRouter.serve(Routes).pipe(
70
+ Layer.provide(NodeHttpServer.layer(() => createServer(), { port: 3030 })),
71
+ Layer.provide(SentryLive),
72
+ );
73
+
74
+ NodeRuntime.runMain(Layer.launch(HttpLive));
75
+ ```
76
+
77
+ ## Links
45
78
 
79
+ - [Official SDK Docs](https://docs.sentry.io/platforms/javascript/guides/effect/)
46
80
  - [Sentry.io](https://sentry.io/?utm_source=github&utm_medium=npm_effect)
47
81
  - [Sentry Discord Server](https://discord.gg/Ww9hbqr)
48
82
  - [Stack Overflow](https://stackoverflow.com/questions/tagged/sentry)
@@ -3,6 +3,20 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3
3
  const core = require('@sentry/core');
4
4
  const Logger = require('effect/Logger');
5
5
 
6
+ function getLogLevelTag(logLevel) {
7
+ // Effect v4: logLevel is a string literal directly
8
+ if (typeof logLevel === 'string') {
9
+ return logLevel;
10
+ }
11
+
12
+ // Effect v3: logLevel has _tag property
13
+ if (logLevel && typeof logLevel === 'object' && '_tag' in logLevel) {
14
+ return (logLevel )._tag;
15
+ }
16
+
17
+ return 'Info';
18
+ }
19
+
6
20
  /**
7
21
  * Effect Logger that sends logs to Sentry.
8
22
  */
@@ -17,14 +31,17 @@ const SentryEffectLogger = Logger.make(({ logLevel, message }) => {
17
31
  msg = JSON.stringify(message);
18
32
  }
19
33
 
20
- switch (logLevel._tag) {
34
+ const tag = getLogLevelTag(logLevel);
35
+
36
+ switch (tag) {
21
37
  case 'Fatal':
22
38
  core.logger.fatal(msg);
23
39
  break;
24
40
  case 'Error':
25
41
  core.logger.error(msg);
26
42
  break;
27
- case 'Warning':
43
+ case 'Warning': // Effect v3
44
+ case 'Warn': // Effect v4
28
45
  core.logger.warn(msg);
29
46
  break;
30
47
  case 'Info':
@@ -1 +1 @@
1
- {"version":3,"file":"logger.js","sources":["../../src/logger.ts"],"sourcesContent":["import { logger as sentryLogger } from '@sentry/core';\nimport * as Logger from 'effect/Logger';\n\n/**\n * Effect Logger that sends logs to Sentry.\n */\nexport const SentryEffectLogger = Logger.make(({ logLevel, message }) => {\n let msg: string;\n if (typeof message === 'string') {\n msg = message;\n } else if (Array.isArray(message) && message.length === 1) {\n const firstElement = message[0];\n msg = typeof firstElement === 'string' ? firstElement : JSON.stringify(firstElement);\n } else {\n msg = JSON.stringify(message);\n }\n\n switch (logLevel._tag) {\n case 'Fatal':\n sentryLogger.fatal(msg);\n break;\n case 'Error':\n sentryLogger.error(msg);\n break;\n case 'Warning':\n sentryLogger.warn(msg);\n break;\n case 'Info':\n sentryLogger.info(msg);\n break;\n case 'Debug':\n sentryLogger.debug(msg);\n break;\n case 'Trace':\n sentryLogger.trace(msg);\n break;\n case 'All':\n case 'None':\n break;\n default:\n logLevel satisfies never;\n }\n});\n"],"names":["sentryLogger"],"mappings":";;;;;AAGA;AACA;AACA;AACO,MAAM,kBAAA,GAAqB,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAA,EAAS,KAAK;AACzE,EAAE,IAAI,GAAG;AACT,EAAE,IAAI,OAAO,OAAA,KAAY,QAAQ,EAAE;AACnC,IAAI,GAAA,GAAM,OAAO;AACjB,EAAE,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAA,IAAK,OAAO,CAAC,MAAA,KAAW,CAAC,EAAE;AAC7D,IAAI,MAAM,YAAA,GAAe,OAAO,CAAC,CAAC,CAAC;AACnC,IAAI,GAAA,GAAM,OAAO,YAAA,KAAiB,QAAA,GAAW,YAAA,GAAe,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC;AACxF,EAAE,OAAO;AACT,IAAI,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;AACjC,EAAE;;AAEF,EAAE,QAAQ,QAAQ,CAAC,IAAI;AACvB,IAAI,KAAK,OAAO;AAChB,MAAMA,WAAY,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7B,MAAM;AACN,IAAI,KAAK,OAAO;AAChB,MAAMA,WAAY,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7B,MAAM;AACN,IAAI,KAAK,SAAS;AAClB,MAAMA,WAAY,CAAC,IAAI,CAAC,GAAG,CAAC;AAC5B,MAAM;AACN,IAAI,KAAK,MAAM;AACf,MAAMA,WAAY,CAAC,IAAI,CAAC,GAAG,CAAC;AAC5B,MAAM;AACN,IAAI,KAAK,OAAO;AAChB,MAAMA,WAAY,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7B,MAAM;AACN,IAAI,KAAK,OAAO;AAChB,MAAMA,WAAY,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7B,MAAM;AAMN;AACA,CAAC;;;;"}
1
+ {"version":3,"file":"logger.js","sources":["../../src/logger.ts"],"sourcesContent":["import { logger as sentryLogger } from '@sentry/core';\nimport * as Logger from 'effect/Logger';\nimport type * as LogLevel from 'effect/LogLevel';\n\nfunction getLogLevelTag(logLevel: LogLevel.LogLevel): LogLevel.LogLevel | 'Warning' {\n // Effect v4: logLevel is a string literal directly\n if (typeof logLevel === 'string') {\n return logLevel;\n }\n\n // Effect v3: logLevel has _tag property\n if (logLevel && typeof logLevel === 'object' && '_tag' in logLevel) {\n return (logLevel as { _tag: LogLevel.LogLevel })._tag;\n }\n\n return 'Info';\n}\n\n/**\n * Effect Logger that sends logs to Sentry.\n */\nexport const SentryEffectLogger = Logger.make(({ logLevel, message }) => {\n let msg: string;\n if (typeof message === 'string') {\n msg = message;\n } else if (Array.isArray(message) && message.length === 1) {\n const firstElement = message[0];\n msg = typeof firstElement === 'string' ? firstElement : JSON.stringify(firstElement);\n } else {\n msg = JSON.stringify(message);\n }\n\n const tag = getLogLevelTag(logLevel);\n\n switch (tag) {\n case 'Fatal':\n sentryLogger.fatal(msg);\n break;\n case 'Error':\n sentryLogger.error(msg);\n break;\n case 'Warning': // Effect v3\n case 'Warn': // Effect v4\n sentryLogger.warn(msg);\n break;\n case 'Info':\n sentryLogger.info(msg);\n break;\n case 'Debug':\n sentryLogger.debug(msg);\n break;\n case 'Trace':\n sentryLogger.trace(msg);\n break;\n case 'All':\n case 'None':\n break;\n default:\n tag satisfies never;\n }\n});\n"],"names":["sentryLogger"],"mappings":";;;;;AAIA,SAAS,cAAc,CAAC,QAAQ,EAAoD;AACpF;AACA,EAAE,IAAI,OAAO,QAAA,KAAa,QAAQ,EAAE;AACpC,IAAI,OAAO,QAAQ;AACnB,EAAE;;AAEF;AACA,EAAE,IAAI,QAAA,IAAY,OAAO,QAAA,KAAa,QAAA,IAAY,MAAA,IAAU,QAAQ,EAAE;AACtE,IAAI,OAAO,CAAC,QAAA,GAAyC,IAAI;AACzD,EAAE;;AAEF,EAAE,OAAO,MAAM;AACf;;AAEA;AACA;AACA;AACO,MAAM,kBAAA,GAAqB,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAA,EAAS,KAAK;AACzE,EAAE,IAAI,GAAG;AACT,EAAE,IAAI,OAAO,OAAA,KAAY,QAAQ,EAAE;AACnC,IAAI,GAAA,GAAM,OAAO;AACjB,EAAE,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAA,IAAK,OAAO,CAAC,MAAA,KAAW,CAAC,EAAE;AAC7D,IAAI,MAAM,YAAA,GAAe,OAAO,CAAC,CAAC,CAAC;AACnC,IAAI,GAAA,GAAM,OAAO,YAAA,KAAiB,QAAA,GAAW,YAAA,GAAe,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC;AACxF,EAAE,OAAO;AACT,IAAI,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;AACjC,EAAE;;AAEF,EAAE,MAAM,GAAA,GAAM,cAAc,CAAC,QAAQ,CAAC;;AAEtC,EAAE,QAAQ,GAAG;AACb,IAAI,KAAK,OAAO;AAChB,MAAMA,WAAY,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7B,MAAM;AACN,IAAI,KAAK,OAAO;AAChB,MAAMA,WAAY,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7B,MAAM;AACN,IAAI,KAAK,SAAS,CAAA;AAClB,IAAI,KAAK,MAAM;AACf,MAAMA,WAAY,CAAC,IAAI,CAAC,GAAG,CAAC;AAC5B,MAAM;AACN,IAAI,KAAK,MAAM;AACf,MAAMA,WAAY,CAAC,IAAI,CAAC,GAAG,CAAC;AAC5B,MAAM;AACN,IAAI,KAAK,OAAO;AAChB,MAAMA,WAAY,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7B,MAAM;AACN,IAAI,KAAK,OAAO;AAChB,MAAMA,WAAY,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7B,MAAM;AAMN;AACA,CAAC;;;;"}
@@ -1,39 +1,67 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
3
  const core = require('@sentry/core');
4
+ const Context = require('effect/Context');
4
5
  const Effect = require('effect/Effect');
5
6
  const Layer = require('effect/Layer');
6
7
  const Metric = require('effect/Metric');
7
- const MetricKeyType = require('effect/MetricKeyType');
8
- const MetricState = require('effect/MetricState');
9
8
  const Schedule = require('effect/Schedule');
10
9
 
10
+ // Effect v3 `MetricState` implementations brand themselves with a `Symbol.for(...)` TypeId
11
+ // rather than a string `_tag`. We use these globally-registered symbols to classify state
12
+ // instances returned by `Metric.unsafeSnapshot()` without importing `effect/MetricState`
13
+ // (the module does not exist in Effect v4).
14
+ const V3_COUNTER_STATE_TYPE_ID = Symbol.for('effect/MetricState/Counter');
15
+ const V3_GAUGE_STATE_TYPE_ID = Symbol.for('effect/MetricState/Gauge');
16
+ const V3_HISTOGRAM_STATE_TYPE_ID = Symbol.for('effect/MetricState/Histogram');
17
+ const V3_SUMMARY_STATE_TYPE_ID = Symbol.for('effect/MetricState/Summary');
18
+ const V3_FREQUENCY_STATE_TYPE_ID = Symbol.for('effect/MetricState/Frequency');
19
+
11
20
  function labelsToAttributes(labels) {
12
21
  return labels.reduce((acc, label) => ({ ...acc, [label.key]: label.value }), {});
13
22
  }
14
23
 
15
- function sendMetricToSentry(pair) {
24
+ function getMetricIdV3(pair) {
25
+ const tags = pair.metricKey.tags.map(t => `${t.key}=${t.value}`).join(',');
26
+ return `${pair.metricKey.name}:${tags}`;
27
+ }
28
+
29
+ function getMetricIdV4(snapshot) {
30
+ const attrs = snapshot.attributes
31
+ ? Object.entries(snapshot.attributes)
32
+ .map(([k, v]) => `${k}=${v}`)
33
+ .join(',')
34
+ : '';
35
+ return `${snapshot.id}:${attrs}`;
36
+ }
37
+
38
+ function sendV3MetricToSentry(pair, previousCounterValues) {
16
39
  const { metricKey, metricState } = pair;
17
40
  const name = metricKey.name;
18
41
  const attributes = labelsToAttributes(metricKey.tags);
42
+ const metricId = getMetricIdV3(pair);
43
+
44
+ const state = metricState ;
19
45
 
20
- if (MetricState.isCounterState(metricState)) {
21
- const value = Number(metricState.count);
22
- core.metrics.count(name, value, { attributes });
23
- } else if (MetricState.isGaugeState(metricState)) {
46
+ if (state[V3_COUNTER_STATE_TYPE_ID] !== undefined) {
47
+ const currentValue = Number(metricState.count);
48
+ const previousValue = previousCounterValues.get(metricId) ?? 0;
49
+ const delta = currentValue - previousValue;
50
+
51
+ if (delta > 0) {
52
+ core.metrics.count(name, delta, { attributes });
53
+ }
54
+
55
+ previousCounterValues.set(metricId, currentValue);
56
+ } else if (state[V3_GAUGE_STATE_TYPE_ID] !== undefined) {
24
57
  const value = Number(metricState.value);
25
58
  core.metrics.gauge(name, value, { attributes });
26
- } else if (MetricState.isHistogramState(metricState)) {
27
- core.metrics.gauge(`${name}.sum`, metricState.sum, { attributes });
28
- core.metrics.gauge(`${name}.count`, metricState.count, { attributes });
29
- core.metrics.gauge(`${name}.min`, metricState.min, { attributes });
30
- core.metrics.gauge(`${name}.max`, metricState.max, { attributes });
31
- } else if (MetricState.isSummaryState(metricState)) {
32
- core.metrics.gauge(`${name}.sum`, metricState.sum, { attributes });
33
- core.metrics.gauge(`${name}.count`, metricState.count, { attributes });
34
- core.metrics.gauge(`${name}.min`, metricState.min, { attributes });
35
- core.metrics.gauge(`${name}.max`, metricState.max, { attributes });
36
- } else if (MetricState.isFrequencyState(metricState)) {
59
+ } else if (state[V3_HISTOGRAM_STATE_TYPE_ID] !== undefined || state[V3_SUMMARY_STATE_TYPE_ID] !== undefined) {
60
+ core.metrics.gauge(`${name}.sum`, metricState.sum ?? 0, { attributes });
61
+ core.metrics.gauge(`${name}.count`, Number(metricState.count ?? 0), { attributes });
62
+ core.metrics.gauge(`${name}.min`, metricState.min ?? 0, { attributes });
63
+ core.metrics.gauge(`${name}.max`, metricState.max ?? 0, { attributes });
64
+ } else if (state[V3_FREQUENCY_STATE_TYPE_ID] !== undefined && metricState.occurrences) {
37
65
  for (const [word, count] of metricState.occurrences) {
38
66
  core.metrics.count(name, count, {
39
67
  attributes: { ...attributes, word },
@@ -42,50 +70,73 @@ function sendMetricToSentry(pair) {
42
70
  }
43
71
  }
44
72
 
45
- function getMetricId(pair) {
46
- const tags = pair.metricKey.tags.map(t => `${t.key}=${t.value}`).join(',');
47
- return `${pair.metricKey.name}:${tags}`;
48
- }
73
+ function sendV4MetricToSentry(snapshot, previousCounterValues) {
74
+ const name = snapshot.id;
75
+ const attributes = snapshot.attributes ? { ...snapshot.attributes } : {};
76
+ const metricId = getMetricIdV4(snapshot);
49
77
 
50
- function sendDeltaMetricToSentry(
51
- pair,
52
- previousCounterValues,
53
- ) {
54
- const { metricKey, metricState } = pair;
55
- const name = metricKey.name;
56
- const attributes = labelsToAttributes(metricKey.tags);
57
- const metricId = getMetricId(pair);
78
+ switch (snapshot.type) {
79
+ case 'Counter': {
80
+ const currentValue = Number(snapshot.state.count);
81
+ const previousValue = previousCounterValues.get(metricId) ?? 0;
82
+ const delta = currentValue - previousValue;
58
83
 
59
- if (MetricState.isCounterState(metricState)) {
60
- const currentValue = Number(metricState.count);
61
-
62
- const previousValue = previousCounterValues.get(metricId) ?? 0;
63
- const delta = currentValue - previousValue;
84
+ if (delta > 0) {
85
+ core.metrics.count(name, delta, { attributes });
86
+ }
64
87
 
65
- if (delta > 0) {
66
- core.metrics.count(name, delta, { attributes });
88
+ previousCounterValues.set(metricId, currentValue);
89
+ break;
90
+ }
91
+ case 'Gauge': {
92
+ const value = Number(snapshot.state.value);
93
+ core.metrics.gauge(name, value, { attributes });
94
+ break;
95
+ }
96
+ case 'Histogram':
97
+ case 'Summary': {
98
+ core.metrics.gauge(`${name}.sum`, snapshot.state.sum ?? 0, { attributes });
99
+ core.metrics.gauge(`${name}.count`, snapshot.state.count ?? 0, { attributes });
100
+ core.metrics.gauge(`${name}.min`, snapshot.state.min ?? 0, { attributes });
101
+ core.metrics.gauge(`${name}.max`, snapshot.state.max ?? 0, { attributes });
102
+ break;
103
+ }
104
+ case 'Frequency': {
105
+ for (const [word, count] of snapshot.state.occurrences) {
106
+ core.metrics.count(name, count, {
107
+ attributes: { ...attributes, word },
108
+ });
109
+ }
110
+ break;
67
111
  }
68
-
69
- previousCounterValues.set(metricId, currentValue);
70
- } else {
71
- sendMetricToSentry(pair);
72
112
  }
73
113
  }
74
114
 
75
- /**
76
- * Flushes all Effect metrics to Sentry.
77
- * @param previousCounterValues - Map tracking previous counter values for delta calculation
78
- */
79
- function flushMetricsToSentry(previousCounterValues) {
80
- const snapshot = Metric.unsafeSnapshot();
115
+ // =============================================================================
116
+ // Effect v3 snapshot function type (vendored - not exported from effect@3.x)
117
+ // =============================================================================
118
+
119
+ // Use bracket notation to avoid Webpack static analysis flagging missing exports
120
+ // This is important for Effect v3 compatibility.
121
+ const MetricModule = Metric;
122
+ const snapshotUnsafe = MetricModule['snapshotUnsafe'] ;
123
+ // @ts-expect-error - unsafeSnapshot is not exported from effect@3.x
124
+ const unsafeSnapshot = MetricModule['unsafeSnapshot'] ;
81
125
 
82
- snapshot.forEach((pair) => {
83
- if (MetricKeyType.isCounterKey(pair.metricKey.keyType)) {
84
- sendDeltaMetricToSentry(pair, previousCounterValues);
85
- } else {
86
- sendMetricToSentry(pair);
126
+ function flushMetricsToSentry(previousCounterValues) {
127
+ if (snapshotUnsafe) {
128
+ // Effect v4
129
+ const snapshots = snapshotUnsafe(Context.empty());
130
+ for (const snapshot of snapshots) {
131
+ sendV4MetricToSentry(snapshot, previousCounterValues);
87
132
  }
88
- });
133
+ } else if (unsafeSnapshot) {
134
+ // Effect v3
135
+ const snapshots = unsafeSnapshot();
136
+ for (const pair of snapshots) {
137
+ sendV3MetricToSentry(pair, previousCounterValues);
138
+ }
139
+ }
89
140
  }
90
141
 
91
142
  function createMetricsReporterEffect(previousCounterValues) {
@@ -102,7 +153,7 @@ function createMetricsReporterEffect(previousCounterValues) {
102
153
  * The layer manages its own state for delta counter calculations,
103
154
  * which is automatically cleaned up when the layer is finalized.
104
155
  */
105
- const SentryEffectMetricsLayer = Layer.scopedDiscard(
156
+ const SentryEffectMetricsLayer = Layer.effectDiscard(
106
157
  Effect.gen(function* () {
107
158
  const previousCounterValues = new Map();
108
159
 
@@ -1 +1 @@
1
- {"version":3,"file":"metrics.js","sources":["../../src/metrics.ts"],"sourcesContent":["import { metrics as sentryMetrics } from '@sentry/core';\nimport * as Effect from 'effect/Effect';\nimport type * as Layer from 'effect/Layer';\nimport { scopedDiscard } from 'effect/Layer';\nimport * as Metric from 'effect/Metric';\nimport * as MetricKeyType from 'effect/MetricKeyType';\nimport type * as MetricPair from 'effect/MetricPair';\nimport * as MetricState from 'effect/MetricState';\nimport * as Schedule from 'effect/Schedule';\n\ntype MetricAttributes = Record<string, string>;\n\nfunction labelsToAttributes(labels: ReadonlyArray<{ key: string; value: string }>): MetricAttributes {\n return labels.reduce((acc, label) => ({ ...acc, [label.key]: label.value }), {});\n}\n\nfunction sendMetricToSentry(pair: MetricPair.MetricPair.Untyped): void {\n const { metricKey, metricState } = pair;\n const name = metricKey.name;\n const attributes = labelsToAttributes(metricKey.tags);\n\n if (MetricState.isCounterState(metricState)) {\n const value = Number(metricState.count);\n sentryMetrics.count(name, value, { attributes });\n } else if (MetricState.isGaugeState(metricState)) {\n const value = Number(metricState.value);\n sentryMetrics.gauge(name, value, { attributes });\n } else if (MetricState.isHistogramState(metricState)) {\n sentryMetrics.gauge(`${name}.sum`, metricState.sum, { attributes });\n sentryMetrics.gauge(`${name}.count`, metricState.count, { attributes });\n sentryMetrics.gauge(`${name}.min`, metricState.min, { attributes });\n sentryMetrics.gauge(`${name}.max`, metricState.max, { attributes });\n } else if (MetricState.isSummaryState(metricState)) {\n sentryMetrics.gauge(`${name}.sum`, metricState.sum, { attributes });\n sentryMetrics.gauge(`${name}.count`, metricState.count, { attributes });\n sentryMetrics.gauge(`${name}.min`, metricState.min, { attributes });\n sentryMetrics.gauge(`${name}.max`, metricState.max, { attributes });\n } else if (MetricState.isFrequencyState(metricState)) {\n for (const [word, count] of metricState.occurrences) {\n sentryMetrics.count(name, count, {\n attributes: { ...attributes, word },\n });\n }\n }\n}\n\nfunction getMetricId(pair: MetricPair.MetricPair.Untyped): string {\n const tags = pair.metricKey.tags.map(t => `${t.key}=${t.value}`).join(',');\n return `${pair.metricKey.name}:${tags}`;\n}\n\nfunction sendDeltaMetricToSentry(\n pair: MetricPair.MetricPair.Untyped,\n previousCounterValues: Map<string, number>,\n): void {\n const { metricKey, metricState } = pair;\n const name = metricKey.name;\n const attributes = labelsToAttributes(metricKey.tags);\n const metricId = getMetricId(pair);\n\n if (MetricState.isCounterState(metricState)) {\n const currentValue = Number(metricState.count);\n\n const previousValue = previousCounterValues.get(metricId) ?? 0;\n const delta = currentValue - previousValue;\n\n if (delta > 0) {\n sentryMetrics.count(name, delta, { attributes });\n }\n\n previousCounterValues.set(metricId, currentValue);\n } else {\n sendMetricToSentry(pair);\n }\n}\n\n/**\n * Flushes all Effect metrics to Sentry.\n * @param previousCounterValues - Map tracking previous counter values for delta calculation\n */\nfunction flushMetricsToSentry(previousCounterValues: Map<string, number>): void {\n const snapshot = Metric.unsafeSnapshot();\n\n snapshot.forEach((pair: MetricPair.MetricPair.Untyped) => {\n if (MetricKeyType.isCounterKey(pair.metricKey.keyType)) {\n sendDeltaMetricToSentry(pair, previousCounterValues);\n } else {\n sendMetricToSentry(pair);\n }\n });\n}\n\n/**\n * Creates a metrics flusher with its own isolated state for delta tracking.\n * Useful for testing scenarios where you need to control the lifecycle.\n * @internal\n */\nexport function createMetricsFlusher(): {\n flush: () => void;\n clear: () => void;\n} {\n const previousCounterValues = new Map<string, number>();\n return {\n flush: () => flushMetricsToSentry(previousCounterValues),\n clear: () => previousCounterValues.clear(),\n };\n}\n\nfunction createMetricsReporterEffect(previousCounterValues: Map<string, number>): Effect.Effect<void, never, never> {\n const schedule = Schedule.spaced('10 seconds');\n\n return Effect.repeat(\n Effect.sync(() => flushMetricsToSentry(previousCounterValues)),\n schedule,\n ).pipe(Effect.asVoid, Effect.interruptible);\n}\n\n/**\n * Effect Layer that periodically flushes metrics to Sentry.\n * The layer manages its own state for delta counter calculations,\n * which is automatically cleaned up when the layer is finalized.\n */\nexport const SentryEffectMetricsLayer: Layer.Layer<never, never, never> = scopedDiscard(\n Effect.gen(function* () {\n const previousCounterValues = new Map<string, number>();\n\n yield* Effect.acquireRelease(Effect.void, () =>\n Effect.sync(() => {\n previousCounterValues.clear();\n }),\n );\n\n yield* Effect.forkScoped(createMetricsReporterEffect(previousCounterValues));\n }),\n);\n"],"names":["sentryMetrics","scopedDiscard"],"mappings":"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"}
1
+ {"version":3,"file":"metrics.js","sources":["../../src/metrics.ts"],"sourcesContent":["import { metrics as sentryMetrics } from '@sentry/core';\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\nimport * as Metric from 'effect/Metric';\nimport * as Schedule from 'effect/Schedule';\n\ntype MetricAttributes = Record<string, string>;\n\n// =============================================================================\n// Effect v3 Types (vendored - not exported from effect@3.x)\n// =============================================================================\n\ninterface V3MetricLabel {\n key: string;\n value: string;\n}\n\ninterface V3MetricPair {\n metricKey: {\n name: string;\n tags: ReadonlyArray<V3MetricLabel>;\n keyType: { _tag: string };\n };\n metricState: {\n count?: number | bigint;\n value?: number;\n sum?: number;\n min?: number;\n max?: number;\n occurrences?: Map<string, number>;\n };\n}\n\n// Effect v3 `MetricState` implementations brand themselves with a `Symbol.for(...)` TypeId\n// rather than a string `_tag`. We use these globally-registered symbols to classify state\n// instances returned by `Metric.unsafeSnapshot()` without importing `effect/MetricState`\n// (the module does not exist in Effect v4).\nconst V3_COUNTER_STATE_TYPE_ID = Symbol.for('effect/MetricState/Counter');\nconst V3_GAUGE_STATE_TYPE_ID = Symbol.for('effect/MetricState/Gauge');\nconst V3_HISTOGRAM_STATE_TYPE_ID = Symbol.for('effect/MetricState/Histogram');\nconst V3_SUMMARY_STATE_TYPE_ID = Symbol.for('effect/MetricState/Summary');\nconst V3_FREQUENCY_STATE_TYPE_ID = Symbol.for('effect/MetricState/Frequency');\n\nfunction labelsToAttributes(labels: ReadonlyArray<V3MetricLabel>): MetricAttributes {\n return labels.reduce((acc, label) => ({ ...acc, [label.key]: label.value }), {});\n}\n\nfunction getMetricIdV3(pair: V3MetricPair): string {\n const tags = pair.metricKey.tags.map(t => `${t.key}=${t.value}`).join(',');\n return `${pair.metricKey.name}:${tags}`;\n}\n\nfunction getMetricIdV4(snapshot: Metric.Metric.Snapshot): string {\n const attrs = snapshot.attributes\n ? Object.entries(snapshot.attributes)\n .map(([k, v]) => `${k}=${v}`)\n .join(',')\n : '';\n return `${snapshot.id}:${attrs}`;\n}\n\nfunction sendV3MetricToSentry(pair: V3MetricPair, previousCounterValues: Map<string, number>): void {\n const { metricKey, metricState } = pair;\n const name = metricKey.name;\n const attributes = labelsToAttributes(metricKey.tags);\n const metricId = getMetricIdV3(pair);\n\n const state = metricState as unknown as Record<symbol, unknown>;\n\n if (state[V3_COUNTER_STATE_TYPE_ID] !== undefined) {\n const currentValue = Number(metricState.count);\n const previousValue = previousCounterValues.get(metricId) ?? 0;\n const delta = currentValue - previousValue;\n\n if (delta > 0) {\n sentryMetrics.count(name, delta, { attributes });\n }\n\n previousCounterValues.set(metricId, currentValue);\n } else if (state[V3_GAUGE_STATE_TYPE_ID] !== undefined) {\n const value = Number(metricState.value);\n sentryMetrics.gauge(name, value, { attributes });\n } else if (state[V3_HISTOGRAM_STATE_TYPE_ID] !== undefined || state[V3_SUMMARY_STATE_TYPE_ID] !== undefined) {\n sentryMetrics.gauge(`${name}.sum`, metricState.sum ?? 0, { attributes });\n sentryMetrics.gauge(`${name}.count`, Number(metricState.count ?? 0), { attributes });\n sentryMetrics.gauge(`${name}.min`, metricState.min ?? 0, { attributes });\n sentryMetrics.gauge(`${name}.max`, metricState.max ?? 0, { attributes });\n } else if (state[V3_FREQUENCY_STATE_TYPE_ID] !== undefined && metricState.occurrences) {\n for (const [word, count] of metricState.occurrences) {\n sentryMetrics.count(name, count, {\n attributes: { ...attributes, word },\n });\n }\n }\n}\n\nfunction sendV4MetricToSentry(snapshot: Metric.Metric.Snapshot, previousCounterValues: Map<string, number>): void {\n const name = snapshot.id;\n const attributes: MetricAttributes = snapshot.attributes ? { ...snapshot.attributes } : {};\n const metricId = getMetricIdV4(snapshot);\n\n switch (snapshot.type) {\n case 'Counter': {\n const currentValue = Number(snapshot.state.count);\n const previousValue = previousCounterValues.get(metricId) ?? 0;\n const delta = currentValue - previousValue;\n\n if (delta > 0) {\n sentryMetrics.count(name, delta, { attributes });\n }\n\n previousCounterValues.set(metricId, currentValue);\n break;\n }\n case 'Gauge': {\n const value = Number(snapshot.state.value);\n sentryMetrics.gauge(name, value, { attributes });\n break;\n }\n case 'Histogram':\n case 'Summary': {\n sentryMetrics.gauge(`${name}.sum`, snapshot.state.sum ?? 0, { attributes });\n sentryMetrics.gauge(`${name}.count`, snapshot.state.count ?? 0, { attributes });\n sentryMetrics.gauge(`${name}.min`, snapshot.state.min ?? 0, { attributes });\n sentryMetrics.gauge(`${name}.max`, snapshot.state.max ?? 0, { attributes });\n break;\n }\n case 'Frequency': {\n for (const [word, count] of snapshot.state.occurrences) {\n sentryMetrics.count(name, count, {\n attributes: { ...attributes, word },\n });\n }\n break;\n }\n }\n}\n\n// =============================================================================\n// Effect v3 snapshot function type (vendored - not exported from effect@3.x)\n// =============================================================================\n\ntype V3UnsafeSnapshotFn = () => ReadonlyArray<V3MetricPair>;\n\n// Use bracket notation to avoid Webpack static analysis flagging missing exports\n// This is important for Effect v3 compatibility.\nconst MetricModule = Metric;\nconst snapshotUnsafe = MetricModule['snapshotUnsafe'] as typeof Metric.snapshotUnsafe | undefined;\n// @ts-expect-error - unsafeSnapshot is not exported from effect@3.x\nconst unsafeSnapshot = MetricModule['unsafeSnapshot'] as V3UnsafeSnapshotFn | undefined;\n\nfunction flushMetricsToSentry(previousCounterValues: Map<string, number>): void {\n if (snapshotUnsafe) {\n // Effect v4\n const snapshots = snapshotUnsafe(Context.empty());\n for (const snapshot of snapshots) {\n sendV4MetricToSentry(snapshot, previousCounterValues);\n }\n } else if (unsafeSnapshot) {\n // Effect v3\n const snapshots = unsafeSnapshot();\n for (const pair of snapshots) {\n sendV3MetricToSentry(pair, previousCounterValues);\n }\n }\n}\n\nfunction createMetricsReporterEffect(previousCounterValues: Map<string, number>): Effect.Effect<void, never, never> {\n const schedule = Schedule.spaced('10 seconds');\n\n return Effect.repeat(\n Effect.sync(() => flushMetricsToSentry(previousCounterValues)),\n schedule,\n ).pipe(Effect.asVoid, Effect.interruptible);\n}\n\n/**\n * Effect Layer that periodically flushes metrics to Sentry.\n * The layer manages its own state for delta counter calculations,\n * which is automatically cleaned up when the layer is finalized.\n */\nexport const SentryEffectMetricsLayer: Layer.Layer<never, never, never> = Layer.effectDiscard(\n Effect.gen(function* () {\n const previousCounterValues = new Map<string, number>();\n\n yield* Effect.acquireRelease(Effect.void, () =>\n Effect.sync(() => {\n previousCounterValues.clear();\n }),\n );\n\n yield* Effect.forkScoped(createMetricsReporterEffect(previousCounterValues));\n }),\n);\n"],"names":["sentryMetrics"],"mappings":"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"}
@@ -25,6 +25,46 @@ function isSentrySpan(span) {
25
25
  return SENTRY_SPAN_SYMBOL in span;
26
26
  }
27
27
 
28
+ function getErrorMessage(exit) {
29
+ if (!Exit.isFailure(exit)) {
30
+ return undefined;
31
+ }
32
+
33
+ const cause = exit.cause ;
34
+
35
+ // Effect v4: cause.reasons is an array of Reason objects
36
+ if (
37
+ cause &&
38
+ typeof cause === 'object' &&
39
+ 'reasons' in cause &&
40
+ Array.isArray((cause ).reasons)
41
+ ) {
42
+ const reasons = (cause ).reasons;
43
+ for (const reason of reasons) {
44
+ if (reason._tag === 'Fail' && reason.error !== undefined) {
45
+ return String(reason.error);
46
+ }
47
+ if (reason._tag === 'Die' && reason.defect !== undefined) {
48
+ return String(reason.defect);
49
+ }
50
+ }
51
+ return 'internal_error';
52
+ }
53
+
54
+ // Effect v3: cause has _tag directly
55
+ if (cause && typeof cause === 'object' && '_tag' in cause) {
56
+ const v3Cause = cause ;
57
+ if (v3Cause._tag === 'Fail') {
58
+ return String(v3Cause.error);
59
+ }
60
+ if (v3Cause._tag === 'Die') {
61
+ return String(v3Cause.defect);
62
+ }
63
+ }
64
+
65
+ return 'internal_error';
66
+ }
67
+
28
68
  class SentrySpanWrapper {
29
69
 
30
70
  constructor(
@@ -42,6 +82,7 @@ class SentrySpanWrapper {
42
82
  this.parent = parent;
43
83
  this.links = [...links];
44
84
  this.sentrySpan = existingSpan;
85
+ this.annotations = context;
45
86
 
46
87
  const spanContext = this.sentrySpan.spanContext();
47
88
  this.spanId = spanContext.spanId;
@@ -79,9 +120,7 @@ class SentrySpanWrapper {
79
120
  }
80
121
 
81
122
  if (Exit.isFailure(exit)) {
82
- const cause = exit.cause;
83
- const message =
84
- cause._tag === 'Fail' ? String(cause.error) : cause._tag === 'Die' ? String(cause.defect) : 'internal_error';
123
+ const message = getErrorMessage(exit) ?? 'internal_error';
85
124
  this.sentrySpan.setStatus({ code: 2, message });
86
125
  } else {
87
126
  this.sentrySpan.setStatus({ code: 1 });
@@ -122,9 +161,34 @@ function createSentrySpan(
122
161
  return new SentrySpanWrapper(name, parent, context, links, startTime, kind, newSpan);
123
162
  }
124
163
 
125
- const makeSentryTracer = () =>
126
- EffectTracer.make({
127
- span(name, parent, context, links, startTime, kind) {
164
+ // Check if we're running Effect v4 by checking the Exit/Cause structure
165
+ // In v4, causes have a 'reasons' array
166
+ // In v3, causes have '_tag' directly on the cause object
167
+ const isEffectV4 = (() => {
168
+ try {
169
+ const testExit = Exit.fail('test') ;
170
+ const cause = testExit.cause;
171
+ // v4 causes have 'reasons' array, v3 causes have '_tag' directly
172
+ if (cause && typeof cause === 'object' && 'reasons' in cause) {
173
+ return true;
174
+ }
175
+ return false;
176
+ } catch {
177
+ return false;
178
+ }
179
+ })();
180
+
181
+ const makeSentryTracerV3 = () => {
182
+ // Effect v3 API: span(name, parent, context, links, startTime, kind)
183
+ return EffectTracer.make({
184
+ span(
185
+ name,
186
+ parent,
187
+ context,
188
+ links,
189
+ startTime,
190
+ kind,
191
+ ) {
128
192
  return createSentrySpan(name, parent, context, links, startTime, kind);
129
193
  },
130
194
  context(execution, fiber) {
@@ -134,12 +198,37 @@ const makeSentryTracer = () =>
134
198
  }
135
199
  return core.withActiveSpan(currentSpan.sentrySpan, execution);
136
200
  },
201
+ } );
202
+ };
203
+
204
+ const makeSentryTracerV4 = () => {
205
+ const EFFECT_EVALUATE = '~effect/Effect/evaluate' ;
206
+
207
+ return EffectTracer.make({
208
+ span(options) {
209
+ return createSentrySpan(
210
+ options.name,
211
+ options.parent,
212
+ options.annotations,
213
+ options.links,
214
+ options.startTime,
215
+ options.kind,
216
+ );
217
+ },
218
+ context(primitive, fiber) {
219
+ const currentSpan = fiber.currentSpan;
220
+ if (currentSpan === undefined || !isSentrySpan(currentSpan)) {
221
+ return primitive[EFFECT_EVALUATE](fiber);
222
+ }
223
+ return core.withActiveSpan(currentSpan.sentrySpan, () => primitive[EFFECT_EVALUATE](fiber));
224
+ },
137
225
  });
226
+ };
138
227
 
139
228
  /**
140
229
  * Effect Layer that sets up the Sentry tracer for Effect spans.
141
230
  */
142
- const SentryEffectTracer = makeSentryTracer();
231
+ const SentryEffectTracer = isEffectV4 ? makeSentryTracerV4() : makeSentryTracerV3();
143
232
 
144
233
  exports.SentryEffectTracer = SentryEffectTracer;
145
234
  //# sourceMappingURL=tracer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tracer.js","sources":["../../src/tracer.ts"],"sourcesContent":["import type { Span } from '@sentry/core';\nimport { getActiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startInactiveSpan, withActiveSpan } from '@sentry/core';\nimport type * as Context from 'effect/Context';\nimport * as Exit from 'effect/Exit';\nimport * as Option from 'effect/Option';\nimport * as EffectTracer from 'effect/Tracer';\n\nfunction deriveOrigin(name: string): string {\n if (name.startsWith('http.server') || name.startsWith('http.client')) {\n return 'auto.http.effect';\n }\n\n return 'auto.function.effect';\n}\n\ntype HrTime = [number, number];\n\nconst SENTRY_SPAN_SYMBOL = Symbol.for('@sentry/effect.SentrySpan');\n\nfunction nanosToHrTime(nanos: bigint): HrTime {\n const seconds = Number(nanos / BigInt(1_000_000_000));\n const remainingNanos = Number(nanos % BigInt(1_000_000_000));\n return [seconds, remainingNanos];\n}\n\ninterface SentrySpanLike extends EffectTracer.Span {\n readonly [SENTRY_SPAN_SYMBOL]: true;\n readonly sentrySpan: Span;\n}\n\nfunction isSentrySpan(span: EffectTracer.AnySpan): span is SentrySpanLike {\n return SENTRY_SPAN_SYMBOL in span;\n}\n\nclass SentrySpanWrapper implements SentrySpanLike {\n public readonly [SENTRY_SPAN_SYMBOL]: true;\n public readonly _tag: 'Span';\n public readonly spanId: string;\n public readonly traceId: string;\n public readonly attributes: Map<string, unknown>;\n public readonly sampled: boolean;\n public readonly parent: Option.Option<EffectTracer.AnySpan>;\n public readonly links: Array<EffectTracer.SpanLink>;\n public status: EffectTracer.SpanStatus;\n public readonly sentrySpan: Span;\n\n public constructor(\n public readonly name: string,\n parent: Option.Option<EffectTracer.AnySpan>,\n public readonly context: Context.Context<never>,\n links: ReadonlyArray<EffectTracer.SpanLink>,\n startTime: bigint,\n public readonly kind: EffectTracer.SpanKind,\n existingSpan: Span,\n ) {\n this[SENTRY_SPAN_SYMBOL] = true as const;\n this._tag = 'Span' as const;\n this.attributes = new Map<string, unknown>();\n this.parent = parent;\n this.links = [...links];\n this.sentrySpan = existingSpan;\n\n const spanContext = this.sentrySpan.spanContext();\n this.spanId = spanContext.spanId;\n this.traceId = spanContext.traceId;\n this.sampled = this.sentrySpan.isRecording();\n this.status = {\n _tag: 'Started',\n startTime,\n };\n }\n\n public attribute(key: string, value: unknown): void {\n if (!this.sentrySpan.isRecording()) {\n return;\n }\n\n this.sentrySpan.setAttribute(key, value as Parameters<Span['setAttribute']>[1]);\n this.attributes.set(key, value);\n }\n\n public addLinks(links: ReadonlyArray<EffectTracer.SpanLink>): void {\n this.links.push(...links);\n }\n\n public end(endTime: bigint, exit: Exit.Exit<unknown, unknown>): void {\n this.status = {\n _tag: 'Ended',\n endTime,\n exit,\n startTime: this.status.startTime,\n };\n\n if (!this.sentrySpan.isRecording()) {\n return;\n }\n\n if (Exit.isFailure(exit)) {\n const cause = exit.cause;\n const message =\n cause._tag === 'Fail' ? String(cause.error) : cause._tag === 'Die' ? String(cause.defect) : 'internal_error';\n this.sentrySpan.setStatus({ code: 2, message });\n } else {\n this.sentrySpan.setStatus({ code: 1 });\n }\n\n this.sentrySpan.end(nanosToHrTime(endTime));\n }\n\n public event(name: string, startTime: bigint, attributes?: Record<string, unknown>): void {\n if (!this.sentrySpan.isRecording()) {\n return;\n }\n\n this.sentrySpan.addEvent(name, attributes as Parameters<Span['addEvent']>[1], nanosToHrTime(startTime));\n }\n}\n\nfunction createSentrySpan(\n name: string,\n parent: Option.Option<EffectTracer.AnySpan>,\n context: Context.Context<never>,\n links: ReadonlyArray<EffectTracer.SpanLink>,\n startTime: bigint,\n kind: EffectTracer.SpanKind,\n): SentrySpanLike {\n const parentSentrySpan =\n Option.isSome(parent) && isSentrySpan(parent.value) ? parent.value.sentrySpan : (getActiveSpan() ?? null);\n\n const newSpan = startInactiveSpan({\n name,\n startTime: nanosToHrTime(startTime),\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: deriveOrigin(name),\n },\n ...(parentSentrySpan ? { parentSpan: parentSentrySpan } : {}),\n });\n\n return new SentrySpanWrapper(name, parent, context, links, startTime, kind, newSpan);\n}\n\nconst makeSentryTracer = (): EffectTracer.Tracer =>\n EffectTracer.make({\n span(name, parent, context, links, startTime, kind) {\n return createSentrySpan(name, parent, context, links, startTime, kind);\n },\n context(execution, fiber) {\n const currentSpan = fiber.currentSpan;\n if (currentSpan === undefined || !isSentrySpan(currentSpan)) {\n return execution();\n }\n return withActiveSpan(currentSpan.sentrySpan, execution);\n },\n });\n\n/**\n * Effect Layer that sets up the Sentry tracer for Effect spans.\n */\nexport const SentryEffectTracer = makeSentryTracer();\n"],"names":["getActiveSpan","startInactiveSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","withActiveSpan"],"mappings":"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"}
1
+ {"version":3,"file":"tracer.js","sources":["../../src/tracer.ts"],"sourcesContent":["import type { Span } from '@sentry/core';\nimport { getActiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startInactiveSpan, withActiveSpan } from '@sentry/core';\nimport type * as Context from 'effect/Context';\nimport * as Exit from 'effect/Exit';\nimport * as Option from 'effect/Option';\nimport * as EffectTracer from 'effect/Tracer';\n\nfunction deriveOrigin(name: string): string {\n if (name.startsWith('http.server') || name.startsWith('http.client')) {\n return 'auto.http.effect';\n }\n\n return 'auto.function.effect';\n}\n\ntype HrTime = [number, number];\n\nconst SENTRY_SPAN_SYMBOL = Symbol.for('@sentry/effect.SentrySpan');\n\nfunction nanosToHrTime(nanos: bigint): HrTime {\n const seconds = Number(nanos / BigInt(1_000_000_000));\n const remainingNanos = Number(nanos % BigInt(1_000_000_000));\n return [seconds, remainingNanos];\n}\n\ninterface SentrySpanLike extends EffectTracer.Span {\n readonly [SENTRY_SPAN_SYMBOL]: true;\n readonly sentrySpan: Span;\n}\n\nfunction isSentrySpan(span: EffectTracer.AnySpan): span is SentrySpanLike {\n return SENTRY_SPAN_SYMBOL in span;\n}\n\nfunction getErrorMessage(exit: Exit.Exit<unknown, unknown>): string | undefined {\n if (!Exit.isFailure(exit)) {\n return undefined;\n }\n\n const cause = exit.cause as unknown;\n\n // Effect v4: cause.reasons is an array of Reason objects\n if (\n cause &&\n typeof cause === 'object' &&\n 'reasons' in cause &&\n Array.isArray((cause as { reasons: unknown }).reasons)\n ) {\n const reasons = (cause as { reasons: Array<{ _tag?: string; error?: unknown; defect?: unknown }> }).reasons;\n for (const reason of reasons) {\n if (reason._tag === 'Fail' && reason.error !== undefined) {\n return String(reason.error);\n }\n if (reason._tag === 'Die' && reason.defect !== undefined) {\n return String(reason.defect);\n }\n }\n return 'internal_error';\n }\n\n // Effect v3: cause has _tag directly\n if (cause && typeof cause === 'object' && '_tag' in cause) {\n const v3Cause = cause as { _tag: string; error?: unknown; defect?: unknown };\n if (v3Cause._tag === 'Fail') {\n return String(v3Cause.error);\n }\n if (v3Cause._tag === 'Die') {\n return String(v3Cause.defect);\n }\n }\n\n return 'internal_error';\n}\n\nclass SentrySpanWrapper implements SentrySpanLike {\n public readonly [SENTRY_SPAN_SYMBOL]: true;\n public readonly _tag: 'Span';\n public readonly spanId: string;\n public readonly traceId: string;\n public readonly attributes: Map<string, unknown>;\n public readonly sampled: boolean;\n public readonly parent: Option.Option<EffectTracer.AnySpan>;\n public readonly links: Array<EffectTracer.SpanLink>;\n public status: EffectTracer.SpanStatus;\n public readonly sentrySpan: Span;\n public readonly annotations: Context.Context<never>;\n\n public constructor(\n public readonly name: string,\n parent: Option.Option<EffectTracer.AnySpan>,\n public readonly context: Context.Context<never>,\n links: ReadonlyArray<EffectTracer.SpanLink>,\n startTime: bigint,\n public readonly kind: EffectTracer.SpanKind,\n existingSpan: Span,\n ) {\n this[SENTRY_SPAN_SYMBOL] = true as const;\n this._tag = 'Span' as const;\n this.attributes = new Map<string, unknown>();\n this.parent = parent;\n this.links = [...links];\n this.sentrySpan = existingSpan;\n this.annotations = context;\n\n const spanContext = this.sentrySpan.spanContext();\n this.spanId = spanContext.spanId;\n this.traceId = spanContext.traceId;\n this.sampled = this.sentrySpan.isRecording();\n this.status = {\n _tag: 'Started',\n startTime,\n };\n }\n\n public attribute(key: string, value: unknown): void {\n if (!this.sentrySpan.isRecording()) {\n return;\n }\n\n this.sentrySpan.setAttribute(key, value as Parameters<Span['setAttribute']>[1]);\n this.attributes.set(key, value);\n }\n\n public addLinks(links: ReadonlyArray<EffectTracer.SpanLink>): void {\n this.links.push(...links);\n }\n\n public end(endTime: bigint, exit: Exit.Exit<unknown, unknown>): void {\n this.status = {\n _tag: 'Ended',\n endTime,\n exit,\n startTime: this.status.startTime,\n };\n\n if (!this.sentrySpan.isRecording()) {\n return;\n }\n\n if (Exit.isFailure(exit)) {\n const message = getErrorMessage(exit) ?? 'internal_error';\n this.sentrySpan.setStatus({ code: 2, message });\n } else {\n this.sentrySpan.setStatus({ code: 1 });\n }\n\n this.sentrySpan.end(nanosToHrTime(endTime));\n }\n\n public event(name: string, startTime: bigint, attributes?: Record<string, unknown>): void {\n if (!this.sentrySpan.isRecording()) {\n return;\n }\n\n this.sentrySpan.addEvent(name, attributes as Parameters<Span['addEvent']>[1], nanosToHrTime(startTime));\n }\n}\n\nfunction createSentrySpan(\n name: string,\n parent: Option.Option<EffectTracer.AnySpan>,\n context: Context.Context<never>,\n links: ReadonlyArray<EffectTracer.SpanLink>,\n startTime: bigint,\n kind: EffectTracer.SpanKind,\n): SentrySpanLike {\n const parentSentrySpan =\n Option.isSome(parent) && isSentrySpan(parent.value) ? parent.value.sentrySpan : (getActiveSpan() ?? null);\n\n const newSpan = startInactiveSpan({\n name,\n startTime: nanosToHrTime(startTime),\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: deriveOrigin(name),\n },\n ...(parentSentrySpan ? { parentSpan: parentSentrySpan } : {}),\n });\n\n return new SentrySpanWrapper(name, parent, context, links, startTime, kind, newSpan);\n}\n\n// Check if we're running Effect v4 by checking the Exit/Cause structure\n// In v4, causes have a 'reasons' array\n// In v3, causes have '_tag' directly on the cause object\nconst isEffectV4 = (() => {\n try {\n const testExit = Exit.fail('test') as unknown as { cause?: unknown };\n const cause = testExit.cause;\n // v4 causes have 'reasons' array, v3 causes have '_tag' directly\n if (cause && typeof cause === 'object' && 'reasons' in cause) {\n return true;\n }\n return false;\n } catch {\n return false;\n }\n})();\n\nconst makeSentryTracerV3 = (): EffectTracer.Tracer => {\n // Effect v3 API: span(name, parent, context, links, startTime, kind)\n return EffectTracer.make({\n span(\n name: string,\n parent: Option.Option<EffectTracer.AnySpan>,\n context: Context.Context<never>,\n links: ReadonlyArray<EffectTracer.SpanLink>,\n startTime: bigint,\n kind: EffectTracer.SpanKind,\n ) {\n return createSentrySpan(name, parent, context, links, startTime, kind);\n },\n context(execution: () => unknown, fiber: { currentSpan?: EffectTracer.AnySpan }) {\n const currentSpan = fiber.currentSpan;\n if (currentSpan === undefined || !isSentrySpan(currentSpan)) {\n return execution();\n }\n return withActiveSpan(currentSpan.sentrySpan, execution);\n },\n } as unknown as EffectTracer.Tracer);\n};\n\nconst makeSentryTracerV4 = (): EffectTracer.Tracer => {\n const EFFECT_EVALUATE = '~effect/Effect/evaluate' as const;\n\n return EffectTracer.make({\n span(options) {\n return createSentrySpan(\n options.name,\n options.parent,\n options.annotations,\n options.links,\n options.startTime,\n options.kind,\n );\n },\n context(primitive, fiber) {\n const currentSpan = fiber.currentSpan;\n if (currentSpan === undefined || !isSentrySpan(currentSpan)) {\n return primitive[EFFECT_EVALUATE](fiber);\n }\n return withActiveSpan(currentSpan.sentrySpan, () => primitive[EFFECT_EVALUATE](fiber));\n },\n });\n};\n\n/**\n * Effect Layer that sets up the Sentry tracer for Effect spans.\n */\nexport const SentryEffectTracer = isEffectV4 ? makeSentryTracerV4() : makeSentryTracerV3();\n"],"names":["getActiveSpan","startInactiveSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","withActiveSpan"],"mappings":"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"}
@@ -1,6 +1,20 @@
1
1
  import { logger } from '@sentry/core';
2
2
  import * as Logger from 'effect/Logger';
3
3
 
4
+ function getLogLevelTag(logLevel) {
5
+ // Effect v4: logLevel is a string literal directly
6
+ if (typeof logLevel === 'string') {
7
+ return logLevel;
8
+ }
9
+
10
+ // Effect v3: logLevel has _tag property
11
+ if (logLevel && typeof logLevel === 'object' && '_tag' in logLevel) {
12
+ return (logLevel )._tag;
13
+ }
14
+
15
+ return 'Info';
16
+ }
17
+
4
18
  /**
5
19
  * Effect Logger that sends logs to Sentry.
6
20
  */
@@ -15,14 +29,17 @@ const SentryEffectLogger = Logger.make(({ logLevel, message }) => {
15
29
  msg = JSON.stringify(message);
16
30
  }
17
31
 
18
- switch (logLevel._tag) {
32
+ const tag = getLogLevelTag(logLevel);
33
+
34
+ switch (tag) {
19
35
  case 'Fatal':
20
36
  logger.fatal(msg);
21
37
  break;
22
38
  case 'Error':
23
39
  logger.error(msg);
24
40
  break;
25
- case 'Warning':
41
+ case 'Warning': // Effect v3
42
+ case 'Warn': // Effect v4
26
43
  logger.warn(msg);
27
44
  break;
28
45
  case 'Info':
@@ -1 +1 @@
1
- {"version":3,"file":"logger.js","sources":["../../src/logger.ts"],"sourcesContent":["import { logger as sentryLogger } from '@sentry/core';\nimport * as Logger from 'effect/Logger';\n\n/**\n * Effect Logger that sends logs to Sentry.\n */\nexport const SentryEffectLogger = Logger.make(({ logLevel, message }) => {\n let msg: string;\n if (typeof message === 'string') {\n msg = message;\n } else if (Array.isArray(message) && message.length === 1) {\n const firstElement = message[0];\n msg = typeof firstElement === 'string' ? firstElement : JSON.stringify(firstElement);\n } else {\n msg = JSON.stringify(message);\n }\n\n switch (logLevel._tag) {\n case 'Fatal':\n sentryLogger.fatal(msg);\n break;\n case 'Error':\n sentryLogger.error(msg);\n break;\n case 'Warning':\n sentryLogger.warn(msg);\n break;\n case 'Info':\n sentryLogger.info(msg);\n break;\n case 'Debug':\n sentryLogger.debug(msg);\n break;\n case 'Trace':\n sentryLogger.trace(msg);\n break;\n case 'All':\n case 'None':\n break;\n default:\n logLevel satisfies never;\n }\n});\n"],"names":["sentryLogger"],"mappings":";;;AAGA;AACA;AACA;AACO,MAAM,kBAAA,GAAqB,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAA,EAAS,KAAK;AACzE,EAAE,IAAI,GAAG;AACT,EAAE,IAAI,OAAO,OAAA,KAAY,QAAQ,EAAE;AACnC,IAAI,GAAA,GAAM,OAAO;AACjB,EAAE,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAA,IAAK,OAAO,CAAC,MAAA,KAAW,CAAC,EAAE;AAC7D,IAAI,MAAM,YAAA,GAAe,OAAO,CAAC,CAAC,CAAC;AACnC,IAAI,GAAA,GAAM,OAAO,YAAA,KAAiB,QAAA,GAAW,YAAA,GAAe,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC;AACxF,EAAE,OAAO;AACT,IAAI,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;AACjC,EAAE;;AAEF,EAAE,QAAQ,QAAQ,CAAC,IAAI;AACvB,IAAI,KAAK,OAAO;AAChB,MAAMA,MAAY,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7B,MAAM;AACN,IAAI,KAAK,OAAO;AAChB,MAAMA,MAAY,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7B,MAAM;AACN,IAAI,KAAK,SAAS;AAClB,MAAMA,MAAY,CAAC,IAAI,CAAC,GAAG,CAAC;AAC5B,MAAM;AACN,IAAI,KAAK,MAAM;AACf,MAAMA,MAAY,CAAC,IAAI,CAAC,GAAG,CAAC;AAC5B,MAAM;AACN,IAAI,KAAK,OAAO;AAChB,MAAMA,MAAY,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7B,MAAM;AACN,IAAI,KAAK,OAAO;AAChB,MAAMA,MAAY,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7B,MAAM;AAMN;AACA,CAAC;;;;"}
1
+ {"version":3,"file":"logger.js","sources":["../../src/logger.ts"],"sourcesContent":["import { logger as sentryLogger } from '@sentry/core';\nimport * as Logger from 'effect/Logger';\nimport type * as LogLevel from 'effect/LogLevel';\n\nfunction getLogLevelTag(logLevel: LogLevel.LogLevel): LogLevel.LogLevel | 'Warning' {\n // Effect v4: logLevel is a string literal directly\n if (typeof logLevel === 'string') {\n return logLevel;\n }\n\n // Effect v3: logLevel has _tag property\n if (logLevel && typeof logLevel === 'object' && '_tag' in logLevel) {\n return (logLevel as { _tag: LogLevel.LogLevel })._tag;\n }\n\n return 'Info';\n}\n\n/**\n * Effect Logger that sends logs to Sentry.\n */\nexport const SentryEffectLogger = Logger.make(({ logLevel, message }) => {\n let msg: string;\n if (typeof message === 'string') {\n msg = message;\n } else if (Array.isArray(message) && message.length === 1) {\n const firstElement = message[0];\n msg = typeof firstElement === 'string' ? firstElement : JSON.stringify(firstElement);\n } else {\n msg = JSON.stringify(message);\n }\n\n const tag = getLogLevelTag(logLevel);\n\n switch (tag) {\n case 'Fatal':\n sentryLogger.fatal(msg);\n break;\n case 'Error':\n sentryLogger.error(msg);\n break;\n case 'Warning': // Effect v3\n case 'Warn': // Effect v4\n sentryLogger.warn(msg);\n break;\n case 'Info':\n sentryLogger.info(msg);\n break;\n case 'Debug':\n sentryLogger.debug(msg);\n break;\n case 'Trace':\n sentryLogger.trace(msg);\n break;\n case 'All':\n case 'None':\n break;\n default:\n tag satisfies never;\n }\n});\n"],"names":["sentryLogger"],"mappings":";;;AAIA,SAAS,cAAc,CAAC,QAAQ,EAAoD;AACpF;AACA,EAAE,IAAI,OAAO,QAAA,KAAa,QAAQ,EAAE;AACpC,IAAI,OAAO,QAAQ;AACnB,EAAE;;AAEF;AACA,EAAE,IAAI,QAAA,IAAY,OAAO,QAAA,KAAa,QAAA,IAAY,MAAA,IAAU,QAAQ,EAAE;AACtE,IAAI,OAAO,CAAC,QAAA,GAAyC,IAAI;AACzD,EAAE;;AAEF,EAAE,OAAO,MAAM;AACf;;AAEA;AACA;AACA;AACO,MAAM,kBAAA,GAAqB,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAA,EAAS,KAAK;AACzE,EAAE,IAAI,GAAG;AACT,EAAE,IAAI,OAAO,OAAA,KAAY,QAAQ,EAAE;AACnC,IAAI,GAAA,GAAM,OAAO;AACjB,EAAE,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAA,IAAK,OAAO,CAAC,MAAA,KAAW,CAAC,EAAE;AAC7D,IAAI,MAAM,YAAA,GAAe,OAAO,CAAC,CAAC,CAAC;AACnC,IAAI,GAAA,GAAM,OAAO,YAAA,KAAiB,QAAA,GAAW,YAAA,GAAe,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC;AACxF,EAAE,OAAO;AACT,IAAI,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;AACjC,EAAE;;AAEF,EAAE,MAAM,GAAA,GAAM,cAAc,CAAC,QAAQ,CAAC;;AAEtC,EAAE,QAAQ,GAAG;AACb,IAAI,KAAK,OAAO;AAChB,MAAMA,MAAY,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7B,MAAM;AACN,IAAI,KAAK,OAAO;AAChB,MAAMA,MAAY,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7B,MAAM;AACN,IAAI,KAAK,SAAS,CAAA;AAClB,IAAI,KAAK,MAAM;AACf,MAAMA,MAAY,CAAC,IAAI,CAAC,GAAG,CAAC;AAC5B,MAAM;AACN,IAAI,KAAK,MAAM;AACf,MAAMA,MAAY,CAAC,IAAI,CAAC,GAAG,CAAC;AAC5B,MAAM;AACN,IAAI,KAAK,OAAO;AAChB,MAAMA,MAAY,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7B,MAAM;AACN,IAAI,KAAK,OAAO;AAChB,MAAMA,MAAY,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7B,MAAM;AAMN;AACA,CAAC;;;;"}
@@ -1,37 +1,65 @@
1
1
  import { metrics } from '@sentry/core';
2
+ import * as Context from 'effect/Context';
2
3
  import * as Effect from 'effect/Effect';
3
- import { scopedDiscard } from 'effect/Layer';
4
+ import * as Layer from 'effect/Layer';
4
5
  import * as Metric from 'effect/Metric';
5
- import * as MetricKeyType from 'effect/MetricKeyType';
6
- import * as MetricState from 'effect/MetricState';
7
6
  import * as Schedule from 'effect/Schedule';
8
7
 
8
+ // Effect v3 `MetricState` implementations brand themselves with a `Symbol.for(...)` TypeId
9
+ // rather than a string `_tag`. We use these globally-registered symbols to classify state
10
+ // instances returned by `Metric.unsafeSnapshot()` without importing `effect/MetricState`
11
+ // (the module does not exist in Effect v4).
12
+ const V3_COUNTER_STATE_TYPE_ID = Symbol.for('effect/MetricState/Counter');
13
+ const V3_GAUGE_STATE_TYPE_ID = Symbol.for('effect/MetricState/Gauge');
14
+ const V3_HISTOGRAM_STATE_TYPE_ID = Symbol.for('effect/MetricState/Histogram');
15
+ const V3_SUMMARY_STATE_TYPE_ID = Symbol.for('effect/MetricState/Summary');
16
+ const V3_FREQUENCY_STATE_TYPE_ID = Symbol.for('effect/MetricState/Frequency');
17
+
9
18
  function labelsToAttributes(labels) {
10
19
  return labels.reduce((acc, label) => ({ ...acc, [label.key]: label.value }), {});
11
20
  }
12
21
 
13
- function sendMetricToSentry(pair) {
22
+ function getMetricIdV3(pair) {
23
+ const tags = pair.metricKey.tags.map(t => `${t.key}=${t.value}`).join(',');
24
+ return `${pair.metricKey.name}:${tags}`;
25
+ }
26
+
27
+ function getMetricIdV4(snapshot) {
28
+ const attrs = snapshot.attributes
29
+ ? Object.entries(snapshot.attributes)
30
+ .map(([k, v]) => `${k}=${v}`)
31
+ .join(',')
32
+ : '';
33
+ return `${snapshot.id}:${attrs}`;
34
+ }
35
+
36
+ function sendV3MetricToSentry(pair, previousCounterValues) {
14
37
  const { metricKey, metricState } = pair;
15
38
  const name = metricKey.name;
16
39
  const attributes = labelsToAttributes(metricKey.tags);
40
+ const metricId = getMetricIdV3(pair);
41
+
42
+ const state = metricState ;
17
43
 
18
- if (MetricState.isCounterState(metricState)) {
19
- const value = Number(metricState.count);
20
- metrics.count(name, value, { attributes });
21
- } else if (MetricState.isGaugeState(metricState)) {
44
+ if (state[V3_COUNTER_STATE_TYPE_ID] !== undefined) {
45
+ const currentValue = Number(metricState.count);
46
+ const previousValue = previousCounterValues.get(metricId) ?? 0;
47
+ const delta = currentValue - previousValue;
48
+
49
+ if (delta > 0) {
50
+ metrics.count(name, delta, { attributes });
51
+ }
52
+
53
+ previousCounterValues.set(metricId, currentValue);
54
+ } else if (state[V3_GAUGE_STATE_TYPE_ID] !== undefined) {
22
55
  const value = Number(metricState.value);
23
56
  metrics.gauge(name, value, { attributes });
24
- } else if (MetricState.isHistogramState(metricState)) {
25
- metrics.gauge(`${name}.sum`, metricState.sum, { attributes });
26
- metrics.gauge(`${name}.count`, metricState.count, { attributes });
27
- metrics.gauge(`${name}.min`, metricState.min, { attributes });
28
- metrics.gauge(`${name}.max`, metricState.max, { attributes });
29
- } else if (MetricState.isSummaryState(metricState)) {
30
- metrics.gauge(`${name}.sum`, metricState.sum, { attributes });
31
- metrics.gauge(`${name}.count`, metricState.count, { attributes });
32
- metrics.gauge(`${name}.min`, metricState.min, { attributes });
33
- metrics.gauge(`${name}.max`, metricState.max, { attributes });
34
- } else if (MetricState.isFrequencyState(metricState)) {
57
+ } else if (state[V3_HISTOGRAM_STATE_TYPE_ID] !== undefined || state[V3_SUMMARY_STATE_TYPE_ID] !== undefined) {
58
+ metrics.gauge(`${name}.sum`, metricState.sum ?? 0, { attributes });
59
+ metrics.gauge(`${name}.count`, Number(metricState.count ?? 0), { attributes });
60
+ metrics.gauge(`${name}.min`, metricState.min ?? 0, { attributes });
61
+ metrics.gauge(`${name}.max`, metricState.max ?? 0, { attributes });
62
+ } else if (state[V3_FREQUENCY_STATE_TYPE_ID] !== undefined && metricState.occurrences) {
35
63
  for (const [word, count] of metricState.occurrences) {
36
64
  metrics.count(name, count, {
37
65
  attributes: { ...attributes, word },
@@ -40,50 +68,73 @@ function sendMetricToSentry(pair) {
40
68
  }
41
69
  }
42
70
 
43
- function getMetricId(pair) {
44
- const tags = pair.metricKey.tags.map(t => `${t.key}=${t.value}`).join(',');
45
- return `${pair.metricKey.name}:${tags}`;
46
- }
71
+ function sendV4MetricToSentry(snapshot, previousCounterValues) {
72
+ const name = snapshot.id;
73
+ const attributes = snapshot.attributes ? { ...snapshot.attributes } : {};
74
+ const metricId = getMetricIdV4(snapshot);
47
75
 
48
- function sendDeltaMetricToSentry(
49
- pair,
50
- previousCounterValues,
51
- ) {
52
- const { metricKey, metricState } = pair;
53
- const name = metricKey.name;
54
- const attributes = labelsToAttributes(metricKey.tags);
55
- const metricId = getMetricId(pair);
76
+ switch (snapshot.type) {
77
+ case 'Counter': {
78
+ const currentValue = Number(snapshot.state.count);
79
+ const previousValue = previousCounterValues.get(metricId) ?? 0;
80
+ const delta = currentValue - previousValue;
56
81
 
57
- if (MetricState.isCounterState(metricState)) {
58
- const currentValue = Number(metricState.count);
59
-
60
- const previousValue = previousCounterValues.get(metricId) ?? 0;
61
- const delta = currentValue - previousValue;
82
+ if (delta > 0) {
83
+ metrics.count(name, delta, { attributes });
84
+ }
62
85
 
63
- if (delta > 0) {
64
- metrics.count(name, delta, { attributes });
86
+ previousCounterValues.set(metricId, currentValue);
87
+ break;
88
+ }
89
+ case 'Gauge': {
90
+ const value = Number(snapshot.state.value);
91
+ metrics.gauge(name, value, { attributes });
92
+ break;
93
+ }
94
+ case 'Histogram':
95
+ case 'Summary': {
96
+ metrics.gauge(`${name}.sum`, snapshot.state.sum ?? 0, { attributes });
97
+ metrics.gauge(`${name}.count`, snapshot.state.count ?? 0, { attributes });
98
+ metrics.gauge(`${name}.min`, snapshot.state.min ?? 0, { attributes });
99
+ metrics.gauge(`${name}.max`, snapshot.state.max ?? 0, { attributes });
100
+ break;
101
+ }
102
+ case 'Frequency': {
103
+ for (const [word, count] of snapshot.state.occurrences) {
104
+ metrics.count(name, count, {
105
+ attributes: { ...attributes, word },
106
+ });
107
+ }
108
+ break;
65
109
  }
66
-
67
- previousCounterValues.set(metricId, currentValue);
68
- } else {
69
- sendMetricToSentry(pair);
70
110
  }
71
111
  }
72
112
 
73
- /**
74
- * Flushes all Effect metrics to Sentry.
75
- * @param previousCounterValues - Map tracking previous counter values for delta calculation
76
- */
77
- function flushMetricsToSentry(previousCounterValues) {
78
- const snapshot = Metric.unsafeSnapshot();
113
+ // =============================================================================
114
+ // Effect v3 snapshot function type (vendored - not exported from effect@3.x)
115
+ // =============================================================================
116
+
117
+ // Use bracket notation to avoid Webpack static analysis flagging missing exports
118
+ // This is important for Effect v3 compatibility.
119
+ const MetricModule = Metric;
120
+ const snapshotUnsafe = MetricModule['snapshotUnsafe'] ;
121
+ // @ts-expect-error - unsafeSnapshot is not exported from effect@3.x
122
+ const unsafeSnapshot = MetricModule['unsafeSnapshot'] ;
79
123
 
80
- snapshot.forEach((pair) => {
81
- if (MetricKeyType.isCounterKey(pair.metricKey.keyType)) {
82
- sendDeltaMetricToSentry(pair, previousCounterValues);
83
- } else {
84
- sendMetricToSentry(pair);
124
+ function flushMetricsToSentry(previousCounterValues) {
125
+ if (snapshotUnsafe) {
126
+ // Effect v4
127
+ const snapshots = snapshotUnsafe(Context.empty());
128
+ for (const snapshot of snapshots) {
129
+ sendV4MetricToSentry(snapshot, previousCounterValues);
85
130
  }
86
- });
131
+ } else if (unsafeSnapshot) {
132
+ // Effect v3
133
+ const snapshots = unsafeSnapshot();
134
+ for (const pair of snapshots) {
135
+ sendV3MetricToSentry(pair, previousCounterValues);
136
+ }
137
+ }
87
138
  }
88
139
 
89
140
  function createMetricsReporterEffect(previousCounterValues) {
@@ -100,7 +151,7 @@ function createMetricsReporterEffect(previousCounterValues) {
100
151
  * The layer manages its own state for delta counter calculations,
101
152
  * which is automatically cleaned up when the layer is finalized.
102
153
  */
103
- const SentryEffectMetricsLayer = scopedDiscard(
154
+ const SentryEffectMetricsLayer = Layer.effectDiscard(
104
155
  Effect.gen(function* () {
105
156
  const previousCounterValues = new Map();
106
157
 
@@ -1 +1 @@
1
- {"version":3,"file":"metrics.js","sources":["../../src/metrics.ts"],"sourcesContent":["import { metrics as sentryMetrics } from '@sentry/core';\nimport * as Effect from 'effect/Effect';\nimport type * as Layer from 'effect/Layer';\nimport { scopedDiscard } from 'effect/Layer';\nimport * as Metric from 'effect/Metric';\nimport * as MetricKeyType from 'effect/MetricKeyType';\nimport type * as MetricPair from 'effect/MetricPair';\nimport * as MetricState from 'effect/MetricState';\nimport * as Schedule from 'effect/Schedule';\n\ntype MetricAttributes = Record<string, string>;\n\nfunction labelsToAttributes(labels: ReadonlyArray<{ key: string; value: string }>): MetricAttributes {\n return labels.reduce((acc, label) => ({ ...acc, [label.key]: label.value }), {});\n}\n\nfunction sendMetricToSentry(pair: MetricPair.MetricPair.Untyped): void {\n const { metricKey, metricState } = pair;\n const name = metricKey.name;\n const attributes = labelsToAttributes(metricKey.tags);\n\n if (MetricState.isCounterState(metricState)) {\n const value = Number(metricState.count);\n sentryMetrics.count(name, value, { attributes });\n } else if (MetricState.isGaugeState(metricState)) {\n const value = Number(metricState.value);\n sentryMetrics.gauge(name, value, { attributes });\n } else if (MetricState.isHistogramState(metricState)) {\n sentryMetrics.gauge(`${name}.sum`, metricState.sum, { attributes });\n sentryMetrics.gauge(`${name}.count`, metricState.count, { attributes });\n sentryMetrics.gauge(`${name}.min`, metricState.min, { attributes });\n sentryMetrics.gauge(`${name}.max`, metricState.max, { attributes });\n } else if (MetricState.isSummaryState(metricState)) {\n sentryMetrics.gauge(`${name}.sum`, metricState.sum, { attributes });\n sentryMetrics.gauge(`${name}.count`, metricState.count, { attributes });\n sentryMetrics.gauge(`${name}.min`, metricState.min, { attributes });\n sentryMetrics.gauge(`${name}.max`, metricState.max, { attributes });\n } else if (MetricState.isFrequencyState(metricState)) {\n for (const [word, count] of metricState.occurrences) {\n sentryMetrics.count(name, count, {\n attributes: { ...attributes, word },\n });\n }\n }\n}\n\nfunction getMetricId(pair: MetricPair.MetricPair.Untyped): string {\n const tags = pair.metricKey.tags.map(t => `${t.key}=${t.value}`).join(',');\n return `${pair.metricKey.name}:${tags}`;\n}\n\nfunction sendDeltaMetricToSentry(\n pair: MetricPair.MetricPair.Untyped,\n previousCounterValues: Map<string, number>,\n): void {\n const { metricKey, metricState } = pair;\n const name = metricKey.name;\n const attributes = labelsToAttributes(metricKey.tags);\n const metricId = getMetricId(pair);\n\n if (MetricState.isCounterState(metricState)) {\n const currentValue = Number(metricState.count);\n\n const previousValue = previousCounterValues.get(metricId) ?? 0;\n const delta = currentValue - previousValue;\n\n if (delta > 0) {\n sentryMetrics.count(name, delta, { attributes });\n }\n\n previousCounterValues.set(metricId, currentValue);\n } else {\n sendMetricToSentry(pair);\n }\n}\n\n/**\n * Flushes all Effect metrics to Sentry.\n * @param previousCounterValues - Map tracking previous counter values for delta calculation\n */\nfunction flushMetricsToSentry(previousCounterValues: Map<string, number>): void {\n const snapshot = Metric.unsafeSnapshot();\n\n snapshot.forEach((pair: MetricPair.MetricPair.Untyped) => {\n if (MetricKeyType.isCounterKey(pair.metricKey.keyType)) {\n sendDeltaMetricToSentry(pair, previousCounterValues);\n } else {\n sendMetricToSentry(pair);\n }\n });\n}\n\n/**\n * Creates a metrics flusher with its own isolated state for delta tracking.\n * Useful for testing scenarios where you need to control the lifecycle.\n * @internal\n */\nexport function createMetricsFlusher(): {\n flush: () => void;\n clear: () => void;\n} {\n const previousCounterValues = new Map<string, number>();\n return {\n flush: () => flushMetricsToSentry(previousCounterValues),\n clear: () => previousCounterValues.clear(),\n };\n}\n\nfunction createMetricsReporterEffect(previousCounterValues: Map<string, number>): Effect.Effect<void, never, never> {\n const schedule = Schedule.spaced('10 seconds');\n\n return Effect.repeat(\n Effect.sync(() => flushMetricsToSentry(previousCounterValues)),\n schedule,\n ).pipe(Effect.asVoid, Effect.interruptible);\n}\n\n/**\n * Effect Layer that periodically flushes metrics to Sentry.\n * The layer manages its own state for delta counter calculations,\n * which is automatically cleaned up when the layer is finalized.\n */\nexport const SentryEffectMetricsLayer: Layer.Layer<never, never, never> = scopedDiscard(\n Effect.gen(function* () {\n const previousCounterValues = new Map<string, number>();\n\n yield* Effect.acquireRelease(Effect.void, () =>\n Effect.sync(() => {\n previousCounterValues.clear();\n }),\n );\n\n yield* Effect.forkScoped(createMetricsReporterEffect(previousCounterValues));\n }),\n);\n"],"names":["sentryMetrics"],"mappings":"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"}
1
+ {"version":3,"file":"metrics.js","sources":["../../src/metrics.ts"],"sourcesContent":["import { metrics as sentryMetrics } from '@sentry/core';\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\nimport * as Metric from 'effect/Metric';\nimport * as Schedule from 'effect/Schedule';\n\ntype MetricAttributes = Record<string, string>;\n\n// =============================================================================\n// Effect v3 Types (vendored - not exported from effect@3.x)\n// =============================================================================\n\ninterface V3MetricLabel {\n key: string;\n value: string;\n}\n\ninterface V3MetricPair {\n metricKey: {\n name: string;\n tags: ReadonlyArray<V3MetricLabel>;\n keyType: { _tag: string };\n };\n metricState: {\n count?: number | bigint;\n value?: number;\n sum?: number;\n min?: number;\n max?: number;\n occurrences?: Map<string, number>;\n };\n}\n\n// Effect v3 `MetricState` implementations brand themselves with a `Symbol.for(...)` TypeId\n// rather than a string `_tag`. We use these globally-registered symbols to classify state\n// instances returned by `Metric.unsafeSnapshot()` without importing `effect/MetricState`\n// (the module does not exist in Effect v4).\nconst V3_COUNTER_STATE_TYPE_ID = Symbol.for('effect/MetricState/Counter');\nconst V3_GAUGE_STATE_TYPE_ID = Symbol.for('effect/MetricState/Gauge');\nconst V3_HISTOGRAM_STATE_TYPE_ID = Symbol.for('effect/MetricState/Histogram');\nconst V3_SUMMARY_STATE_TYPE_ID = Symbol.for('effect/MetricState/Summary');\nconst V3_FREQUENCY_STATE_TYPE_ID = Symbol.for('effect/MetricState/Frequency');\n\nfunction labelsToAttributes(labels: ReadonlyArray<V3MetricLabel>): MetricAttributes {\n return labels.reduce((acc, label) => ({ ...acc, [label.key]: label.value }), {});\n}\n\nfunction getMetricIdV3(pair: V3MetricPair): string {\n const tags = pair.metricKey.tags.map(t => `${t.key}=${t.value}`).join(',');\n return `${pair.metricKey.name}:${tags}`;\n}\n\nfunction getMetricIdV4(snapshot: Metric.Metric.Snapshot): string {\n const attrs = snapshot.attributes\n ? Object.entries(snapshot.attributes)\n .map(([k, v]) => `${k}=${v}`)\n .join(',')\n : '';\n return `${snapshot.id}:${attrs}`;\n}\n\nfunction sendV3MetricToSentry(pair: V3MetricPair, previousCounterValues: Map<string, number>): void {\n const { metricKey, metricState } = pair;\n const name = metricKey.name;\n const attributes = labelsToAttributes(metricKey.tags);\n const metricId = getMetricIdV3(pair);\n\n const state = metricState as unknown as Record<symbol, unknown>;\n\n if (state[V3_COUNTER_STATE_TYPE_ID] !== undefined) {\n const currentValue = Number(metricState.count);\n const previousValue = previousCounterValues.get(metricId) ?? 0;\n const delta = currentValue - previousValue;\n\n if (delta > 0) {\n sentryMetrics.count(name, delta, { attributes });\n }\n\n previousCounterValues.set(metricId, currentValue);\n } else if (state[V3_GAUGE_STATE_TYPE_ID] !== undefined) {\n const value = Number(metricState.value);\n sentryMetrics.gauge(name, value, { attributes });\n } else if (state[V3_HISTOGRAM_STATE_TYPE_ID] !== undefined || state[V3_SUMMARY_STATE_TYPE_ID] !== undefined) {\n sentryMetrics.gauge(`${name}.sum`, metricState.sum ?? 0, { attributes });\n sentryMetrics.gauge(`${name}.count`, Number(metricState.count ?? 0), { attributes });\n sentryMetrics.gauge(`${name}.min`, metricState.min ?? 0, { attributes });\n sentryMetrics.gauge(`${name}.max`, metricState.max ?? 0, { attributes });\n } else if (state[V3_FREQUENCY_STATE_TYPE_ID] !== undefined && metricState.occurrences) {\n for (const [word, count] of metricState.occurrences) {\n sentryMetrics.count(name, count, {\n attributes: { ...attributes, word },\n });\n }\n }\n}\n\nfunction sendV4MetricToSentry(snapshot: Metric.Metric.Snapshot, previousCounterValues: Map<string, number>): void {\n const name = snapshot.id;\n const attributes: MetricAttributes = snapshot.attributes ? { ...snapshot.attributes } : {};\n const metricId = getMetricIdV4(snapshot);\n\n switch (snapshot.type) {\n case 'Counter': {\n const currentValue = Number(snapshot.state.count);\n const previousValue = previousCounterValues.get(metricId) ?? 0;\n const delta = currentValue - previousValue;\n\n if (delta > 0) {\n sentryMetrics.count(name, delta, { attributes });\n }\n\n previousCounterValues.set(metricId, currentValue);\n break;\n }\n case 'Gauge': {\n const value = Number(snapshot.state.value);\n sentryMetrics.gauge(name, value, { attributes });\n break;\n }\n case 'Histogram':\n case 'Summary': {\n sentryMetrics.gauge(`${name}.sum`, snapshot.state.sum ?? 0, { attributes });\n sentryMetrics.gauge(`${name}.count`, snapshot.state.count ?? 0, { attributes });\n sentryMetrics.gauge(`${name}.min`, snapshot.state.min ?? 0, { attributes });\n sentryMetrics.gauge(`${name}.max`, snapshot.state.max ?? 0, { attributes });\n break;\n }\n case 'Frequency': {\n for (const [word, count] of snapshot.state.occurrences) {\n sentryMetrics.count(name, count, {\n attributes: { ...attributes, word },\n });\n }\n break;\n }\n }\n}\n\n// =============================================================================\n// Effect v3 snapshot function type (vendored - not exported from effect@3.x)\n// =============================================================================\n\ntype V3UnsafeSnapshotFn = () => ReadonlyArray<V3MetricPair>;\n\n// Use bracket notation to avoid Webpack static analysis flagging missing exports\n// This is important for Effect v3 compatibility.\nconst MetricModule = Metric;\nconst snapshotUnsafe = MetricModule['snapshotUnsafe'] as typeof Metric.snapshotUnsafe | undefined;\n// @ts-expect-error - unsafeSnapshot is not exported from effect@3.x\nconst unsafeSnapshot = MetricModule['unsafeSnapshot'] as V3UnsafeSnapshotFn | undefined;\n\nfunction flushMetricsToSentry(previousCounterValues: Map<string, number>): void {\n if (snapshotUnsafe) {\n // Effect v4\n const snapshots = snapshotUnsafe(Context.empty());\n for (const snapshot of snapshots) {\n sendV4MetricToSentry(snapshot, previousCounterValues);\n }\n } else if (unsafeSnapshot) {\n // Effect v3\n const snapshots = unsafeSnapshot();\n for (const pair of snapshots) {\n sendV3MetricToSentry(pair, previousCounterValues);\n }\n }\n}\n\nfunction createMetricsReporterEffect(previousCounterValues: Map<string, number>): Effect.Effect<void, never, never> {\n const schedule = Schedule.spaced('10 seconds');\n\n return Effect.repeat(\n Effect.sync(() => flushMetricsToSentry(previousCounterValues)),\n schedule,\n ).pipe(Effect.asVoid, Effect.interruptible);\n}\n\n/**\n * Effect Layer that periodically flushes metrics to Sentry.\n * The layer manages its own state for delta counter calculations,\n * which is automatically cleaned up when the layer is finalized.\n */\nexport const SentryEffectMetricsLayer: Layer.Layer<never, never, never> = Layer.effectDiscard(\n Effect.gen(function* () {\n const previousCounterValues = new Map<string, number>();\n\n yield* Effect.acquireRelease(Effect.void, () =>\n Effect.sync(() => {\n previousCounterValues.clear();\n }),\n );\n\n yield* Effect.forkScoped(createMetricsReporterEffect(previousCounterValues));\n }),\n);\n"],"names":["sentryMetrics"],"mappings":"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"}
@@ -1 +1 @@
1
- {"type":"module","version":"10.50.0-alpha.0","sideEffects":false}
1
+ {"type":"module","version":"10.51.0","sideEffects":false}
@@ -23,6 +23,46 @@ function isSentrySpan(span) {
23
23
  return SENTRY_SPAN_SYMBOL in span;
24
24
  }
25
25
 
26
+ function getErrorMessage(exit) {
27
+ if (!Exit.isFailure(exit)) {
28
+ return undefined;
29
+ }
30
+
31
+ const cause = exit.cause ;
32
+
33
+ // Effect v4: cause.reasons is an array of Reason objects
34
+ if (
35
+ cause &&
36
+ typeof cause === 'object' &&
37
+ 'reasons' in cause &&
38
+ Array.isArray((cause ).reasons)
39
+ ) {
40
+ const reasons = (cause ).reasons;
41
+ for (const reason of reasons) {
42
+ if (reason._tag === 'Fail' && reason.error !== undefined) {
43
+ return String(reason.error);
44
+ }
45
+ if (reason._tag === 'Die' && reason.defect !== undefined) {
46
+ return String(reason.defect);
47
+ }
48
+ }
49
+ return 'internal_error';
50
+ }
51
+
52
+ // Effect v3: cause has _tag directly
53
+ if (cause && typeof cause === 'object' && '_tag' in cause) {
54
+ const v3Cause = cause ;
55
+ if (v3Cause._tag === 'Fail') {
56
+ return String(v3Cause.error);
57
+ }
58
+ if (v3Cause._tag === 'Die') {
59
+ return String(v3Cause.defect);
60
+ }
61
+ }
62
+
63
+ return 'internal_error';
64
+ }
65
+
26
66
  class SentrySpanWrapper {
27
67
 
28
68
  constructor(
@@ -40,6 +80,7 @@ class SentrySpanWrapper {
40
80
  this.parent = parent;
41
81
  this.links = [...links];
42
82
  this.sentrySpan = existingSpan;
83
+ this.annotations = context;
43
84
 
44
85
  const spanContext = this.sentrySpan.spanContext();
45
86
  this.spanId = spanContext.spanId;
@@ -77,9 +118,7 @@ class SentrySpanWrapper {
77
118
  }
78
119
 
79
120
  if (Exit.isFailure(exit)) {
80
- const cause = exit.cause;
81
- const message =
82
- cause._tag === 'Fail' ? String(cause.error) : cause._tag === 'Die' ? String(cause.defect) : 'internal_error';
121
+ const message = getErrorMessage(exit) ?? 'internal_error';
83
122
  this.sentrySpan.setStatus({ code: 2, message });
84
123
  } else {
85
124
  this.sentrySpan.setStatus({ code: 1 });
@@ -120,9 +159,34 @@ function createSentrySpan(
120
159
  return new SentrySpanWrapper(name, parent, context, links, startTime, kind, newSpan);
121
160
  }
122
161
 
123
- const makeSentryTracer = () =>
124
- EffectTracer.make({
125
- span(name, parent, context, links, startTime, kind) {
162
+ // Check if we're running Effect v4 by checking the Exit/Cause structure
163
+ // In v4, causes have a 'reasons' array
164
+ // In v3, causes have '_tag' directly on the cause object
165
+ const isEffectV4 = (() => {
166
+ try {
167
+ const testExit = Exit.fail('test') ;
168
+ const cause = testExit.cause;
169
+ // v4 causes have 'reasons' array, v3 causes have '_tag' directly
170
+ if (cause && typeof cause === 'object' && 'reasons' in cause) {
171
+ return true;
172
+ }
173
+ return false;
174
+ } catch {
175
+ return false;
176
+ }
177
+ })();
178
+
179
+ const makeSentryTracerV3 = () => {
180
+ // Effect v3 API: span(name, parent, context, links, startTime, kind)
181
+ return EffectTracer.make({
182
+ span(
183
+ name,
184
+ parent,
185
+ context,
186
+ links,
187
+ startTime,
188
+ kind,
189
+ ) {
126
190
  return createSentrySpan(name, parent, context, links, startTime, kind);
127
191
  },
128
192
  context(execution, fiber) {
@@ -132,12 +196,37 @@ const makeSentryTracer = () =>
132
196
  }
133
197
  return withActiveSpan(currentSpan.sentrySpan, execution);
134
198
  },
199
+ } );
200
+ };
201
+
202
+ const makeSentryTracerV4 = () => {
203
+ const EFFECT_EVALUATE = '~effect/Effect/evaluate' ;
204
+
205
+ return EffectTracer.make({
206
+ span(options) {
207
+ return createSentrySpan(
208
+ options.name,
209
+ options.parent,
210
+ options.annotations,
211
+ options.links,
212
+ options.startTime,
213
+ options.kind,
214
+ );
215
+ },
216
+ context(primitive, fiber) {
217
+ const currentSpan = fiber.currentSpan;
218
+ if (currentSpan === undefined || !isSentrySpan(currentSpan)) {
219
+ return primitive[EFFECT_EVALUATE](fiber);
220
+ }
221
+ return withActiveSpan(currentSpan.sentrySpan, () => primitive[EFFECT_EVALUATE](fiber));
222
+ },
135
223
  });
224
+ };
136
225
 
137
226
  /**
138
227
  * Effect Layer that sets up the Sentry tracer for Effect spans.
139
228
  */
140
- const SentryEffectTracer = makeSentryTracer();
229
+ const SentryEffectTracer = isEffectV4 ? makeSentryTracerV4() : makeSentryTracerV3();
141
230
 
142
231
  export { SentryEffectTracer };
143
232
  //# sourceMappingURL=tracer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tracer.js","sources":["../../src/tracer.ts"],"sourcesContent":["import type { Span } from '@sentry/core';\nimport { getActiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startInactiveSpan, withActiveSpan } from '@sentry/core';\nimport type * as Context from 'effect/Context';\nimport * as Exit from 'effect/Exit';\nimport * as Option from 'effect/Option';\nimport * as EffectTracer from 'effect/Tracer';\n\nfunction deriveOrigin(name: string): string {\n if (name.startsWith('http.server') || name.startsWith('http.client')) {\n return 'auto.http.effect';\n }\n\n return 'auto.function.effect';\n}\n\ntype HrTime = [number, number];\n\nconst SENTRY_SPAN_SYMBOL = Symbol.for('@sentry/effect.SentrySpan');\n\nfunction nanosToHrTime(nanos: bigint): HrTime {\n const seconds = Number(nanos / BigInt(1_000_000_000));\n const remainingNanos = Number(nanos % BigInt(1_000_000_000));\n return [seconds, remainingNanos];\n}\n\ninterface SentrySpanLike extends EffectTracer.Span {\n readonly [SENTRY_SPAN_SYMBOL]: true;\n readonly sentrySpan: Span;\n}\n\nfunction isSentrySpan(span: EffectTracer.AnySpan): span is SentrySpanLike {\n return SENTRY_SPAN_SYMBOL in span;\n}\n\nclass SentrySpanWrapper implements SentrySpanLike {\n public readonly [SENTRY_SPAN_SYMBOL]: true;\n public readonly _tag: 'Span';\n public readonly spanId: string;\n public readonly traceId: string;\n public readonly attributes: Map<string, unknown>;\n public readonly sampled: boolean;\n public readonly parent: Option.Option<EffectTracer.AnySpan>;\n public readonly links: Array<EffectTracer.SpanLink>;\n public status: EffectTracer.SpanStatus;\n public readonly sentrySpan: Span;\n\n public constructor(\n public readonly name: string,\n parent: Option.Option<EffectTracer.AnySpan>,\n public readonly context: Context.Context<never>,\n links: ReadonlyArray<EffectTracer.SpanLink>,\n startTime: bigint,\n public readonly kind: EffectTracer.SpanKind,\n existingSpan: Span,\n ) {\n this[SENTRY_SPAN_SYMBOL] = true as const;\n this._tag = 'Span' as const;\n this.attributes = new Map<string, unknown>();\n this.parent = parent;\n this.links = [...links];\n this.sentrySpan = existingSpan;\n\n const spanContext = this.sentrySpan.spanContext();\n this.spanId = spanContext.spanId;\n this.traceId = spanContext.traceId;\n this.sampled = this.sentrySpan.isRecording();\n this.status = {\n _tag: 'Started',\n startTime,\n };\n }\n\n public attribute(key: string, value: unknown): void {\n if (!this.sentrySpan.isRecording()) {\n return;\n }\n\n this.sentrySpan.setAttribute(key, value as Parameters<Span['setAttribute']>[1]);\n this.attributes.set(key, value);\n }\n\n public addLinks(links: ReadonlyArray<EffectTracer.SpanLink>): void {\n this.links.push(...links);\n }\n\n public end(endTime: bigint, exit: Exit.Exit<unknown, unknown>): void {\n this.status = {\n _tag: 'Ended',\n endTime,\n exit,\n startTime: this.status.startTime,\n };\n\n if (!this.sentrySpan.isRecording()) {\n return;\n }\n\n if (Exit.isFailure(exit)) {\n const cause = exit.cause;\n const message =\n cause._tag === 'Fail' ? String(cause.error) : cause._tag === 'Die' ? String(cause.defect) : 'internal_error';\n this.sentrySpan.setStatus({ code: 2, message });\n } else {\n this.sentrySpan.setStatus({ code: 1 });\n }\n\n this.sentrySpan.end(nanosToHrTime(endTime));\n }\n\n public event(name: string, startTime: bigint, attributes?: Record<string, unknown>): void {\n if (!this.sentrySpan.isRecording()) {\n return;\n }\n\n this.sentrySpan.addEvent(name, attributes as Parameters<Span['addEvent']>[1], nanosToHrTime(startTime));\n }\n}\n\nfunction createSentrySpan(\n name: string,\n parent: Option.Option<EffectTracer.AnySpan>,\n context: Context.Context<never>,\n links: ReadonlyArray<EffectTracer.SpanLink>,\n startTime: bigint,\n kind: EffectTracer.SpanKind,\n): SentrySpanLike {\n const parentSentrySpan =\n Option.isSome(parent) && isSentrySpan(parent.value) ? parent.value.sentrySpan : (getActiveSpan() ?? null);\n\n const newSpan = startInactiveSpan({\n name,\n startTime: nanosToHrTime(startTime),\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: deriveOrigin(name),\n },\n ...(parentSentrySpan ? { parentSpan: parentSentrySpan } : {}),\n });\n\n return new SentrySpanWrapper(name, parent, context, links, startTime, kind, newSpan);\n}\n\nconst makeSentryTracer = (): EffectTracer.Tracer =>\n EffectTracer.make({\n span(name, parent, context, links, startTime, kind) {\n return createSentrySpan(name, parent, context, links, startTime, kind);\n },\n context(execution, fiber) {\n const currentSpan = fiber.currentSpan;\n if (currentSpan === undefined || !isSentrySpan(currentSpan)) {\n return execution();\n }\n return withActiveSpan(currentSpan.sentrySpan, execution);\n },\n });\n\n/**\n * Effect Layer that sets up the Sentry tracer for Effect spans.\n */\nexport const SentryEffectTracer = makeSentryTracer();\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tracer.js","sources":["../../src/tracer.ts"],"sourcesContent":["import type { Span } from '@sentry/core';\nimport { getActiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startInactiveSpan, withActiveSpan } from '@sentry/core';\nimport type * as Context from 'effect/Context';\nimport * as Exit from 'effect/Exit';\nimport * as Option from 'effect/Option';\nimport * as EffectTracer from 'effect/Tracer';\n\nfunction deriveOrigin(name: string): string {\n if (name.startsWith('http.server') || name.startsWith('http.client')) {\n return 'auto.http.effect';\n }\n\n return 'auto.function.effect';\n}\n\ntype HrTime = [number, number];\n\nconst SENTRY_SPAN_SYMBOL = Symbol.for('@sentry/effect.SentrySpan');\n\nfunction nanosToHrTime(nanos: bigint): HrTime {\n const seconds = Number(nanos / BigInt(1_000_000_000));\n const remainingNanos = Number(nanos % BigInt(1_000_000_000));\n return [seconds, remainingNanos];\n}\n\ninterface SentrySpanLike extends EffectTracer.Span {\n readonly [SENTRY_SPAN_SYMBOL]: true;\n readonly sentrySpan: Span;\n}\n\nfunction isSentrySpan(span: EffectTracer.AnySpan): span is SentrySpanLike {\n return SENTRY_SPAN_SYMBOL in span;\n}\n\nfunction getErrorMessage(exit: Exit.Exit<unknown, unknown>): string | undefined {\n if (!Exit.isFailure(exit)) {\n return undefined;\n }\n\n const cause = exit.cause as unknown;\n\n // Effect v4: cause.reasons is an array of Reason objects\n if (\n cause &&\n typeof cause === 'object' &&\n 'reasons' in cause &&\n Array.isArray((cause as { reasons: unknown }).reasons)\n ) {\n const reasons = (cause as { reasons: Array<{ _tag?: string; error?: unknown; defect?: unknown }> }).reasons;\n for (const reason of reasons) {\n if (reason._tag === 'Fail' && reason.error !== undefined) {\n return String(reason.error);\n }\n if (reason._tag === 'Die' && reason.defect !== undefined) {\n return String(reason.defect);\n }\n }\n return 'internal_error';\n }\n\n // Effect v3: cause has _tag directly\n if (cause && typeof cause === 'object' && '_tag' in cause) {\n const v3Cause = cause as { _tag: string; error?: unknown; defect?: unknown };\n if (v3Cause._tag === 'Fail') {\n return String(v3Cause.error);\n }\n if (v3Cause._tag === 'Die') {\n return String(v3Cause.defect);\n }\n }\n\n return 'internal_error';\n}\n\nclass SentrySpanWrapper implements SentrySpanLike {\n public readonly [SENTRY_SPAN_SYMBOL]: true;\n public readonly _tag: 'Span';\n public readonly spanId: string;\n public readonly traceId: string;\n public readonly attributes: Map<string, unknown>;\n public readonly sampled: boolean;\n public readonly parent: Option.Option<EffectTracer.AnySpan>;\n public readonly links: Array<EffectTracer.SpanLink>;\n public status: EffectTracer.SpanStatus;\n public readonly sentrySpan: Span;\n public readonly annotations: Context.Context<never>;\n\n public constructor(\n public readonly name: string,\n parent: Option.Option<EffectTracer.AnySpan>,\n public readonly context: Context.Context<never>,\n links: ReadonlyArray<EffectTracer.SpanLink>,\n startTime: bigint,\n public readonly kind: EffectTracer.SpanKind,\n existingSpan: Span,\n ) {\n this[SENTRY_SPAN_SYMBOL] = true as const;\n this._tag = 'Span' as const;\n this.attributes = new Map<string, unknown>();\n this.parent = parent;\n this.links = [...links];\n this.sentrySpan = existingSpan;\n this.annotations = context;\n\n const spanContext = this.sentrySpan.spanContext();\n this.spanId = spanContext.spanId;\n this.traceId = spanContext.traceId;\n this.sampled = this.sentrySpan.isRecording();\n this.status = {\n _tag: 'Started',\n startTime,\n };\n }\n\n public attribute(key: string, value: unknown): void {\n if (!this.sentrySpan.isRecording()) {\n return;\n }\n\n this.sentrySpan.setAttribute(key, value as Parameters<Span['setAttribute']>[1]);\n this.attributes.set(key, value);\n }\n\n public addLinks(links: ReadonlyArray<EffectTracer.SpanLink>): void {\n this.links.push(...links);\n }\n\n public end(endTime: bigint, exit: Exit.Exit<unknown, unknown>): void {\n this.status = {\n _tag: 'Ended',\n endTime,\n exit,\n startTime: this.status.startTime,\n };\n\n if (!this.sentrySpan.isRecording()) {\n return;\n }\n\n if (Exit.isFailure(exit)) {\n const message = getErrorMessage(exit) ?? 'internal_error';\n this.sentrySpan.setStatus({ code: 2, message });\n } else {\n this.sentrySpan.setStatus({ code: 1 });\n }\n\n this.sentrySpan.end(nanosToHrTime(endTime));\n }\n\n public event(name: string, startTime: bigint, attributes?: Record<string, unknown>): void {\n if (!this.sentrySpan.isRecording()) {\n return;\n }\n\n this.sentrySpan.addEvent(name, attributes as Parameters<Span['addEvent']>[1], nanosToHrTime(startTime));\n }\n}\n\nfunction createSentrySpan(\n name: string,\n parent: Option.Option<EffectTracer.AnySpan>,\n context: Context.Context<never>,\n links: ReadonlyArray<EffectTracer.SpanLink>,\n startTime: bigint,\n kind: EffectTracer.SpanKind,\n): SentrySpanLike {\n const parentSentrySpan =\n Option.isSome(parent) && isSentrySpan(parent.value) ? parent.value.sentrySpan : (getActiveSpan() ?? null);\n\n const newSpan = startInactiveSpan({\n name,\n startTime: nanosToHrTime(startTime),\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: deriveOrigin(name),\n },\n ...(parentSentrySpan ? { parentSpan: parentSentrySpan } : {}),\n });\n\n return new SentrySpanWrapper(name, parent, context, links, startTime, kind, newSpan);\n}\n\n// Check if we're running Effect v4 by checking the Exit/Cause structure\n// In v4, causes have a 'reasons' array\n// In v3, causes have '_tag' directly on the cause object\nconst isEffectV4 = (() => {\n try {\n const testExit = Exit.fail('test') as unknown as { cause?: unknown };\n const cause = testExit.cause;\n // v4 causes have 'reasons' array, v3 causes have '_tag' directly\n if (cause && typeof cause === 'object' && 'reasons' in cause) {\n return true;\n }\n return false;\n } catch {\n return false;\n }\n})();\n\nconst makeSentryTracerV3 = (): EffectTracer.Tracer => {\n // Effect v3 API: span(name, parent, context, links, startTime, kind)\n return EffectTracer.make({\n span(\n name: string,\n parent: Option.Option<EffectTracer.AnySpan>,\n context: Context.Context<never>,\n links: ReadonlyArray<EffectTracer.SpanLink>,\n startTime: bigint,\n kind: EffectTracer.SpanKind,\n ) {\n return createSentrySpan(name, parent, context, links, startTime, kind);\n },\n context(execution: () => unknown, fiber: { currentSpan?: EffectTracer.AnySpan }) {\n const currentSpan = fiber.currentSpan;\n if (currentSpan === undefined || !isSentrySpan(currentSpan)) {\n return execution();\n }\n return withActiveSpan(currentSpan.sentrySpan, execution);\n },\n } as unknown as EffectTracer.Tracer);\n};\n\nconst makeSentryTracerV4 = (): EffectTracer.Tracer => {\n const EFFECT_EVALUATE = '~effect/Effect/evaluate' as const;\n\n return EffectTracer.make({\n span(options) {\n return createSentrySpan(\n options.name,\n options.parent,\n options.annotations,\n options.links,\n options.startTime,\n options.kind,\n );\n },\n context(primitive, fiber) {\n const currentSpan = fiber.currentSpan;\n if (currentSpan === undefined || !isSentrySpan(currentSpan)) {\n return primitive[EFFECT_EVALUATE](fiber);\n }\n return withActiveSpan(currentSpan.sentrySpan, () => primitive[EFFECT_EVALUATE](fiber));\n },\n });\n};\n\n/**\n * Effect Layer that sets up the Sentry tracer for Effect spans.\n */\nexport const SentryEffectTracer = isEffectV4 ? makeSentryTracerV4() : makeSentryTracerV3();\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/logger.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC;;GAEG;AACH,eAAO,MAAM,kBAAkB,8BAoC7B,CAAC"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/logger.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAiBxC;;GAEG;AACH,eAAO,MAAM,kBAAkB,8BAuC7B,CAAC"}
@@ -1,13 +1,4 @@
1
- import type * as Layer from 'effect/Layer';
2
- /**
3
- * Creates a metrics flusher with its own isolated state for delta tracking.
4
- * Useful for testing scenarios where you need to control the lifecycle.
5
- * @internal
6
- */
7
- export declare function createMetricsFlusher(): {
8
- flush: () => void;
9
- clear: () => void;
10
- };
1
+ import * as Layer from 'effect/Layer';
11
2
  /**
12
3
  * Effect Layer that periodically flushes metrics to Sentry.
13
4
  * The layer manages its own state for delta counter calculations,
@@ -1 +1 @@
1
- {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/metrics.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,KAAK,MAAM,cAAc,CAAC;AA0F3C;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI;IACtC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAMA;AAWD;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAYrE,CAAC"}
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/metrics.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AA8KtC;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAYrE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"tracer.d.ts","sourceRoot":"","sources":["../../src/tracer.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,YAAY,MAAM,eAAe,CAAC;AAsJ9C;;GAEG;AACH,eAAO,MAAM,kBAAkB,qBAAqB,CAAC"}
1
+ {"version":3,"file":"tracer.d.ts","sourceRoot":"","sources":["../../src/tracer.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,YAAY,MAAM,eAAe,CAAC;AAgP9C;;GAEG;AACH,eAAO,MAAM,kBAAkB,qBAA2D,CAAC"}
@@ -1,13 +1,4 @@
1
1
  import * as Layer from 'effect/Layer';
2
- /**
3
- * Creates a metrics flusher with its own isolated state for delta tracking.
4
- * Useful for testing scenarios where you need to control the lifecycle.
5
- * @internal
6
- */
7
- export declare function createMetricsFlusher(): {
8
- flush: () => void;
9
- clear: () => void;
10
- };
11
2
  /**
12
3
  * Effect Layer that periodically flushes metrics to Sentry.
13
4
  * The layer manages its own state for delta counter calculations,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/effect",
3
- "version": "10.50.0-alpha.0",
3
+ "version": "10.51.0",
4
4
  "description": "Official Sentry SDK for Effect",
5
5
  "repository": "git://github.com/getsentry/sentry-javascript.git",
6
6
  "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/effect",
@@ -57,12 +57,12 @@
57
57
  "access": "public"
58
58
  },
59
59
  "dependencies": {
60
- "@sentry/browser": "10.50.0-alpha.0",
61
- "@sentry/core": "10.50.0-alpha.0",
62
- "@sentry/node-core": "10.50.0-alpha.0"
60
+ "@sentry/browser": "10.51.0",
61
+ "@sentry/core": "10.51.0",
62
+ "@sentry/node-core": "10.51.0"
63
63
  },
64
64
  "peerDependencies": {
65
- "effect": "^3.0.0"
65
+ "effect": "^3.0.0 || ^4.0.0-beta.50"
66
66
  },
67
67
  "peerDependenciesMeta": {
68
68
  "effect": {
@@ -70,8 +70,8 @@
70
70
  }
71
71
  },
72
72
  "devDependencies": {
73
- "@effect/vitest": "^0.23.9",
74
- "effect": "^3.21.0"
73
+ "@effect/vitest": "^4.0.0-beta.50",
74
+ "effect": "^4.0.0-beta.50"
75
75
  },
76
76
  "scripts": {
77
77
  "build": "run-p build:transpile build:types",