Skip to content

Commit 9835680

Browse files
committed
refactor: inject logging service
1 parent 04c8c0e commit 9835680

File tree

13 files changed

+101
-97
lines changed

13 files changed

+101
-97
lines changed

apps/api/src/ability/ability.factory.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
import { AbilityBuilder, detectSubjectType } from '@casl/ability';
22
import { createPrismaAbility } from '@casl/prisma';
3-
import { Injectable, Logger } from '@nestjs/common';
3+
import { LoggingService } from '@douglasneuroinformatics/libnest/logging';
4+
import { Injectable } from '@nestjs/common';
45
import type { AppSubjectName } from '@opendatacapture/schemas/core';
56
import { type UserModel } from '@prisma/generated-client';
67

78
import type { AppAbility } from '@/core/types';
89

910
@Injectable()
1011
export class AbilityFactory {
11-
private readonly logger = new Logger(AbilityFactory.name);
12+
constructor(private readonly loggingService: LoggingService) {}
1213

1314
createForUser(user: UserModel): AppAbility {
14-
this.logger.verbose('Creating ability for user: ' + user.username);
15+
this.loggingService.verbose('Creating ability for user: ' + user.username);
1516
const ability = new AbilityBuilder<AppAbility>(createPrismaAbility);
1617
switch (user.basePermissionLevel) {
1718
case 'ADMIN':
Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { type ExecutionContext, Injectable, Logger } from '@nestjs/common';
1+
import { LoggingService } from '@douglasneuroinformatics/libnest/logging';
2+
import { type ExecutionContext, Injectable } from '@nestjs/common';
23
import { Reflector } from '@nestjs/core';
34
import { AuthGuard } from '@nestjs/passport';
45
import { type Request } from 'express';
@@ -9,14 +10,15 @@ import { type RouteAccessType } from '@/core/decorators/route-access.decorator';
910
/** Allows request to proceed if the route is public or the user provides a valid JWT */
1011
@Injectable()
1112
export class AuthenticationGuard extends AuthGuard('jwt') {
12-
private readonly logger = new Logger(AuthenticationGuard.name);
13-
14-
constructor(private readonly reflector: Reflector) {
13+
constructor(
14+
private readonly loggingService: LoggingService,
15+
private readonly reflector: Reflector
16+
) {
1517
super();
1618
}
1719

1820
override canActivate(context: ExecutionContext): boolean | Observable<boolean> | Promise<boolean> {
19-
this.logger.verbose(`Request URL: ${context.switchToHttp().getRequest<Request>().url}`);
21+
this.loggingService.verbose(`Request URL: ${context.switchToHttp().getRequest<Request>().url}`);
2022
return this.isPublicRoute(context) || super.canActivate(context);
2123
}
2224

@@ -26,7 +28,7 @@ export class AuthenticationGuard extends AuthGuard('jwt') {
2628
context.getClass()
2729
]);
2830
const result = routeAccess === 'public';
29-
this.logger.verbose(`Public Route: ${result}`);
31+
this.loggingService.verbose(`Public Route: ${result}`);
3032
return result;
3133
}
3234
}

apps/api/src/auth/guards/authorization.guard.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Injectable, Logger } from '@nestjs/common';
1+
import { LoggingService } from '@douglasneuroinformatics/libnest/logging';
2+
import { Injectable } from '@nestjs/common';
23
import type { CanActivate, ExecutionContext } from '@nestjs/common';
34
import { Reflector } from '@nestjs/core';
45
import type { Request } from 'express';
@@ -8,13 +9,14 @@ import type { RouteAccessType } from '@/core/decorators/route-access.decorator';
89

910
@Injectable()
1011
export class AuthorizationGuard implements CanActivate {
11-
private readonly logger = new Logger(AuthorizationGuard.name);
12-
13-
constructor(private readonly reflector: Reflector) {}
12+
constructor(
13+
private readonly loggingService: LoggingService,
14+
private readonly reflector: Reflector
15+
) {}
1416

1517
canActivate(context: ExecutionContext): boolean | Observable<boolean> | Promise<boolean> {
1618
const request = context.switchToHttp().getRequest<Request>();
17-
this.logger.verbose(`Request URL: ${request.url}`);
19+
this.loggingService.verbose(`Request URL: ${request.url}`);
1820

1921
const routeAccess = this.reflector.getAllAndOverride<RouteAccessType | undefined>('RouteAccess', [
2022
context.getHandler(),

apps/api/src/auth/strategies/jwt.strategy.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Injectable, Logger, NotFoundException, UnauthorizedException } from '@nestjs/common';
1+
import { LoggingService } from '@douglasneuroinformatics/libnest/logging';
2+
import { Injectable, NotFoundException, UnauthorizedException } from '@nestjs/common';
23
import { PassportStrategy } from '@nestjs/passport';
34
import type { JwtPayload } from '@opendatacapture/schemas/auth';
45
import type { GroupModel, UserModel } from '@prisma/generated-client';
@@ -11,11 +12,10 @@ import { UsersService } from '@/users/users.service';
1112

1213
@Injectable()
1314
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
14-
private readonly logger = new Logger(JwtStrategy.name);
15-
1615
constructor(
1716
config: ConfigurationService,
1817
private readonly abilityFactory: AbilityFactory,
18+
private readonly loggingService: LoggingService,
1919
private readonly usersService: UsersService
2020
) {
2121
super({
@@ -29,7 +29,7 @@ export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
2929
async validate({ username }: JwtPayload): Promise<Request['user']> {
3030
const user = await this.getUser(username);
3131
const ability = this.abilityFactory.createForUser(user);
32-
this.logger.verbose(`Validated Token for User: ${username}`);
32+
this.loggingService.verbose(`Validated Token for User: ${username}`);
3333
return { ...user, ability };
3434
}
3535

apps/api/src/demo/demo.service.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { randomValue } from '@douglasneuroinformatics/libjs';
22
import { toUpperCase } from '@douglasneuroinformatics/libjs';
3+
import { LoggingService } from '@douglasneuroinformatics/libnest/logging';
34
import { faker } from '@faker-js/faker';
4-
import { Injectable, Logger } from '@nestjs/common';
5+
import { Injectable } from '@nestjs/common';
56
import { DEMO_GROUPS, DEMO_USERS } from '@opendatacapture/demo';
67
import enhancedDemographicsQuestionnaire from '@opendatacapture/instrument-library/forms/enhanced-demographics-questionnaire.js';
78
import generalConsentForm from '@opendatacapture/instrument-library/forms/general-consent-form.js';
@@ -33,12 +34,11 @@ faker.seed(123);
3334

3435
@Injectable()
3536
export class DemoService {
36-
private readonly logger = new Logger(DemoService.name);
37-
3837
constructor(
3938
private readonly groupsService: GroupsService,
4039
private readonly instrumentRecordsService: InstrumentRecordsService,
4140
private readonly instrumentsService: InstrumentsService,
41+
private readonly loggingService: LoggingService,
4242
private readonly prismaService: PrismaService,
4343
private readonly sessionsService: SessionsService,
4444
private readonly subjectsService: SubjectsService,
@@ -54,7 +54,7 @@ export class DemoService {
5454
}): Promise<void> {
5555
try {
5656
const dbName = await this.prismaService.getDbName();
57-
this.logger.log(`Initializing demo for database: '${dbName}'`);
57+
this.loggingService.log(`Initializing demo for database: '${dbName}'`);
5858

5959
const hq = (await this.instrumentsService.create({ bundle: happinessQuestionnaire })) as WithID<
6060
FormInstrument<HappinessQuestionnaireData, Language[]>
@@ -66,33 +66,33 @@ export class DemoService {
6666
this.instrumentsService.create({ bundle: patientHealthQuestionnaire9 })
6767
]);
6868

69-
this.logger.debug('Done creating forms');
69+
this.loggingService.debug('Done creating forms');
7070

7171
await this.instrumentsService.create({ bundle: breakoutTask });
72-
this.logger.debug('Done creating interactive instruments');
72+
this.loggingService.debug('Done creating interactive instruments');
7373

7474
await this.instrumentsService.create({ bundle: happinessQuestionnaireWithConsent });
75-
this.logger.debug('Done creating series instruments');
75+
this.loggingService.debug('Done creating series instruments');
7676

7777
const groups: (Group & { dummyIdPrefix?: string })[] = [];
7878
for (const group of DEMO_GROUPS) {
7979
const { dummyIdPrefix, ...createGroupData } = group;
8080
const groupModel = await this.groupsService.create(createGroupData);
8181
groups.push({ ...groupModel, dummyIdPrefix });
8282
}
83-
this.logger.debug('Done creating groups');
83+
this.loggingService.debug('Done creating groups');
8484

8585
for (const user of DEMO_USERS) {
8686
await this.usersService.create({
8787
...user,
8888
groupIds: user.groupNames.map((name) => groups.find((group) => group.name === name)!.id)
8989
});
9090
}
91-
this.logger.debug('Done creating users');
91+
this.loggingService.debug('Done creating users');
9292

9393
let researchId = 1;
9494
for (let i = 0; i < dummySubjectCount; i++) {
95-
this.logger.debug(`Creating dummy subject ${i + 1}/${dummySubjectCount}`);
95+
this.loggingService.debug(`Creating dummy subject ${i + 1}/${dummySubjectCount}`);
9696
const group = randomValue(groups)!;
9797
const subjectIdData = {
9898
dateOfBirth: faker.date.birthdate(),
@@ -141,12 +141,12 @@ export class DemoService {
141141
subjectId: subject.id
142142
});
143143
}
144-
this.logger.debug(`Done creating dummy subject ${i + 1}`);
144+
this.loggingService.debug(`Done creating dummy subject ${i + 1}`);
145145
}
146146
} catch (err) {
147147
if (err instanceof Error) {
148-
this.logger.error(err.cause);
149-
this.logger.error(err);
148+
this.loggingService.error(err.cause);
149+
this.loggingService.error(err);
150150
}
151151
throw err;
152152
}

apps/api/src/gateway/gateway.service.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { HybridCrypto } from '@douglasneuroinformatics/libcrypto';
2+
import { LoggingService } from '@douglasneuroinformatics/libnest/logging';
23
import { HttpService } from '@nestjs/axios';
3-
import { BadGatewayException, HttpStatus, Injectable, Logger } from '@nestjs/common';
4+
import { BadGatewayException, HttpStatus, Injectable } from '@nestjs/common';
45
import { $MutateAssignmentResponseBody, $RemoteAssignment } from '@opendatacapture/schemas/assignment';
56
import type {
67
Assignment,
@@ -18,11 +19,10 @@ import { InstrumentsService } from '@/instruments/instruments.service';
1819

1920
@Injectable()
2021
export class GatewayService {
21-
private readonly logger = new Logger(GatewayService.name);
22-
2322
constructor(
2423
private readonly httpService: HttpService,
25-
private readonly instrumentsService: InstrumentsService
24+
private readonly instrumentsService: InstrumentsService,
25+
private readonly loggingService: LoggingService
2626
) {}
2727

2828
async createRemoteAssignment(assignment: Assignment, publicKey: CryptoKey): Promise<MutateAssignmentResponseBody> {
@@ -63,7 +63,7 @@ export class GatewayService {
6363
}
6464
const result = await $RemoteAssignment.array().safeParseAsync(response.data);
6565
if (!result.success) {
66-
this.logger.error({
66+
this.loggingService.error({
6767
data: response.data as unknown,
6868
error: result.error.format(),
6969
message: 'ERROR: Remote assignments received from gateway do not match expected structure'
@@ -85,7 +85,7 @@ export class GatewayService {
8585
const result = await $GatewayHealthcheckSuccessResult.safeParseAsync(response.data);
8686
if (!result.success) {
8787
const statusText = 'Healthcheck data received from gateway do not match expected structure';
88-
this.logger.error({
88+
this.loggingService.error({
8989
data: response.data as unknown,
9090
error: result.error.format(),
9191
message: `ERROR: ${statusText}`

apps/api/src/gateway/gateway.synchronizer.ts

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { HybridCrypto } from '@douglasneuroinformatics/libcrypto';
2-
import { Injectable, InternalServerErrorException, Logger, type OnApplicationBootstrap } from '@nestjs/common';
2+
import { LoggingService } from '@douglasneuroinformatics/libnest/logging';
3+
import { Injectable, InternalServerErrorException, type OnApplicationBootstrap } from '@nestjs/common';
34
import type { RemoteAssignment } from '@opendatacapture/schemas/assignment';
45
import { $Json } from '@opendatacapture/schemas/core';
56

@@ -9,13 +10,11 @@ import { InstrumentRecordsService } from '@/instrument-records/instrument-record
910
import { InstrumentsService } from '@/instruments/instruments.service';
1011
import { SessionsService } from '@/sessions/sessions.service';
1112
import { SetupService } from '@/setup/setup.service';
12-
import { VirtualizationService } from '@/virtualization/virtualization.service';
1313

1414
import { GatewayService } from './gateway.service';
1515

1616
@Injectable()
1717
export class GatewaySynchronizer implements OnApplicationBootstrap {
18-
private readonly logger = new Logger(GatewaySynchronizer.name);
1918
private readonly refreshInterval: number;
2019

2120
constructor(
@@ -24,9 +23,9 @@ export class GatewaySynchronizer implements OnApplicationBootstrap {
2423
private readonly gatewayService: GatewayService,
2524
private readonly instrumentsService: InstrumentsService,
2625
private readonly instrumentRecordsService: InstrumentRecordsService,
26+
private readonly loggingService: LoggingService,
2727
private readonly sessionsService: SessionsService,
28-
private readonly setupService: SetupService,
29-
private readonly virtualizationService: VirtualizationService
28+
private readonly setupService: SetupService
3029
) {
3130
this.refreshInterval = configurationService.get('GATEWAY_REFRESH_INTERVAL');
3231
}
@@ -42,10 +41,10 @@ export class GatewaySynchronizer implements OnApplicationBootstrap {
4241
const assignment = await this.assignmentsService.findById(remoteAssignment.id);
4342

4443
if (!remoteAssignment.completedAt) {
45-
this.logger.error(`Field 'completedAt' is null for assignment '${assignment.id}'`);
44+
this.loggingService.error(`Field 'completedAt' is null for assignment '${assignment.id}'`);
4645
return;
4746
} else if (!remoteAssignment.symmetricKey) {
48-
this.logger.error(`Field 'symmetricKey' is null for assignment '${assignment.id}'`);
47+
this.loggingService.error(`Field 'symmetricKey' is null for assignment '${assignment.id}'`);
4948
return;
5049
}
5150

@@ -65,7 +64,7 @@ export class GatewaySynchronizer implements OnApplicationBootstrap {
6564

6665
if (instrument.kind === 'SERIES') {
6766
if (!(remoteAssignment.encryptedData.startsWith('$') && remoteAssignment.symmetricKey.startsWith('$'))) {
68-
this.logger.error({ remoteAssignment });
67+
this.loggingService.error({ remoteAssignment });
6968
throw new InternalServerErrorException('Malformed remote assignment for series instrument');
7069
}
7170
cipherTexts.push(...remoteAssignment.encryptedData.slice(1).split('$'));
@@ -80,7 +79,7 @@ export class GatewaySynchronizer implements OnApplicationBootstrap {
8079
);
8180
}
8281
} else if (remoteAssignment.encryptedData.includes('$') || remoteAssignment.symmetricKey.includes('$')) {
83-
this.logger.error({ remoteAssignment });
82+
this.loggingService.error({ remoteAssignment });
8483
throw new InternalServerErrorException('Malformed remote assignment for scalar instrument');
8584
} else {
8685
cipherTexts.push(remoteAssignment.encryptedData);
@@ -113,12 +112,12 @@ export class GatewaySynchronizer implements OnApplicationBootstrap {
113112
sessionId: session.id,
114113
subjectId: assignment.subjectId
115114
});
116-
this.logger.log(`Created record with ID: ${record.id}`);
115+
this.loggingService.log(`Created record with ID: ${record.id}`);
117116
createdRecordIds.push(record.id);
118117
}
119118
await this.gatewayService.deleteRemoteAssignment(assignment.id);
120119
} catch (err) {
121-
this.logger.error({
120+
this.loggingService.error({
122121
data: {
123122
assignment,
124123
cipherTexts,
@@ -127,10 +126,10 @@ export class GatewaySynchronizer implements OnApplicationBootstrap {
127126
},
128127
message: 'Failed to Process Data'
129128
});
130-
this.logger.error(err);
129+
this.loggingService.error(err);
131130
for (const id of createdRecordIds) {
132131
await this.instrumentRecordsService.deleteById(id);
133-
this.logger.log(`Deleted Record with ID: ${id}`);
132+
this.loggingService.log(`Deleted Record with ID: ${id}`);
134133
}
135134
throw err;
136135
}
@@ -139,16 +138,19 @@ export class GatewaySynchronizer implements OnApplicationBootstrap {
139138
private async sync() {
140139
const setupState = await this.setupService.getState();
141140
if (!setupState.isSetup) {
142-
this.logger.log('Will not attempt synchronizing with gateway: app is not setup');
141+
this.loggingService.log('Will not attempt synchronizing with gateway: app is not setup');
143142
return;
144143
}
145144

146-
this.logger.log('Synchronizing with gateway...');
145+
this.loggingService.log('Synchronizing with gateway...');
147146
let remoteAssignments: RemoteAssignment[];
148147
try {
149148
remoteAssignments = await this.gatewayService.fetchRemoteAssignments();
150149
} catch (err) {
151-
this.logger.error('Failed to Fetch Remote Assignments', err);
150+
this.loggingService.error({
151+
cause: err,
152+
error: 'Failed to Fetch Remote Assignments'
153+
});
152154
return;
153155
}
154156

@@ -164,6 +166,6 @@ export class GatewaySynchronizer implements OnApplicationBootstrap {
164166
status: assignment.status
165167
});
166168
}
167-
this.logger.log('Done synchronizing with gateway');
169+
this.loggingService.log('Done synchronizing with gateway');
168170
}
169171
}

apps/api/src/instrument-records/instrument-measures.service.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Injectable, InternalServerErrorException, Logger } from '@nestjs/common';
1+
import { LoggingService } from '@douglasneuroinformatics/libnest/logging';
2+
import { Injectable, InternalServerErrorException } from '@nestjs/common';
23
import type {
34
FormInstrument,
45
InstrumentMeasure,
@@ -11,7 +12,7 @@ import { match } from 'ts-pattern';
1112

1213
@Injectable()
1314
export class InstrumentMeasuresService {
14-
private readonly logger = new Logger(InstrumentMeasuresService.name);
15+
constructor(private readonly loggingService: LoggingService) {}
1516

1617
computeMeasures(measures: InstrumentMeasures, data: FormInstrument.Data | Json | Prisma.JsonValue) {
1718
const computedMeasures: { [key: string]: InstrumentMeasureValue } = {};
@@ -28,7 +29,7 @@ export class InstrumentMeasuresService {
2829
})
2930
.with({ kind: 'const' }, (measure) => {
3031
if (!(data && typeof data === 'object')) {
31-
this.logger.error({ data, message: 'Invalid Data' });
32+
this.loggingService.error({ data, message: 'Invalid Data' });
3233
const label = typeof measure.label === 'string' ? measure.label : (measure.label?.en ?? measure.label?.fr)!;
3334
throw new InternalServerErrorException(`Failed to compute measure '${label}': data must be object'`);
3435
}

0 commit comments

Comments
 (0)