@@ -105,6 +105,9 @@ type Server struct {
105
105
connCountVSCode atomic.Int64
106
106
connCountJetBrains atomic.Int64
107
107
connCountSSHSession atomic.Int64
108
+ seenVSCode atomic.Bool
109
+ seenJetBrains atomic.Bool
110
+ seenSSHSession atomic.Bool
108
111
109
112
metrics * sshServerMetrics
110
113
}
@@ -167,7 +170,7 @@ func NewServer(ctx context.Context, logger slog.Logger, prometheusRegistry *prom
167
170
ChannelHandlers : map [string ]ssh.ChannelHandler {
168
171
"direct-tcpip" : func (srv * ssh.Server , conn * gossh.ServerConn , newChan gossh.NewChannel , ctx ssh.Context ) {
169
172
// Wrapper is designed to find and track JetBrains Gateway connections.
170
- wrapped := NewJetbrainsChannelWatcher (ctx , s .logger , newChan , & s .connCountJetBrains )
173
+ wrapped := NewJetbrainsChannelWatcher (ctx , s .logger , newChan , & s .connCountJetBrains , & s . seenJetBrains )
171
174
ssh .DirectTCPIPHandler (srv , conn , wrapped , ctx )
172
175
},
173
176
"direct-streamlocal@openssh.com" : directStreamLocalHandler ,
@@ -245,10 +248,31 @@ type ConnStats struct {
245
248
}
246
249
247
250
func (s * Server ) ConnStats () ConnStats {
251
+ // if we have 0 active connections, but we have seen a connection
252
+ // since the last time we collected, count it as 1 so that workspace
253
+ // activity is properly counted.
254
+ sshCount := s .connCountSSHSession .Load ()
255
+ if sshCount == 0 && s .seenSSHSession .Load () {
256
+ sshCount = 1
257
+ }
258
+ vscode := s .connCountVSCode .Load ()
259
+ if vscode == 0 && s .seenVSCode .Load () {
260
+ vscode = 1
261
+ }
262
+ jetbrains := s .connCountJetBrains .Load ()
263
+ if jetbrains == 0 && s .seenJetBrains .Load () {
264
+ jetbrains = 1
265
+ }
266
+
267
+ // Reset the seen trackers for the next collection.
268
+ s .seenSSHSession .Store (false )
269
+ s .seenVSCode .Store (false )
270
+ s .seenJetBrains .Store (false )
271
+
248
272
return ConnStats {
249
- Sessions : s . connCountSSHSession . Load () ,
250
- VSCode : s . connCountVSCode . Load () ,
251
- JetBrains : s . connCountJetBrains . Load () ,
273
+ Sessions : sshCount ,
274
+ VSCode : vscode ,
275
+ JetBrains : jetbrains ,
252
276
}
253
277
}
254
278
@@ -392,12 +416,14 @@ func (s *Server) sessionStart(logger slog.Logger, session ssh.Session, extraEnv
392
416
switch magicType {
393
417
case MagicSessionTypeVSCode :
394
418
s .connCountVSCode .Add (1 )
419
+ s .seenVSCode .Store (true )
395
420
defer s .connCountVSCode .Add (- 1 )
396
421
case MagicSessionTypeJetBrains :
397
422
// Do nothing here because JetBrains launches hundreds of ssh sessions.
398
423
// We instead track JetBrains in the single persistent tcp forwarding channel.
399
424
case "" :
400
425
s .connCountSSHSession .Add (1 )
426
+ s .seenSSHSession .Store (true )
401
427
defer s .connCountSSHSession .Add (- 1 )
402
428
default :
403
429
logger .Warn (ctx , "invalid magic ssh session type specified" , slog .F ("type" , magicType ))
0 commit comments