- Notifications
You must be signed in to change notification settings - Fork928
feat: add connection statistics for workspace agents#6469
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
8f1f141
ddf9841
28d6db5
29719a4
09a2dad
12a52b1
a1804a9
93f013b
50260c3
d1bae99
9fe9d4c
00ebe2e
cd76533
506740b
1924f58
9f00ac5
4b6992c
1af9f64
e3ca39f
8ad39d6
0f06b23
e87ba59
99d7d1a
37ad03f
415d8b1
0037a64
3d70b2a
d708210
c951d5a
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -17,6 +17,7 @@ import ( | ||
"os/exec" | ||
"os/user" | ||
"path/filepath" | ||
"reflect" | ||
"runtime" | ||
"sort" | ||
"strconv" | ||
@@ -60,7 +61,7 @@ const ( | ||
// MagicSSHSessionTypeEnvironmentVariable is used to track the purpose behind an SSH connection. | ||
// This is stripped from any commands being executed, and is counted towards connection stats. | ||
MagicSSHSessionTypeEnvironmentVariable = "CODER_SSH_SESSION_TYPE" | ||
// MagicSSHSessionTypeVSCode is set in the SSH config by the VS Code extension to identify itself. | ||
MagicSSHSessionTypeVSCode = "vscode" | ||
// MagicSSHSessionTypeJetBrains is set in the SSH config by the JetBrains extension to identify itself. | ||
@@ -122,9 +123,7 @@ func New(options Options) io.Closer { | ||
tempDir: options.TempDir, | ||
lifecycleUpdate: make(chan struct{}, 1), | ||
lifecycleReported: make(chan codersdk.WorkspaceAgentLifecycle, 1), | ||
connStatsChan: make(chan *agentsdk.Stats, 1), | ||
} | ||
a.init(ctx) | ||
return a | ||
@@ -159,11 +158,8 @@ type agent struct { | ||
network *tailnet.Conn | ||
connStatsChan chan *agentsdk.Stats | ||
latestStat atomic.Pointer[agentsdk.Stats] | ||
connCountVSCode atomic.Int64 | ||
connCountJetBrains atomic.Int64 | ||
connCountReconnectingPTY atomic.Int64 | ||
@@ -905,10 +901,13 @@ func (a *agent) handleSSHSession(session ssh.Session) (retErr error) { | ||
switch magicType { | ||
case MagicSSHSessionTypeVSCode: | ||
a.connCountVSCode.Add(1) | ||
defer a.connCountVSCode.Add(-1) | ||
case MagicSSHSessionTypeJetBrains: | ||
a.connCountJetBrains.Add(1) | ||
defer a.connCountJetBrains.Add(-1) | ||
case "": | ||
a.connCountSSHSession.Add(1) | ||
defer a.connCountSSHSession.Add(-1) | ||
default: | ||
a.logger.Warn(ctx, "invalid magic ssh session type specified", slog.F("type", magicType)) | ||
} | ||
@@ -1012,6 +1011,7 @@ func (a *agent) handleReconnectingPTY(ctx context.Context, logger slog.Logger, m | ||
defer conn.Close() | ||
a.connCountReconnectingPTY.Add(1) | ||
defer a.connCountReconnectingPTY.Add(-1) | ||
connectionID := uuid.NewString() | ||
logger = logger.With(slog.F("id", msg.ID), slog.F("connection_id", connectionID)) | ||
@@ -1210,18 +1210,15 @@ func (a *agent) startReportingConnectionStats(ctx context.Context) { | ||
ConnectionCount: int64(len(networkStats)), | ||
ConnectionsByProto: map[string]int64{}, | ||
} | ||
for conn, counts := range networkStats { | ||
stats.ConnectionsByProto[conn.Proto.String()]++ | ||
stats.RxBytes+=int64(counts.RxBytes) | ||
stats.RxPackets+=int64(counts.RxPackets) | ||
stats.TxBytes+=int64(counts.TxBytes) | ||
stats.TxPackets+=int64(counts.TxPackets) | ||
} | ||
// The count of active sessions. | ||
stats.SessionCountSSH = a.connCountSSHSession.Load() | ||
stats.SessionCountVSCode = a.connCountVSCode.Load() | ||
stats.SessionCountJetBrains = a.connCountJetBrains.Load() | ||
@@ -1270,10 +1267,16 @@ func (a *agent) startReportingConnectionStats(ctx context.Context) { | ||
// Convert from microseconds to milliseconds. | ||
stats.ConnectionMedianLatencyMS /= 1000 | ||
lastStat := a.latestStat.Load() | ||
if lastStat != nil && reflect.DeepEqual(lastStat, stats) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. I guess this still confuses me a bit. If Tailscale stats aren't cumulative, isn't the only way this matches lastStat if there was no chatter (tx/rx), the latency and sessions for SSH/Code/JetBrains stayed the same? Since we're also doing network pings in the latency check, I think there is a non-zero chance for multiple There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Hmm, good points. I'll refactor this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. After looking at this again, it seems like this should be fine. This will only match if there's no traffic, but that's arguably great because then we aren't spamming the database with nonsense. I don't want to do this in
Let me know if I'm overlooking something or didn't understand properly, I'm sick and my brain is stuffy right now ;p | ||
a.logger.Info(ctx, "skipping stat because nothing changed") | ||
return | ||
} | ||
a.latestStat.Store(stats) | ||
select { | ||
case a.connStatsChan <- stats: | ||
case <-a.closed: | ||
} | ||
} | ||
Uh oh!
There was an error while loading.Please reload this page.