@@ -375,4 +375,302 @@ describe('_INTERNAL_captureLog', () => {
375
375
expect ( beforeCaptureLogSpy ) . toHaveBeenCalledWith ( 'afterCaptureLog' , log ) ;
376
376
beforeCaptureLogSpy . mockRestore ( ) ;
377
377
} ) ;
378
+
379
+ describe ( 'user functionality' , ( ) => {
380
+ it ( 'includes user data in log attributes when sendDefaultPii is enabled' , ( ) => {
381
+ const options = getDefaultTestClientOptions ( {
382
+ dsn : PUBLIC_DSN ,
383
+ _experiments : { enableLogs : true } ,
384
+ sendDefaultPii : true ,
385
+ } ) ;
386
+ const client = new TestClient ( options ) ;
387
+ const scope = new Scope ( ) ;
388
+ scope . setUser ( {
389
+ id : '123' ,
390
+
391
+ username : 'testuser' ,
392
+ } ) ;
393
+
394
+ _INTERNAL_captureLog ( { level : 'info' , message : 'test log with user' } , client , scope ) ;
395
+
396
+ const logAttributes = _INTERNAL_getLogBuffer ( client ) ?. [ 0 ] ?. attributes ;
397
+ expect ( logAttributes ) . toEqual ( {
398
+ 'user.id' : {
399
+ value : '123' ,
400
+ type : 'string' ,
401
+ } ,
402
+ 'user.email' : {
403
+
404
+ type : 'string' ,
405
+ } ,
406
+ 'user.name' : {
407
+ value : 'testuser' ,
408
+ type : 'string' ,
409
+ } ,
410
+ } ) ;
411
+ } ) ;
412
+
413
+ it ( 'does not include user data in log attributes when sendDefaultPii is disabled' , ( ) => {
414
+ const options = getDefaultTestClientOptions ( {
415
+ dsn : PUBLIC_DSN ,
416
+ _experiments : { enableLogs : true } ,
417
+ sendDefaultPii : false ,
418
+ } ) ;
419
+ const client = new TestClient ( options ) ;
420
+ const scope = new Scope ( ) ;
421
+ scope . setUser ( {
422
+ id : '123' ,
423
+
424
+ username : 'testuser' ,
425
+ } ) ;
426
+
427
+ _INTERNAL_captureLog ( { level : 'info' , message : 'test log without user' } , client , scope ) ;
428
+
429
+ const logAttributes = _INTERNAL_getLogBuffer ( client ) ?. [ 0 ] ?. attributes ;
430
+ expect ( logAttributes ) . toEqual ( { } ) ;
431
+ } ) ;
432
+
433
+ it ( 'includes partial user data when only some fields are available' , ( ) => {
434
+ const options = getDefaultTestClientOptions ( {
435
+ dsn : PUBLIC_DSN ,
436
+ _experiments : { enableLogs : true } ,
437
+ sendDefaultPii : true ,
438
+ } ) ;
439
+ const client = new TestClient ( options ) ;
440
+ const scope = new Scope ( ) ;
441
+ scope . setUser ( {
442
+ id : '123' ,
443
+ // email and username are missing
444
+ } ) ;
445
+
446
+ _INTERNAL_captureLog ( { level : 'info' , message : 'test log with partial user' } , client , scope ) ;
447
+
448
+ const logAttributes = _INTERNAL_getLogBuffer ( client ) ?. [ 0 ] ?. attributes ;
449
+ expect ( logAttributes ) . toEqual ( {
450
+ 'user.id' : {
451
+ value : '123' ,
452
+ type : 'string' ,
453
+ } ,
454
+ } ) ;
455
+ } ) ;
456
+
457
+ it ( 'includes user email and username without id' , ( ) => {
458
+ const options = getDefaultTestClientOptions ( {
459
+ dsn : PUBLIC_DSN ,
460
+ _experiments : { enableLogs : true } ,
461
+ sendDefaultPii : true ,
462
+ } ) ;
463
+ const client = new TestClient ( options ) ;
464
+ const scope = new Scope ( ) ;
465
+ scope . setUser ( {
466
+
467
+ username : 'testuser' ,
468
+ // id is missing
469
+ } ) ;
470
+
471
+ _INTERNAL_captureLog ( { level : 'info' , message : 'test log with email and username' } , client , scope ) ;
472
+
473
+ const logAttributes = _INTERNAL_getLogBuffer ( client ) ?. [ 0 ] ?. attributes ;
474
+ expect ( logAttributes ) . toEqual ( {
475
+ 'user.email' : {
476
+
477
+ type : 'string' ,
478
+ } ,
479
+ 'user.name' : {
480
+ value : 'testuser' ,
481
+ type : 'string' ,
482
+ } ,
483
+ } ) ;
484
+ } ) ;
485
+
486
+ it ( 'does not include user data when user object is empty' , ( ) => {
487
+ const options = getDefaultTestClientOptions ( {
488
+ dsn : PUBLIC_DSN ,
489
+ _experiments : { enableLogs : true } ,
490
+ sendDefaultPii : true ,
491
+ } ) ;
492
+ const client = new TestClient ( options ) ;
493
+ const scope = new Scope ( ) ;
494
+ scope . setUser ( { } ) ;
495
+
496
+ _INTERNAL_captureLog ( { level : 'info' , message : 'test log with empty user' } , client , scope ) ;
497
+
498
+ const logAttributes = _INTERNAL_getLogBuffer ( client ) ?. [ 0 ] ?. attributes ;
499
+ expect ( logAttributes ) . toEqual ( { } ) ;
500
+ } ) ;
501
+
502
+ it ( 'combines user data with other log attributes' , ( ) => {
503
+ const options = getDefaultTestClientOptions ( {
504
+ dsn : PUBLIC_DSN ,
505
+ _experiments : { enableLogs : true } ,
506
+ sendDefaultPii : true ,
507
+ release : '1.0.0' ,
508
+ environment : 'test' ,
509
+ } ) ;
510
+ const client = new TestClient ( options ) ;
511
+ const scope = new Scope ( ) ;
512
+ scope . setUser ( {
513
+ id : '123' ,
514
+
515
+ } ) ;
516
+
517
+ _INTERNAL_captureLog (
518
+ {
519
+ level : 'info' ,
520
+ message : 'test log with user and other attributes' ,
521
+ attributes : { component : 'auth' , action : 'login' } ,
522
+ } ,
523
+ client ,
524
+ scope ,
525
+ ) ;
526
+
527
+ const logAttributes = _INTERNAL_getLogBuffer ( client ) ?. [ 0 ] ?. attributes ;
528
+ expect ( logAttributes ) . toEqual ( {
529
+ component : {
530
+ value : 'auth' ,
531
+ type : 'string' ,
532
+ } ,
533
+ action : {
534
+ value : 'login' ,
535
+ type : 'string' ,
536
+ } ,
537
+ 'user.id' : {
538
+ value : '123' ,
539
+ type : 'string' ,
540
+ } ,
541
+ 'user.email' : {
542
+
543
+ type : 'string' ,
544
+ } ,
545
+ 'sentry.release' : {
546
+ value : '1.0.0' ,
547
+ type : 'string' ,
548
+ } ,
549
+ 'sentry.environment' : {
550
+ value : 'test' ,
551
+ type : 'string' ,
552
+ } ,
553
+ } ) ;
554
+ } ) ;
555
+
556
+ it ( 'handles user data with non-string values' , ( ) => {
557
+ const options = getDefaultTestClientOptions ( {
558
+ dsn : PUBLIC_DSN ,
559
+ _experiments : { enableLogs : true } ,
560
+ sendDefaultPii : true ,
561
+ } ) ;
562
+ const client = new TestClient ( options ) ;
563
+ const scope = new Scope ( ) ;
564
+ scope . setUser ( {
565
+ id : 123 , // number instead of string
566
+
567
+ username : undefined , // undefined value
568
+ } ) ;
569
+
570
+ _INTERNAL_captureLog ( { level : 'info' , message : 'test log with non-string user values' } , client , scope ) ;
571
+
572
+ const logAttributes = _INTERNAL_getLogBuffer ( client ) ?. [ 0 ] ?. attributes ;
573
+ expect ( logAttributes ) . toEqual ( {
574
+ 'user.id' : {
575
+ value : 123 ,
576
+ type : 'integer' ,
577
+ } ,
578
+ 'user.email' : {
579
+
580
+ type : 'string' ,
581
+ } ,
582
+ } ) ;
583
+ } ) ;
584
+
585
+ it ( 'preserves existing user attributes in log and does not override them' , ( ) => {
586
+ const options = getDefaultTestClientOptions ( {
587
+ dsn : PUBLIC_DSN ,
588
+ _experiments : { enableLogs : true } ,
589
+ sendDefaultPii : true ,
590
+ } ) ;
591
+ const client = new TestClient ( options ) ;
592
+ const scope = new Scope ( ) ;
593
+ scope . setUser ( {
594
+ id : '123' ,
595
+
596
+ } ) ;
597
+
598
+ _INTERNAL_captureLog (
599
+ {
600
+ level : 'info' ,
601
+ message : 'test log with existing user attributes' ,
602
+ attributes : {
603
+ 'user.id' : 'existing-id' , // This should NOT be overridden by scope user
604
+ 'user.custom' : 'custom-value' , // This should be preserved
605
+ } ,
606
+ } ,
607
+ client ,
608
+ scope ,
609
+ ) ;
610
+
611
+ const logAttributes = _INTERNAL_getLogBuffer ( client ) ?. [ 0 ] ?. attributes ;
612
+ expect ( logAttributes ) . toEqual ( {
613
+ 'user.custom' : {
614
+ value : 'custom-value' ,
615
+ type : 'string' ,
616
+ } ,
617
+ 'user.id' : {
618
+ value : 'existing-id' , // Existing value is preserved
619
+ type : 'string' ,
620
+ } ,
621
+ 'user.email' : {
622
+ value :
'[email protected] ' , // Only added because user.email wasn't already present
623
+ type : 'string' ,
624
+ } ,
625
+ } ) ;
626
+ } ) ;
627
+
628
+ it ( 'only adds scope user data for attributes that do not already exist' , ( ) => {
629
+ const options = getDefaultTestClientOptions ( {
630
+ dsn : PUBLIC_DSN ,
631
+ _experiments : { enableLogs : true } ,
632
+ sendDefaultPii : true ,
633
+ } ) ;
634
+ const client = new TestClient ( options ) ;
635
+ const scope = new Scope ( ) ;
636
+ scope . setUser ( {
637
+ id : 'scope-id' ,
638
+
639
+ username : 'scope-user' ,
640
+ } ) ;
641
+
642
+ _INTERNAL_captureLog (
643
+ {
644
+ level : 'info' ,
645
+ message : 'test log with partial existing user attributes' ,
646
+ attributes : {
647
+ 'user.email' :
'[email protected] ' , // This should be preserved
648
+ 'other.attr' : 'value' ,
649
+ } ,
650
+ } ,
651
+ client ,
652
+ scope ,
653
+ ) ;
654
+
655
+ const logAttributes = _INTERNAL_getLogBuffer ( client ) ?. [ 0 ] ?. attributes ;
656
+ expect ( logAttributes ) . toEqual ( {
657
+ 'other.attr' : {
658
+ value : 'value' ,
659
+ type : 'string' ,
660
+ } ,
661
+ 'user.email' : {
662
+ value :
'[email protected] ' , // Existing email is preserved
663
+ type : 'string' ,
664
+ } ,
665
+ 'user.id' : {
666
+ value : 'scope-id' , // Added from scope because not present
667
+ type : 'string' ,
668
+ } ,
669
+ 'user.name' : {
670
+ value : 'scope-user' , // Added from scope because not present
671
+ type : 'string' ,
672
+ } ,
673
+ } ) ;
674
+ } ) ;
675
+ } ) ;
378
676
} ) ;
0 commit comments