Skip to content

Commit dedb6ce

Browse files
Fixed UI freeze issue on SocketTimeoutException + fixed setting of correct env in combobox after click on goToSpan link in RecentActivity tab
1 parent a40253c commit dedb6ce

File tree

10 files changed

+162
-50
lines changed

10 files changed

+162
-50
lines changed

CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
# Changelog
22
All notable changes to this project will be documented in this file.
33

4-
## [2.0.40] - 2023-03-21
4+
## [2.0.40] - 2023-03-22
55
### Changed
66
- Quick instrumentation java code (#395)
77
- Decreased and fixed height for navigation panel rows (#392)
88
- Change background color of navigation panel dynamically (#392)
99
- Applied new background color for navigation panel (#392)
1010
- Used ComboBox for environment selector (#392)
1111
- Fixed flickering of environment selector (#392)
12+
- Feature/Insights pending and no data yet (#396)
13+
- Set default value for ComboBox when connection was lost and when there are no environments
14+
- Add links to TopUsage/Bottleneck insights
15+
- Fixed Error links (#394)
16+
- Add Scaling Root Cause Insight
17+
- Feature/Add SpanInfo to SpanInsights - as in backend (#403)
18+
- Fixed UI freeze issue on SocketTimeoutException
19+
- Fixed setting of correct env in combobox after click on goToSpan link in RecentActivity tab
1220

1321
## [2.0.39] - 2023-03-17
1422
### Changed

ide-common/src/main/java/org/digma/intellij/plugin/analytics/AnalyticsService.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import java.lang.reflect.Method;
4444
import java.lang.reflect.UndeclaredThrowableException;
4545
import java.net.SocketException;
46+
import java.net.SocketTimeoutException;
4647
import java.net.UnknownHostException;
4748
import java.net.http.HttpTimeoutException;
4849
import java.time.Instant;
@@ -374,6 +375,11 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
374375
// while status is in error the following connection exceptions will not be logged, other exceptions
375376
// will be logged only once.
376377

378+
if (e.getTargetException().getCause() instanceof SocketTimeoutException) {
379+
Log.log(LOGGER::warn, "SocketTimeoutException for {} request => {}", method.getName(), e.getTargetException().getCause());
380+
return null;
381+
}
382+
377383
boolean isConnectionException = isConnectionException(e) || isSslConnectionException(e);
378384
if (status.isOk() && isConnectionException) {
379385
status.connectError();

ide-common/src/main/java/org/digma/intellij/plugin/analytics/Environment.java

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

33
import com.intellij.openapi.diagnostic.Logger;
44
import com.intellij.openapi.project.Project;
5+
import org.apache.commons.lang3.StringUtils;
56
import org.apache.commons.lang3.time.StopWatch;
67
import org.digma.intellij.plugin.common.Backgroundable;
78
import org.digma.intellij.plugin.log.Log;
@@ -22,6 +23,7 @@
2223
public class Environment implements EnvironmentsSupplier {
2324

2425
private static final Logger LOGGER = Logger.getInstance(Environment.class);
26+
private static final String NO_ENVIRONMENTS_MESSAGE = "No Environments";
2527

2628
private String current;
2729
private final SettingsState settingsState;
@@ -74,8 +76,8 @@ public void setCurrent(@NotNull String newEnv) {
7476

7577
Log.log(LOGGER::debug, "Setting current environment , old={},new={}", this.current, newEnv);
7678

77-
//don't change or fire the event if it's the same env. it happens because we have two combobox, one on each tab
78-
if (Objects.equals(this.current, newEnv)) {
79+
//don't change or fire the event if it's the same env.
80+
if (Objects.equals(this.current, newEnv) || StringUtils.isEmpty(newEnv) || NO_ENVIRONMENTS_MESSAGE.equals(newEnv)) {
7981
return;
8082
}
8183

@@ -98,10 +100,12 @@ public void setCurrent(@NotNull String newEnv) {
98100

99101

100102
private void changeEnvironment(@NotNull String newEnv) {
101-
var oldEnv = this.current;
102-
this.current = newEnv;
103-
persistenceData.setCurrentEnv(newEnv);
104-
notifyEnvironmentChanged(oldEnv, newEnv);
103+
if (StringUtils.isNotEmpty(newEnv)) {
104+
var oldEnv = this.current;
105+
this.current = newEnv;
106+
persistenceData.setCurrentEnv(newEnv);
107+
notifyEnvironmentChanged(oldEnv, newEnv);
108+
}
105109
}
106110

107111

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.digma.intellij.plugin.common
2+
3+
import com.intellij.openapi.diagnostic.Logger
4+
import com.intellij.openapi.progress.ProgressIndicator
5+
import com.intellij.openapi.progress.Task
6+
import org.digma.intellij.plugin.log.Log
7+
import java.util.concurrent.locks.ReentrantLock
8+
9+
@Suppress("DialogTitle")
10+
class AsynchronousBackgroundTask(private val lock: ReentrantLock, private val task: Runnable) : Task.Backgroundable(null, "Loading recent activity data") {
11+
private val logger: Logger = Logger.getInstance(AsynchronousBackgroundTask::class.java)
12+
override fun run(indicator: ProgressIndicator) {
13+
if (lock.tryLock()) {
14+
try {
15+
task.run()
16+
} finally {
17+
lock.unlock()
18+
}
19+
} else {
20+
// Previous task is still in progress, skip this task
21+
Log.log(logger::warn, "New task was skip because previous task is still in progress.")
22+
}
23+
}
24+
}

src/main/java/org/digma/intellij/plugin/toolwindow/recentactivity/DigmaBottomToolWindowFactory.java

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.digma.intellij.plugin.analytics.AnalyticsServiceException;
2525
import org.digma.intellij.plugin.analytics.BackendConnectionMonitor;
2626
import org.digma.intellij.plugin.analytics.EnvironmentChanged;
27+
import org.digma.intellij.plugin.common.AsynchronousBackgroundTask;
2728
import org.digma.intellij.plugin.common.Backgroundable;
2829
import org.digma.intellij.plugin.common.CommonUtils;
2930
import org.digma.intellij.plugin.log.Log;
@@ -42,9 +43,9 @@
4243
import java.awt.*;
4344
import java.util.ArrayList;
4445
import java.util.Collections;
45-
import java.util.Date;
4646
import java.util.List;
4747
import java.util.Map;
48+
import java.util.concurrent.locks.ReentrantLock;
4849

4950
import static org.digma.intellij.plugin.toolwindow.recentactivity.ToolWindowUtil.RECENT_ACTIVITY_GET_DATA;
5051
import static org.digma.intellij.plugin.toolwindow.recentactivity.ToolWindowUtil.RECENT_ACTIVITY_GO_TO_SPAN;
@@ -68,6 +69,8 @@ public class DigmaBottomToolWindowFactory implements ToolWindowFactory {
6869
private AnalyticsService analyticsService;
6970
private String localHostname;
7071

72+
private ReentrantLock recentActivityGetDataLock = new ReentrantLock();
73+
7174
/**
7275
* this is the starting point of the plugin. this method is called when the tool window is opened.
7376
* before the window is opened there may be no reason to do anything, listen to events for example will be
@@ -125,15 +128,16 @@ public boolean onQuery(CefBrowser browser, CefFrame frame, long queryId, String
125128
Log.log(LOGGER::debug, "request: {}", request);
126129
JcefMessageRequest reactMessageRequest = parseJsonToObject(request, JcefMessageRequest.class);
127130
if (RECENT_ACTIVITY_GET_DATA.equalsIgnoreCase(reactMessageRequest.getAction())) {
128-
return processRecentActivityGetDataRequest(analyticsService, jbCefBrowser, callback);
131+
new AsynchronousBackgroundTask(recentActivityGetDataLock,
132+
() -> processRecentActivityGetDataRequest(analyticsService, jbCefBrowser)).queue();
129133
}
130134
if (RECENT_ACTIVITY_GO_TO_SPAN.equalsIgnoreCase(reactMessageRequest.getAction())) {
131135
RecentActivityGoToSpanRequest recentActivityGoToSpanRequest = parseJsonToObject(request, RecentActivityGoToSpanRequest.class);
132-
return processRecentActivityGoToSpanRequest(recentActivityGoToSpanRequest.getPayload(), project, callback);
136+
processRecentActivityGoToSpanRequest(recentActivityGoToSpanRequest.getPayload(), project);
133137
}
134138
if (RECENT_ACTIVITY_GO_TO_TRACE.equalsIgnoreCase(reactMessageRequest.getAction())) {
135139
RecentActivityGoToTraceRequest recentActivityGoToTraceRequest = parseJsonToObject(request, RecentActivityGoToTraceRequest.class);
136-
return processRecentActivityGoToTraceRequest(recentActivityGoToTraceRequest, project, callback);
140+
processRecentActivityGoToTraceRequest(recentActivityGoToTraceRequest, project);
137141
}
138142

139143
callback.success("");
@@ -163,7 +167,7 @@ public void onQueryCanceled(CefBrowser browser, CefFrame frame, long queryId) {
163167
return jcefContent;
164168
}
165169

166-
private boolean processRecentActivityGoToSpanRequest(RecentActivityEntrySpanPayload payload, Project project, CefQueryCallback callback) {
170+
private void processRecentActivityGoToSpanRequest(RecentActivityEntrySpanPayload payload, Project project) {
167171
if (payload != null) {
168172
String methodCodeObjectId = payload.getSpan().getMethodCodeObjectId();
169173

@@ -186,46 +190,39 @@ private boolean processRecentActivityGoToSpanRequest(RecentActivityEntrySpanPayl
186190
}
187191
}
188192
});
189-
callback.success(SUCCESSFULLY_PROCESSED_JCEF_REQUEST_MESSAGE + " RECENT_ACTIVITY_GO_TO_SPAN at " + new Date());
190-
return true;
191-
} else {
192-
return false;
193193
}
194194
}
195195

196-
private boolean processRecentActivityGoToTraceRequest(RecentActivityGoToTraceRequest recentActivityGoToTraceRequest, Project project, CefQueryCallback callback) {
196+
private void processRecentActivityGoToTraceRequest(RecentActivityGoToTraceRequest recentActivityGoToTraceRequest, Project project) {
197197
RecentActivityEntrySpanForTracePayload payload = recentActivityGoToTraceRequest.getPayload();
198198
if (payload != null) {
199199
openJaegerFromRecentActivity(project, payload.getTraceId(), payload.getSpan().getScopeId());
200200
} else {
201201
Log.log(LOGGER::debug, "processRecentActivityGoToTraceRequest payload is empty");
202202
}
203-
callback.success(SUCCESSFULLY_PROCESSED_JCEF_REQUEST_MESSAGE + " RECENT_ACTIVITY_GO_TO_TRACE at " + new Date());
204-
return true;
205203
}
206204

207-
private boolean processRecentActivityGetDataRequest(AnalyticsService analyticsService, JBCefBrowser jbCefBrowser, CefQueryCallback callback) {
205+
private void processRecentActivityGetDataRequest(AnalyticsService analyticsService, JBCefBrowser jbCefBrowser) {
208206
List<String> allEnvironments = analyticsService.getEnvironments();
209207
List<String> sortedEnvironments = getSortedEnvironments(allEnvironments, localHostname);
210208
RecentActivityResult recentActivityData = null;
211209
try {
212210
recentActivityData = analyticsService.getRecentActivity(allEnvironments);
213211
} catch (AnalyticsServiceException e) {
214-
Log.log(LOGGER::debug, "AnalyticsServiceException for getRecentActivity: {}", e.getMessage());
212+
Log.log(LOGGER::warn, "AnalyticsServiceException for getRecentActivity: {}", e.getMessage());
213+
}
214+
if (recentActivityData != null) {
215+
String requestMessage = JBCefBrowserUtil.resultToString(new JcefMessageRequest(
216+
REQUEST_MESSAGE_TYPE,
217+
RECENT_ACTIVITY_SET_DATA,
218+
new JcefMessagePayload(
219+
sortedEnvironments,
220+
getEntriesWithAdjustedLocalEnvs(recentActivityData)
221+
)
222+
));
223+
224+
JBCefBrowserUtil.postJSMessage(requestMessage, jbCefBrowser);
215225
}
216-
String requestMessage = JBCefBrowserUtil.resultToString(new JcefMessageRequest(
217-
REQUEST_MESSAGE_TYPE,
218-
RECENT_ACTIVITY_SET_DATA,
219-
new JcefMessagePayload(
220-
sortedEnvironments,
221-
getEntriesWithAdjustedLocalEnvs(recentActivityData)
222-
)
223-
));
224-
225-
JBCefBrowserUtil.postJSMessage(requestMessage, jbCefBrowser);
226-
227-
callback.success(SUCCESSFULLY_PROCESSED_JCEF_REQUEST_MESSAGE + " RECENT_ACTIVITY_SET_DATA at " + new Date());
228-
return true;
229226
}
230227

231228
private List<RecentActivityResponseEntry> getEntriesWithAdjustedLocalEnvs(RecentActivityResult recentActivityData) {
@@ -244,7 +241,7 @@ private List<RecentActivityResponseEntry> getEntriesWithAdjustedLocalEnvs(Recent
244241
}
245242

246243
private String getAdjustedEnvName(String environment) {
247-
return environment.toUpperCase().endsWith(SUFFIX_OF_LOCAL) ? LOCAL_ENV: environment;
244+
return environment.toUpperCase().endsWith(SUFFIX_OF_LOCAL) ? LOCAL_ENV : environment;
248245
}
249246

250247
private String adjustBackEnvNameIfNeeded(String environment) {

src/main/java/org/digma/intellij/plugin/toolwindow/recentactivity/JcefMessagePayload.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ import org.digma.intellij.plugin.model.rest.recentactivity.RecentActivityRespons
66

77
data class JcefMessagePayload
88
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
9-
constructor(val environments: MutableList<String>, val entries: MutableList<RecentActivityResponseEntry>)
9+
constructor(val environments: List<String>, val entries: List<RecentActivityResponseEntry>)

src/main/kotlin/org/digma/intellij/plugin/ui/common/EnvironmentsDropdownPanel.kt

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import java.util.*
3232
import java.util.concurrent.atomic.AtomicBoolean
3333
import java.util.concurrent.locks.ReentrantLock
3434
import javax.swing.BoxLayout
35+
import javax.swing.DefaultComboBoxModel
3536
import javax.swing.Icon
3637
import javax.swing.JList
3738
import javax.swing.event.PopupMenuEvent
@@ -58,6 +59,7 @@ class EnvironmentsDropdownPanel(
5859
private val changeEnvAlarm: Alarm
5960
private val popupMenuOpened: AtomicBoolean = AtomicBoolean(false)
6061
private val wasNotInitializedYet: AtomicBoolean = AtomicBoolean(true)
62+
private val comboBox = ComboBox<String>()
6163

6264
init {
6365
usageStatusChangeConnection.subscribe(
@@ -81,11 +83,11 @@ class EnvironmentsDropdownPanel(
8183
//there are few instances of EnvironmentsPanel, if a button is clicked in the insights tab the selected button
8284
//need to change also in the errors tab, and vice versa.
8385
override fun environmentChanged(newEnv: String?) {
84-
EDT.ensureEDT{select(newEnv)}
86+
EDT.ensureEDT { select(newEnv) }
8587
}
8688

8789
override fun environmentsListChanged(newEnvironments: MutableList<String>?) {
88-
EDT.ensureEDT{rebuildInBackground(usageStatusResult)}
90+
EDT.ensureEDT { rebuildInBackground(usageStatusResult) }
8991
}
9092
})
9193
backendConnectionMonitor = project.getService(BackendConnectionMonitor::class.java)
@@ -198,27 +200,27 @@ class EnvironmentsDropdownPanel(
198200
environmentsInfo: MutableMap<String, MutableMap<String, Any>>,
199201
hasUsageFunction: (String) -> Boolean
200202
) {
201-
val items = mutableListOf<String>()
202-
val icons = mutableListOf<Icon>()
203+
val itemsWithIcons = mutableMapOf<String, Icon>()
203204

204205
for (envInfo in environmentsInfo) {
205206
val buttonData = envInfo.value
206207
val currEnv = envInfo.key
207208
val linkText = buttonData.getValue("linkText").toString()
208209
val icon: Icon = if (hasUsageFunction(currEnv)) Laf.Icons.Environment.ENVIRONMENT_HAS_USAGE else Laf.Icons.Environment.ENVIRONMENT_HAS_NO_USAGE
209-
items.add(linkText)
210-
icons.add(icon)
210+
itemsWithIcons[linkText] = icon
211211
}
212212

213-
val comboBox = ComboBox(items.toTypedArray())
214-
if (items.size > 0) {
213+
// initialize comboBox with items list
214+
comboBox.model = DefaultComboBoxModel(itemsWithIcons.keys.toTypedArray())
215+
216+
if (itemsWithIcons.keys.size > 0) {
215217
// this flag fixes initial load issue
216218
wasNotInitializedYet.set(false)
217219

218220
comboBox.renderer = object : SimpleListCellRenderer<String>() {
219221
override fun customize(list: JList<out String>, value: String, index: Int, selected: Boolean, hasFocus: Boolean) {
220222
text = value
221-
icon = icons.getOrElse(index) { null }
223+
icon = if (itemsWithIcons.size >= index && index >= 0) { itemsWithIcons.values.elementAt(index) } else { null }
222224
foreground = if (selected) JBColor.WHITE else JBColor.BLACK
223225
background = if (selected) JBColor.BLUE else JBColor.WHITE
224226
}
@@ -232,7 +234,7 @@ class EnvironmentsDropdownPanel(
232234
val popup = comboBox.getUI().getAccessibleChild(comboBox, 0)
233235
val popupList = (popup as? BasicComboPopup)?.list
234236
if (popupList != null) {
235-
val popupWidth = items.maxOfOrNull { comboBox.getFontMetrics(comboBox.font).stringWidth(it) } ?: 0
237+
val popupWidth = itemsWithIcons.keys.maxOfOrNull { comboBox.getFontMetrics(comboBox.font).stringWidth(it) } ?: 0
236238
comboBox.preferredSize = Dimension(popupWidth + 40, comboBox.preferredSize.height)
237239
}
238240
}
@@ -329,7 +331,8 @@ class EnvironmentsDropdownPanel(
329331
return
330332
}
331333

332-
buildLinkText(newSelectedEnv)
334+
selectedItem = buildLinkText(newSelectedEnv)
335+
comboBox.selectedItem = selectedItem
333336
}
334337

335338
private fun buildLinkText(currEnv: String): String {

src/main/kotlin/org/digma/intellij/plugin/ui/common/EnvironmentsPanel.kt

Whitespace-only changes.

0 commit comments

Comments
 (0)