Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit22f53f6

Browse files
authored
impl: improved debugging with named coroutines and additional logging (#185)
- this commit add descriptive names to launched coroutines for betterstack traces.- extra logging lines during connection setup. Should be helpful incases where the coroutinesfail with exceptions
1 parent9822876 commit22f53f6

File tree

9 files changed

+169
-135
lines changed

9 files changed

+169
-135
lines changed

‎CHANGELOG.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
##Unreleased
44

5+
###Added
6+
7+
- improved diagnose support
8+
59
##0.6.3 - 2025-08-25
610

711
###Added

‎gradle.properties‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
version=0.6.3
1+
version=0.6.4
22
group=com.coder.toolbox
33
name=coder-toolbox

‎src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt‎

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import com.jetbrains.toolbox.api.remoteDev.states.EnvironmentDescription
2424
importcom.jetbrains.toolbox.api.remoteDev.states.RemoteEnvironmentState
2525
importcom.jetbrains.toolbox.api.ui.actions.ActionDescription
2626
importcom.squareup.moshi.Moshi
27+
importkotlinx.coroutines.CoroutineName
2728
importkotlinx.coroutines.Job
2829
importkotlinx.coroutines.delay
2930
importkotlinx.coroutines.flow.MutableStateFlow
@@ -81,7 +82,7 @@ class CoderRemoteEnvironment(
8182
val actions= mutableListOf<Action>()
8283
if (wsRawStatus.canStop()) {
8384
actions.add(Action(context.i18n.ptrl("Open web terminal")) {
84-
context.cs.launch {
85+
context.cs.launch(CoroutineName("Open Web Terminal Action")) {
8586
context.desktop.browse(client.url.withPath("/${workspace.ownerName}/$name/terminal").toString()) {
8687
context.ui.showErrorInfoPopup(it)
8788
}
@@ -90,7 +91,7 @@ class CoderRemoteEnvironment(
9091
}
9192
actions.add(
9293
Action(context.i18n.ptrl("Open in dashboard")) {
93-
context.cs.launch {
94+
context.cs.launch(CoroutineName("Open in Dashboard Action")) {
9495
context.desktop.browse(
9596
client.url.withPath("/@${workspace.ownerName}/${workspace.name}").toString()
9697
) {
@@ -100,7 +101,7 @@ class CoderRemoteEnvironment(
100101
})
101102

102103
actions.add(Action(context.i18n.ptrl("View template")) {
103-
context.cs.launch {
104+
context.cs.launch(CoroutineName("View Template Action")) {
104105
context.desktop.browse(client.url.withPath("/templates/${workspace.templateName}").toString()) {
105106
context.ui.showErrorInfoPopup(it)
106107
}
@@ -110,14 +111,14 @@ class CoderRemoteEnvironment(
110111
if (wsRawStatus.canStart()) {
111112
if (workspace.outdated) {
112113
actions.add(Action(context.i18n.ptrl("Update and start")) {
113-
context.cs.launch {
114+
context.cs.launch(CoroutineName("Update and Start Action")) {
114115
val build= client.updateWorkspace(workspace)
115116
update(workspace.copy(latestBuild= build), agent)
116117
}
117118
})
118119
}else {
119120
actions.add(Action(context.i18n.ptrl("Start")) {
120-
context.cs.launch {
121+
context.cs.launch(CoroutineName("Start Action")) {
121122
val build= client.startWorkspace(workspace)
122123
update(workspace.copy(latestBuild= build), agent)
123124

@@ -128,14 +129,14 @@ class CoderRemoteEnvironment(
128129
if (wsRawStatus.canStop()) {
129130
if (workspace.outdated) {
130131
actions.add(Action(context.i18n.ptrl("Update and restart")) {
131-
context.cs.launch {
132+
context.cs.launch(CoroutineName("Update and Restart Action")) {
132133
val build= client.updateWorkspace(workspace)
133134
update(workspace.copy(latestBuild= build), agent)
134135
}
135136
})
136137
}
137138
actions.add(Action(context.i18n.ptrl("Stop")) {
138-
context.cs.launch {
139+
context.cs.launch(CoroutineName("Stop Action")) {
139140
tryStopSshConnection()
140141

141142
val build= client.stopWorkspace(workspace)
@@ -169,7 +170,7 @@ class CoderRemoteEnvironment(
169170
pollJob= pollNetworkMetrics()
170171
}
171172

172-
privatefunpollNetworkMetrics():Job= context.cs.launch {
173+
privatefunpollNetworkMetrics():Job= context.cs.launch(CoroutineName("Network Metrics Poller")) {
173174
context.logger.info("Starting the network metrics poll job for$id")
174175
while (isActive) {
175176
context.logger.debug("Searching SSH command's PID for workspace$id...")
@@ -227,7 +228,7 @@ class CoderRemoteEnvironment(
227228
actionsList.update {
228229
getAvailableActions()
229230
}
230-
context.cs.launch {
231+
context.cs.launch(CoroutineName("Workspace Status Updater")) {
231232
state.update {
232233
wsRawStatus.toRemoteEnvironmentState(context)
233234
}
@@ -262,7 +263,7 @@ class CoderRemoteEnvironment(
262263
*/
263264
funstartSshConnection():Boolean {
264265
if (wsRawStatus.ready()&&!isConnected.value) {
265-
context.cs.launch {
266+
context.cs.launch(CoroutineName("SSH Connection Trigger")) {
266267
connectionRequest.update {
267268
true
268269
}
@@ -284,7 +285,7 @@ class CoderRemoteEnvironment(
284285
}
285286

286287
overrideval deleteActionFlow:StateFlow<(()->Unit)?>=MutableStateFlow {
287-
context.cs.launch {
288+
context.cs.launch(CoroutineName("Delete Workspace Action")) {
288289
try {
289290
client.removeWorkspace(workspace)
290291
// mark the env as deleting otherwise we will have to
@@ -293,7 +294,7 @@ class CoderRemoteEnvironment(
293294
WorkspaceAndAgentStatus.DELETING.toRemoteEnvironmentState(context)
294295
}
295296

296-
context.cs.launch {
297+
context.cs.launch(CoroutineName("Workspace Deletion Poller")) {
297298
withTimeout(5.minutes) {
298299
var workspaceStillExists=true
299300
while (context.cs.isActive&& workspaceStillExists) {

‎src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt‎

Lines changed: 101 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import com.jetbrains.toolbox.api.remoteDev.RemoteProvider
2626
importcom.jetbrains.toolbox.api.ui.actions.ActionDelimiter
2727
importcom.jetbrains.toolbox.api.ui.actions.ActionDescription
2828
importcom.jetbrains.toolbox.api.ui.components.UiPage
29+
importkotlinx.coroutines.CoroutineName
2930
importkotlinx.coroutines.ExperimentalCoroutinesApi
3031
importkotlinx.coroutines.Job
3132
importkotlinx.coroutines.channels.Channel
@@ -87,113 +88,114 @@ class CoderRemoteProvider(
8788
* workspace is added, reconfigure SSH using the provided cli (including the
8889
* first time).
8990
*/
90-
privatefunpoll(client:CoderRestClient,cli:CoderCLIManager):Job= context.cs.launch {
91-
var lastPollTime=TimeSource.Monotonic.markNow()
92-
while (isActive) {
93-
try {
94-
context.logger.debug("Fetching workspace agents from${client.url}")
95-
val resolvedEnvironments= client.workspaces().flatMap { ws->
96-
// Agents are not included in workspaces that are off
97-
// so fetch them separately.
98-
when (ws.latestBuild.status) {
99-
WorkspaceStatus.RUNNING-> ws.latestBuild.resources
100-
else-> emptyList()
101-
}.ifEmpty {
102-
client.resources(ws)
103-
}.flatMap { resource->
104-
resource.agents?.distinctBy {
105-
// There can be duplicates with coder_agent_instance.
106-
// TODO: Can we just choose one or do they hold
107-
// different information?
108-
it.name
109-
}?.map { agent->
110-
// If we have an environment already, update that.
111-
val env=CoderRemoteEnvironment(context, client, cli, ws, agent)
112-
lastEnvironments.firstOrNull { it== env }?.let {
113-
it.update(ws, agent)
114-
it
115-
}?: env
116-
}?: emptyList()
117-
}
118-
}.toSet()
91+
privatefunpoll(client:CoderRestClient,cli:CoderCLIManager):Job=
92+
context.cs.launch(CoroutineName("Workspace Poller")) {
93+
var lastPollTime=TimeSource.Monotonic.markNow()
94+
while (isActive) {
95+
try {
96+
context.logger.debug("Fetching workspace agents from${client.url}")
97+
val resolvedEnvironments= client.workspaces().flatMap { ws->
98+
// Agents are not included in workspaces that are off
99+
// so fetch them separately.
100+
when (ws.latestBuild.status) {
101+
WorkspaceStatus.RUNNING-> ws.latestBuild.resources
102+
else-> emptyList()
103+
}.ifEmpty {
104+
client.resources(ws)
105+
}.flatMap { resource->
106+
resource.agents?.distinctBy {
107+
// There can be duplicates with coder_agent_instance.
108+
// TODO: Can we just choose one or do they hold
109+
// different information?
110+
it.name
111+
}?.map { agent->
112+
// If we have an environment already, update that.
113+
val env=CoderRemoteEnvironment(context, client, cli, ws, agent)
114+
lastEnvironments.firstOrNull { it== env }?.let {
115+
it.update(ws, agent)
116+
it
117+
}?: env
118+
}?: emptyList()
119+
}
120+
}.toSet()
119121

120-
// In case we logged out while running the query.
121-
if (!isActive) {
122-
return@launch
123-
}
122+
// In case we logged out while running the query.
123+
if (!isActive) {
124+
return@launch
125+
}
124126

125-
// Reconfigure if environments changed.
126-
if (lastEnvironments.size!= resolvedEnvironments.size|| lastEnvironments!= resolvedEnvironments) {
127-
context.logger.info("Workspaces have changed, reconfiguring CLI:$resolvedEnvironments")
128-
cli.configSsh(resolvedEnvironments.map { it.asPairOfWorkspaceAndAgent() }.toSet())
129-
}
127+
// Reconfigure if environments changed.
128+
if (lastEnvironments.size!= resolvedEnvironments.size|| lastEnvironments!= resolvedEnvironments) {
129+
context.logger.info("Workspaces have changed, reconfiguring CLI:$resolvedEnvironments")
130+
cli.configSsh(resolvedEnvironments.map { it.asPairOfWorkspaceAndAgent() }.toSet())
131+
}
130132

131-
environments.update {
132-
LoadableState.Value(resolvedEnvironments.toList())
133-
}
134-
if (!isInitialized.value) {
135-
context.logger.info("Environments for${client.url} are now initialized")
136-
isInitialized.update {
137-
true
133+
environments.update {
134+
LoadableState.Value(resolvedEnvironments.toList())
135+
}
136+
if (!isInitialized.value) {
137+
context.logger.info("Environments for${client.url} are now initialized")
138+
isInitialized.update {
139+
true
140+
}
141+
}
142+
lastEnvironments.apply {
143+
clear()
144+
addAll(resolvedEnvironments.sortedBy { it.id })
138145
}
139-
}
140-
lastEnvironments.apply {
141-
clear()
142-
addAll(resolvedEnvironments.sortedBy { it.id })
143-
}
144146

145-
if (WorkspaceConnectionManager.shouldEstablishWorkspaceConnections) {
146-
WorkspaceConnectionManager.allConnected().forEach { wsId->
147-
val env= lastEnvironments.firstOrNull() { it.id== wsId }
148-
if (env!=null&&!env.isConnected()) {
149-
context.logger.info("Establishing lost SSH connection for workspace with id$wsId")
150-
if (!env.startSshConnection()) {
151-
context.logger.info("Can't establish lost SSH connection for workspace with id$wsId")
147+
if (WorkspaceConnectionManager.shouldEstablishWorkspaceConnections) {
148+
WorkspaceConnectionManager.allConnected().forEach { wsId->
149+
val env= lastEnvironments.firstOrNull() { it.id== wsId }
150+
if (env!=null&&!env.isConnected()) {
151+
context.logger.info("Establishing lost SSH connection for workspace with id$wsId")
152+
if (!env.startSshConnection()) {
153+
context.logger.info("Can't establish lost SSH connection for workspace with id$wsId")
154+
}
152155
}
153156
}
157+
WorkspaceConnectionManager.reset()
154158
}
155-
WorkspaceConnectionManager.reset()
156-
}
157159

158-
WorkspaceConnectionManager.collectStatuses(lastEnvironments)
159-
}catch (_:CancellationException) {
160-
context.logger.debug("${client.url} polling loop canceled")
161-
break
162-
}catch (ex:Exception) {
163-
val elapsed= lastPollTime.elapsedNow()
164-
if (elapsed>POLL_INTERVAL*2) {
165-
context.logger.info("wake-up from an OS sleep was detected")
166-
}else {
167-
context.logger.error(ex,"workspace polling error encountered")
168-
if (exisAPIResponseException&& ex.isTokenExpired) {
169-
WorkspaceConnectionManager.shouldEstablishWorkspaceConnections=true
170-
close()
171-
context.envPageManager.showPluginEnvironmentsPage()
172-
errorBuffer.add(ex)
173-
break
160+
WorkspaceConnectionManager.collectStatuses(lastEnvironments)
161+
}catch (_:CancellationException) {
162+
context.logger.debug("${client.url} polling loop canceled")
163+
break
164+
}catch (ex:Exception) {
165+
val elapsed= lastPollTime.elapsedNow()
166+
if (elapsed>POLL_INTERVAL*2) {
167+
context.logger.info("wake-up from an OS sleep was detected")
168+
}else {
169+
context.logger.error(ex,"workspace polling error encountered")
170+
if (exisAPIResponseException&& ex.isTokenExpired) {
171+
WorkspaceConnectionManager.shouldEstablishWorkspaceConnections=true
172+
close()
173+
context.envPageManager.showPluginEnvironmentsPage()
174+
errorBuffer.add(ex)
175+
break
176+
}
174177
}
175178
}
176-
}
177179

178-
select {
179-
onTimeout(POLL_INTERVAL) {
180-
context.logger.debug("workspace poller waked up by the$POLL_INTERVAL timeout")
181-
}
182-
triggerSshConfig.onReceive { shouldTrigger->
183-
if (shouldTrigger) {
184-
context.logger.debug("workspace poller waked up because it should reconfigure the ssh configurations")
185-
cli.configSsh(lastEnvironments.map { it.asPairOfWorkspaceAndAgent() }.toSet())
180+
select {
181+
onTimeout(POLL_INTERVAL) {
182+
context.logger.debug("workspace poller waked up by the$POLL_INTERVAL timeout")
186183
}
187-
}
188-
triggerProviderVisible.onReceive { isCoderProviderVisible->
189-
if (isCoderProviderVisible) {
190-
context.logger.debug("workspace poller waked up by Coder Toolbox which is currently visible, fetching latest workspace statuses")
184+
triggerSshConfig.onReceive { shouldTrigger->
185+
if (shouldTrigger) {
186+
context.logger.debug("workspace poller waked up because it should reconfigure the ssh configurations")
187+
cli.configSsh(lastEnvironments.map { it.asPairOfWorkspaceAndAgent() }.toSet())
188+
}
189+
}
190+
triggerProviderVisible.onReceive { isCoderProviderVisible->
191+
if (isCoderProviderVisible) {
192+
context.logger.debug("workspace poller waked up by Coder Toolbox which is currently visible, fetching latest workspace statuses")
193+
}
191194
}
192195
}
196+
lastPollTime=TimeSource.Monotonic.markNow()
193197
}
194-
lastPollTime=TimeSource.Monotonic.markNow()
195198
}
196-
}
197199

198200
/**
199201
* Stop polling, clear the client and environments, then go back to the
@@ -221,7 +223,7 @@ class CoderRemoteProvider(
221223
overrideval additionalPluginActions:StateFlow<List<ActionDescription>>=MutableStateFlow(
222224
listOf(
223225
Action(context.i18n.ptrl("Create workspace")) {
224-
context.cs.launch {
226+
context.cs.launch(CoroutineName("Create Workspace Action")) {
225227
context.desktop.browse(client?.url?.withPath("/templates").toString()) {
226228
context.ui.showErrorInfoPopup(it)
227229
}
@@ -299,7 +301,7 @@ class CoderRemoteProvider(
299301
visibility
300302
}
301303
if (visibility.providerVisible) {
302-
context.cs.launch {
304+
context.cs.launch(CoroutineName("Notify Plugin Visibility")) {
303305
triggerProviderVisible.send(true)
304306
}
305307
}
@@ -396,11 +398,17 @@ class CoderRemoteProvider(
396398
context.secrets.lastDeploymentURL= client.url.toString()
397399
context.secrets.lastToken= client.token?:""
398400
context.secrets.storeTokenFor(client.url, context.secrets.lastToken)
401+
context.logger.info("Deployment URL and token were stored and will be available for automatic connection")
399402
this.client= client
400-
pollJob?.cancel()
403+
pollJob?.let {
404+
it.cancel()
405+
context.logger.info("Workspace poll job with reference${pollJob} was canceled")
406+
}
401407
environments.showLoadingMessage()
402408
coderHeaderPage.setTitle(context.i18n.pnotr(client.url.toString()))
409+
context.logger.info("Displaying${client.url} in the UI")
403410
pollJob= poll(client, cli)
411+
context.logger.info("Workspace poll job created with reference$pollJob")
404412
context.envPageManager.showPluginEnvironmentsPage()
405413
}
406414

‎src/main/kotlin/com/coder/toolbox/cli/CoderCLIManager.kt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ class CoderCLIManager(
315315
) {
316316
context.logger.info("Configuring SSH config at${context.settingsStore.sshConfigPath}")
317317
writeSSHConfig(modifySSHConfig(readSSHConfig(), wsWithAgents, feats))
318+
context.logger.info("Finished configuring SSH config")
318319
}
319320

320321
/**

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp