Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
533 changes: 532 additions & 1 deletion README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module.exports = {
coverageThreshold: {
global: {
branches: 80,
lines: 91,
lines: 90,
},
},
};
10,074 changes: 5,320 additions & 4,754 deletions package-lock.json

Large diffs are not rendered by default.

96 changes: 47 additions & 49 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"main": "dist/index.js",
"repository": {
"type": "git",
"url": "https://github.com/overbit/opentelemetry-nestjs.git"
"url": "git+https://github.com/overbit/opentelemetry-nestjs.git"
},
"release": {
"branches": [
Expand All @@ -34,61 +34,59 @@
"prebuild": "rimraf dist",
"build": "nest build",
"prepublishOnly": "npm run build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"format": "prettier --write \"**/*.ts\"",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage --coverageReporters=text-summary",
"semantic-release": "semantic-release"
},
"dependencies": {
"@nestjs/event-emitter": "^2.0.0",
"@nestjs/microservices": "^10.0.3",
"@nestjs/schedule": "^3.0.1",
"@opentelemetry/api": "^1.4.1",
"@opentelemetry/auto-instrumentations-node": "^0.37.1",
"@opentelemetry/context-async-hooks": "^1.14.0",
"@opentelemetry/exporter-metrics-otlp-proto": "^0.40.0",
"@opentelemetry/exporter-trace-otlp-http": "^0.40.0",
"@opentelemetry/exporter-trace-otlp-proto": "^0.40.0",
"@opentelemetry/propagator-b3": "^1.14.0",
"@opentelemetry/propagator-jaeger": "^1.14.0",
"@opentelemetry/resource-detector-container": "^0.2.5",
"@opentelemetry/sdk-node": "^0.40.0",
"@opentelemetry/sdk-trace-base": "^1.14.0",
"rimraf": "^5.0.1",
"rxjs": "^7.8.1"
},
"dependencies": {},
"devDependencies": {
"@nestjs/cli": "^10.0.5",
"@nestjs/common": "^10.0.3",
"@nestjs/core": "^10.0.3",
"@nestjs/event-emitter": "^2.0.0",
"@nestjs/microservices": "^10.0.3",
"@nestjs/platform-express": "^10.0.3",
"@nestjs/schedule": "^3.0.1",
"@nestjs/schematics": "^10.0.1",
"@nestjs/testing": "^10.0.3",
"@types/cron": "^2.0.1",
"@types/express": "^4.17.17",
"@types/jest": "^29.5.2",
"@types/node": "^18.14.6",
"@types/supertest": "^2.0.12",
"@typescript-eslint/eslint-plugin": "^5.60.1",
"@typescript-eslint/parser": "^5.60.1",
"eslint": "^8.43.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"jest": "^29.5.0",
"prettier": "^2.8.8",
"reflect-metadata": "^0.1.13",
"supertest": "^6.3.3",
"ts-jest": "^29.1.0",
"ts-loader": "^9.4.3",
"ts-node": "^10.9.1",
"@nestjs/cli": "^10.3.2",
"@nestjs/testing": "^10.3.3",
"@types/express": "^4.17.21",
"@types/jest": "^29.5.12",
"@types/node": "^20.11.22",
"@types/supertest": "^6.0.2",
"@typescript-eslint/eslint-plugin": "^7.1.0",
"@typescript-eslint/parser": "^7.1.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"jest": "^29.7.0",
"prettier": "^3.2.5",
"reflect-metadata": "^0.2.1",
"rimraf": "^5.0.5",
"rxjs": "^7.8.1",
"semantic-release": "^23.0.2",
"supertest": "^6.3.4",
"ts-jest": "^29.1.2",
"ts-loader": "^9.5.1",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.1.5",
"wait-for-expect": "^3.0.2",
"semantic-release": "^21.0.5"
"typescript": "^5.3.3",
"wait-for-expect": "^3.0.2"
},
"peerDependencies": {
"@nestjs/core": " ^8.0.0 || ^9.0.0 || ^10.0.0",
"@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0",
"@nestjs/event-emitter": "^1.0.0 || ^2.0.0",
"@nestjs/microservices": "^8.0.0 || ^9.0.0 || ^10.0.0",
"@nestjs/graphql": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0",
"@nestjs/platform-express": "^8.0.0 || ^9.0.0 || ^10.0.0",
"@nestjs/schedule": "^3.0.0 || ^4.0.1",
"@opentelemetry/auto-instrumentations-node": "^0.41.1",
"@opentelemetry/context-async-hooks": "^1.21.0",
"@opentelemetry/exporter-metrics-otlp-grpc": "^0.48.0",
"@opentelemetry/exporter-metrics-otlp-proto": "^0.48.0",
"@opentelemetry/exporter-trace-otlp-grpc": "^0.48.0",
"@opentelemetry/exporter-trace-otlp-http": "^0.48.0",
"@opentelemetry/exporter-trace-otlp-proto": "^0.48.0",
"@opentelemetry/propagator-b3": "^1.21.0",
"@opentelemetry/propagator-jaeger": "^1.21.0",
"@opentelemetry/resource-detector-container": "^0.3.6",
"@opentelemetry/sdk-node": "^0.48.0",
"@opentelemetry/sdk-trace-base": "^1.21.0"
}
}
2 changes: 1 addition & 1 deletion src/Constants.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
export enum Constants {
SDK = 'OPEN_TELEMETRY_SDK',
SDK_CONFIG = 'OPEN_TELEMETRY_SDK_CONFIG',
SDK_INJECTORS = 'SDK_INJECTORS',
TRACE_METADATA = 'OPEN_TELEMETRY_TRACE_METADATA',
METRIC_METADATA = 'OPEN_TELEMETRY_METRIC_METADATA',
TRACE_METADATA_ACTIVE = 'OPEN_TELEMETRY_TRACE_METADATA_ACTIVE',
METRIC_METADATA_ACTIVE = 'OPEN_TELEMETRY_METRIC_METADATA_ACTIVE',
TRACER_NAME = '@amplication/opentelemetry-nestjs',
}
68 changes: 68 additions & 0 deletions src/MetaScanner.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* eslint-disable @typescript-eslint/no-empty-function */
import { MetadataScanner } from './MetaScanner';

