Skip to content

Commit 2db4b85

Browse files
committed
feat(effect): Add extra opt-in for logs and metrics (#19755)
This PR is now adding a different naming schema for enabling logs and metrics based on: https://develop.sentry.dev/sdk/telemetry/metrics/#auto-emitted-metrics For the logs I also added them, which might not make the most sense, as `enableLogs` is now `false` by default, which means that there is a double opt-in needed to make logs work via `Effect.log`. The naming is TBD, but this is the best I came up with: `enableEffectLogs` & `enableEffectMetrics`
1 parent c6540b9 commit 2db4b85

7 files changed

Lines changed: 78 additions & 47 deletions

File tree

packages/core/src/client.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,10 +256,10 @@ export abstract class Client<O extends ClientOptions = ClientOptions> {
256256

257257
// todo(v11): Remove the experimental flag
258258
// eslint-disable-next-line deprecation/deprecation
259-
const enableMetrics = this._options.enableMetrics ?? this._options._experiments?.enableMetrics ?? true;
259+
this._options.enableMetrics = this._options.enableMetrics ?? this._options._experiments?.enableMetrics ?? true;
260260

261261
// Setup metric flushing with weight and timeout tracking
262-
if (enableMetrics) {
262+
if (this._options.enableMetrics) {
263263
setupWeightBasedFlushing(
264264
this,
265265
'afterCaptureMetric',

packages/effect/README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ const MainLive = HttpLive.pipe(
2323
Sentry.effectLayer({
2424
dsn: '__DSN__',
2525
enableLogs: true,
26-
enableMetrics: true,
26+
enableEffectLogs: true,
27+
enableEffectMetrics: true,
2728
}),
2829
),
2930
);
@@ -35,8 +36,8 @@ The `effectLayer` function initializes Sentry and returns an Effect Layer that p
3536

3637
- Distributed tracing with automatic HTTP header extraction/injection
3738
- Effect spans traced as Sentry spans
38-
- Effect logs forwarded to Sentry (when `enableLogs` is set)
39-
- Effect metrics sent to Sentry (when `enableMetrics` is set)
39+
- Effect logs forwarded to Sentry (when `enableEffectLogs` is set)
40+
- Effect metrics sent to Sentry (when `enableEffectMetrics` is set)
4041

4142
## Links
4243

packages/effect/src/client/index.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { BrowserOptions } from '@sentry/browser';
22
import type * as EffectLayer from 'effect/Layer';
33
import { suspend as suspendLayer } from 'effect/Layer';
4+
import type { EffectLayerBaseOptions } from '../utils/buildEffectLayer';
45
import { buildEffectLayer } from '../utils/buildEffectLayer';
56
import { init } from './sdk';
67

@@ -9,15 +10,15 @@ export { init } from './sdk';
910
/**
1011
* Options for the Sentry Effect client layer.
1112
*/
12-
export type EffectClientLayerOptions = BrowserOptions;
13+
export type EffectClientLayerOptions = BrowserOptions & EffectLayerBaseOptions;
1314

1415
/**
1516
* Creates an Effect Layer that initializes Sentry for browser clients.
1617
*
1718
* This layer provides Effect applications with full Sentry instrumentation including:
1819
* - Effect spans traced as Sentry spans
19-
* - Effect logs forwarded to Sentry (when `enableLogs` is set)
20-
* - Effect metrics sent to Sentry (when `enableMetrics` is set)
20+
* - Effect logs forwarded to Sentry (when `enableEffectLogs` is set)
21+
* - Effect metrics sent to Sentry (when `enableEffectMetrics` is set)
2122
*
2223
* @example
2324
* ```typescript

packages/effect/src/server/index.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { NodeOptions } from '@sentry/node-core/light';
22
import type * as EffectLayer from 'effect/Layer';
3+
import type { EffectLayerBaseOptions } from '../utils/buildEffectLayer';
34
import { buildEffectLayer } from '../utils/buildEffectLayer';
45
import { init } from './sdk';
56

@@ -8,15 +9,15 @@ export { init } from './sdk';
89
/**
910
* Options for the Sentry Effect server layer.
1011
*/
11-
export type EffectServerLayerOptions = NodeOptions;
12+
export type EffectServerLayerOptions = NodeOptions & EffectLayerBaseOptions;
1213

1314
/**
1415
* Creates an Effect Layer that initializes Sentry for Node.js servers.
1516
*
1617
* This layer provides Effect applications with full Sentry instrumentation including:
1718
* - Effect spans traced as Sentry spans
18-
* - Effect logs forwarded to Sentry (when `enableLogs` is set)
19-
* - Effect metrics sent to Sentry (when `enableMetrics` is set)
19+
* - Effect logs forwarded to Sentry (when `enableEffectLogs` is set)
20+
* - Effect metrics sent to Sentry (when `enableEffectMetrics` is set)
2021
*
2122
* @example
2223
* ```typescript
@@ -28,8 +29,8 @@ export type EffectServerLayerOptions = NodeOptions;
2829
* const MainLive = HttpLive.pipe(
2930
* Layer.provide(Sentry.effectLayer({
3031
* dsn: '__DSN__',
31-
* enableLogs: true,
32-
* enableMetrics: true,
32+
* enableEffectLogs: true,
33+
* enableEffectMetrics: true,
3334
* })),
3435
* );
3536
*

packages/effect/src/utils/buildEffectLayer.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { Client } from '@sentry/core';
12
import type * as EffectLayer from 'effect/Layer';
23
import { empty as emptyLayer, provideMerge } from 'effect/Layer';
34
import { defaultLogger, replace as replaceLogger } from 'effect/Logger';
@@ -6,8 +7,8 @@ import { SentryEffectMetricsLayer } from '../metrics';
67
import { SentryEffectTracerLayer } from '../tracer';
78

89
export interface EffectLayerBaseOptions {
9-
enableLogs?: boolean;
10-
enableMetrics?: boolean;
10+
enableEffectLogs?: boolean;
11+
enableEffectMetrics?: boolean;
1112
}
1213

1314
/**
@@ -19,21 +20,22 @@ export interface EffectLayerBaseOptions {
1920
*/
2021
export function buildEffectLayer<T extends EffectLayerBaseOptions>(
2122
options: T,
22-
client: unknown,
23+
client: Client | undefined,
2324
): EffectLayer.Layer<never, never, never> {
2425
if (!client) {
2526
return emptyLayer;
2627
}
2728

28-
const { enableLogs = false, enableMetrics = true } = options;
29+
const clientOptions = client.getOptions();
30+
const { enableEffectLogs = false, enableEffectMetrics = false } = options;
2931
let layer: EffectLayer.Layer<never, never, never> = SentryEffectTracerLayer;
3032

31-
if (enableLogs) {
33+
if (enableEffectLogs && clientOptions.enableLogs) {
3234
const effectLogger = replaceLogger(defaultLogger, SentryEffectLogger);
3335
layer = layer.pipe(provideMerge(effectLogger));
3436
}
3537

36-
if (enableMetrics) {
38+
if (enableEffectMetrics && clientOptions.enableMetrics) {
3739
layer = layer.pipe(provideMerge(SentryEffectMetricsLayer));
3840
}
3941

packages/effect/test/buildEffectLayer.test.ts

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,31 @@
11
import { describe, expect, it, vi } from '@effect/vitest';
22
import * as sentryCore from '@sentry/core';
33
import { logger as sentryLogger } from '@sentry/core';
4+
import type { NodeOptions } from '@sentry/node-core';
45
import { Effect, Layer } from 'effect';
56
import { empty as emptyLayer } from 'effect/Layer';
7+
import { init } from '../src/index.server';
68
import { buildEffectLayer } from '../src/utils/buildEffectLayer';
79

10+
function getMockTransport() {
11+
return () => ({
12+
send: vi.fn().mockResolvedValue({}),
13+
flush: vi.fn().mockResolvedValue(true),
14+
});
15+
}
16+
17+
function createClient(options: NodeOptions = {}) {
18+
return init({
19+
dsn: 'https://username@domain/123',
20+
transport: getMockTransport(),
21+
...options,
22+
});
23+
}
24+
825
describe('buildEffectLayer', () => {
926
describe('when client is falsy', () => {
1027
it('returns empty layer when client is null', () => {
11-
const layer = buildEffectLayer({}, null);
28+
const layer = buildEffectLayer({}, undefined);
1229

1330
expect(layer).toBeDefined();
1431
expect(Layer.isLayer(layer)).toBe(true);
@@ -25,45 +42,49 @@ describe('buildEffectLayer', () => {
2542
});
2643

2744
describe('when client is truthy', () => {
28-
const mockClient = { mock: true };
29-
3045
it('returns a valid layer with default options', () => {
31-
const layer = buildEffectLayer({}, mockClient);
46+
const client = createClient();
47+
const layer = buildEffectLayer({}, client);
3248

3349
expect(layer).toBeDefined();
3450
expect(Layer.isLayer(layer)).toBe(true);
3551
});
3652

37-
it('returns a valid layer with enableLogs: false', () => {
38-
const layer = buildEffectLayer({ enableLogs: false }, mockClient);
53+
it('returns a valid layer with enableEffectLogs: false', () => {
54+
const client = createClient();
55+
const layer = buildEffectLayer({ enableEffectLogs: false }, client);
3956

4057
expect(layer).toBeDefined();
4158
expect(Layer.isLayer(layer)).toBe(true);
4259
});
4360

44-
it('returns a valid layer with enableLogs: true', () => {
45-
const layer = buildEffectLayer({ enableLogs: true }, mockClient);
61+
it('returns a valid layer with enableEffectLogs: true', () => {
62+
const client = createClient();
63+
const layer = buildEffectLayer({ enableEffectLogs: true }, client);
4664

4765
expect(layer).toBeDefined();
4866
expect(Layer.isLayer(layer)).toBe(true);
4967
});
5068

51-
it('returns a valid layer with enableMetrics: false', () => {
52-
const layer = buildEffectLayer({ enableMetrics: false }, mockClient);
69+
it('returns a valid layer with enableEffectMetrics: false', () => {
70+
const client = createClient();
71+
const layer = buildEffectLayer({ enableEffectMetrics: false }, client);
5372

5473
expect(layer).toBeDefined();
5574
expect(Layer.isLayer(layer)).toBe(true);
5675
});
5776

58-
it('returns a valid layer with enableMetrics: true', () => {
59-
const layer = buildEffectLayer({ enableMetrics: true }, mockClient);
77+
it('returns a valid layer with enableEffectMetrics: true', () => {
78+
const client = createClient();
79+
const layer = buildEffectLayer({ enableEffectMetrics: true }, client);
6080

6181
expect(layer).toBeDefined();
6282
expect(Layer.isLayer(layer)).toBe(true);
6383
});
6484

6585
it('returns a valid layer with all features enabled', () => {
66-
const layer = buildEffectLayer({ enableLogs: true, enableMetrics: true }, mockClient);
86+
const client = createClient();
87+
const layer = buildEffectLayer({ enableEffectLogs: true, enableEffectMetrics: true }, client);
6788

6889
expect(layer).toBeDefined();
6990
expect(Layer.isLayer(layer)).toBe(true);
@@ -73,7 +94,7 @@ describe('buildEffectLayer', () => {
7394
Effect.gen(function* () {
7495
const result = yield* Effect.succeed('test-result');
7596
expect(result).toBe('test-result');
76-
}).pipe(Effect.provide(buildEffectLayer({}, mockClient))),
97+
}).pipe(Effect.provide(buildEffectLayer({}, createClient()))),
7798
);
7899

79100
it.effect('layer with logs enabled routes Effect logs to Sentry logger', () =>
@@ -82,12 +103,13 @@ describe('buildEffectLayer', () => {
82103
yield* Effect.log('test log message');
83104
expect(infoSpy).toHaveBeenCalledWith('test log message');
84105
infoSpy.mockRestore();
85-
}).pipe(Effect.provide(buildEffectLayer({ enableLogs: true }, mockClient))),
106+
}).pipe(Effect.provide(buildEffectLayer({ enableEffectLogs: true }, createClient({ enableLogs: true })))),
86107
);
87108

88-
it('returns different layer when enableMetrics is true vs false', () => {
89-
const layerWithMetrics = buildEffectLayer({ enableMetrics: true }, mockClient);
90-
const layerWithoutMetrics = buildEffectLayer({ enableMetrics: false }, mockClient);
109+
it('returns different layer when enableEffectMetrics is true vs false', () => {
110+
const client = createClient();
111+
const layerWithMetrics = buildEffectLayer({ enableEffectMetrics: true }, client);
112+
const layerWithoutMetrics = buildEffectLayer({ enableEffectMetrics: false }, client);
91113

92114
expect(layerWithMetrics).not.toBe(layerWithoutMetrics);
93115
});
@@ -96,7 +118,11 @@ describe('buildEffectLayer', () => {
96118
Effect.gen(function* () {
97119
const result = yield* Effect.succeed('all-features');
98120
expect(result).toBe('all-features');
99-
}).pipe(Effect.provide(buildEffectLayer({ enableLogs: true, enableMetrics: true }, mockClient))),
121+
}).pipe(
122+
Effect.provide(
123+
buildEffectLayer({ enableEffectLogs: true, enableEffectMetrics: true }, createClient({ enableLogs: true })),
124+
),
125+
),
100126
);
101127

102128
it.effect('layer enables tracing for Effect spans via Sentry tracer', () =>
@@ -110,22 +136,22 @@ describe('buildEffectLayer', () => {
110136
}),
111137
);
112138
startInactiveSpanSpy.mockRestore();
113-
}).pipe(Effect.provide(buildEffectLayer({}, mockClient))),
139+
}).pipe(Effect.provide(buildEffectLayer({}, createClient()))),
114140
);
115141
});
116142

117143
describe('with additional options', () => {
118-
const mockClient = { mock: true };
144+
const client = createClient({ enableLogs: true });
119145

120146
it('accepts options with additional properties', () => {
121147
const layer = buildEffectLayer(
122148
{
123-
enableLogs: true,
124-
enableMetrics: true,
149+
enableEffectLogs: true,
150+
enableEffectMetrics: true,
125151
dsn: 'https://test@sentry.io/123',
126152
debug: true,
127-
} as { enableLogs?: boolean; enableMetrics?: boolean; dsn?: string; debug?: boolean },
128-
mockClient,
153+
} as { enableEffectLogs?: boolean; enableEffectMetrics?: boolean; dsn?: string; debug?: boolean },
154+
client,
129155
);
130156

131157
expect(layer).toBeDefined();

packages/effect/test/layer.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ describe.each([
6363
const layer = effectLayer({
6464
dsn: TEST_DSN,
6565
transport: getMockTransport(),
66-
enableLogs: true,
66+
enableEffectLogs: true,
6767
});
6868

6969
expect(layer).toBeDefined();
@@ -73,8 +73,8 @@ describe.each([
7373
const layer = effectLayer({
7474
dsn: TEST_DSN,
7575
transport: getMockTransport(),
76-
enableLogs: true,
77-
enableMetrics: true,
76+
enableEffectLogs: true,
77+
enableEffectMetrics: true,
7878
});
7979

8080
expect(layer).toBeDefined();

0 commit comments

Comments
 (0)