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
5 changes: 3 additions & 2 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"singleQuote": true,
"trailingComma": "all"
}
"trailingComma": "all",
"tabWidth": 2
}
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,25 @@ import { DatadogTraceModule } from 'nestjs-ddtrace';
export class AppModule {}
```

## Async loading of options
```ts
import { DatadogTraceModule } from 'nestjs-ddtrace';

@Module({
imports: [
DatadogTraceModule.forRootAsync({
imports: [CustomModule],
injects: [CustonService],
useFactory: async (customService: CustomService) => {
return await customService.getOptions();
}
})
],
})

export class AppModule {}
```

## Miscellaneous

Inspired by the [nestjs-otel](https://github.com/pragmaticivan/nestjs-otel) and [nestjs-opentelemetry](https://github.com/MetinSeylan/Nestjs-OpenTelemetry#readme) repository.
48 changes: 48 additions & 0 deletions src/datadog-trace.module.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Test } from '@nestjs/testing';
import { DatadogTraceModule } from './datadog-trace.module';
import { TraceService } from './trace.service';
import type { DatadogTraceModuleOptions } from './datadog-trace-module-options.interface';
import { Injectable, Module } from '@nestjs/common';

describe('DatadogTraceModule', () => {
it('forRoot should register TraceService, DecoratorInjector and TRACE_INJECTORS provider', async () => {
const options: DatadogTraceModuleOptions = {};

const moduleRef = await Test.createTestingModule({
imports: [DatadogTraceModule.forRoot(options)],
}).compile();

// exports
expect(moduleRef.get(TraceService)).toBeInstanceOf(TraceService);
});


it('forRootAsync should resolve options via factory and export TraceService', async () => {
@Injectable()
class CustomService {
getOptions(): DatadogTraceModuleOptions {
return { providers: true };
}
}

@Module({
providers: [CustomService],
exports: [CustomService],
})
class CustomModule { }

const moduleRef = await Test.createTestingModule({
imports: [
DatadogTraceModule.forRootAsync({
imports: [CustomModule],
inject: [CustomService],
useFactory: async (customService: CustomService) => {
return await customService.getOptions()
},
}),
],
}).compile();

expect(moduleRef.get(TraceService)).toBeInstanceOf(TraceService);
});
});
51 changes: 39 additions & 12 deletions src/datadog-trace.module.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import { DynamicModule, Module } from '@nestjs/common';
import { DynamicModule, Module, type ModuleMetadata } from '@nestjs/common';
import { FactoryProvider } from '@nestjs/common/interfaces/modules/provider.interface';
import { TraceService } from './trace.service';
import { DecoratorInjector } from './decorator.injector';
import { Injector } from 'src/injector.interface';
import { Constants } from './constants';
import { DatadogTraceModuleOptions } from './datadog-trace-module-options.interface';

@Module({})
interface DatadogTraceAsyncModuleOptions extends Pick<ModuleMetadata, 'imports'> {
useFactory: (...args: any[]) => Promise<DatadogTraceModuleOptions> | DatadogTraceModuleOptions;
inject: any[];
}
const DATADOG_TRACE_MODULE_PARAMS = Symbol('DATADOG_TRACE_MODULE_PARAMS');


export class DatadogTraceModule {
static forRoot(options: DatadogTraceModuleOptions = {}): DynamicModule {
return {
Expand All @@ -15,23 +21,44 @@ export class DatadogTraceModule {
providers: [
TraceService,
DecoratorInjector,
this.buildInjectors(options),
{
provide: Constants.TRACE_INJECTORS,
useFactory: async (...injectors: Injector[]) => {
for await (const injector of injectors) {
if (injector.inject) await injector.inject(options);
}
},
inject: [DecoratorInjector],
}
],
exports: [TraceService],
};
}

private static buildInjectors(
options: DatadogTraceModuleOptions,
): FactoryProvider {
static forRootAsync(options: DatadogTraceAsyncModuleOptions): DynamicModule {
return {
provide: Constants.TRACE_INJECTORS,
useFactory: async (...injectors: Injector[]) => {
for await (const injector of injectors) {
if (injector.inject) await injector.inject(options);
global: true,
module: DatadogTraceModule,
imports: options.imports ?? [],
providers: [
TraceService,
DecoratorInjector,
{
provide: DATADOG_TRACE_MODULE_PARAMS,
inject: options.inject ?? [],
useFactory: options.useFactory,
},
{
provide: Constants.TRACE_INJECTORS,
inject: [DATADOG_TRACE_MODULE_PARAMS, DecoratorInjector],
useFactory: async (moduleOptions: DatadogTraceModuleOptions, ...injectors: Injector[]) => {
for await (const injector of injectors) {
if (injector.inject) await injector.inject(moduleOptions);
}
},
}
},
inject: [DecoratorInjector],
],
exports: [TraceService],
};
}
}