@@ -21,6 +21,7 @@ import { computeSSHProperties, sshSupportsSetEnv } from "./sshSupport"
21
21
import { Storage } from "./storage"
22
22
import { AuthorityPrefix , expandPath , parseRemoteAuthority } from "./util"
23
23
import { WorkspaceMonitor } from "./workspaceMonitor"
24
+ import { getMemoryLogger } from "./memoryLogger"
24
25
25
26
export interface RemoteDetails extends vscode . Disposable {
26
27
url : string
@@ -688,9 +689,20 @@ export class Remote {
688
689
// showNetworkUpdates finds the SSH process ID that is being used by this
689
690
// workspace and reads the file being created by the Coder CLI.
690
691
private showNetworkUpdates ( sshPid : number ) : vscode . Disposable {
692
+ const logger = getMemoryLogger ( )
693
+ logger . trackResourceCreated ( "NetworkStatusBar" )
694
+ logger . info ( `Starting network updates monitor for SSH PID: ${ sshPid } ` )
695
+
691
696
const networkStatus = vscode . window . createStatusBarItem ( vscode . StatusBarAlignment . Left , 1000 )
697
+ networkStatus . name = "Coder Workspace Update"
692
698
const networkInfoFile = path . join ( this . storage . getNetworkInfoPath ( ) , `${ sshPid } .json` )
693
699
700
+ logger . debug ( `Network info file path: ${ networkInfoFile } ` )
701
+
702
+ let refreshCount = 0
703
+ let disposed = false
704
+ let lastFileSize = 0
705
+
694
706
const updateStatus = ( network : {
695
707
p2p : boolean
696
708
latency : number
@@ -699,78 +711,117 @@ export class Remote {
699
711
upload_bytes_sec : number
700
712
download_bytes_sec : number
701
713
} ) => {
702
- let statusText = "$(globe) "
703
- if ( network . p2p ) {
704
- statusText += "Direct "
705
- networkStatus . tooltip = "You're connected peer-to-peer ✨."
706
- } else {
707
- statusText += network . preferred_derp + " "
708
- networkStatus . tooltip =
709
- "You're connected through a relay 🕵.\nWe'll switch over to peer-to-peer when available."
710
- }
711
- networkStatus . tooltip +=
712
- "\n\nDownload ↓ " +
713
- prettyBytes ( network . download_bytes_sec , {
714
- bits : true ,
715
- } ) +
716
- "/s • Upload ↑ " +
717
- prettyBytes ( network . upload_bytes_sec , {
718
- bits : true ,
719
- } ) +
720
- "/s\n"
721
-
722
- if ( ! network . p2p ) {
723
- const derpLatency = network . derp_latency [ network . preferred_derp ]
724
-
725
- networkStatus . tooltip += `You ↔ ${ derpLatency . toFixed ( 2 ) } ms ↔ ${ network . preferred_derp } ↔ ${ ( network . latency - derpLatency ) . toFixed ( 2 ) } ms ↔ Workspace`
726
-
727
- let first = true
728
- Object . keys ( network . derp_latency ) . forEach ( ( region ) => {
729
- if ( region === network . preferred_derp ) {
730
- return
731
- }
732
- if ( first ) {
733
- networkStatus . tooltip += `\n\nOther regions:`
734
- first = false
735
- }
736
- networkStatus . tooltip += `\n${ region } : ${ Math . round ( network . derp_latency [ region ] * 100 ) / 100 } ms`
737
- } )
738
- }
714
+ try {
715
+ let statusText = "$(globe) "
716
+ if ( network . p2p ) {
717
+ statusText += "Direct "
718
+ networkStatus . tooltip = "You're connected peer-to-peer ✨."
719
+ } else {
720
+ statusText += network . preferred_derp + " "
721
+ networkStatus . tooltip =
722
+ "You're connected through a relay 🕵.\nWe'll switch over to peer-to-peer when available."
723
+ }
724
+ networkStatus . tooltip +=
725
+ "\n\nDownload ↓ " +
726
+ prettyBytes ( network . download_bytes_sec , {
727
+ bits : true ,
728
+ } ) +
729
+ "/s • Upload ↑ " +
730
+ prettyBytes ( network . upload_bytes_sec , {
731
+ bits : true ,
732
+ } ) +
733
+ "/s\n"
734
+
735
+ if ( ! network . p2p ) {
736
+ const derpLatency = network . derp_latency [ network . preferred_derp ]
737
+
738
+ networkStatus . tooltip += `You ↔ ${ derpLatency . toFixed ( 2 ) } ms ↔ ${ network . preferred_derp } ↔ ${ (
739
+ network . latency - derpLatency
740
+ ) . toFixed ( 2 ) } ms ↔ Workspace`
741
+
742
+ let first = true
743
+ Object . keys ( network . derp_latency ) . forEach ( ( region ) => {
744
+ if ( region === network . preferred_derp ) {
745
+ return
746
+ }
747
+ if ( first ) {
748
+ networkStatus . tooltip += `\n\nOther regions:`
749
+ first = false
750
+ }
751
+ networkStatus . tooltip += `\n${ region } : ${ Math . round ( network . derp_latency [ region ] * 100 ) / 100 } ms`
752
+ } )
753
+ }
739
754
740
- statusText += "(" + network . latency . toFixed ( 2 ) + "ms)"
741
- networkStatus . text = statusText
742
- networkStatus . show ( )
755
+ statusText += "(" + network . latency . toFixed ( 2 ) + "ms)"
756
+ networkStatus . text = statusText
757
+ networkStatus . show ( )
758
+
759
+ // Log occasional network stats updates (every 20 refreshes)
760
+ if ( refreshCount % 20 === 0 ) {
761
+ logger . debug (
762
+ `Network stats update #${ refreshCount } : p2p=${ network . p2p } , latency=${ network . latency . toFixed ( 2 ) } ms` ,
763
+ )
764
+ }
765
+ } catch ( ex ) {
766
+ // Replace silent error ignoring with proper logging
767
+ logger . error ( "Error updating network status" , ex )
768
+ }
743
769
}
744
- let disposed = false
770
+
745
771
const periodicRefresh = ( ) => {
746
772
if ( disposed ) {
773
+ logger . debug ( "Network updates: Skipping refresh as disposed=true" )
747
774
return
748
775
}
776
+
777
+ refreshCount ++
778
+
779
+ // Log every 100 refreshes to track long-term operation
780
+ if ( refreshCount % 100 === 0 ) {
781
+ logger . info ( `Network updates: Completed ${ refreshCount } refresh cycles for SSH PID: ${ sshPid } ` )
782
+ logger . logMemoryUsage ( "NETWORK_REFRESH" )
783
+ }
784
+
749
785
fs . readFile ( networkInfoFile , "utf8" )
750
786
. then ( ( content ) => {
787
+ const currentSize = content . length
788
+ if ( lastFileSize !== currentSize ) {
789
+ logger . debug ( `Network info file size changed: ${ lastFileSize } -> ${ currentSize } bytes` )
790
+ lastFileSize = currentSize
791
+ }
751
792
return JSON . parse ( content )
752
793
} )
753
794
. then ( ( parsed ) => {
754
795
try {
755
796
updateStatus ( parsed )
756
797
} catch ( ex ) {
757
- // Ignore
798
+ logger . error ( `Failed to update status from parsed network info` , ex )
758
799
}
759
800
} )
760
- . catch ( ( ) => {
761
- // TODO: Log a failure here!
801
+ . catch ( ( error ) => {
802
+ // Replace empty catch with proper error logging
803
+ logger . error ( `Failed to read or parse network info file: ${ networkInfoFile } ` , error )
762
804
} )
763
805
. finally ( ( ) => {
764
806
// This matches the write interval of `coder vscodessh`.
765
- setTimeout ( periodicRefresh , 3000 )
807
+ if ( ! disposed ) {
808
+ setTimeout ( periodicRefresh , 3000 )
809
+ }
766
810
} )
767
811
}
812
+
813
+ // Log the first refresh
814
+ logger . debug ( `Starting initial network refresh for SSH PID: ${ sshPid } ` )
768
815
periodicRefresh ( )
769
816
770
817
return {
771
818
dispose : ( ) => {
772
- disposed = true
773
- networkStatus . dispose ( )
819
+ if ( ! disposed ) {
820
+ logger . info ( `Disposing network updates monitor for SSH PID: ${ sshPid } after ${ refreshCount } refreshes` )
821
+ disposed = true
822
+ networkStatus . dispose ( )
823
+ logger . trackResourceDisposed ( "NetworkStatusBar" )
824
+ }
774
825
} ,
775
826
}
776
827
}
0 commit comments