Skip to content

Commit 2343380

Browse files
authored
feat(node): Add lru-memoizer instrumentation (#13796)
Resolves: #13309 Adds integration for `lru-memoizer` using [@opentelemetry/instrumentation-lru-memoizer](https://www.npmjs.com/package/@opentelemetry/instrumentation-lru-memoizer). This instrumentation does not create any spans. It only assigns the span context into memoized callbacks used in `lru-memoizer`'s `load`. Ported a test case from the original implementation and tested manually to validate.
1 parent 5e2bc47 commit 2343380

File tree

12 files changed

+133
-7
lines changed

12 files changed

+133
-7
lines changed

dev-packages/node-integration-tests/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"http-terminator": "^3.2.0",
5252
"ioredis": "^5.4.1",
5353
"kafkajs": "2.2.4",
54+
"lru-memoizer": "2.3.0",
5455
"mongodb": "^3.7.3",
5556
"mongodb-memory-server-global": "^7.6.3",
5657
"mongoose": "^5.13.22",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
const { loggingTransport } = require('@sentry-internal/node-integration-tests');
2+
const Sentry = require('@sentry/node');
3+
4+
Sentry.init({
5+
dsn: 'https://[email protected]/1337',
6+
release: '1.0',
7+
tracesSampleRate: 1.0,
8+
transport: loggingTransport,
9+
});
10+
11+
// Stop the process from exiting before the transaction is sent
12+
setInterval(() => {}, 1000);
13+
14+
const run = async () => {
15+
// Test ported from the OTEL implementation:
16+
// https://github.com/open-telemetry/opentelemetry-js-contrib/blob/0d6ebded313bb75b5a0e7a6422206c922daf3943/plugins/node/instrumentation-lru-memoizer/test/index.test.ts#L28
17+
const memoizer = require('lru-memoizer');
18+
19+
let memoizerLoadCallback;
20+
const memoizedFoo = memoizer({
21+
load: (_param, callback) => {
22+
memoizerLoadCallback = callback;
23+
},
24+
hash: () => 'bar',
25+
});
26+
27+
Sentry.startSpan({ op: 'run' }, async span => {
28+
const outerSpanContext = span.spanContext();
29+
30+
memoizedFoo({ foo: 'bar' }, () => {
31+
const innerContext = Sentry.getActiveSpan().spanContext();
32+
33+
// The span context should be the same as the outer span
34+
// Throwing an error here will cause the test to fail
35+
if (outerSpanContext !== innerContext) {
36+
throw new Error('Outer and inner span context should match');
37+
}
38+
});
39+
40+
span.end();
41+
});
42+
43+
// Invoking the load callback outside the span
44+
memoizerLoadCallback();
45+
};
46+
47+
run();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { cleanupChildProcesses, createRunner } from '../../../utils/runner';
2+
3+
describe('lru-memoizer', () => {
4+
afterAll(() => {
5+
cleanupChildProcesses();
6+
});
7+
8+
test('keeps outer context inside the memoized inner functions', done => {
9+
createRunner(__dirname, 'scenario.js')
10+
// We expect only one transaction and nothing else.
11+
// A failed test will result in an error event being sent to Sentry.
12+
// Which will fail this suite.
13+
.expect({
14+
transaction: {
15+
transaction: '<unknown>',
16+
contexts: {
17+
trace: expect.objectContaining({
18+
op: 'run',
19+
data: expect.objectContaining({
20+
'sentry.op': 'run',
21+
'sentry.origin': 'manual',
22+
}),
23+
}),
24+
},
25+
},
26+
})
27+
.start(done);
28+
});
29+
});

packages/astro/src/index.server.ts

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export {
7272
lastEventId,
7373
linkedErrorsIntegration,
7474
localVariablesIntegration,
75+
lruMemoizerIntegration,
7576
makeNodeTransport,
7677
metrics,
7778
modulesIntegration,

packages/aws-serverless/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export {
9191
genericPoolIntegration,
9292
graphqlIntegration,
9393
kafkaIntegration,
94+
lruMemoizerIntegration,
9495
mongoIntegration,
9596
mongooseIntegration,
9697
mysqlIntegration,

packages/bun/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ export {
112112
genericPoolIntegration,
113113
graphqlIntegration,
114114
kafkaIntegration,
115+
lruMemoizerIntegration,
115116
mongoIntegration,
116117
mongooseIntegration,
117118
mysqlIntegration,

packages/google-cloud-serverless/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export {
9191
genericPoolIntegration,
9292
graphqlIntegration,
9393
kafkaIntegration,
94+
lruMemoizerIntegration,
9495
mongoIntegration,
9596
mongooseIntegration,
9697
mysqlIntegration,

packages/node/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
"@opentelemetry/instrumentation-ioredis": "0.43.0",
8383
"@opentelemetry/instrumentation-kafkajs": "0.3.0",
8484
"@opentelemetry/instrumentation-koa": "0.43.0",
85+
"@opentelemetry/instrumentation-lru-memoizer": "0.40.0",
8586
"@opentelemetry/instrumentation-mongodb": "0.47.0",
8687
"@opentelemetry/instrumentation-mongoose": "0.42.0",
8788
"@opentelemetry/instrumentation-mysql": "0.41.0",

packages/node/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export { expressIntegration, expressErrorHandler, setupExpressErrorHandler } fro
1515
export { fastifyIntegration, setupFastifyErrorHandler } from './integrations/tracing/fastify';
1616
export { graphqlIntegration } from './integrations/tracing/graphql';
1717
export { kafkaIntegration } from './integrations/tracing/kafka';
18+
export { lruMemoizerIntegration } from './integrations/tracing/lrumemoizer';
1819
export { mongoIntegration } from './integrations/tracing/mongo';
1920
export { mongooseIntegration } from './integrations/tracing/mongoose';
2021
export { mysqlIntegration } from './integrations/tracing/mysql';

packages/node/src/integrations/tracing/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { graphqlIntegration, instrumentGraphql } from './graphql';
1111
import { hapiIntegration, instrumentHapi } from './hapi';
1212
import { instrumentKafka, kafkaIntegration } from './kafka';
1313
import { instrumentKoa, koaIntegration } from './koa';
14+
import { instrumentLruMemoizer, lruMemoizerIntegration } from './lrumemoizer';
1415
import { instrumentMongo, mongoIntegration } from './mongo';
1516
import { instrumentMongoose, mongooseIntegration } from './mongoose';
1617
import { instrumentMysql, mysqlIntegration } from './mysql';
@@ -45,6 +46,7 @@ export function getAutoPerformanceIntegrations(): Integration[] {
4546
kafkaIntegration(),
4647
dataloaderIntegration(),
4748
amqplibIntegration(),
49+
lruMemoizerIntegration(),
4850
];
4951
}
5052

@@ -61,6 +63,7 @@ export function getOpenTelemetryInstrumentationToPreload(): (((options?: any) =>
6163
instrumentHapi,
6264
instrumentKafka,
6365
instrumentKoa,
66+
instrumentLruMemoizer,
6467
instrumentNest,
6568
instrumentMongo,
6669
instrumentMongoose,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { LruMemoizerInstrumentation } from '@opentelemetry/instrumentation-lru-memoizer';
2+
3+
import { defineIntegration } from '@sentry/core';
4+
import type { IntegrationFn } from '@sentry/types';
5+
import { generateInstrumentOnce } from '../../otel/instrument';
6+
7+
const INTEGRATION_NAME = 'LruMemoizer';
8+
9+
export const instrumentLruMemoizer = generateInstrumentOnce(INTEGRATION_NAME, () => new LruMemoizerInstrumentation());
10+
11+
const _lruMemoizerIntegration = (() => {
12+
return {
13+
name: INTEGRATION_NAME,
14+
setupOnce() {
15+
instrumentLruMemoizer();
16+
},
17+
};
18+
}) satisfies IntegrationFn;
19+
20+
/**
21+
* LruMemoizer integration
22+
*
23+
* Propagate traces through LruMemoizer.
24+
*/
25+
export const lruMemoizerIntegration = defineIntegration(_lruMemoizerIntegration);

yarn.lock

+22-7
Original file line numberDiff line numberDiff line change
@@ -7321,6 +7321,13 @@
73217321
"@opentelemetry/instrumentation" "^0.53.0"
73227322
"@opentelemetry/semantic-conventions" "^1.27.0"
73237323

7324+
"@opentelemetry/[email protected]":
7325+
version "0.40.0"
7326+
resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.40.0.tgz#dc60d7fdfd2a0c681cb23e7ed4f314d1506ccdc0"
7327+
integrity sha512-21xRwZsEdMPnROu/QsaOIODmzw59IYpGFmuC4aFWvMj6stA8+Ei1tX67nkarJttlNjoM94um0N4X26AD7ff54A==
7328+
dependencies:
7329+
"@opentelemetry/instrumentation" "^0.53.0"
7330+
73247331
"@opentelemetry/[email protected]":
73257332
version "0.47.0"
73267333
resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.47.0.tgz#f8107d878281433905e717f223fb4c0f10356a7b"
@@ -23413,6 +23420,13 @@ lowercase-keys@^2.0.0:
2341323420
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
2341423421
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
2341523422

23423+
[email protected], lru-cache@^6.0.0:
23424+
version "6.0.0"
23425+
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
23426+
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
23427+
dependencies:
23428+
yallist "^4.0.0"
23429+
2341623430
lru-cache@^10.0.1, lru-cache@^10.2.0:
2341723431
version "10.2.2"
2341823432
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.2.tgz#48206bc114c1252940c41b25b41af5b545aca878"
@@ -23425,13 +23439,6 @@ lru-cache@^5.1.1:
2342523439
dependencies:
2342623440
yallist "^3.0.2"
2342723441

23428-
lru-cache@^6.0.0:
23429-
version "6.0.0"
23430-
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
23431-
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
23432-
dependencies:
23433-
yallist "^4.0.0"
23434-
2343523442
lru-cache@^7.10.1, lru-cache@^7.4.4, lru-cache@^7.5.1, lru-cache@^7.7.1:
2343623443
version "7.14.1"
2343723444
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.14.1.tgz#8da8d2f5f59827edb388e63e459ac23d6d408fea"
@@ -23457,6 +23464,14 @@ lru-cache@^9.0.0:
2345723464
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.0.tgz#b9e2a6a72a129d81ab317202d93c7691df727e61"
2345823465
integrity sha512-svTf/fzsKHffP42sujkO/Rjs37BCIsQVRCeNYIm9WN8rgT7ffoUnRtZCqU+6BqcSBdv8gwJeTz8knJpgACeQMw==
2345923466

23467+
23468+
version "2.3.0"
23469+
resolved "https://registry.yarnpkg.com/lru-memoizer/-/lru-memoizer-2.3.0.tgz#ef0fbc021bceb666794b145eefac6be49dc47f31"
23470+
integrity sha512-GXn7gyHAMhO13WSKrIiNfztwxodVsP8IoZ3XfrJV4yH2x0/OeTO/FIaAHTY5YekdGgW94njfuKmyyt1E0mR6Ug==
23471+
dependencies:
23472+
lodash.clonedeep "^4.5.0"
23473+
lru-cache "6.0.0"
23474+
2346023475
lunr@^2.3.8:
2346123476
version "2.3.9"
2346223477
resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1"

0 commit comments

Comments
 (0)