Skip to content

Commit 928931d

Browse files
committed
prevent posthog errors when can't connect
1 parent 876a3dd commit 928931d

File tree

6 files changed

+118
-5
lines changed

6 files changed

+118
-5
lines changed

ide-common/src/main/java/org/digma/intellij/plugin/log/Log.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public class Log {
1818
public static final String API_LOGGER_NAME = "api.digma.org";
1919

2020

21-
private static final FrequentErrorDetector FREQUENT_ERROR_DETECTOR = new FrequentErrorDetector(Duration.ofMinutes(10));
21+
private static final FrequentErrorDetector FREQUENT_ERROR_DETECTOR = new FrequentErrorDetector(Duration.ofMinutes(30));
2222

2323

2424

ide-common/src/main/kotlin/org/digma/intellij/plugin/posthog/ActivityMonitor.kt

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package org.digma.intellij.plugin.posthog
22

33
import com.fasterxml.jackson.core.JsonProcessingException
4+
import com.intellij.collaboration.async.disposingScope
45
import com.intellij.openapi.Disposable
56
import com.intellij.openapi.application.ApplicationInfo
67
import com.intellij.openapi.components.Service
78
import com.intellij.openapi.project.Project
89
import com.intellij.ui.jcef.JBCefApp
910
import com.posthog.java.PostHog
11+
import kotlinx.coroutines.delay
12+
import kotlinx.coroutines.isActive
13+
import kotlinx.coroutines.launch
1014
import kotlinx.datetime.toJavaInstant
1115
import org.digma.intellij.plugin.analytics.BackendConnectionMonitor
1216
import org.digma.intellij.plugin.common.ExceptionUtils
@@ -32,6 +36,7 @@ import java.time.Duration
3236
import java.time.Instant
3337
import java.time.temporal.ChronoUnit
3438
import java.util.Date
39+
import kotlin.time.Duration.Companion.minutes
3540

3641
private const val INSTALL_STATUS_PROPERTY_NAME = "install_status"
3742
private const val ENVIRONMENT_ADDED_PROPERTY_NAME = "environment_added"
@@ -44,10 +49,24 @@ enum class InstallStatus { Active, Uninstalled, Disabled }
4449
class ActivityMonitor(private val project: Project) : Disposable {
4550

4651
companion object {
52+
53+
private const val TOKEN = "phc_5sy6Kuv1EYJ9GAdWPeGl7gx31RAw7BR7NHnOuLCUQZK"
54+
55+
4756
@JvmStatic
4857
fun getInstance(project: Project): ActivityMonitor {
4958
return project.getService(ActivityMonitor::class.java)
5059
}
60+
61+
62+
private fun checkAndConnect(): PostHog? {
63+
return if (PosthogConnectionTester.isConnectionToPosthogOk()) {
64+
return PostHog.Builder(TOKEN).build()
65+
} else {
66+
null
67+
}
68+
}
69+
5170
}
5271

5372

@@ -62,18 +81,55 @@ class ActivityMonitor(private val project: Project) : Disposable {
6281

6382
SessionMetadataProperties.getInstance().put(CURRENT_INSTALL_STATUS_KEY, InstallStatus.Active)
6483

65-
val token = "phc_5sy6Kuv1EYJ9GAdWPeGl7gx31RAw7BR7NHnOuLCUQZK"
66-
postHog = PostHog.Builder(token).build()
84+
postHog = checkAndConnect()
85+
6786
registerSessionDetails()
6887

6988
ServerVersionMonitor.getInstance(project)
7089
PluginActivityMonitor.getInstance(project)
7190

7291
settingsChangeTracker.start(this)
7392

93+
//why we need all that?
94+
//there are users that can't connect to posthog due to network restrictions like firewalls or company proxies.
95+
//these users complain that there are many errors in idea.log. that is because PostHog prints connection errors with
96+
//System.out/err and e.printStackTrace(), this is fault behaviour of posthog java client, and we can't change it.
97+
//posthog does not throw or notifies about connection errors,it just prints them and doesn't send the events.
98+
//So, on initialization, we try to connect with checkAndConnect(), if it fails then maybe it's one of these users,
99+
// and we'll probably never succeed. checkAndConnect() will return null and when posthog is null no events will be
100+
// sent and no errors will be logged.
101+
//but, it could be just a momentary network issue, that's why we keep trying every 5 minutes.
102+
//once we succeed connection and posthog is not null we stop trying because we have a posthog client.
103+
//don't care if there are network issues later, the only reason for all this is to identify users that
104+
// can never connect to posthog and prevent the unnecessary errors to idea.log.
105+
106+
//if posthog is not null don't even start the coroutine.
107+
//try to keep connecting to posthog every 5 minutes but give up after 1 hour, if we couldn't connect for
108+
// 1 hour it probably means we can't connect. this is meant to prevent endless trying when in fact there is
109+
// no way to connect, usually it will be the users mentioned above were connection to posthog is impossible.
110+
if (postHog == null) {
111+
val startTime = Instant.now()
112+
@Suppress("UnstableApiUsage")
113+
disposingScope().launch {
114+
//once we have a non-null posthog stop this coroutine.
115+
//give up 1 hour after startTime.
116+
while (isActive &&
117+
postHog == null &&
118+
startTime.plus(1, ChronoUnit.HOURS).isAfter(Instant.now())
119+
) {
120+
delay(5.minutes.inWholeMilliseconds)
121+
if (isActive) {
122+
postHog = checkAndConnect()
123+
}
124+
}
125+
}
126+
}
127+
74128
}
75129

76130

131+
132+
77133
override fun dispose() {
78134
//nothing to do, used as parent disposable
79135
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.digma.intellij.plugin.posthog
2+
3+
import com.intellij.openapi.project.Project
4+
import com.intellij.openapi.startup.StartupActivity
5+
6+
class ActivityMonitorStarter : StartupActivity.Background {
7+
8+
//try to start ActivityMonitor as early as possible. although if the digma tool window is opened on start it will call
9+
// ActivityMonitor on UI thread
10+
override fun runActivity(project: Project) {
11+
ActivityMonitor.getInstance(project)
12+
}
13+
14+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package org.digma.intellij.plugin.posthog
2+
3+
import com.intellij.openapi.diagnostic.Logger
4+
import com.posthog.java.shaded.okhttp3.OkHttpClient
5+
import com.posthog.java.shaded.okhttp3.Request
6+
import org.digma.intellij.plugin.log.Log
7+
import java.util.concurrent.TimeUnit
8+
9+
object PosthogConnectionTester {
10+
11+
var LOGGER: Logger = Logger.getInstance(PosthogConnectionTester::class.java)
12+
13+
//Note that this code uses the OkHttpClient class that is packaged with posthog
14+
// com.posthog.java.shaded.okhttp3.OkHttpClient
15+
fun isConnectionToPosthogOk(): Boolean {
16+
17+
return try {
18+
19+
val url = "https://app.posthog.com"
20+
21+
val client = OkHttpClient.Builder()
22+
.connectTimeout(10, TimeUnit.SECONDS)
23+
.writeTimeout(10, TimeUnit.SECONDS)
24+
.readTimeout(10, TimeUnit.SECONDS)
25+
.build()
26+
27+
val request: Request = Request.Builder()
28+
.url(url)
29+
.build()
30+
31+
client.newCall(request).execute().isSuccessful
32+
33+
} catch (e: Throwable) {
34+
Log.warnWithException(LOGGER, e, "could not connect to posthog {}", e)
35+
false
36+
}
37+
}
38+
39+
}

src/main/java/org/digma/intellij/plugin/toolwindow/DigmaSidePaneToolWindowFactory.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import com.intellij.ui.content.ContentFactory;
88
import com.intellij.util.ui.JBUI;
99
import org.digma.intellij.plugin.analytics.AnalyticsService;
10-
import org.digma.intellij.plugin.common.IDEUtilsService;
10+
import org.digma.intellij.plugin.common.*;
1111
import org.digma.intellij.plugin.log.Log;
1212
import org.digma.intellij.plugin.persistence.PersistenceService;
1313
import org.digma.intellij.plugin.posthog.ActivityMonitor;
@@ -104,7 +104,10 @@ public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindo
104104
MainToolWindowCardsController.getInstance(project).showWizard(false);
105105
}
106106
else{
107-
ActivityMonitor.getInstance(project).registerCustomEvent("skip-installation-wizard", Collections.emptyMap());
107+
//run it on background because it may be the first time ActivityMonitor.getInstance(project) and that may
108+
// cause the UI to wait for ActivityMonitor initialization
109+
Backgroundable.executeOnPooledThread(() -> ActivityMonitor.getInstance(project).registerCustomEvent("skip-installation-wizard", Collections.emptyMap()));
110+
108111
}
109112

110113
}

src/main/resources/META-INF/plugin.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@
113113
<editorNotificationProvider implementation="org.digma.intellij.plugin.editor.DigmaEditorNotificationProvider"
114114
id="org.digma.intellij.plugin.editor.DigmaEditorNotificationProvider"/>
115115

116+
<postStartupActivity implementation="org.digma.intellij.plugin.posthog.ActivityMonitorStarter"/>
116117
<postStartupActivity implementation="org.digma.intellij.plugin.common.StartupStartupActivity"/>
117118
<postStartupActivity implementation="org.digma.intellij.plugin.ui.recentactivity.RecentActivitiesStartup"/>
118119
<postStartupActivity implementation="org.digma.intellij.plugin.posthog.ContainerEngineStartupActivity"/>

0 commit comments

Comments
 (0)