From 794099f37d535db11a3d9ec04cee181c5174c391 Mon Sep 17 00:00:00 2001 From: "makabe.t" Date: Wed, 2 Aug 2023 01:07:02 +0000 Subject: [PATCH] =?UTF-8?q?Merged=20PR=20292:=20=E5=A4=96=E9=83=A8?= =?UTF-8?q?=E9=80=A3=E6=90=BAAPI=E3=81=AB=E3=83=AD=E3=82=B0=E3=82=92?= =?UTF-8?q?=E5=85=A5=E3=82=8C=E8=BE=BC=E3=82=80=EF=BC=88=E5=BC=B7=E5=8C=96?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task2294: 外部連携APIにログを入れ込む(強化)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2294) - 外部連携APIのログを強化しました。 - contextオブジェクトで操作者情報を渡すようにしています。 - ログポリシーに従って追加しています。 - [ログポリシー](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/OMDSDictation/_wiki/wikis/OMDSDictation_wiki/223/%E3%83%AD%E3%82%B0%E3%83%9D%E3%83%AA%E3%82%B7%E3%83%BC) ## レビューポイント - 出力内容に過不足はないか - ログ追加対象に過不足はないか。 - contextで操作者情報を渡しているが想定通りか ## UIの変更 - なし ## 動作確認状況 - ローカルで確認 --- dictation_server/src/common/log/context.ts | 7 + dictation_server/src/common/log/index.ts | 4 + dictation_server/src/common/log/types.ts | 6 + .../src/features/accounts/accounts.service.ts | 6 +- .../src/features/auth/auth.controller.ts | 10 + .../src/features/auth/auth.service.ts | 37 +++- .../src/features/files/files.controller.ts | 17 +- .../src/features/files/files.service.spec.ts | 86 +++++++-- .../src/features/files/files.service.ts | 85 +++++++- .../notification/notification.controller.ts | 5 +- .../notification/notification.service.spec.ts | 26 ++- .../notification/notification.service.ts | 9 +- .../src/features/tasks/tasks.controller.ts | 24 ++- .../src/features/tasks/tasks.service.spec.ts | 181 +++++++++++++++--- .../src/features/tasks/tasks.service.ts | 58 +++++- .../src/features/users/users.controller.ts | 6 +- .../src/features/users/users.service.ts | 18 +- .../src/gateways/adb2c/adb2c.service.ts | 12 +- .../blobstorage/blobstorage.service.ts | 42 +++- .../notificationhub.service.ts | 18 +- .../user_groups.repository.service.ts | 2 - 21 files changed, 576 insertions(+), 83 deletions(-) create mode 100644 dictation_server/src/common/log/context.ts create mode 100644 dictation_server/src/common/log/index.ts create mode 100644 dictation_server/src/common/log/types.ts diff --git a/dictation_server/src/common/log/context.ts b/dictation_server/src/common/log/context.ts new file mode 100644 index 0000000..575132d --- /dev/null +++ b/dictation_server/src/common/log/context.ts @@ -0,0 +1,7 @@ +import { Context } from './types'; + +export const makeContext = (externaiId: string): Context => { + return { + trackingId: externaiId, + }; +}; diff --git a/dictation_server/src/common/log/index.ts b/dictation_server/src/common/log/index.ts new file mode 100644 index 0000000..d42adad --- /dev/null +++ b/dictation_server/src/common/log/index.ts @@ -0,0 +1,4 @@ +import { Context } from './types'; +import { makeContext } from './context'; + +export { Context, makeContext }; diff --git a/dictation_server/src/common/log/types.ts b/dictation_server/src/common/log/types.ts new file mode 100644 index 0000000..da7e2ba --- /dev/null +++ b/dictation_server/src/common/log/types.ts @@ -0,0 +1,6 @@ +export class Context { + /** + * APIの操作ユーザーを追跡するためのID + */ + trackingId: string; +} diff --git a/dictation_server/src/features/accounts/accounts.service.ts b/dictation_server/src/features/accounts/accounts.service.ts index 59c4482..3d53f23 100644 --- a/dictation_server/src/features/accounts/accounts.service.ts +++ b/dictation_server/src/features/accounts/accounts.service.ts @@ -278,7 +278,11 @@ export class AccountsService { const externalIds = typistUsers.map((x) => x.external_id); // B2Cからユーザー名を取得する - const adb2cUsers = await this.adB2cService.getUsers(externalIds); + const adb2cUsers = await this.adB2cService.getUsers( + // TODO: 外部連携以外のログ強化時に、ContollerからContextを取得するように修正する + { trackingId: 'dummy' }, + externalIds, + ); const typists = typistUsers.map((x) => { const user = adb2cUsers.find((adb2c) => adb2c.id === x.external_id); diff --git a/dictation_server/src/features/auth/auth.controller.ts b/dictation_server/src/features/auth/auth.controller.ts index cf29a4e..a3c1742 100644 --- a/dictation_server/src/features/auth/auth.controller.ts +++ b/dictation_server/src/features/auth/auth.controller.ts @@ -21,6 +21,8 @@ import { TokenResponse, } from './types/types'; import { retrieveAuthorizationToken } from '../../common/http/helper'; +import { makeContext } from '../../common/log'; +import { v4 as uuidv4 } from 'uuid'; @ApiTags('auth') @Controller('auth') @@ -60,12 +62,16 @@ export class AuthController { ); } + const context = makeContext(uuidv4()); + const refreshToken = await this.authService.generateRefreshToken( + context, idToken, body.type, ); const accessToken = await this.authService.generateAccessToken( + context, refreshToken, ); @@ -98,6 +104,7 @@ export class AuthController { }) async accessToken(@Req() req): Promise { const refreshToken = retrieveAuthorizationToken(req); + if (!refreshToken) { throw new HttpException( makeErrorResponse('E000107'), @@ -105,7 +112,10 @@ export class AuthController { ); } + const context = makeContext(uuidv4()); + const accessToken = await this.authService.generateAccessToken( + context, refreshToken, ); return { accessToken }; diff --git a/dictation_server/src/features/auth/auth.service.ts b/dictation_server/src/features/auth/auth.service.ts index c06605b..a3198d7 100644 --- a/dictation_server/src/features/auth/auth.service.ts +++ b/dictation_server/src/features/auth/auth.service.ts @@ -21,6 +21,7 @@ import { ADMIN_ROLES, USER_ROLES } from '../../constants'; import { AdB2cService } from '../../gateways/adb2c/adb2c.service'; import { User } from '../../repositories/users/entity/user.entity'; import { UsersRepositoryService } from '../../repositories/users/users.repository.service'; +import { Context } from '../../common/log'; @Injectable() export class AuthService { @@ -59,7 +60,14 @@ export class AuthService { * @param type 環境を表す文字列(web/desktop/mobile) * @returns refresh token */ - async generateRefreshToken(idToken: IDToken, type: string): Promise { + async generateRefreshToken( + context: Context, + idToken: IDToken, + type: string, + ): Promise { + this.logger.log( + `[IN] [${context.trackingId}] ${this.generateRefreshToken.name}`, + ); const lifetimeWeb = this.configService.get('REFRESH_TOKEN_LIFETIME_WEB'); const lifetimeDefault = this.configService.get( 'REFRESH_TOKEN_LIFETIME_DEFAULT', @@ -73,6 +81,9 @@ export class AuthService { } } catch (e) { this.logger.error(`error=${e}`); + this.logger.log( + `[OUT] [${context.trackingId}] ${this.generateRefreshToken.name}`, + ); throw new HttpException( makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, @@ -86,6 +97,9 @@ export class AuthService { this.logger.error( `Tier from DB is unexpected value. tier=${user.account.tier}`, ); + this.logger.log( + `[OUT] [${context.trackingId}] ${this.generateRefreshToken.name}`, + ); throw new HttpException( makeErrorResponse('E010206'), HttpStatus.INTERNAL_SERVER_ERROR, @@ -108,6 +122,9 @@ export class AuthService { role = USER_ROLES.TYPIST; } else { this.logger.error(`Role from DB is unexpected value. role=${user.role}`); + this.logger.log( + `[OUT] [${context.trackingId}] ${this.generateRefreshToken.name}`, + ); throw new HttpException( makeErrorResponse('E010205'), HttpStatus.INTERNAL_SERVER_ERROR, @@ -129,6 +146,10 @@ export class AuthService { refreshTokenLifetime, privateKey, ); + + this.logger.log( + `[OUT] [${context.trackingId}] ${this.generateRefreshToken.name}`, + ); return token; } @@ -137,7 +158,13 @@ export class AuthService { * @param refreshToken リフレッシュトークン(jwt) * @returns access token(jwt) */ - async generateAccessToken(refreshToken: string): Promise { + async generateAccessToken( + context: Context, + refreshToken: string, + ): Promise { + this.logger.log( + `[IN] [${context.trackingId}] ${this.generateAccessToken.name}`, + ); const lifetime = this.configService.get('ACCESS_TOKEN_LIFETIME_WEB'); const privateKey = getPrivateKey(this.configService); @@ -146,6 +173,9 @@ export class AuthService { const token = verify(refreshToken, pubkey); if (isVerifyError(token)) { this.logger.error(`${token.reason} | ${token.message}`); + this.logger.log( + `[OUT] [${context.trackingId}] ${this.generateAccessToken.name}`, + ); throw new HttpException( makeErrorResponse('E000101'), HttpStatus.UNAUTHORIZED, @@ -162,6 +192,9 @@ export class AuthService { privateKey, ); + this.logger.log( + `[OUT] [${context.trackingId}] ${this.generateAccessToken.name}`, + ); return accessToken; } /** diff --git a/dictation_server/src/features/files/files.controller.ts b/dictation_server/src/features/files/files.controller.ts index 5aeb394..19b1ffa 100644 --- a/dictation_server/src/features/files/files.controller.ts +++ b/dictation_server/src/features/files/files.controller.ts @@ -33,6 +33,7 @@ import { RoleGuard } from '../../common/guards/role/roleguards'; import { USER_ROLES } from '../../constants'; import { retrieveAuthorizationToken } from '../../common/http/helper'; import { Request } from 'express'; +import { makeContext } from '../../common/log'; @ApiTags('files') @Controller('files') @@ -75,6 +76,8 @@ export class FilesController { const token = retrieveAuthorizationToken(req); const accessToken = jwt.decode(token, { json: true }) as AccessToken; + const context = makeContext(accessToken.userId); + const { url, authorId, @@ -93,6 +96,7 @@ export class FilesController { } = body; const res = await this.filesService.uploadFinished( + context, accessToken.userId, url, authorId, @@ -146,7 +150,10 @@ export class FilesController { ): Promise { const token = retrieveAuthorizationToken(req); const accessToken = jwt.decode(token, { json: true }) as AccessToken; - const url = await this.filesService.publishUploadSas(accessToken); + + const context = makeContext(accessToken.userId); + + const url = await this.filesService.publishUploadSas(context, accessToken); return { url }; } @@ -189,7 +196,11 @@ export class FilesController { const token = retrieveAuthorizationToken(req); const accessToken = jwt.decode(token, { json: true }) as AccessToken; + + const context = makeContext(accessToken.userId); + const url = await this.filesService.publishAudioFileDownloadSas( + context, accessToken.userId, audioFileId, ); @@ -236,7 +247,11 @@ export class FilesController { const token = retrieveAuthorizationToken(req); const accessToken = jwt.decode(token, { json: true }) as AccessToken; + + const context = makeContext(accessToken.userId); + const url = await this.filesService.publishTemplateFileDownloadSas( + context, accessToken.userId, audioFileId, ); diff --git a/dictation_server/src/features/files/files.service.spec.ts b/dictation_server/src/features/files/files.service.spec.ts index ddd9973..556f2f2 100644 --- a/dictation_server/src/features/files/files.service.spec.ts +++ b/dictation_server/src/features/files/files.service.spec.ts @@ -14,6 +14,7 @@ import { makeTestingModuleWithBlob, } from './test/utility'; import { FilesService } from './files.service'; +import { makeContext } from '../../common/log'; describe('音声ファイルアップロードURL取得', () => { it('アップロードSASトークンが乗っているURLを返却する', async () => { @@ -27,7 +28,7 @@ describe('音声ファイルアップロードURL取得', () => { ); expect( - await service.publishUploadSas({ + await service.publishUploadSas(makeContext('trackingId'), { userId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx', role: 'Author', tier: 5, @@ -49,7 +50,7 @@ describe('音声ファイルアップロードURL取得', () => { ); expect( - await service.publishUploadSas({ + await service.publishUploadSas(makeContext('trackingId'), { userId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx', role: 'Author', tier: 5, @@ -70,7 +71,7 @@ describe('音声ファイルアップロードURL取得', () => { ); await expect( - service.publishUploadSas({ + service.publishUploadSas(makeContext('trackingId'), { userId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx', role: 'Author', tier: 5, @@ -94,7 +95,7 @@ describe('音声ファイルアップロードURL取得', () => { blobParam.publishUploadSas = new Error('Azure service down'); await expect( - service.publishUploadSas({ + service.publishUploadSas(makeContext('trackingId'), { userId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx', role: 'Author', tier: 5, @@ -118,6 +119,7 @@ describe('タスク作成', () => { expect( await service.uploadFinished( + makeContext('trackingId'), 'userId', 'http://blob/url/file.zip', 'AUTHOR_01', @@ -149,6 +151,7 @@ describe('タスク作成', () => { await expect( service.uploadFinished( + makeContext('trackingId'), 'userId', 'http://blob/url/file.zip', 'AUTHOR_01', @@ -182,6 +185,7 @@ describe('タスク作成', () => { await expect( service.uploadFinished( + makeContext('trackingId'), 'userId', 'http://blob/url/file.zip', 'AUTHOR_01', @@ -222,6 +226,7 @@ describe('タスク作成', () => { await expect( service.uploadFinished( + makeContext('trackingId'), 'userId', 'http://blob/url/file.zip', 'AUTHOR_01', @@ -256,6 +261,7 @@ describe('タスク作成', () => { await expect( service.uploadFinished( + makeContext('trackingId'), 'userId', 'http://blob/url/file.zip', 'AUTHOR_01', @@ -328,7 +334,11 @@ describe('音声ファイルダウンロードURL取得', () => { const service = module.get(FilesService); expect( - await service.publishAudioFileDownloadSas(externalId, audioFileId), + await service.publishAudioFileDownloadSas( + makeContext('trackingId'), + externalId, + audioFileId, + ), ).toEqual(`${url}?sas-token`); }); @@ -367,7 +377,11 @@ describe('音声ファイルダウンロードURL取得', () => { const service = module.get(FilesService); await expect( - service.publishAudioFileDownloadSas(externalId, audioFileId), + service.publishAudioFileDownloadSas( + makeContext('trackingId'), + externalId, + audioFileId, + ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010603'), HttpStatus.BAD_REQUEST), ); @@ -413,7 +427,11 @@ describe('音声ファイルダウンロードURL取得', () => { const service = module.get(FilesService); await expect( - service.publishTemplateFileDownloadSas(externalId, audioFileId), + service.publishTemplateFileDownloadSas( + makeContext('tracking'), + externalId, + audioFileId, + ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010603'), HttpStatus.BAD_REQUEST), ); @@ -448,7 +466,11 @@ describe('音声ファイルダウンロードURL取得', () => { const service = module.get(FilesService); await expect( - service.publishAudioFileDownloadSas(externalId, audioFileId), + service.publishAudioFileDownloadSas( + makeContext('trackingId'), + externalId, + audioFileId, + ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010603'), HttpStatus.BAD_REQUEST), ); @@ -470,7 +492,11 @@ describe('音声ファイルダウンロードURL取得', () => { const service = module.get(FilesService); await expect( - service.publishAudioFileDownloadSas(externalId, 1), + service.publishAudioFileDownloadSas( + makeContext('trackingId'), + externalId, + 1, + ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010603'), HttpStatus.BAD_REQUEST), ); @@ -505,7 +531,11 @@ describe('音声ファイルダウンロードURL取得', () => { const service = module.get(FilesService); await expect( - service.publishAudioFileDownloadSas(externalId, audioFileId), + service.publishAudioFileDownloadSas( + makeContext('trackingId'), + externalId, + audioFileId, + ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010701'), HttpStatus.BAD_REQUEST), ); @@ -559,7 +589,11 @@ describe('テンプレートファイルダウンロードURL取得', () => { const service = module.get(FilesService); expect( - await service.publishTemplateFileDownloadSas(externalId, audioFileId), + await service.publishTemplateFileDownloadSas( + makeContext('tracking'), + externalId, + audioFileId, + ), ).toEqual(`${url}?sas-token`); }); @@ -591,7 +625,11 @@ describe('テンプレートファイルダウンロードURL取得', () => { const service = module.get(FilesService); await expect( - service.publishTemplateFileDownloadSas(externalId, audioFileId), + service.publishTemplateFileDownloadSas( + makeContext('tracking'), + externalId, + audioFileId, + ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010603'), HttpStatus.BAD_REQUEST), ); @@ -632,7 +670,11 @@ describe('テンプレートファイルダウンロードURL取得', () => { const service = module.get(FilesService); await expect( - service.publishTemplateFileDownloadSas(externalId, audioFileId), + service.publishTemplateFileDownloadSas( + makeContext('tracking'), + externalId, + audioFileId, + ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010603'), HttpStatus.BAD_REQUEST), ); @@ -667,7 +709,11 @@ describe('テンプレートファイルダウンロードURL取得', () => { const service = module.get(FilesService); await expect( - service.publishTemplateFileDownloadSas(externalId, audioFileId), + service.publishTemplateFileDownloadSas( + makeContext('tracking'), + externalId, + audioFileId, + ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010603'), HttpStatus.BAD_REQUEST), ); @@ -689,7 +735,11 @@ describe('テンプレートファイルダウンロードURL取得', () => { const service = module.get(FilesService); await expect( - service.publishTemplateFileDownloadSas(externalId, 1), + service.publishTemplateFileDownloadSas( + makeContext('tracking'), + externalId, + 1, + ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010603'), HttpStatus.BAD_REQUEST), ); @@ -724,7 +774,11 @@ describe('テンプレートファイルダウンロードURL取得', () => { const service = module.get(FilesService); await expect( - service.publishTemplateFileDownloadSas(externalId, audioFileId), + service.publishTemplateFileDownloadSas( + makeContext('tracking'), + externalId, + audioFileId, + ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010701'), HttpStatus.BAD_REQUEST), ); diff --git a/dictation_server/src/features/files/files.service.ts b/dictation_server/src/features/files/files.service.ts index 188e5a1..0b16cf2 100644 --- a/dictation_server/src/features/files/files.service.ts +++ b/dictation_server/src/features/files/files.service.ts @@ -22,6 +22,7 @@ import { TasksNotFoundError, TypistUserNotFoundError, } from '../../repositories/tasks/errors/types'; +import { Context } from '../../common/log'; @Injectable() export class FilesService { @@ -52,6 +53,7 @@ export class FilesService { * @returns finished */ async uploadFinished( + context: Context, userId: string, url: string, authorId: string, @@ -68,6 +70,24 @@ export class FilesService { optionItemList: AudioOptionItem[], isEncrypted: boolean, ): Promise { + this.logger.log( + `[IN] [${context.trackingId}] ${this.uploadFinished.name} | params: { ` + + `url: ${url}, ` + + `authorId: ${authorId}, ` + + `fileName: ${fileName}, ` + + `duration: ${duration}, ` + + `createdDate: ${createdDate}, ` + + `finishedDate: ${finishedDate}, ` + + `uploadedDate: ${uploadedDate}, ` + + `fileSize: ${fileSize}, ` + + `priority: ${priority}, ` + + `audioFormat: ${audioFormat}, ` + + `comment: ${comment}, ` + + `workType: ${workType}, ` + + `optionItemList: ${JSON.stringify(optionItemList)}, ` + + `isEncrypted: ${isEncrypted} };`, + ); + const formattedCreatedDate = new Date(createdDate); const formattedFinishedDate = new Date(finishedDate); const formattedUploadedDate = new Date(uploadedDate); @@ -97,6 +117,9 @@ export class FilesService { `param uploadedDate is invalid format:[uploadedDate=${uploadedDate}]`, ); } + this.logger.log( + `[OUT] [${context.trackingId}] ${this.uploadFinished.name}`, + ); throw new HttpException( makeErrorResponse('E010001'), @@ -109,6 +132,9 @@ export class FilesService { this.logger.error( `param optionItemList expects ${OPTION_ITEM_NUM} items, but has ${optionItemList.length} items`, ); + this.logger.log( + `[OUT] [${context.trackingId}] ${this.uploadFinished.name}`, + ); throw new HttpException( makeErrorResponse('E010001'), HttpStatus.BAD_REQUEST, @@ -121,6 +147,9 @@ export class FilesService { user = await this.usersRepository.findUserByExternalId(userId); } catch (e) { this.logger.error(`error=${e}`); + this.logger.log( + `[OUT] [${context.trackingId}] ${this.uploadFinished.name}`, + ); throw new HttpException( makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, @@ -161,6 +190,10 @@ export class FilesService { makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, ); + } finally { + this.logger.log( + `[OUT] [${context.trackingId}] ${this.uploadFinished.name}`, + ); } } @@ -169,7 +202,14 @@ export class FilesService { * @param companyName * @returns upload sas */ - async publishUploadSas(token: AccessToken): Promise { + async publishUploadSas( + context: Context, + token: AccessToken, + ): Promise { + this.logger.log( + `[IN] [${context.trackingId}] ${this.publishUploadSas.name}`, + ); + //DBから国情報とアカウントIDを取得する let accountId: number; let country: string; @@ -183,6 +223,9 @@ export class FilesService { country = user.account.country; } catch (e) { this.logger.error(`error=${e}`); + this.logger.log( + `[OUT] [${context.trackingId}] ${this.publishUploadSas.name}`, + ); throw new HttpException( makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, @@ -192,6 +235,7 @@ export class FilesService { try { // 国に応じたリージョンのBlobストレージにコンテナが存在するか確認 const isContainerExist = await this.blobStorageService.containerExists( + context, accountId, country, ); @@ -201,6 +245,9 @@ export class FilesService { } } catch (e) { this.logger.error(`error=${e}`); + this.logger.log( + `[OUT] [${context.trackingId}] ${this.publishUploadSas.name}`, + ); throw new HttpException( makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, @@ -210,6 +257,7 @@ export class FilesService { try { // SASトークン発行 const url = await this.blobStorageService.publishUploadSas( + context, accountId, userId, country, @@ -221,6 +269,10 @@ export class FilesService { makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, ); + } finally { + this.logger.log( + `[OUT] [${context.trackingId}] ${this.publishUploadSas.name}`, + ); } } @@ -231,9 +283,14 @@ export class FilesService { * @returns audio file download sas */ async publishAudioFileDownloadSas( + context: Context, externalId: string, audioFileId: number, ): Promise { + this.logger.log( + `[IN] [${context.trackingId}] ${this.publishAudioFileDownloadSas.name} | params: { externalId: ${externalId}, audioFileId: ${audioFileId} };`, + ); + //DBから国情報とアカウントID,ユーザーIDを取得する let accountId: number; let userId: number; @@ -250,7 +307,10 @@ export class FilesService { authorId = user.author_id; } catch (e) { this.logger.error(`error=${e}`); - console.log(e); + + this.logger.log( + `[OUT] [${context.trackingId}] ${this.publishAudioFileDownloadSas.name}`, + ); throw new HttpException( makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, @@ -294,6 +354,7 @@ export class FilesService { const filePath = `${file.owner_user_id}/${file.file_name}`; const isFileExist = await this.blobStorageService.fileExists( + context, accountId, country, filePath, @@ -308,6 +369,7 @@ export class FilesService { // SASトークン発行 const url = await this.blobStorageService.publishDownloadSas( + context, accountId, country, filePath, @@ -342,6 +404,10 @@ export class FilesService { makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, ); + } finally { + this.logger.log( + `[OUT] [${context.trackingId}] ${this.publishAudioFileDownloadSas.name}`, + ); } } @@ -352,9 +418,14 @@ export class FilesService { * @returns template file download sas */ async publishTemplateFileDownloadSas( + context: Context, externalId: string, audioFileId: number, ): Promise { + this.logger.log( + `[IN] [${context.trackingId}] ${this.publishTemplateFileDownloadSas.name} | params: { externalId: ${externalId}, audioFileId: ${audioFileId} };`, + ); + //DBから国情報とアカウントID,ユーザーIDを取得する let accountId: number; let userId: number; @@ -370,7 +441,9 @@ export class FilesService { authorId = user.author_id; } catch (e) { this.logger.error(`error=${e}`); - console.log(e); + this.logger.log( + `[OUT] [${context.trackingId}] ${this.publishTemplateFileDownloadSas.name}`, + ); throw new HttpException( makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, @@ -415,6 +488,7 @@ export class FilesService { const filePath = `Templates/${template_file.file_name}`; const isFileExist = await this.blobStorageService.fileExists( + context, accountId, country, filePath, @@ -428,6 +502,7 @@ export class FilesService { // SASトークン発行 const url = await this.blobStorageService.publishDownloadSas( + context, accountId, country, filePath, @@ -462,6 +537,10 @@ export class FilesService { makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, ); + } finally { + this.logger.log( + `[OUT] [${context.trackingId}] ${this.publishTemplateFileDownloadSas.name}`, + ); } } } diff --git a/dictation_server/src/features/notification/notification.controller.ts b/dictation_server/src/features/notification/notification.controller.ts index 2ab80b2..c234163 100644 --- a/dictation_server/src/features/notification/notification.controller.ts +++ b/dictation_server/src/features/notification/notification.controller.ts @@ -20,6 +20,7 @@ import { AuthGuard } from '../../common/guards/auth/authguards'; import { retrieveAuthorizationToken } from '../../common/http/helper'; import { AccessToken } from '../../common/token'; import jwt from 'jsonwebtoken'; +import { makeContext } from '../../common/log'; @ApiTags('notification') @Controller('notification') @@ -58,7 +59,9 @@ export class NotificationController { const accessToken = retrieveAuthorizationToken(req); const { userId } = jwt.decode(accessToken, { json: true }) as AccessToken; - await this.notificationService.register(userId, pns, handler); + const context = makeContext(userId); + + await this.notificationService.register(context, userId, pns, handler); return {}; } } diff --git a/dictation_server/src/features/notification/notification.service.spec.ts b/dictation_server/src/features/notification/notification.service.spec.ts index bbcb289..bd714e7 100644 --- a/dictation_server/src/features/notification/notification.service.spec.ts +++ b/dictation_server/src/features/notification/notification.service.spec.ts @@ -5,6 +5,7 @@ import { makeDefaultUsersRepositoryMockValue, } from './test/notification.service.mock'; import { makeErrorResponse } from '../../common/error/makeErrorResponse'; +import { makeContext } from '../../common/log'; describe('NotificationService.register', () => { it('ユーザーから渡されたPNSハンドルをNotificationHubに登録できる', async () => { @@ -16,9 +17,14 @@ describe('NotificationService.register', () => { notificationHubMockValue, ); - expect(await service.register('external_id', 'apns', 'handler')).toEqual( - undefined, - ); + expect( + await service.register( + makeContext('trackingId'), + 'external_id', + 'apns', + 'handler', + ), + ).toEqual(undefined); }); it('DBからのユーザー取得に失敗した場合、エラーとなる', async () => { const notificationHubMockValue = makeDefaultNotificationHubMockValue(); @@ -31,7 +37,12 @@ describe('NotificationService.register', () => { ); await expect( - service.register('external_id', 'apns', 'handler'), + service.register( + makeContext('trackingId'), + 'external_id', + 'apns', + 'handler', + ), ).rejects.toEqual( new HttpException( makeErrorResponse('E009999'), @@ -51,7 +62,12 @@ describe('NotificationService.register', () => { ); await expect( - service.register('external_id', 'apns', 'handler'), + service.register( + makeContext('trackingId'), + 'external_id', + 'apns', + 'handler', + ), ).rejects.toEqual( new HttpException( makeErrorResponse('E009999'), diff --git a/dictation_server/src/features/notification/notification.service.ts b/dictation_server/src/features/notification/notification.service.ts index f0ccf09..5ab803b 100644 --- a/dictation_server/src/features/notification/notification.service.ts +++ b/dictation_server/src/features/notification/notification.service.ts @@ -4,6 +4,7 @@ import { NotificationhubService } from '../../gateways/notificationhub/notificat import { UsersRepositoryService } from '../../repositories/users/users.repository.service'; import { UserNotFoundError } from '../../repositories/users/errors/types'; import { v4 as uuidv4 } from 'uuid'; +import { Context } from '../../common/log'; @Injectable() export class NotificationService { @@ -19,11 +20,14 @@ export class NotificationService { * @returns register */ async register( + context: Context, externalId: string, pns: string, pnsHandler: string, ): Promise { - this.logger.log(`[IN] ${this.register.name}`); + this.logger.log( + `[IN] [${context.trackingId}] ${this.register.name} | params: { externalId: ${externalId}, pns: ${pns}, pnsHandler: ${pnsHandler} }`, + ); // ユーザIDからアカウントIDを取得する let userId: number; @@ -52,6 +56,7 @@ export class NotificationService { this.logger.log(installationId); await this.notificationhubService.register( + context, userId, pns, pnsHandler, @@ -64,7 +69,7 @@ export class NotificationService { HttpStatus.INTERNAL_SERVER_ERROR, ); } finally { - this.logger.log(`[OUT] ${this.register.name}`); + this.logger.log(`[OUT] [${context.trackingId}] ${this.register.name}`); } } } diff --git a/dictation_server/src/features/tasks/tasks.controller.ts b/dictation_server/src/features/tasks/tasks.controller.ts index bbfe15d..f09a622 100644 --- a/dictation_server/src/features/tasks/tasks.controller.ts +++ b/dictation_server/src/features/tasks/tasks.controller.ts @@ -42,6 +42,7 @@ import { AuthGuard } from '../../common/guards/auth/authguards'; import { RoleGuard } from '../../common/guards/role/roleguards'; import { ADMIN_ROLES, USER_ROLES } from '../../constants'; import { Roles } from '../../common/types/role'; +import { makeContext } from '../../common/log'; @ApiTags('tasks') @Controller('tasks') @@ -82,6 +83,8 @@ export class TasksController { const accessToken = retrieveAuthorizationToken(req); const decodedToken = jwt.decode(accessToken, { json: true }) as AccessToken; + const context = makeContext(decodedToken.userId); + const { limit, offset, status } = body; const paramName = isTaskListSortableAttribute(body.paramName) ? body.paramName @@ -91,6 +94,7 @@ export class TasksController { : undefined; const { tasks, total } = await this.taskService.getTasks( + context, decodedToken, offset, limit, @@ -189,7 +193,9 @@ export class TasksController { // RoleGuardでroleの文字列に想定外の文字列や重複がないことは担保されているためここでは型変換のみ行う const roles = role.split(' ') as Roles[]; - await this.taskService.checkout(param.audioFileId, roles, userId); + const context = makeContext(userId); + + await this.taskService.checkout(context, param.audioFileId, roles, userId); return {}; } @@ -242,7 +248,9 @@ export class TasksController { json: true, }) as AccessToken; - await this.taskService.checkin(audioFileId, userId); + const context = makeContext(userId); + + await this.taskService.checkin(context, audioFileId, userId); return {}; } @@ -296,7 +304,10 @@ export class TasksController { }) as AccessToken; // RoleGuardでroleの文字列に想定外の文字列や重複がないことは担保されているためここでは型変換のみ行う const roles = role.split(' ') as Roles[]; - await this.taskService.cancel(audioFileId, userId, roles); + + const context = makeContext(userId); + + await this.taskService.cancel(context, audioFileId, userId, roles); return {}; } @@ -349,7 +360,9 @@ export class TasksController { json: true, }) as AccessToken; - await this.taskService.suspend(audioFileId, userId); + const context = makeContext(userId); + + await this.taskService.suspend(context, audioFileId, userId); return {}; } @@ -494,7 +507,10 @@ export class TasksController { // RoleGuardでroleの文字列に想定外の文字列や重複がないことは担保されているためここでは型変換のみ行う const roles = role.split(' ') as Roles[]; + const context = makeContext(userId); + await this.taskService.changeCheckoutPermission( + context, audioFileId, assignees, userId, diff --git a/dictation_server/src/features/tasks/tasks.service.spec.ts b/dictation_server/src/features/tasks/tasks.service.spec.ts index babfbed..0d47fe7 100644 --- a/dictation_server/src/features/tasks/tasks.service.spec.ts +++ b/dictation_server/src/features/tasks/tasks.service.spec.ts @@ -21,6 +21,7 @@ import { makeTaskTestingModule, } from './test/utility'; import { Adb2cTooManyRequestsError } from '../../gateways/adb2c/adb2c.service'; +import { makeContext } from '../../common/log'; describe('TasksService', () => { it('タスク一覧を取得できる(admin)', async () => { @@ -47,6 +48,7 @@ describe('TasksService', () => { const direction = 'ASC'; expect( await service.tasksService.getTasks( + makeContext('trackingId'), accessToken, offset, limit, @@ -121,6 +123,7 @@ describe('TasksService', () => { const direction = 'ASC'; await expect( service.tasksService.getTasks( + makeContext('trackingId'), accessToken, offset, limit, @@ -161,6 +164,7 @@ describe('TasksService', () => { const direction = 'ASC'; await expect( service.tasksService.getTasks( + makeContext('trackingId'), accessToken, offset, limit, @@ -234,6 +238,7 @@ describe('TasksService', () => { const direction = 'ASC'; await expect( service.tasksService.getTasks( + makeContext('trackingId'), accessToken, offset, limit, @@ -276,6 +281,7 @@ describe('TasksService', () => { const paramName = 'JOB_NUMBER'; const direction = 'ASC'; const result = await service.tasksService.getTasks( + makeContext('trackingId'), accessToken, offset, limit, @@ -357,6 +363,7 @@ describe('TasksService', () => { const direction = 'ASC'; await expect( service.tasksService.getTasks( + makeContext('trackingId'), accessToken, offset, limit, @@ -400,6 +407,7 @@ describe('TasksService', () => { const paramName = 'JOB_NUMBER'; const direction = 'ASC'; const result = await service.tasksService.getTasks( + makeContext('trackingId'), accessToken, offset, limit, @@ -481,6 +489,7 @@ describe('TasksService', () => { const direction = 'ASC'; await expect( service.tasksService.getTasks( + makeContext('trackingId'), accessToken, offset, limit, @@ -520,6 +529,7 @@ describe('TasksService', () => { const direction = 'ASC'; await expect( service.tasksService.getTasks( + makeContext('trackingId'), accessToken, offset, limit, @@ -560,6 +570,7 @@ describe('TasksService', () => { const direction = 'ASC'; await expect( service.tasksService.getTasks( + makeContext('trackingId'), accessToken, offset, limit, @@ -617,6 +628,7 @@ describe('TasksService', () => { const direction = 'ASC'; const { tasks, total } = await service.getTasks( + makeContext('trackingId'), accessToken, offset, limit, @@ -672,6 +684,7 @@ describe('TasksService', () => { const direction = 'ASC'; const { tasks, total } = await service.getTasks( + makeContext('trackingId'), accessToken, offset, limit, @@ -743,6 +756,7 @@ describe('TasksService', () => { const direction = 'ASC'; const { tasks, total } = await service.getTasks( + makeContext('trackingId'), accessToken, offset, limit, @@ -824,6 +838,7 @@ describe('changeCheckoutPermission', () => { await createCheckoutPermissions(source, taskId, undefined, userGroupId); const service = module.get(TasksService); await service.changeCheckoutPermission( + makeContext('trackingId'), 1, [{ typistName: 'typist-user-2', typistUserId: typistUserId_2 }], 'author-user-external-id', @@ -892,6 +907,7 @@ describe('changeCheckoutPermission', () => { await createCheckoutPermissions(source, taskId, undefined, userGroupId_1); const service = module.get(TasksService); await service.changeCheckoutPermission( + makeContext('trackingId'), 1, [{ typistName: 'USER_GROUP_B', typistGroupId: userGroupId_2 }], 'author-user-external-id', @@ -947,9 +963,13 @@ describe('changeCheckoutPermission', () => { await createCheckoutPermissions(source, taskId, typistUserId_1); await createCheckoutPermissions(source, taskId, undefined, userGroupId); const service = module.get(TasksService); - await service.changeCheckoutPermission(1, [], 'author-user-external-id', [ - 'admin', - ]); + await service.changeCheckoutPermission( + makeContext('trackingId'), + 1, + [], + 'author-user-external-id', + ['admin'], + ); const permisions = await getCheckoutPermissions(source, taskId); expect(permisions.length).toEqual(0); }); @@ -997,6 +1017,7 @@ describe('changeCheckoutPermission', () => { await expect( service.changeCheckoutPermission( + makeContext('trackingId'), 1, [{ typistName: 'not-exist-user', typistUserId: 999 }], 'author-user-external-id', @@ -1050,6 +1071,7 @@ describe('changeCheckoutPermission', () => { await expect( service.changeCheckoutPermission( + makeContext('trackingId'), 1, [{ typistName: 'not-exist-user-group', typistGroupId: 999 }], 'author-user-external-id', @@ -1085,6 +1107,7 @@ describe('changeCheckoutPermission', () => { await expect( service.changeCheckoutPermission( + makeContext('trackingId'), 1, [{ typistName: 'typist-user', typistUserId: typistUserId }], 'author-user-external-id', @@ -1130,6 +1153,7 @@ describe('changeCheckoutPermission', () => { await expect( service.changeCheckoutPermission( + makeContext('trackingId'), 1, [{ typistName: 'typist-user', typistUserId: typistUserId }], 'author-user-external-id', @@ -1175,6 +1199,7 @@ describe('changeCheckoutPermission', () => { await expect( service.changeCheckoutPermission( + makeContext('trackingId'), 1, [{ typistName: 'typist-user', typistUserId: typistUserId }], 'author-user-external-id', @@ -1235,6 +1260,7 @@ describe('changeCheckoutPermission', () => { await expect( service.changeCheckoutPermission( + makeContext('trackingId'), 1, [{ typistName: 'typist-user-2', typistUserId: typistUserId_2 }], 'author-user-external-id', @@ -1311,7 +1337,12 @@ describe('checkout', () => { const initTask = await getTask(source, taskId); - await service.checkout(1, ['typist'], 'typist-user-external-id'); + await service.checkout( + makeContext('trackingId'), + 1, + ['typist'], + 'typist-user-external-id', + ); const { status, typist_user_id, started_at } = await getTask( source, taskId, @@ -1374,7 +1405,12 @@ describe('checkout', () => { const initTask = await getTask(source, taskId); - await service.checkout(1, ['typist'], 'typist-user-external-id'); + await service.checkout( + makeContext('trackingId'), + 1, + ['typist'], + 'typist-user-external-id', + ); const { status, typist_user_id, started_at } = await getTask( source, taskId, @@ -1430,7 +1466,12 @@ describe('checkout', () => { const initTask = await getTask(source, taskId); - await service.checkout(1, ['typist'], 'typist-user-external-id'); + await service.checkout( + makeContext('trackingId'), + 1, + ['typist'], + 'typist-user-external-id', + ); const { status, typist_user_id, started_at } = await getTask( source, taskId, @@ -1485,7 +1526,12 @@ describe('checkout', () => { const service = module.get(TasksService); await expect( - service.checkout(1, ['typist'], 'typist-user-external-id'), + service.checkout( + makeContext('trackingId'), + 1, + ['typist'], + 'typist-user-external-id', + ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST), ); @@ -1526,7 +1572,12 @@ describe('checkout', () => { const service = module.get(TasksService); await expect( - service.checkout(1, ['typist'], 'typist-user-external-id'), + service.checkout( + makeContext('trackingId'), + 1, + ['typist'], + 'typist-user-external-id', + ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010602'), HttpStatus.BAD_REQUEST), ); @@ -1560,7 +1611,12 @@ describe('checkout', () => { const service = module.get(TasksService); expect( - await service.checkout(1, ['author'], 'author-user-external-id'), + await service.checkout( + makeContext('trackingId'), + 1, + ['author'], + 'author-user-external-id', + ), ).toEqual(undefined); }); @@ -1592,7 +1648,12 @@ describe('checkout', () => { const service = module.get(TasksService); expect( - await service.checkout(1, ['author'], 'author-user-external-id'), + await service.checkout( + makeContext('trackingId'), + 1, + ['author'], + 'author-user-external-id', + ), ).toEqual(undefined); }); @@ -1614,7 +1675,12 @@ describe('checkout', () => { const service = module.get(TasksService); await expect( - service.checkout(1, ['author'], 'author-user-external-id'), + service.checkout( + makeContext('trackingId'), + 1, + ['author'], + 'author-user-external-id', + ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST), ); @@ -1648,7 +1714,12 @@ describe('checkout', () => { const service = module.get(TasksService); await expect( - service.checkout(1, ['author'], 'author-user-external-id'), + service.checkout( + makeContext('trackingId'), + 1, + ['author'], + 'author-user-external-id', + ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010602'), HttpStatus.BAD_REQUEST), ); @@ -1672,7 +1743,12 @@ describe('checkout', () => { const service = module.get(TasksService); await expect( - service.checkout(1, ['none'], 'none-user-external-id'), + service.checkout( + makeContext('trackingId'), + 1, + ['none'], + 'none-user-external-id', + ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010602'), HttpStatus.BAD_REQUEST), ); @@ -1735,7 +1811,11 @@ describe('checkin', () => { const initTask = await getTask(source, taskId); - await service.checkin(1, 'typist-user-external-id'); + await service.checkin( + makeContext('trackingId'), + 1, + 'typist-user-external-id', + ); const { status, finished_at } = await getTask(source, taskId); expect(status).toEqual('Finished'); @@ -1777,7 +1857,9 @@ describe('checkin', () => { await createCheckoutPermissions(source, taskId, typistUserId); const service = module.get(TasksService); - await expect(service.checkin(1, 'typist-user-external-id')).rejects.toEqual( + await expect( + service.checkin(makeContext('trackingId'), 1, 'typist-user-external-id'), + ).rejects.toEqual( new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST), ); }); @@ -1819,7 +1901,9 @@ describe('checkin', () => { const service = module.get(TasksService); - await expect(service.checkin(1, 'typist-user-external-id')).rejects.toEqual( + await expect( + service.checkin(makeContext('trackingId'), 1, 'typist-user-external-id'), + ).rejects.toEqual( new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST), ); }); @@ -1844,7 +1928,9 @@ describe('checkin', () => { const service = module.get(TasksService); - await expect(service.checkin(1, 'typist-user-external-id')).rejects.toEqual( + await expect( + service.checkin(makeContext('trackingId'), 1, 'typist-user-external-id'), + ).rejects.toEqual( new HttpException(makeErrorResponse('E010603'), HttpStatus.NOT_FOUND), ); }); @@ -1903,7 +1989,11 @@ describe('suspend', () => { const service = module.get(TasksService); - await service.suspend(1, 'typist-user-external-id'); + await service.suspend( + makeContext('trackingId'), + 1, + 'typist-user-external-id', + ); const { status } = await getTask(source, taskId); expect(status).toEqual('Pending'); @@ -1944,7 +2034,9 @@ describe('suspend', () => { await createCheckoutPermissions(source, taskId, typistUserId); const service = module.get(TasksService); - await expect(service.suspend(1, 'typist-user-external-id')).rejects.toEqual( + await expect( + service.suspend(makeContext('trackingId'), 1, 'typist-user-external-id'), + ).rejects.toEqual( new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST), ); }); @@ -1986,7 +2078,9 @@ describe('suspend', () => { const service = module.get(TasksService); - await expect(service.checkin(1, 'typist-user-external-id')).rejects.toEqual( + await expect( + service.checkin(makeContext('trackingId'), 1, 'typist-user-external-id'), + ).rejects.toEqual( new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST), ); }); @@ -2011,7 +2105,9 @@ describe('suspend', () => { const service = module.get(TasksService); - await expect(service.checkin(1, 'typist-user-external-id')).rejects.toEqual( + await expect( + service.checkin(makeContext('trackingId'), 1, 'typist-user-external-id'), + ).rejects.toEqual( new HttpException(makeErrorResponse('E010603'), HttpStatus.NOT_FOUND), ); }); @@ -2071,7 +2167,12 @@ describe('cancel', () => { const service = module.get(TasksService); - await service.cancel(1, 'typist-user-external-id', ['typist', 'standard']); + await service.cancel( + makeContext('trackingId'), + 1, + 'typist-user-external-id', + ['typist', 'standard'], + ); const { status, typist_user_id } = await getTask(source, taskId); const permisions = await getCheckoutPermissions(source, taskId); @@ -2115,7 +2216,12 @@ describe('cancel', () => { await createCheckoutPermissions(source, taskId, typistUserId); const service = module.get(TasksService); - await service.cancel(1, 'typist-user-external-id', ['typist', 'standard']); + await service.cancel( + makeContext('trackingId'), + 1, + 'typist-user-external-id', + ['typist', 'standard'], + ); const { status, typist_user_id } = await getTask(source, taskId); const permisions = await getCheckoutPermissions(source, taskId); @@ -2162,7 +2268,12 @@ describe('cancel', () => { const service = module.get(TasksService); - await service.cancel(1, 'typist-user-external-id', ['admin', 'author']); + await service.cancel( + makeContext('trackingId'), + 1, + 'typist-user-external-id', + ['admin', 'author'], + ); const { status, typist_user_id } = await getTask(source, taskId); const permisions = await getCheckoutPermissions(source, taskId); @@ -2208,7 +2319,12 @@ describe('cancel', () => { const service = module.get(TasksService); - await service.cancel(1, 'typist-user-external-id', ['admin', 'author']); + await service.cancel( + makeContext('trackingId'), + 1, + 'typist-user-external-id', + ['admin', 'author'], + ); const { status, typist_user_id } = await getTask(source, taskId); const permisions = await getCheckoutPermissions(source, taskId); @@ -2253,7 +2369,10 @@ describe('cancel', () => { const service = module.get(TasksService); await expect( - service.cancel(1, 'typist-user-external-id', ['admin', 'author']), + service.cancel(makeContext('trackingId'), 1, 'typist-user-external-id', [ + 'admin', + 'author', + ]), ).rejects.toEqual( new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST), ); @@ -2297,7 +2416,10 @@ describe('cancel', () => { const service = module.get(TasksService); await expect( - service.cancel(1, 'typist-user-external-id', ['typist', 'standard']), + service.cancel(makeContext('trackingId'), 1, 'typist-user-external-id', [ + 'typist', + 'standard', + ]), ).rejects.toEqual( new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST), ); @@ -2324,7 +2446,10 @@ describe('cancel', () => { const service = module.get(TasksService); await expect( - service.cancel(1, 'typist-user-external-id', ['typist', 'standard']), + service.cancel(makeContext('trackingId'), 1, 'typist-user-external-id', [ + 'typist', + 'standard', + ]), ).rejects.toEqual( new HttpException(makeErrorResponse('E010603'), HttpStatus.NOT_FOUND), ); diff --git a/dictation_server/src/features/tasks/tasks.service.ts b/dictation_server/src/features/tasks/tasks.service.ts index 3c4bc4f..7326ac0 100644 --- a/dictation_server/src/features/tasks/tasks.service.ts +++ b/dictation_server/src/features/tasks/tasks.service.ts @@ -32,6 +32,7 @@ import { InvalidRoleError } from './errors/types'; import { NotificationhubService } from '../../gateways/notificationhub/notificationhub.service'; import { UserGroupsRepositoryService } from '../../repositories/user_groups/user_groups.repository.service'; import { makeNotifyMessage } from '../../common/notify/makeNotifyMessage'; +import { Context } from '../../common/log'; @Injectable() export class TasksService { @@ -46,6 +47,7 @@ export class TasksService { // TODO [Task2244] 引数にAccessTokenがあるのは不適切なのでController側で分解したい async getTasks( + context: Context, accessToken: AccessToken, offset: number, limit: number, @@ -53,6 +55,10 @@ export class TasksService { paramName?: TaskListSortableAttribute, direction?: SortDirection, ): Promise<{ tasks: Task[]; total: number }> { + this.logger.log( + `[IN] [${context.trackingId}] ${this.getTasks.name} | params: { offset: ${offset}, limit: ${limit}, status: ${status}, paramName: ${paramName}, direction: ${direction} };`, + ); + const { role, userId } = accessToken; // TODO [Task2244] Roleに型で定義されている値が入っているかをチェックして異常値を弾く実装に修正する const roles = role.split(' '); @@ -77,6 +83,7 @@ export class TasksService { // B2Cからユーザー名を取得する const b2cUsers = await this.getB2cUsers( + context, result.tasks, result.permissions, ); @@ -99,6 +106,7 @@ export class TasksService { // B2Cからユーザー名を取得する const b2cUsers = await this.getB2cUsers( + context, result.tasks, result.permissions, ); @@ -118,6 +126,7 @@ export class TasksService { ); // B2Cからユーザー名を取得する const b2cUsers = await this.getB2cUsers( + context, result.tasks, result.permissions, ); @@ -142,6 +151,8 @@ export class TasksService { makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, ); + } finally { + this.logger.log(`[OUT] [${context.trackingId}] ${this.getTasks.name}`); } } /** @@ -152,11 +163,16 @@ export class TasksService { * @returns checkout */ async checkout( + context: Context, audioFileId: number, roles: Roles[], externalId: string, ): Promise { try { + this.logger.log( + `[IN] [${context.trackingId}] ${this.checkout.name} | params: { audioFileId: ${audioFileId}, roles: ${roles}, externalId: ${externalId} };`, + ); + const { id, account_id, author_id } = await this.usersRepository.findUserByExternalId(externalId); @@ -211,6 +227,8 @@ export class TasksService { makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, ); + } finally { + this.logger.log(`[OUT] [${context.trackingId}] ${this.checkout.name}`); } } @@ -220,8 +238,15 @@ export class TasksService { * @param externalId * @returns checkin */ - async checkin(audioFileId: number, externalId: string): Promise { + async checkin( + context: Context, + audioFileId: number, + externalId: string, + ): Promise { try { + this.logger.log( + `[IN] [${context.trackingId}] ${this.checkin.name} | params: { audioFileId: ${audioFileId}, externalId: ${externalId} };`, + ); const { id } = await this.usersRepository.findUserByExternalId( externalId, ); @@ -257,6 +282,8 @@ export class TasksService { makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, ); + } finally { + this.logger.log(`[OUT] [${context.trackingId}] ${this.checkin.name}`); } } /** @@ -267,11 +294,15 @@ export class TasksService { * @returns cancel */ async cancel( + context: Context, audioFileId: number, externalId: string, role: Roles[], ): Promise { try { + this.logger.log( + `[IN] [${context.trackingId}] ${this.cancel.name} | params: { audioFileId: ${audioFileId}, externalId: ${externalId}, role: ${role} };`, + ); const { id, account_id } = await this.usersRepository.findUserByExternalId(externalId); @@ -308,6 +339,8 @@ export class TasksService { makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, ); + } finally { + this.logger.log(`[OUT] [${context.trackingId}] ${this.cancel.name}`); } } @@ -317,8 +350,15 @@ export class TasksService { * @param externalId * @returns suspend */ - async suspend(audioFileId: number, externalId: string): Promise { + async suspend( + context: Context, + audioFileId: number, + externalId: string, + ): Promise { try { + this.logger.log( + `[IN] [${context.trackingId}] ${this.suspend.name} | params: { audioFileId: ${audioFileId}, externalId: ${externalId} };`, + ); const { id } = await this.usersRepository.findUserByExternalId( externalId, ); @@ -354,10 +394,13 @@ export class TasksService { makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, ); + } finally { + this.logger.log(`[OUT] [${context.trackingId}] ${this.suspend.name}`); } } private async getB2cUsers( + context: Context, tasks: TaskEntity[], permissions: CheckoutPermission[], ): Promise { @@ -385,7 +428,7 @@ export class TasksService { ); // B2Cからユーザー名を取得する - return await this.adB2cService.getUsers(filteredExternalIds); + return await this.adB2cService.getUsers(context, filteredExternalIds); } /** * 文字起こし候補を変更する @@ -394,12 +437,16 @@ export class TasksService { * @returns checkout permission */ async changeCheckoutPermission( + context: Context, audioFileId: number, assignees: Assignee[], externalId: string, role: Roles[], ): Promise { try { + this.logger.log( + `[IN] [${context.trackingId}] ${this.changeCheckoutPermission.name} | params: { audioFileId: ${audioFileId}, assignees: ${assignees}, externalId: ${externalId}, role: ${role} };`, + ); const { author_id, account_id } = await this.usersRepository.findUserByExternalId(externalId); @@ -444,6 +491,7 @@ export class TasksService { // タグ対象に通知送信 await this.notificationhubService.notify( + context, tags, makeNotifyMessage('M000101'), ); @@ -473,6 +521,10 @@ export class TasksService { makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, ); + } finally { + this.logger.log( + `[OUT] [${context.trackingId}] ${this.changeCheckoutPermission.name}`, + ); } } } diff --git a/dictation_server/src/features/users/users.controller.ts b/dictation_server/src/features/users/users.controller.ts index 9a31882..c3a1474 100644 --- a/dictation_server/src/features/users/users.controller.ts +++ b/dictation_server/src/features/users/users.controller.ts @@ -41,6 +41,7 @@ import { } from '../../common/types/sort'; import { ADMIN_ROLES } from '../../constants'; import { RoleGuard } from '../../common/guards/role/roleguards'; +import { makeContext } from '../../common/log'; @ApiTags('users') @Controller('users') @@ -205,7 +206,10 @@ export class UsersController { async getRelations(@Req() req: Request): Promise { const token = retrieveAuthorizationToken(req); const { userId } = jwt.decode(token, { json: true }) as AccessToken; - return await this.usersService.getRelations(userId); + + const context = makeContext(userId); + + return await this.usersService.getRelations(context, userId); } @ApiResponse({ diff --git a/dictation_server/src/features/users/users.service.ts b/dictation_server/src/features/users/users.service.ts index d816a99..6e23f4c 100644 --- a/dictation_server/src/features/users/users.service.ts +++ b/dictation_server/src/features/users/users.service.ts @@ -27,6 +27,7 @@ import { USER_LICENSE_STATUS, } from '../../constants'; import { DateWithZeroTime } from '../licenses/types/types'; +import { Context } from '../../common/log'; @Injectable() export class UsersService { @@ -308,7 +309,11 @@ export class UsersService { // DBから取得したユーザーの外部IDをもとにADB2Cからユーザーを取得する const externalIds = dbUsers.map((x) => x.external_id); - const adb2cUsers = await this.adB2cService.getUsers(externalIds); + const adb2cUsers = await this.adB2cService.getUsers( + // TODO: 外部連携以外のログ強化時に、ContollerからContextを取得するように修正する + { trackingId: 'dummy' }, + externalIds, + ); // DBから取得した各ユーザーをもとにADB2C情報をマージしライセンス情報を算出 const users = dbUsers.map((x) => { @@ -479,8 +484,11 @@ export class UsersService { * @param userId * @returns relations */ - async getRelations(userId: string): Promise { - this.logger.log(`[IN] ${this.getRelations.name}`); + async getRelations( + context: Context, + userId: string, + ): Promise { + this.logger.log(`[IN] [${context.trackingId}] ${this.getRelations.name}`); try { const user = await this.usersRepository.findUserByExternalId(userId); @@ -614,7 +622,9 @@ export class UsersService { HttpStatus.INTERNAL_SERVER_ERROR, ); } finally { - this.logger.log(`[OUT] ${this.getRelations.name}`); + this.logger.log( + `[OUT] [${context.trackingId}] ${this.getRelations.name}`, + ); } } } diff --git a/dictation_server/src/gateways/adb2c/adb2c.service.ts b/dictation_server/src/gateways/adb2c/adb2c.service.ts index 194d59c..82b0a4a 100644 --- a/dictation_server/src/gateways/adb2c/adb2c.service.ts +++ b/dictation_server/src/gateways/adb2c/adb2c.service.ts @@ -6,6 +6,7 @@ import { ConfigService } from '@nestjs/config'; import axios from 'axios'; import { Aadb2cUser, B2cMetadata, JwkSignKey } from '../../common/token'; import { AdB2cResponse, AdB2cUser } from './types/types'; +import { Context } from '../../common/log'; export type ConflictError = { reason: 'email'; @@ -188,9 +189,14 @@ export class AdB2cService { * @param externalIds * @returns users */ - async getUsers(externalIds: string[]): Promise { + async getUsers( + context: Context, + externalIds: string[], + ): Promise { this.logger.log( - `[IN] ${this.getUsers.name}; externalIds:[${externalIds.join(',')}]`, + `[IN] [${context.trackingId}] ${ + this.getUsers.name + } | params: { externalIds:[${externalIds.join(',')}] };`, ); /* @@ -223,7 +229,7 @@ export class AdB2cService { throw e; } finally { - this.logger.log(`[OUT] ${this.getUsers.name}`); + this.logger.log(`[OUT] [${context.trackingId}] ${this.getUsers.name}`); } } } diff --git a/dictation_server/src/gateways/blobstorage/blobstorage.service.ts b/dictation_server/src/gateways/blobstorage/blobstorage.service.ts index f238963..3f41678 100644 --- a/dictation_server/src/gateways/blobstorage/blobstorage.service.ts +++ b/dictation_server/src/gateways/blobstorage/blobstorage.service.ts @@ -14,6 +14,7 @@ import { BLOB_STORAGE_REGION_EU, BLOB_STORAGE_REGION_US, } from '../../constants'; +import { Context } from '../../common/log'; @Injectable() export class BlobstorageService { @@ -77,10 +78,21 @@ export class BlobstorageService { * @param accountId * @returns exists */ - async containerExists(accountId: number, country: string): Promise { + async containerExists( + context: Context, + accountId: number, + country: string, + ): Promise { + this.logger.log( + `[IN] [${context.trackingId}] ${this.containerExists.name}`, + ); // 国に応じたリージョンでコンテナ名を指定してClientを取得 const containerClient = this.getContainerClient(accountId, country); const exists = await containerClient.exists(); + + this.logger.log( + `[OUT] [${context.trackingId}] ${this.containerExists.name}`, + ); return exists; } @@ -94,14 +106,18 @@ export class BlobstorageService { * @returns exists */ async fileExists( + context: Context, accountId: number, country: string, filePath: string, ): Promise { + this.logger.log(`[IN] [${context.trackingId}] ${this.fileExists.name}`); + const containerClient = this.getContainerClient(accountId, country); const blob = containerClient.getBlobClient(`${filePath}`); const exists = await blob.exists(); + this.logger.log(`[OUT] [${context.trackingId}] ${this.fileExists.name}`); return exists; } @@ -113,11 +129,14 @@ export class BlobstorageService { * @returns upload sas */ async publishUploadSas( + context: Context, accountId: number, userId: number, country: string, ): Promise { - this.logger.log(`[IN] ${this.publishUploadSas.name}`); + this.logger.log( + `[IN] [${context.trackingId}] ${this.publishUploadSas.name}`, + ); let containerClient: ContainerClient; let sharedKeyCredential: StorageSharedKeyCredential; try { @@ -127,6 +146,9 @@ export class BlobstorageService { sharedKeyCredential = this.getSharedKeyCredential(country); } catch (e) { this.logger.error(`error=${e}`); + this.logger.log( + `[OUT] [${context.trackingId}] ${this.publishUploadSas.name}`, + ); throw e; } @@ -155,6 +177,10 @@ export class BlobstorageService { const url = new URL(containerClient.url); url.pathname += `/${userId}`; url.search = `${sasToken}`; + + this.logger.log( + `[OUT] [${context.trackingId}] ${this.publishUploadSas.name}`, + ); return url.toString(); } @@ -167,11 +193,14 @@ export class BlobstorageService { * @returns download sas */ async publishDownloadSas( + context: Context, accountId: number, country: string, filePath: string, ): Promise { - this.logger.log(`[IN] ${this.publishDownloadSas.name}`); + this.logger.log( + `[IN] [${context.trackingId}] ${this.publishDownloadSas.name}`, + ); let containerClient: ContainerClient; let blobClient: BlobClient; let sharedKeyCredential: StorageSharedKeyCredential; @@ -184,6 +213,9 @@ export class BlobstorageService { sharedKeyCredential = this.getSharedKeyCredential(country); } catch (e) { this.logger.error(`error=${e}`); + this.logger.log( + `[OUT] [${context.trackingId}] ${this.publishDownloadSas.name}`, + ); throw e; } @@ -212,6 +244,10 @@ export class BlobstorageService { const url = new URL(blobClient.url); url.search = `${sasToken}`; + + this.logger.log( + `[OUT] [${context.trackingId}] ${this.publishDownloadSas.name}`, + ); return url.toString(); } diff --git a/dictation_server/src/gateways/notificationhub/notificationhub.service.ts b/dictation_server/src/gateways/notificationhub/notificationhub.service.ts index dfc44cc..2f8fe90 100644 --- a/dictation_server/src/gateways/notificationhub/notificationhub.service.ts +++ b/dictation_server/src/gateways/notificationhub/notificationhub.service.ts @@ -11,6 +11,7 @@ import { } from '@azure/notification-hubs'; import { TAG_MAX_COUNT } from '../../constants'; import { PNS } from '../../constants'; +import { Context } from '../../common/log'; @Injectable() export class NotificationhubService { private readonly logger = new Logger(NotificationhubService.name); @@ -29,12 +30,15 @@ export class NotificationhubService { * @returns register */ async register( + context: Context, userId: number, pns: string, pnsHandler: string, installationId: string, ): Promise { - this.logger.log(`[IN] ${this.register.name}`); + this.logger.log( + `[IN] [${context.trackingId}] ${this.register.name} | params: { userId: ${userId}, pns: ${pns}, pnsHandler: ${pnsHandler}, installationId: ${installationId} }`, + ); const tag = `user_${userId}`; @@ -66,7 +70,7 @@ export class NotificationhubService { this.logger.error(`error=${e.message}`); throw e; } finally { - this.logger.log(`[OUT] ${this.register.name}`); + this.logger.log(`[OUT] [${context.trackingId}] ${this.register.name}`); } } @@ -76,8 +80,14 @@ export class NotificationhubService { * @param message * @returns notify */ - async notify(tags: string[], message: string): Promise { - this.logger.log(`[IN] ${this.notify.name}`); + async notify( + context: Context, + tags: string[], + message: string, + ): Promise { + this.logger.log( + `[IN] [${context.trackingId}] ${this.notify.name} | params: { tags: ${tags}, message: ${message} }`, + ); try { // OR条件によるtag指定は20個までなので分割して送信する diff --git a/dictation_server/src/repositories/user_groups/user_groups.repository.service.ts b/dictation_server/src/repositories/user_groups/user_groups.repository.service.ts index dbb167c..770ecaa 100644 --- a/dictation_server/src/repositories/user_groups/user_groups.repository.service.ts +++ b/dictation_server/src/repositories/user_groups/user_groups.repository.service.ts @@ -1,9 +1,7 @@ import { Injectable } from '@nestjs/common'; import { DataSource, In, IsNull } from 'typeorm'; import { UserGroup } from './entity/user_group.entity'; -import { Assignee } from '../../features/tasks/types/types'; import { UserGroupMember } from './entity/user_group_member.entity'; -import { User } from '../users/entity/user.entity'; @Injectable() export class UserGroupsRepositoryService {