@@ -107,20 +107,33 @@ async function tokenMetaHandler(
107107 req : UpdateReqType < typeof schemas . examEnvironmentTokenMeta > ,
108108 reply : FastifyReply
109109) {
110+ const logger = this . log . child ( { req } ) ;
110111 const { 'exam-environment-authorization-token' : encodedToken } = req . headers ;
112+ logger . info ( { encodedToken } ) ;
111113
112114 let payload : JwtPayload ;
113115 try {
114116 payload = jwt . verify ( encodedToken , JWT_SECRET ) as JwtPayload ;
115117 } catch ( e ) {
116118 // Server refuses to brew (verify) coffee (jwts) with a teapot (random strings)
119+ logger . warn (
120+ { examEnvironmentAuthorizationTokenError : e } ,
121+ 'Invalid token provided.'
122+ ) ;
117123 void reply . code ( 418 ) ;
118124 return reply . send (
119125 ERRORS . FCC_EINVAL_EXAM_ENVIRONMENT_AUTHORIZATION_TOKEN ( JSON . stringify ( e ) )
120126 ) ;
121127 }
122128
123129 if ( ! isObjectID ( payload . examEnvironmentAuthorizationToken ) ) {
130+ logger . warn (
131+ {
132+ examEnvironmentAuthorizationToken :
133+ payload . examEnvironmentAuthorizationToken
134+ } ,
135+ 'Token is not an object id.'
136+ ) ;
124137 void reply . code ( 418 ) ;
125138 return reply . send (
126139 ERRORS . FCC_EINVAL_EXAM_ENVIRONMENT_AUTHORIZATION_TOKEN (
@@ -137,6 +150,7 @@ async function tokenMetaHandler(
137150
138151 if ( ! token ) {
139152 // Endpoint is valid, but resource does not exists
153+ logger . warn ( 'Token does not appear to exist.' ) ;
140154 void reply . code ( 404 ) ;
141155 return reply . send (
142156 ERRORS . FCC_EINVAL_EXAM_ENVIRONMENT_AUTHORIZATION_TOKEN (
@@ -161,6 +175,8 @@ async function postExamGeneratedExamHandler(
161175 req : UpdateReqType < typeof schemas . examEnvironmentPostExamGeneratedExam > ,
162176 reply : FastifyReply
163177) {
178+ const logger = this . log . child ( { req } ) ;
179+ logger . info ( { userId : req . user ?. id } ) ;
164180 // Get exam from DB
165181 const examId = req . body . examId ;
166182 const maybeExam = await mapErr (
@@ -172,10 +188,12 @@ async function postExamGeneratedExamHandler(
172188 ) ;
173189 if ( maybeExam . hasError ) {
174190 if ( maybeExam . error instanceof PrismaClientValidationError ) {
191+ logger . warn ( { examError : maybeExam . error } , 'Invalid exam id given.' ) ;
175192 void reply . code ( 400 ) ;
176193 return reply . send ( ERRORS . FCC_EINVAL_EXAM_ID ( maybeExam . error . message ) ) ;
177194 }
178195
196+ logger . error ( { examError : maybeExam . error } ) ;
179197 void reply . code ( 500 ) ;
180198 return reply . send (
181199 ERRORS . FCC_ERR_EXAM_ENVIRONMENT ( JSON . stringify ( maybeExam . error ) )
@@ -185,6 +203,7 @@ async function postExamGeneratedExamHandler(
185203 const exam = maybeExam . data ;
186204
187205 if ( ! exam ) {
206+ logger . warn ( { examId } , 'No exam with given id.' ) ;
188207 void reply . code ( 404 ) ;
189208 return reply . send (
190209 ERRORS . FCC_ENOENT_EXAM_ENVIRONMENT_MISSING_EXAM ( 'Invalid exam id given.' )
@@ -196,6 +215,10 @@ async function postExamGeneratedExamHandler(
196215 const isExamPrerequisitesMet = checkPrerequisites ( user , exam . prerequisites ) ;
197216
198217 if ( ! isExamPrerequisitesMet ) {
218+ logger . warn (
219+ { examId : exam . id } ,
220+ 'User has not completed prerequisites to take exam.'
221+ ) ;
199222 void reply . code ( 403 ) ;
200223 // TODO: Consider sending unmet prerequisites
201224 return reply . send (
@@ -216,6 +239,10 @@ async function postExamGeneratedExamHandler(
216239 ) ;
217240
218241 if ( maybeExamAttempts . hasError ) {
242+ logger . error (
243+ { examAttemptsError : maybeExamAttempts . error } ,
244+ 'Unable to query exam attempts.'
245+ ) ;
219246 void reply . code ( 500 ) ;
220247 return reply . send (
221248 ERRORS . FCC_ERR_EXAM_ENVIRONMENT ( JSON . stringify ( maybeExamAttempts . error ) )
@@ -238,6 +265,10 @@ async function postExamGeneratedExamHandler(
238265 examExpirationTime + exam . config . retakeTimeInMS < Date . now ( ) ;
239266
240267 if ( ! retakeAllowed ) {
268+ logger . warn (
269+ { examExpirationTime } ,
270+ 'User has completed exam too recently to retake.'
271+ ) ;
241272 void reply . code ( 429 ) ;
242273 // TODO: Consider sending last completed time
243274 return reply . send (
@@ -259,13 +290,21 @@ async function postExamGeneratedExamHandler(
259290 ) ;
260291
261292 if ( generated . hasError ) {
293+ logger . error (
294+ { generatedError : generated . error } ,
295+ 'Unable to query generated exam.'
296+ ) ;
262297 void reply . code ( 500 ) ;
263298 return reply . send (
264299 ERRORS . FCC_ERR_EXAM_ENVIRONMENT ( JSON . stringify ( generated . error ) )
265300 ) ;
266301 }
267302
268303 if ( generated . data === null ) {
304+ logger . error (
305+ { generatedExamId : lastAttempt . generatedExamId } ,
306+ 'Generated exam not found.'
307+ ) ;
269308 void reply . code ( 500 ) ;
270309 return reply . send (
271310 ERRORS . FCC_ERR_EXAM_ENVIRONMENT (
@@ -301,6 +340,7 @@ async function postExamGeneratedExamHandler(
301340 ) ;
302341
303342 if ( maybeGeneratedExams . hasError ) {
343+ logger . error ( { generatedExamsError : maybeGeneratedExams . error } ) ;
304344 void reply . code ( 500 ) ;
305345 return reply . send (
306346 ERRORS . FCC_ERR_EXAM_ENVIRONMENT ( maybeGeneratedExams . error )
@@ -310,12 +350,10 @@ async function postExamGeneratedExamHandler(
310350 const generatedExams = maybeGeneratedExams . data ;
311351
312352 if ( generatedExams . length === 0 ) {
353+ const errMessage = `Unable to provide a generated exam. Either all generated exams have been exhausted, or all generated exams are deprecated.` ;
354+ logger . error ( { examId : exam . id } , errMessage ) ;
313355 void reply . code ( 500 ) ;
314- return reply . send (
315- ERRORS . FCC_ERR_EXAM_ENVIRONMENT (
316- `Unable to provide a generated exam. Either all generated exams have been exhausted, or all generated exams are deprecated.`
317- )
318- ) ;
356+ return reply . send ( ERRORS . FCC_ERR_EXAM_ENVIRONMENT ( errMessage ) ) ;
319357 }
320358
321359 const randomGeneratedExam =
@@ -330,6 +368,7 @@ async function postExamGeneratedExamHandler(
330368 ) ;
331369
332370 if ( maybeGeneratedExam . hasError ) {
371+ logger . error ( { generatedExamError : maybeGeneratedExam . error } ) ;
333372 void reply . code ( 500 ) ;
334373 return reply . send (
335374 // TODO: Consider more specific code
@@ -343,6 +382,10 @@ async function postExamGeneratedExamHandler(
343382 const generatedExam = maybeGeneratedExam . data ;
344383
345384 if ( generatedExam === null ) {
385+ logger . error (
386+ { generatedExamId : randomGeneratedExam . id } ,
387+ 'Generated exam not found.'
388+ ) ;
346389 void reply . code ( 500 ) ;
347390 return reply . send (
348391 ERRORS . FCC_ERR_EXAM_ENVIRONMENT ( `Unable to locate generated exam.` )
@@ -364,6 +407,7 @@ async function postExamGeneratedExamHandler(
364407 ) ;
365408
366409 if ( attempt . hasError ) {
410+ logger . error ( { attemptError : attempt . error } ) ;
367411 void reply . code ( 500 ) ;
368412 return reply . send (
369413 ERRORS . FCC_ERR_EXAM_ENVIRONMENT_CREATE_EXAM_ATTEMPT (
@@ -378,6 +422,7 @@ async function postExamGeneratedExamHandler(
378422 ) ;
379423
380424 if ( maybeUserExam . hasError ) {
425+ logger . error ( { userExamError : maybeUserExam . error } ) ;
381426 await this . prisma . envExamAttempt . delete ( {
382427 where : {
383428 id : attempt . data . id
@@ -413,6 +458,8 @@ async function postExamAttemptHandler(
413458 req : UpdateReqType < typeof schemas . examEnvironmentPostExamAttempt > ,
414459 reply : FastifyReply
415460) {
461+ const logger = this . log . child ( { req } ) ;
462+ logger . info ( { userId : req . user ?. id } ) ;
416463 const { attempt } = req . body ;
417464
418465 const user = req . user ! ;
@@ -427,6 +474,10 @@ async function postExamAttemptHandler(
427474 ) ;
428475
429476 if ( maybeAttempts . hasError ) {
477+ logger . error (
478+ { error : maybeAttempts . error } ,
479+ 'User attempt cannot be linked to an exam attempt.'
480+ ) ;
430481 void reply . code ( 500 ) ;
431482 return reply . send (
432483 ERRORS . FCC_ERR_EXAM_ENVIRONMENT ( JSON . stringify ( maybeAttempts . error ) )
@@ -436,6 +487,7 @@ async function postExamAttemptHandler(
436487 const attempts = maybeAttempts . data ;
437488
438489 if ( attempts . length === 0 ) {
490+ logger . warn ( { examId : attempt . examId } , 'No attempts found for user.' ) ;
439491 void reply . code ( 404 ) ;
440492 return reply . send (
441493 ERRORS . FCC_ERR_EXAM_ENVIRONMENT_EXAM_ATTEMPT (
@@ -457,6 +509,7 @@ async function postExamAttemptHandler(
457509 ) ;
458510
459511 if ( maybeExam . hasError ) {
512+ logger . error ( { examError : maybeExam . error } ) ;
460513 void reply . code ( 500 ) ;
461514 return reply . send (
462515 ERRORS . FCC_ERR_EXAM_ENVIRONMENT ( JSON . stringify ( maybeExam . error ) )
@@ -466,6 +519,7 @@ async function postExamAttemptHandler(
466519 const exam = maybeExam . data ;
467520
468521 if ( exam === null ) {
522+ logger . warn ( { examId : attempt . examId } , 'Invalid exam id given.' ) ;
469523 void reply . code ( 404 ) ;
470524 return reply . send (
471525 ERRORS . FCC_ENOENT_EXAM_ENVIRONMENT_MISSING_EXAM ( 'Invalid exam id given.' )
@@ -476,6 +530,10 @@ async function postExamAttemptHandler(
476530 latestAttempt . startTimeInMS + exam . config . totalTimeInMS < Date . now ( ) ;
477531
478532 if ( isAttemptExpired ) {
533+ logger . warn (
534+ { examAttemptId : latestAttempt . id } ,
535+ 'Attempt has exceeded submission time.'
536+ ) ;
479537 void reply . code ( 403 ) ;
480538 return reply . send (
481539 ERRORS . FCC_EINVAL_EXAM_ENVIRONMENT_EXAM_ATTEMPT (
@@ -494,6 +552,7 @@ async function postExamAttemptHandler(
494552 ) ;
495553
496554 if ( maybeGeneratedExam . hasError ) {
555+ logger . error ( { generatedExamError : maybeGeneratedExam . error } ) ;
497556 void reply . code ( 500 ) ;
498557 return reply . send (
499558 ERRORS . FCC_ERR_EXAM_ENVIRONMENT ( JSON . stringify ( maybeGeneratedExam . error ) )
@@ -503,6 +562,10 @@ async function postExamAttemptHandler(
503562 const generatedExam = maybeGeneratedExam . data ;
504563
505564 if ( generatedExam === null ) {
565+ logger . warn (
566+ { generatedExamId : latestAttempt . generatedExamId } ,
567+ 'Generated exam not found.'
568+ ) ;
506569 void reply . code ( 404 ) ;
507570 return reply . send (
508571 ERRORS . FCC_ENOENT_EXAM_ENVIRONMENT_GENERATED_EXAM (
@@ -536,6 +599,10 @@ async function postExamAttemptHandler(
536599 ) ;
537600
538601 if ( maybeValidExamAttempt . hasError ) {
602+ logger . warn (
603+ { validExamAttemptError : maybeValidExamAttempt . error } ,
604+ 'Invalid exam attempt.'
605+ ) ;
539606 void reply . code ( 400 ) ;
540607 const message =
541608 maybeValidExamAttempt . error instanceof Error
@@ -545,6 +612,7 @@ async function postExamAttemptHandler(
545612 }
546613
547614 if ( maybeUpdatedAttempt . hasError ) {
615+ logger . error ( { updatedAttemptError : maybeUpdatedAttempt . error } ) ;
548616 void reply . code ( 500 ) ;
549617 return reply . send (
550618 ERRORS . FCC_ERR_EXAM_ENVIRONMENT ( JSON . stringify ( maybeUpdatedAttempt . error ) )
@@ -564,9 +632,12 @@ async function postScreenshotHandler(
564632 req : UpdateReqType < typeof schemas . examEnvironmentPostScreenshot > ,
565633 reply : FastifyReply
566634) {
635+ const logger = this . log . child ( { req } ) ;
636+ logger . info ( { userId : req . user ?. id } ) ;
567637 const isMultipart = req . isMultipart ( ) ;
568638
569639 if ( ! isMultipart ) {
640+ logger . warn ( 'Request is not multipart form data.' ) ;
570641 void reply . code ( 400 ) ;
571642 return reply . send (
572643 ERRORS . FCC_EINVAL_EXAM_ENVIRONMENT_SCREENSHOT (
@@ -579,6 +650,7 @@ async function postScreenshotHandler(
579650 const imgData = await req . file ( ) ;
580651
581652 if ( ! imgData ) {
653+ logger . warn ( 'No image provided.' ) ;
582654 void reply . code ( 400 ) ;
583655 return reply . send (
584656 ERRORS . FCC_EINVAL_EXAM_ENVIRONMENT_SCREENSHOT ( 'No image provided.' )
@@ -594,6 +666,10 @@ async function postScreenshotHandler(
594666 ) ;
595667
596668 if ( maybeAttempt . hasError ) {
669+ logger . error (
670+ { error : maybeAttempt . error } ,
671+ 'User screenshot cannot be linked to an exam attempt.'
672+ ) ;
597673 void reply . code ( 500 ) ;
598674 return reply . send (
599675 ERRORS . FCC_ERR_EXAM_ENVIRONMENT ( JSON . stringify ( maybeAttempt . error ) )
@@ -603,6 +679,7 @@ async function postScreenshotHandler(
603679 const attempt = maybeAttempt . data ;
604680
605681 if ( attempt . length === 0 ) {
682+ logger . warn ( 'No exam attempts found for user.' ) ;
606683 void reply . code ( 404 ) ;
607684 return reply . send (
608685 ERRORS . FCC_ERR_EXAM_ENVIRONMENT_EXAM_ATTEMPT (
@@ -615,6 +692,7 @@ async function postScreenshotHandler(
615692
616693 // Verify image is JPG using magic number
617694 if ( imgBinary [ 0 ] !== 0xff || imgBinary [ 1 ] !== 0xd8 || imgBinary [ 2 ] !== 0xff ) {
695+ logger . warn ( 'Invalid image format' ) ;
618696 void reply . code ( 400 ) ;
619697 return reply . send (
620698 ERRORS . FCC_EINVAL_EXAM_ENVIRONMENT_SCREENSHOT ( 'Invalid image format.' )
@@ -642,6 +720,9 @@ async function getExams(
642720 req : UpdateReqType < typeof schemas . examEnvironmentExams > ,
643721 reply : FastifyReply
644722) {
723+ const logger = this . log . child ( { req } ) ;
724+ logger . info ( { user : req . user } ) ;
725+
645726 const user = req . user ! ;
646727 const exams = await this . prisma . envExam . findMany ( {
647728 where : {
0 commit comments