dce-reactkit 3.2.0-beta.3 → 3.2.0-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23,6 +23,7 @@ import LogSource from '../types/LogSource';
23
23
  import LogTypeSpecificInfo from '../types/Log/LogTypeSpecificInfo';
24
24
  import LogMainInfo from '../types/Log/LogMainInfo';
25
25
  import LogSourceSpecificInfo from '../types/Log/LogSourceSpecificInfo';
26
+ import LogBuiltInCategory from '../types/LogBuiltInCategory';
26
27
 
27
28
  /**
28
29
  * Generate an express API route handler
@@ -469,109 +470,172 @@ const genRouteHandler = (
469
470
  // that indicates that this is actually a client event, but we don't
470
471
  // include that in the LogFunction type because this is internal and
471
472
  // hidden from users
473
+ try {
474
+ // Parse user agent
475
+ const {
476
+ browser,
477
+ device,
478
+ } = parseUserAgent(req.headers['user-agent']);
479
+
480
+ // Get time info in ET
481
+ const {
482
+ timestamp,
483
+ year,
484
+ month,
485
+ day,
486
+ hour,
487
+ minute,
488
+ } = getTimeInfoInET();
489
+
490
+ // Main log info
491
+ const mainLogInfo: LogMainInfo = {
492
+ id: `${launchInfo.userId}-${Date.now()}-${Math.floor(Math.random() * 100000)}-${Math.floor(Math.random() * 100000)}`,
493
+ userFirstName: launchInfo.userFirstName,
494
+ userLastName: launchInfo.userLastName,
495
+ userEmail: launchInfo.userEmail,
496
+ userId: launchInfo.userId,
497
+ isLearner: !!launchInfo.isLearner,
498
+ isAdmin: !!launchInfo.isAdmin,
499
+ isTTM: !!launchInfo.isTTM,
500
+ courseId: launchInfo.courseId,
501
+ courseName: launchInfo.courseName,
502
+ browser,
503
+ device,
504
+ year,
505
+ month,
506
+ day,
507
+ hour,
508
+ minute,
509
+ timestamp,
510
+ category: (
511
+ typeof opts.category === 'string'
512
+ ? opts.category
513
+ : (
514
+ ((opts.category as any) ?? {})._
515
+ ?? LogBuiltInCategory.Uncategorized
516
+ )
517
+ ),
518
+ subcategory: (
519
+ typeof opts.category === 'string'
520
+ ? opts.subcategory
521
+ : (
522
+ ((opts.subcategory as any) ?? {})._
523
+ ?? LogBuiltInCategory.Uncategorized
524
+ )
525
+ ),
526
+ tags: opts.tags ?? [],
527
+ metadata: opts.metadata ?? {},
528
+ };
529
+
530
+ // Type-specific info
531
+ const typeSpecificInfo: LogTypeSpecificInfo = (
532
+ ('error' in opts && opts.error)
533
+ ? {
534
+ type: LogType.Error,
535
+ errorMessage: opts.error.message ?? 'Unknown message',
536
+ errorCode: opts.error.code ?? ReactKitErrorCode.NoCode,
537
+ errorStack: opts.error.stack ?? 'No stack',
538
+ }
539
+ : {
540
+ type: LogType.Action,
541
+ target: (opts as any).target ?? 'Unknown',
542
+ action: (opts as any).action ?? 'Unknown'
543
+ }
544
+ );
472
545
 
473
- // Parse user agent
474
- const {
475
- browser,
476
- device,
477
- } = parseUserAgent(req.headers['user-agent']);
478
-
479
- // Get time info in ET
480
- const {
481
- timestamp,
482
- year,
483
- month,
484
- day,
485
- hour,
486
- minute,
487
- } = getTimeInfoInET();
488
-
489
- // Main log info
490
- const mainLogInfo: LogMainInfo = {
491
- id: `${launchInfo.userId}-${Date.now()}-${Math.floor(Math.random() * 100000)}-${Math.floor(Math.random() * 100000)}`,
492
- userFirstName: launchInfo.userFirstName,
493
- userLastName: launchInfo.userLastName,
494
- userEmail: launchInfo.userEmail,
495
- userId: launchInfo.userId,
496
- isLearner: !!launchInfo.isLearner,
497
- isAdmin: !!launchInfo.isAdmin,
498
- isTTM: !!launchInfo.isTTM,
499
- courseId: launchInfo.courseId,
500
- courseName: launchInfo.courseName,
501
- browser,
502
- device,
503
- year,
504
- month,
505
- day,
506
- hour,
507
- minute,
508
- timestamp,
509
- category: (
510
- typeof opts.category === 'string'
511
- ? opts.category
512
- : opts.category.name
513
- ),
514
- subcategory: (
515
- typeof opts.category === 'string'
516
- ? opts.subcategory
517
- : ((opts.subcategory as any) ?? { name: 'none' }).name
518
- ),
519
- tags: opts.tags ?? [],
520
- metadata: opts.metadata ?? {},
521
- };
522
-
523
- // Type-specific info
524
- const typeSpecificInfo: LogTypeSpecificInfo = (
525
- ('error' in opts && opts.error)
526
- ? {
527
- type: LogType.Error,
528
- errorMessage: opts.error.message ?? 'Unknown message',
529
- errorCode: opts.error.code ?? ReactKitErrorCode.NoCode,
530
- errorStack: opts.error.stack ?? 'No stack',
531
- }
532
- : {
533
- type: LogType.Action,
534
- target: (opts as any).target ?? 'Unknown',
535
- action: (opts as any).action ?? 'Unknown'
536
- }
537
- );
538
-
539
- // Source-specific info
540
- const sourceSpecificInfo: LogSourceSpecificInfo = (
541
- (opts as any).overrideAsClientEvent
542
- ? {
543
- source: LogSource.Client,
544
- }
545
- : {
546
- source: LogSource.Server,
547
- routePath: req.path,
548
- routeTemplate: req.route.path,
549
- }
550
- );
546
+ // Source-specific info
547
+ const sourceSpecificInfo: LogSourceSpecificInfo = (
548
+ (opts as any).overrideAsClientEvent
549
+ ? {
550
+ source: LogSource.Client,
551
+ }
552
+ : {
553
+ source: LogSource.Server,
554
+ routePath: req.path,
555
+ routeTemplate: req.route.path,
556
+ }
557
+ );
551
558
 
552
- // Build log event
553
- const log: Log = {
554
- ...mainLogInfo,
555
- ...typeSpecificInfo,
556
- ...sourceSpecificInfo,
557
- };
558
-
559
- // Either print to console or save to db
560
- const logCollection = internalGetLogCollection();
561
- if (logCollection) {
562
- // Store to the log collection
563
- await logCollection.insert(log);
564
- } else {
565
- // Print to console
566
- if (log.type === LogType.Error) {
567
- console.error('dce-reactkit error log:', log);
559
+ // Build log event
560
+ const log: Log = {
561
+ ...mainLogInfo,
562
+ ...typeSpecificInfo,
563
+ ...sourceSpecificInfo,
564
+ };
565
+
566
+ // Either print to console or save to db
567
+ const logCollection = internalGetLogCollection();
568
+ if (logCollection) {
569
+ // Store to the log collection
570
+ await logCollection.insert(log);
568
571
  } else {
569
- console.log('dce-reactkit action log:', log);
572
+ // Print to console
573
+ if (log.type === LogType.Error) {
574
+ console.error('dce-reactkit error log:', log);
575
+ } else {
576
+ console.log('dce-reactkit action log:', log);
577
+ }
570
578
  }
571
- }
572
579
 
573
- // Return log entry
574
- return log;
580
+ // Return log entry
581
+ return log;
582
+ } catch (err) {
583
+ // Print because we cannot store the error
584
+ console.error('Could not log the following:', opts);
585
+
586
+ // Create a dummy log to return
587
+ const dummyMainInfo: LogMainInfo = {
588
+ id: '-1',
589
+ userFirstName: 'Unknown',
590
+ userLastName: 'Unknown',
591
+ userEmail: 'unknown@harvard.edu',
592
+ userId: 1,
593
+ isLearner: false,
594
+ isAdmin: false,
595
+ isTTM: false,
596
+ courseId: 1,
597
+ courseName: 'Unknown',
598
+ browser: {
599
+ name: 'Unknown',
600
+ version: 'Unknown',
601
+ },
602
+ device: {
603
+ isMobile: false,
604
+ os: 'Unknown',
605
+ },
606
+ year: 1,
607
+ month: 1,
608
+ day: 1,
609
+ hour: 1,
610
+ minute: 1,
611
+ timestamp: Date.now(),
612
+ tags: [],
613
+ metadata: {},
614
+ category: LogBuiltInCategory.Uncategorized,
615
+ subcategory: LogBuiltInCategory.Uncategorized,
616
+ };
617
+
618
+ const dummyTypeSpecificInfo: LogTypeSpecificInfo = {
619
+ type: LogType.Error,
620
+ errorMessage: 'Unknown',
621
+ errorCode: 'Unknown',
622
+ errorStack: 'No Stack',
623
+ };
624
+
625
+ const dummySourceSpecificInfo: LogSourceSpecificInfo = {
626
+ source: LogSource.Server,
627
+ routePath: req.path,
628
+ routeTemplate: req.route.path,
629
+ };
630
+
631
+ const log: Log = {
632
+ ...dummyMainInfo,
633
+ ...dummyTypeSpecificInfo,
634
+ ...dummySourceSpecificInfo,
635
+ };
636
+
637
+ return log;
638
+ }
575
639
  };
576
640
 
577
641
  /*------------------------------------------------------------------------*/