describe('MetadataScanner', () => {
let scanner: MetadataScanner;
beforeEach(() => {
scanner = new MetadataScanner();
});
describe('scanFromPrototype', () => {
class Parent {
constructor() {}
public testParent() {}
public testParent2() {}
get propParent() {
return '';
}
set valParent(value) {}
}

class Test extends Parent {
constructor() {
super();
}
get prop() {
return '';
}
set val(value) {}
public test() {}
public test2() {}
}

it('should return only methods', () => {
const methods = scanner.getAllMethodNames(Test.prototype);
expect(methods).toStrictEqual([
'test',
'test2',
'testParent',
'testParent2',
]);
});

it('should return the same instance for the same prototype', () => {
const methods1 = scanner.getAllMethodNames(Test.prototype);
const methods2 = scanner.getAllMethodNames(Test.prototype);
expect(methods1 === methods2).toBeTruthy();
});

it('should keep compatibility with older methods', () => {
const methods1 = scanner
.getAllMethodNames(Test.prototype)
.map((m) => m[0]);
const methods2 = scanner.scanFromPrototype(
new Test(),
Test.prototype,
(r) => r[0],
);

expect(methods1).toEqual(methods2);

const methods3 = scanner.getAllMethodNames(Test.prototype);
const methods4 = [
...new Set(scanner.getAllFilteredMethodNames(Test.prototype)),
];

expect(methods3).toEqual(methods4);
});
});
});
118 changes: 118 additions & 0 deletions src/MetaScanner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { Injectable } from '@nestjs/common/interfaces';
import {
isConstructor,
isFunction,
isNil,
} from '@nestjs/common/utils/shared.utils';

export class MetadataScanner {
private readonly cachedScannedPrototypes: Map<object, string[]> = new Map();

/**
* @deprecated
* @see {@link getAllMethodNames}
* @see getAllMethodNames
*/
public scanFromPrototype<T extends Injectable, R = any>(
instance: T,
prototype: object,
callback: (name: string) => R,
): R[] {
if (!prototype) {
return [];
}

const visitedNames = new Map<string, boolean>();
const result: R[] = [];

do {
for (const property of Object.getOwnPropertyNames(prototype)) {
if (visitedNames.has(property)) {
continue;
}

visitedNames.set(property, true);

// reason: https://github.com/nestjs/nest/pull/10821#issuecomment-1411916533
const descriptor = Object.getOwnPropertyDescriptor(prototype, property);

if (
descriptor.set ||
descriptor.get ||
isConstructor(property) ||
!isFunction(prototype[property])
) {
continue;
}

const value = callback(property);

if (isNil(value)) {
continue;
}

result.push(value);
}
} while (
(prototype = Reflect.getPrototypeOf(prototype)) &&
prototype !== Object.prototype
);

return result;
}

/**
* @deprecated
* @see {@link getAllMethodNames}
* @see getAllMethodNames
*/
public *getAllFilteredMethodNames(
prototype: object,
): IterableIterator<string> {
yield* this.getAllMethodNames(prototype);
}

public getAllMethodNames(prototype: object | null): string[] {
if (!prototype) {
return [];
}

if (this.cachedScannedPrototypes.has(prototype)) {
return this.cachedScannedPrototypes.get(prototype);
}

const visitedNames = new Map<string, boolean>();
const result: string[] = [];

this.cachedScannedPrototypes.set(prototype, result);

do {
for (const property of Object.getOwnPropertyNames(prototype)) {
if (visitedNames.has(property)) {
continue;
}

visitedNames.set(property, true);

// reason: https://github.com/nestjs/nest/pull/10821#issuecomment-1411916533
const descriptor = Object.getOwnPropertyDescriptor(prototype, property);

if (
descriptor.set ||
descriptor.get ||
isConstructor(property) ||
!isFunction(prototype[property])
) {
continue;
}

result.push(property);
}
} while (
(prototype = Reflect.getPrototypeOf(prototype)) &&
prototype !== Object.prototype
);

return result;
}
}
Loading