Skip to content

Commit

Permalink
feat(node): Add lru-memoizer instrumentation (#13796)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
onurtemizkan authored Sep 26, 2024
1 parent 5e2bc47 commit 2343380
Show file tree
Hide file tree
Showing 12 changed files with 133 additions and 7 deletions.
1 change: 1 addition & 0 deletions dev-packages/node-integration-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"http-terminator": "^3.2.0",
"ioredis": "^5.4.1",
"kafkajs": "2.2.4",
"lru-memoizer": "2.3.0",
"mongodb": "^3.7.3",
"mongodb-memory-server-global": "^7.6.3",
"mongoose": "^5.13.22",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const { loggingTransport } = require('@sentry-internal/node-integration-tests');
const Sentry = require('@sentry/node');

Sentry.init({
dsn: 'https://public@dsn.ingest.sentry.io/1337',
release: '1.0',
tracesSampleRate: 1.0,
transport: loggingTransport,
});

// Stop the process from exiting before the transaction is sent
setInterval(() => {}, 1000);

const run = async () => {
// Test ported from the OTEL implementation:
// https://github.com/open-telemetry/opentelemetry-js-contrib/blob/0d6ebded313bb75b5a0e7a6422206c922daf3943/plugins/node/instrumentation-lru-memoizer/test/index.test.ts#L28
const memoizer = require('lru-memoizer');

let memoizerLoadCallback;
const memoizedFoo = memoizer({
load: (_param, callback) => {
memoizerLoadCallback = callback;
},
hash: () => 'bar',
});

Sentry.startSpan({ op: 'run' }, async span => {
const outerSpanContext = span.spanContext();

memoizedFoo({ foo: 'bar' }, () => {
const innerContext = Sentry.getActiveSpan().spanContext();

// The span context should be the same as the outer span
// Throwing an error here will cause the test to fail
if (outerSpanContext !== innerContext) {
throw new Error('Outer and inner span context should match');
}
});

span.end();
});

// Invoking the load callback outside the span
memoizerLoadCallback();
};

run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { cleanupChildProcesses, createRunner } from '../../../utils/runner';

describe('lru-memoizer', () => {
afterAll(() => {
cleanupChildProcesses();
});

test('keeps outer context inside the memoized inner functions', done => {
createRunner(__dirname, 'scenario.js')
// We expect only one transaction and nothing else.
// A failed test will result in an error event being sent to Sentry.
// Which will fail this suite.
.expect({
transaction: {
transaction: '<unknown>',
contexts: {
trace: expect.objectContaining({
op: 'run',
data: expect.objectContaining({
'sentry.op': 'run',
'sentry.origin': 'manual',
}),
}),
},
},
})
.start(done);
});
});
1 change: 1 addition & 0 deletions packages/astro/src/index.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export {
lastEventId,
linkedErrorsIntegration,
localVariablesIntegration,
lruMemoizerIntegration,
makeNodeTransport,
metrics,
modulesIntegration,
Expand Down
1 change: 1 addition & 0 deletions packages/aws-serverless/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export {
genericPoolIntegration,
graphqlIntegration,
kafkaIntegration,
lruMemoizerIntegration,
mongoIntegration,
mongooseIntegration,
mysqlIntegration,
Expand Down
1 change: 1 addition & 0 deletions packages/bun/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ export {
genericPoolIntegration,
graphqlIntegration,
kafkaIntegration,
lruMemoizerIntegration,
mongoIntegration,
mongooseIntegration,
mysqlIntegration,
Expand Down
1 change: 1 addition & 0 deletions packages/google-cloud-serverless/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export {
genericPoolIntegration,
graphqlIntegration,
kafkaIntegration,
lruMemoizerIntegration,
mongoIntegration,
mongooseIntegration,
mysqlIntegration,
Expand Down
1 change: 1 addition & 0 deletions packages/node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
"@opentelemetry/instrumentation-ioredis": "0.43.0",
"@opentelemetry/instrumentation-kafkajs": "0.3.0",
"@opentelemetry/instrumentation-koa": "0.43.0",
"@opentelemetry/instrumentation-lru-memoizer": "0.40.0",
"@opentelemetry/instrumentation-mongodb": "0.47.0",
"@opentelemetry/instrumentation-mongoose": "0.42.0",
"@opentelemetry/instrumentation-mysql": "0.41.0",
Expand Down
1 change: 1 addition & 0 deletions packages/node/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export { expressIntegration, expressErrorHandler, setupExpressErrorHandler } fro
export { fastifyIntegration, setupFastifyErrorHandler } from './integrations/tracing/fastify';
export { graphqlIntegration } from './integrations/tracing/graphql';
export { kafkaIntegration } from './integrations/tracing/kafka';
export { lruMemoizerIntegration } from './integrations/tracing/lrumemoizer';
export { mongoIntegration } from './integrations/tracing/mongo';
export { mongooseIntegration } from './integrations/tracing/mongoose';
export { mysqlIntegration } from './integrations/tracing/mysql';
Expand Down
3 changes: 3 additions & 0 deletions packages/node/src/integrations/tracing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { graphqlIntegration, instrumentGraphql } from './graphql';
import { hapiIntegration, instrumentHapi } from './hapi';
import { instrumentKafka, kafkaIntegration } from './kafka';
import { instrumentKoa, koaIntegration } from './koa';
import { instrumentLruMemoizer, lruMemoizerIntegration } from './lrumemoizer';
import { instrumentMongo, mongoIntegration } from './mongo';
import { instrumentMongoose, mongooseIntegration } from './mongoose';
import { instrumentMysql, mysqlIntegration } from './mysql';
Expand Down Expand Up @@ -45,6 +46,7 @@ export function getAutoPerformanceIntegrations(): Integration[] {
kafkaIntegration(),
dataloaderIntegration(),
amqplibIntegration(),
lruMemoizerIntegration(),
];
}

Expand All @@ -61,6 +63,7 @@ export function getOpenTelemetryInstrumentationToPreload(): (((options?: any) =>
instrumentHapi,
instrumentKafka,
instrumentKoa,
instrumentLruMemoizer,
instrumentNest,
instrumentMongo,
instrumentMongoose,
Expand Down
25 changes: 25 additions & 0 deletions packages/node/src/integrations/tracing/lrumemoizer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { LruMemoizerInstrumentation } from '@opentelemetry/instrumentation-lru-memoizer';

import { defineIntegration } from '@sentry/core';
import type { IntegrationFn } from '@sentry/types';
import { generateInstrumentOnce } from '../../otel/instrument';

const INTEGRATION_NAME = 'LruMemoizer';

export const instrumentLruMemoizer = generateInstrumentOnce(INTEGRATION_NAME, () => new LruMemoizerInstrumentation());

const _lruMemoizerIntegration = (() => {
return {
name: INTEGRATION_NAME,
setupOnce() {
instrumentLruMemoizer();
},
};
}) satisfies IntegrationFn;

/**
* LruMemoizer integration
*
* Propagate traces through LruMemoizer.
*/
export const lruMemoizerIntegration = defineIntegration(_lruMemoizerIntegration);
29 changes: 22 additions & 7 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7321,6 +7321,13 @@
"@opentelemetry/instrumentation" "^0.53.0"
"@opentelemetry/semantic-conventions" "^1.27.0"

"@opentelemetry/instrumentation-lru-memoizer@0.40.0":
version "0.40.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.40.0.tgz#dc60d7fdfd2a0c681cb23e7ed4f314d1506ccdc0"
integrity sha512-21xRwZsEdMPnROu/QsaOIODmzw59IYpGFmuC4aFWvMj6stA8+Ei1tX67nkarJttlNjoM94um0N4X26AD7ff54A==
dependencies:
"@opentelemetry/instrumentation" "^0.53.0"

"@opentelemetry/instrumentation-mongodb@0.47.0":
version "0.47.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.47.0.tgz#f8107d878281433905e717f223fb4c0f10356a7b"
Expand Down Expand Up @@ -23413,6 +23420,13 @@ lowercase-keys@^2.0.0:
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==

lru-cache@6.0.0, lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
yallist "^4.0.0"

lru-cache@^10.0.1, lru-cache@^10.2.0:
version "10.2.2"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.2.tgz#48206bc114c1252940c41b25b41af5b545aca878"
Expand All @@ -23425,13 +23439,6 @@ lru-cache@^5.1.1:
dependencies:
yallist "^3.0.2"

lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
yallist "^4.0.0"

lru-cache@^7.10.1, lru-cache@^7.4.4, lru-cache@^7.5.1, lru-cache@^7.7.1:
version "7.14.1"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.14.1.tgz#8da8d2f5f59827edb388e63e459ac23d6d408fea"
Expand All @@ -23457,6 +23464,14 @@ lru-cache@^9.0.0:
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.0.tgz#b9e2a6a72a129d81ab317202d93c7691df727e61"
integrity sha512-svTf/fzsKHffP42sujkO/Rjs37BCIsQVRCeNYIm9WN8rgT7ffoUnRtZCqU+6BqcSBdv8gwJeTz8knJpgACeQMw==

lru-memoizer@2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/lru-memoizer/-/lru-memoizer-2.3.0.tgz#ef0fbc021bceb666794b145eefac6be49dc47f31"
integrity sha512-GXn7gyHAMhO13WSKrIiNfztwxodVsP8IoZ3XfrJV4yH2x0/OeTO/FIaAHTY5YekdGgW94njfuKmyyt1E0mR6Ug==
dependencies:
lodash.clonedeep "^4.5.0"
lru-cache "6.0.0"

lunr@^2.3.8:
version "2.3.9"
resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1"
Expand Down

0 comments on commit 2343380

Please sign in to comment.