@@ -625,6 +689,22 @@ const genRouteHandler = (
625
689
  ) => {
626
690
  const html = genErrorPage(opts);
627
691
  send(html, opts.status ?? 500);
692
+
693
+ // Log
694
+ logServerEvent({
695
+ category: LogBuiltInCategory.ServerRenderedErrorPage,
696
+ error: {
697
+ message: `${opts.title}: ${opts.description}`,
698
+ code: opts.code,
699
+ },
700
+ metadata: {
701
+ title: opts.title,
702
+ description: opts.description,
703
+ code: opts.code,
704
+ pageTitle: opts.pageTitle,
705
+ status: opts.status ?? 500,
706
+ },
707
+ });
628
708
  };
629
709
 
630
710
  // Call the handler
@@ -649,7 +729,15 @@ const genRouteHandler = (
649
729
  } catch (err) {
650
730
  // Send error to client (only if next wasn't called)
651
731
  if (!responseSent) {
652
- return handleError(res, err);
732
+ handleError(res, err);
733
+
734
+ // Log server-side error
735
+ logServerEvent({
736
+ category: LogBuiltInCategory.ServerEndpointError,
737
+ error: err,
738
+ });
739
+
740
+ return;
653
741
  }
654
742
 
655
743
  // Log error that was not responded with
@@ -1,5 +1,6 @@
1
1
  // Import shared types
2
2
  import LOG_ROUTE_PATH from '../constants/LOG_ROUTE_PATH';
3
+ import LogBuiltInCategory from '../types/LogBuiltInCategory';
3
4
  import LogFunction from '../types/LogFunction';
4
5
 
5
6
  // Import shared functions
@@ -17,12 +18,18 @@ const logClientEvent: LogFunction = async (opts) => {
17
18
  category: (
18
19
  typeof opts.category === 'string'
19
20
  ? opts.category
20
- : opts.category.name
21
+ : (
22
+ ((opts.category as any) ?? {})._
23
+ ?? LogBuiltInCategory.Uncategorized
24
+ )
21
25
  ),
22
26
  subcategory: (
23
27
  typeof opts.category === 'string'
24
28
  ? opts.subcategory
25
- : ((opts.subcategory as any) ?? { name: 'none' }).name
29
+ : (
30
+ ((opts.subcategory as any) ?? {})._
31
+ ?? LogBuiltInCategory.Uncategorized
32
+ )
26
33
  ),
27
34
  tags: JSON.stringify(opts.tags),
28
35
  metadata: JSON.stringify(opts.metadata ?? {}),
package/src/index.ts CHANGED
@@ -63,6 +63,7 @@ import Log from './types/Log';
63
63
  import LogType from './types/LogType';
64
64
  import LogSource from './types/LogSource';
65
65
  import LogAction from './types/LogAction';
66
+ import LogBuiltInCategory from './types/LogBuiltInCategory';
66
67
 
67
68
  // Component-specific-types
68
69
  import PickableItem from './components/ItemPicker/types/PickableItem';
@@ -135,6 +136,7 @@ export {
135
136
  LogType,
136
137
  LogSource,
137
138
  LogAction,
139
+ LogBuiltInCategory,
138
140
  // Component-specific-types
139
141
  PickableItem,
140
142
  // Server types
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Built-in categories for logs
3
+ * @author Gabe Abrams
4
+ */
5
+ enum LogBuiltInCategory {
6
+ Uncategorized = 'n/a',
7
+ ServerRenderedErrorPage = '_server-rendered-error-page',
8
+ ServerEndpointError = '_server-endpoint-error',
9
+ };
10
+
11
+ export default LogBuiltInCategory;