From f38bc13d3987d45a872559f201075a8670e0b3ba Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Tue, 15 Mar 2022 14:43:29 +0100 Subject: [PATCH 01/42] fix view history on watch log expression --- .../sourcemarker/status/LogStatusBar.java | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/plugin/src/main/java/spp/jetbrains/sourcemarker/status/LogStatusBar.java b/plugin/src/main/java/spp/jetbrains/sourcemarker/status/LogStatusBar.java index 35cd57af9..6078d8dca 100644 --- a/plugin/src/main/java/spp/jetbrains/sourcemarker/status/LogStatusBar.java +++ b/plugin/src/main/java/spp/jetbrains/sourcemarker/status/LogStatusBar.java @@ -60,6 +60,7 @@ import java.time.Instant; import java.time.ZoneId; import java.time.format.DateTimeFormatter; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -166,6 +167,7 @@ public Icon getIcon() { configDropdownLabel.setVisible(false); displayTimeField(); addExpandButton(); + initCommandModel(); } else { LiveStatusManager.addStatusBar(inlayMark, this); showEditableMode(); @@ -187,20 +189,29 @@ public void setLiveInstrument(LiveInstrument liveInstrument) { } private void initCommandModel() { - List logData = LiveStatusManager.INSTANCE.getLogData(inlayMark); - if (logData.isEmpty()) { + if (watchExpression) { liveLogTextField.setPlaceHolderText(WAITING_FOR_LIVE_LOG_DATA); + commandModel = new ListTableModel( + new ColumnInfo[]{ + new LogHitColumnInfo(MESSAGE), + new LogHitColumnInfo(TIME) + }, new ArrayList<>(), 0, SortOrder.DESCENDING); } else { - LiveInstrumentEvent event = (LiveInstrumentEvent) logData.get(0); - LiveLogHit logHit = Json.decodeValue(event.getData(), LiveLogHit.class); - Instant logTime = ((kotlinx.datetime.Instant) logHit.getOccurredAt()).getValue$kotlinx_datetime(); - setLatestLog(logTime, logHit.getLogResult().getLogs().get(0)); + List logData = LiveStatusManager.INSTANCE.getLogData(inlayMark); + if (logData.isEmpty()) { + liveLogTextField.setPlaceHolderText(WAITING_FOR_LIVE_LOG_DATA); + } else { + LiveInstrumentEvent event = (LiveInstrumentEvent) logData.get(0); + LiveLogHit logHit = Json.decodeValue(event.getData(), LiveLogHit.class); + Instant logTime = ((kotlinx.datetime.Instant) logHit.getOccurredAt()).getValue$kotlinx_datetime(); + setLatestLog(logTime, logHit.getLogResult().getLogs().get(0)); + } + commandModel = new ListTableModel( + new ColumnInfo[]{ + new LogHitColumnInfo(MESSAGE), + new LogHitColumnInfo(TIME) + }, logData, 0, SortOrder.DESCENDING); } - commandModel = new ListTableModel( - new ColumnInfo[]{ - new LogHitColumnInfo(MESSAGE), - new LogHitColumnInfo(TIME) - }, logData, 0, SortOrder.DESCENDING); } public void setWrapperPanel(JPanel wrapperPanel) { From 1646eb56478173b24a4a062a372e9fdd733540ff Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Tue, 15 Mar 2022 14:44:11 +0100 Subject: [PATCH 02/42] lower logging --- .../kotlin/spp/jetbrains/marker/jvm/psi/EndpointDetector.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/jvm/psi/EndpointDetector.kt b/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/jvm/psi/EndpointDetector.kt index a2d0fbaf5..2af6967b7 100644 --- a/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/jvm/psi/EndpointDetector.kt +++ b/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/jvm/psi/EndpointDetector.kt @@ -105,7 +105,7 @@ class EndpointDetector(val vertx: Vertx) { log.trace("Determining endpoint name") val detectedEndpoint = determineEndpointName(sourceMark).await().orElse(null) if (detectedEndpoint != null) { - log.debug("Detected endpoint name: ${detectedEndpoint.name}") + log.trace("Detected endpoint name: ${detectedEndpoint.name}") sourceMark.putUserData(ENDPOINT_NAME, detectedEndpoint.name) sourceMark.putUserData(ENDPOINT_INTERNAL, detectedEndpoint.internal) @@ -125,9 +125,9 @@ class EndpointDetector(val vertx: Vertx) { val endpoint = EndpointBridge.searchExactEndpoint(endpointName, vertx) if (endpoint != null) { sourceMark.putUserData(ENDPOINT_ID, endpoint.id) - log.debug("Detected endpoint id: ${endpoint.id}") + log.trace("Detected endpoint id: ${endpoint.id}") } else { - log.debug("Could not find endpoint id for: $endpointName") + log.trace("Could not find endpoint id for: $endpointName") } } catch (ex: ReplyException) { if (ex.failureType() == ReplyFailure.TIMEOUT) { From c0da0b3f2ac9512fa340bad702c515cac68d63bd Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Tue, 15 Mar 2022 14:45:18 +0100 Subject: [PATCH 03/42] rename --- .../kotlin/spp/jetbrains/sourcemarker/SourceMarkerPlugin.kt | 4 ++-- ...QuickStatsInlayHints.kt => ActivityQuickStatsIndicator.kt} | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename plugin/src/main/kotlin/spp/jetbrains/sourcemarker/view/{ActivityQuickStatsInlayHints.kt => ActivityQuickStatsIndicator.kt} (98%) diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/SourceMarkerPlugin.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/SourceMarkerPlugin.kt index ffbd3aeb9..3b344f970 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/SourceMarkerPlugin.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/SourceMarkerPlugin.kt @@ -79,7 +79,7 @@ import spp.jetbrains.sourcemarker.settings.getServicePortNormalized import spp.jetbrains.sourcemarker.settings.isSsl import spp.jetbrains.sourcemarker.settings.serviceHostNormalized import spp.jetbrains.sourcemarker.status.LiveStatusManager -import spp.jetbrains.sourcemarker.view.ActivityQuickStatsInlayHints +import spp.jetbrains.sourcemarker.view.ActivityQuickStatsIndicator import spp.protocol.SourceServices import spp.protocol.SourceServices.Instance import spp.protocol.service.LiveInstrumentService @@ -448,7 +448,7 @@ object SourceMarkerPlugin { private fun initMarker(config: SourceMarkerConfig, project: Project) { log.info("Initializing marker") SourceMarker.addGlobalSourceMarkEventListener(PluginSourceMarkEventListener()) - SourceMarker.addGlobalSourceMarkEventListener(ActivityQuickStatsInlayHints()) + SourceMarker.addGlobalSourceMarkEventListener(ActivityQuickStatsIndicator()) val gutterMarkConfig = GutterMarkConfiguration() gutterMarkConfig.activateOnMouseHover = false diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/view/ActivityQuickStatsInlayHints.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/view/ActivityQuickStatsIndicator.kt similarity index 98% rename from plugin/src/main/kotlin/spp/jetbrains/sourcemarker/view/ActivityQuickStatsInlayHints.kt rename to plugin/src/main/kotlin/spp/jetbrains/sourcemarker/view/ActivityQuickStatsIndicator.kt index ada60327f..c0490dcf5 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/view/ActivityQuickStatsInlayHints.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/view/ActivityQuickStatsIndicator.kt @@ -59,10 +59,10 @@ import java.time.temporal.ChronoUnit * Adds activity quick stats as inlay marks above recognized endpoint methods. * Uses a two-minute delay to ensure metrics have been fully collected. */ -class ActivityQuickStatsInlayHints : SourceMarkEventListener { +class ActivityQuickStatsIndicator : SourceMarkEventListener { companion object { - private val log: Logger = LoggerFactory.getLogger(ActivityQuickStatsInlayHints::class.java) + private val log: Logger = LoggerFactory.getLogger(ActivityQuickStatsIndicator::class.java) private val inlayForegroundColor = JBColor(Color.decode("#3e464a"), Color.decode("#87939a")) val ACTIVITY_QUICK_STATS = SourceKey("ACTIVITY_QUICK_STATS") } From 04543b2fa80039b72200ec128949d44a6a1d292d Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Tue, 15 Mar 2022 14:45:36 +0100 Subject: [PATCH 04/42] update --- README.md | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index c7d743f93..73cc03746 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ![GitHub release](https://img.shields.io/github/v/release/sourceplusplus/interface-jetbrains?include_prereleases) [![Build](https://github.com/sourceplusplus/interface-jetbrains/actions/workflows/build.yml/badge.svg)](https://github.com/sourceplusplus/interface-jetbrains/actions/workflows/build.yml) -## What is this? +# What is this? @@ -12,9 +12,21 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com -## Features +# Live Views -### Live Views +**Live View** commands utilize existing SkyWalking metrics to bring live data of your code to your IDE. + +## Activity Quick Stats + +> Inlay hints which indicate an endpoint's current activity. + +
+ Screencast + +![screencast](https://user-images.githubusercontent.com/3278877/158376181-7fe597f9-f3c2-4609-bd07-4ea55e10b579.gif) +
+ +## View Portal > Contextual popups for displaying live operational data on the code currently in view. @@ -24,9 +36,23 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com ![screencast](https://user-images.githubusercontent.com/3278877/149158868-135568d5-20cc-44d4-886a-2202195b594b.gif) -### Live Breakpoint +## Watch Log + +> Follow specific logging statements in real-time. + +
+ Screencast + + ![screencast](https://user-images.githubusercontent.com/3278877/158381411-214285ba-7291-4c70-8e1f-8489140fa239.gif) +
+ +# Live Instruments + +**Live Instrument** commands require a [Live Probe](#) to inject additional metrics into your code for live debugging. + +## Live Breakpoint -> Live Breakpoints (a.k.a non-breaking breakpoints) are useful debugging instruments for gaining insight into the live variables available in production at a given scope. +> Live Breakpoints (a.k.a. non-breaking breakpoints) are useful debugging instruments for gaining insight into the live variables available in production at a given scope.
Screencast @@ -34,9 +60,9 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com ![live-breakpoint](https://user-images.githubusercontent.com/3278877/136304451-2c98ad30-032b-4ce0-9f37-f98cd750adb3.gif)
-### Live Log +## Live Log -> Live Logs (a.k.a just-in-time logging) are quick and easy debugging instruments for instantly outputting live data from production without redeploying or restarting your application. +> Live Logs (a.k.a. just-in-time logging) are quick and easy debugging instruments for instantly outputting live data from production without redeploying or restarting your application.
Screencast From 5f84af3f5be0f2733cafe685186979797deab214 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Tue, 15 Mar 2022 14:48:28 +0100 Subject: [PATCH 05/42] link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 73cc03746..bc147cb32 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com # Live Instruments -**Live Instrument** commands require a [Live Probe](#) to inject additional metrics into your code for live debugging. +**Live Instrument** commands require a [Live Probe](https://github.com/sourceplusplus/probe-jvm) to inject additional metrics into your code for live debugging. ## Live Breakpoint From 8158f9f0f09b285cc6d9fe6a3be0a6521c4c743d Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Tue, 15 Mar 2022 17:47:44 +0100 Subject: [PATCH 06/42] Update README.md --- README.md | 66 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index bc147cb32..018569e4a 100644 --- a/README.md +++ b/README.md @@ -16,56 +16,66 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com **Live View** commands utilize existing SkyWalking metrics to bring live data of your code to your IDE. -## Activity Quick Stats +
+

Show Commands

-> Inlay hints which indicate an endpoint's current activity. + ### Display Quick Stats -
- Screencast + > Inlay hints which indicate an endpoint's current activity. -![screencast](https://user-images.githubusercontent.com/3278877/158376181-7fe597f9-f3c2-4609-bd07-4ea55e10b579.gif) -
+
+ Screencast -## View Portal + ![screencast](https://user-images.githubusercontent.com/3278877/158376181-7fe597f9-f3c2-4609-bd07-4ea55e10b579.gif) +
-> Contextual popups for displaying live operational data on the code currently in view. + ### View Portal -
- Screencast + > Contextual popups for displaying live operational data on the code currently in view. - ![screencast](https://user-images.githubusercontent.com/3278877/149158868-135568d5-20cc-44d4-886a-2202195b594b.gif) -
+
+ Screencast -## Watch Log + ![screencast](https://user-images.githubusercontent.com/3278877/149158868-135568d5-20cc-44d4-886a-2202195b594b.gif) +
-> Follow specific logging statements in real-time. + ### Watch Log -
- Screencast + > Follow specific logging statements in real-time. + +
+ Screencast - ![screencast](https://user-images.githubusercontent.com/3278877/158381411-214285ba-7291-4c70-8e1f-8489140fa239.gif) + ![screencast](https://user-images.githubusercontent.com/3278877/158381411-214285ba-7291-4c70-8e1f-8489140fa239.gif) +
+
# Live Instruments **Live Instrument** commands require a [Live Probe](https://github.com/sourceplusplus/probe-jvm) to inject additional metrics into your code for live debugging. -## Live Breakpoint +
+

Show Commands

-> Live Breakpoints (a.k.a. non-breaking breakpoints) are useful debugging instruments for gaining insight into the live variables available in production at a given scope. + ### Add Breakpoint -
- Screencast + > Live Breakpoints (a.k.a. non-breaking breakpoints) are useful debugging instruments for gaining insight into the live variables available in production at a given scope. - ![live-breakpoint](https://user-images.githubusercontent.com/3278877/136304451-2c98ad30-032b-4ce0-9f37-f98cd750adb3.gif) -
+
+ Screencast -## Live Log + ![live-breakpoint](https://user-images.githubusercontent.com/3278877/136304451-2c98ad30-032b-4ce0-9f37-f98cd750adb3.gif) +
-> Live Logs (a.k.a. just-in-time logging) are quick and easy debugging instruments for instantly outputting live data from production without redeploying or restarting your application. + ### Add Log -
- Screencast + > Live Logs (a.k.a. just-in-time logging) are quick and easy debugging instruments for instantly outputting live data from production without redeploying or restarting your application. + +
+ Screencast + + ![live-log](https://user-images.githubusercontent.com/3278877/136304738-d46c2796-4dd3-45a3-81bb-5692547c1c71.gif) +
- ![live-log](https://user-images.githubusercontent.com/3278877/136304738-d46c2796-4dd3-45a3-81bb-5692547c1c71.gif)
From 23348e1d463eba1bf328740d136ffe23494573e3 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Tue, 15 Mar 2022 17:49:19 +0100 Subject: [PATCH 07/42] Update README.md --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 018569e4a..f68bc5a83 100644 --- a/README.md +++ b/README.md @@ -29,24 +29,24 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com ![screencast](https://user-images.githubusercontent.com/3278877/158376181-7fe597f9-f3c2-4609-bd07-4ea55e10b579.gif)
- ### View Portal + ### Watch Log - > Contextual popups for displaying live operational data on the code currently in view. + > Follow specific logging statements in real-time.
Screencast - ![screencast](https://user-images.githubusercontent.com/3278877/149158868-135568d5-20cc-44d4-886a-2202195b594b.gif) + ![screencast](https://user-images.githubusercontent.com/3278877/158381411-214285ba-7291-4c70-8e1f-8489140fa239.gif)
- ### Watch Log + ### View Portal - > Follow specific logging statements in real-time. + > Contextual popups for displaying live operational data on the code currently in view.
Screencast - ![screencast](https://user-images.githubusercontent.com/3278877/158381411-214285ba-7291-4c70-8e1f-8489140fa239.gif) + ![screencast](https://user-images.githubusercontent.com/3278877/149158868-135568d5-20cc-44d4-886a-2202195b594b.gif)
From 6568d300a216c620f58dbb248c8c08b8fcdd454d Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Tue, 15 Mar 2022 17:53:29 +0100 Subject: [PATCH 08/42] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f68bc5a83..dd674887d 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ -This project contains the JetBrains IDE plugin for [Source++](https://github.com/sourceplusplus/live-platform), the open-source live coding platform. +This project contains the JetBrains IDE plugin for [Source++](https://github.com/sourceplusplus/live-platform), the open-source live coding platform. This plugin also works for regular [SkyWalking](https://github.com/apache/skywalking) installations, but [Live Instrument](#live-instruments) commands will not be available. From 5c37977cd77121362020af5532abdfdd59d6b60c Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Tue, 15 Mar 2022 17:54:15 +0100 Subject: [PATCH 09/42] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dd674887d..c9a38eafa 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ -This project contains the JetBrains IDE plugin for [Source++](https://github.com/sourceplusplus/live-platform), the open-source live coding platform. This plugin also works for regular [SkyWalking](https://github.com/apache/skywalking) installations, but [Live Instrument](#live-instruments) commands will not be available. +This project contains the JetBrains IDE plugin for [Source++](https://github.com/sourceplusplus/live-platform), the open-source live coding platform. This plugin also works for regular [SkyWalking](https://github.com/apache/skywalking) installations, but only [Live View](#live-view) commands will be available. From c4a8f1b90e9d14abf47a9f6931af29759d4bc20e Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Tue, 15 Mar 2022 17:54:30 +0100 Subject: [PATCH 10/42] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c9a38eafa..daa406304 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ -This project contains the JetBrains IDE plugin for [Source++](https://github.com/sourceplusplus/live-platform), the open-source live coding platform. This plugin also works for regular [SkyWalking](https://github.com/apache/skywalking) installations, but only [Live View](#live-view) commands will be available. +This project contains the JetBrains IDE plugin for [Source++](https://github.com/sourceplusplus/live-platform), the open-source live coding platform. This plugin also works with regular [SkyWalking](https://github.com/apache/skywalking) installations, but only [Live View](#live-view) commands will be available. From a97d92447dc44d91fc539e86ddffaab600d90ba9 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Tue, 15 Mar 2022 17:55:12 +0100 Subject: [PATCH 11/42] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index daa406304..f13cdadc0 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com # Live Instruments -**Live Instrument** commands require a [Live Probe](https://github.com/sourceplusplus/probe-jvm) to inject additional metrics into your code for live debugging. +**Live Instrument** commands require a [Live Probe](https://github.com/sourceplusplus/probe-jvm) to inject additional metrics for live production debugging.

Show Commands

From 8c04cfc298be40ecc9839047ea5b3d56929578f6 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Tue, 15 Mar 2022 17:57:18 +0100 Subject: [PATCH 12/42] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f13cdadc0..1e505b7ac 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com # Live Views -**Live View** commands utilize existing SkyWalking metrics to bring live data of your code to your IDE. +**Live View** commands utilize existing SkyWalking metrics to display live production data directly inside of your IDE.

Show Commands

From b44993ae96fc70ffb5aaa1b246d314630b91f871 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Tue, 15 Mar 2022 17:59:45 +0100 Subject: [PATCH 13/42] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1e505b7ac..8e5a3b984 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com **Live View** commands utilize existing SkyWalking metrics to display live production data directly inside of your IDE.
-

Show Commands

+

Show Commands

  👈 (click to expand)
### Display Quick Stats @@ -56,7 +56,7 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com **Live Instrument** commands require a [Live Probe](https://github.com/sourceplusplus/probe-jvm) to inject additional metrics for live production debugging.
-

Show Commands

+

Show Commands

  👈 (click to expand)
### Add Breakpoint From 5e92668cba7136597a75d9d6dbdb6378a1b3b4d5 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Tue, 15 Mar 2022 18:01:47 +0100 Subject: [PATCH 14/42] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8e5a3b984..72380e8d0 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com
Screencast - ![screencast](https://user-images.githubusercontent.com/3278877/158381411-214285ba-7291-4c70-8e1f-8489140fa239.gif) + ![screencast](https://user-images.githubusercontent.com/3278877/158381411-214285ba-7291-4c70-8e1f-8489140fa239.gif)
### View Portal @@ -46,7 +46,7 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com
Screencast - ![screencast](https://user-images.githubusercontent.com/3278877/149158868-135568d5-20cc-44d4-886a-2202195b594b.gif) + ![screencast](https://user-images.githubusercontent.com/3278877/149158868-135568d5-20cc-44d4-886a-2202195b594b.gif)
@@ -65,7 +65,7 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com
Screencast - ![live-breakpoint](https://user-images.githubusercontent.com/3278877/136304451-2c98ad30-032b-4ce0-9f37-f98cd750adb3.gif) + ![live-breakpoint](https://user-images.githubusercontent.com/3278877/136304451-2c98ad30-032b-4ce0-9f37-f98cd750adb3.gif)
### Add Log @@ -75,7 +75,7 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com
Screencast - ![live-log](https://user-images.githubusercontent.com/3278877/136304738-d46c2796-4dd3-45a3-81bb-5692547c1c71.gif) + ![live-log](https://user-images.githubusercontent.com/3278877/136304738-d46c2796-4dd3-45a3-81bb-5692547c1c71.gif)
From d9cab78763db33069f0893984d2cf478333780ba Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Tue, 15 Mar 2022 18:11:35 +0100 Subject: [PATCH 15/42] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 72380e8d0..f1ac9a101 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com **Live View** commands utilize existing SkyWalking metrics to display live production data directly inside of your IDE.
-

Show Commands

  👈 (click to expand)
+ Show Commands   👈   (click to expand) ### Display Quick Stats @@ -56,7 +56,7 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com **Live Instrument** commands require a [Live Probe](https://github.com/sourceplusplus/probe-jvm) to inject additional metrics for live production debugging.
-

Show Commands

  👈 (click to expand)
+ Show Commands   👈   (click to expand) ### Add Breakpoint From 458ed6257ed88faa22d6fd6b74be017c34d81803 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Tue, 15 Mar 2022 18:13:30 +0100 Subject: [PATCH 16/42] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f1ac9a101..e82217355 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com
Show Commands   👈   (click to expand) - ### Display Quick Stats + ### Show/Hide Quick Stats > Inlay hints which indicate an endpoint's current activity. @@ -39,7 +39,7 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com ![screencast](https://user-images.githubusercontent.com/3278877/158381411-214285ba-7291-4c70-8e1f-8489140fa239.gif)
- ### View Portal + ### Display Portal > Contextual popups for displaying live operational data on the code currently in view. From 4c0c1ad98fbd5e0454a570965c9e2ab70a6c9c3f Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Tue, 15 Mar 2022 18:16:49 +0100 Subject: [PATCH 17/42] Update README.md --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e82217355..e19fb5b62 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,13 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com -# Live Views +# How to use? + +Todo + +# Commands + +## Live Views **Live View** commands utilize existing SkyWalking metrics to display live production data directly inside of your IDE. @@ -51,7 +57,7 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com
-# Live Instruments +## Live Instruments **Live Instrument** commands require a [Live Probe](https://github.com/sourceplusplus/probe-jvm) to inject additional metrics for live production debugging. From af6676d8a49a43873a62190a4e5fd7341f3d6f9a Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Tue, 15 Mar 2022 18:21:58 +0100 Subject: [PATCH 18/42] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e19fb5b62..86d7875a5 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com Todo -# Commands +# Available Commands ## Live Views From 33235aee0c4d902e1419d7db2c48876a0ac3b315 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Tue, 15 Mar 2022 19:55:42 +0100 Subject: [PATCH 19/42] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 86d7875a5..e4625fb8b 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,8 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com # How to use? -Todo +Once installed, this plugin adds a command bar to the JetBrains IDE, which is accessible by pressing `Ctrl+Alt+S`. +The commands available are determined by the location the command bar is opened and the accessibility of either [SkyWalking](https://github.com/apache/skywalking) or the [Live Platform](https://github.com/sourceplusplus/live-platform). # Available Commands From 87e5f9a807c72a034d5ee1ddab30244069699613 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Wed, 16 Mar 2022 09:44:05 +0100 Subject: [PATCH 20/42] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e4625fb8b..4c493b3ee 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ This project contains the JetBrains IDE plugin for [Source++](https://github.com # How to use? -Once installed, this plugin adds a command bar to the JetBrains IDE, which is accessible by pressing `Ctrl+Alt+S`. +Once installed, this plugin adds a command bar to the JetBrains IDE, which is accessible by pressing `Ctrl+Shift+S`. The commands available are determined by the location the command bar is opened and the accessibility of either [SkyWalking](https://github.com/apache/skywalking) or the [Live Platform](https://github.com/sourceplusplus/live-platform). # Available Commands From 48387821df80c38d035c9c2f57689055f7d8fc1e Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Thu, 17 Mar 2022 19:37:34 +0100 Subject: [PATCH 21/42] trigger event --- .../spp/jetbrains/marker/source/mark/api/ClassSourceMark.kt | 1 + .../spp/jetbrains/marker/source/mark/api/ExpressionSourceMark.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/marker/src/main/kotlin/spp/jetbrains/marker/source/mark/api/ClassSourceMark.kt b/marker/src/main/kotlin/spp/jetbrains/marker/source/mark/api/ClassSourceMark.kt index 7db179999..0e60ae834 100644 --- a/marker/src/main/kotlin/spp/jetbrains/marker/source/mark/api/ClassSourceMark.kt +++ b/marker/src/main/kotlin/spp/jetbrains/marker/source/mark/api/ClassSourceMark.kt @@ -107,6 +107,7 @@ abstract class ClassSourceMark( } else { userData.remove(key) } + triggerEvent(SourceMarkEvent(this, SourceMarkEventCode.MARK_USER_DATA_UPDATED, key, value)) } override fun hasUserData(): Boolean = userData.isNotEmpty() diff --git a/marker/src/main/kotlin/spp/jetbrains/marker/source/mark/api/ExpressionSourceMark.kt b/marker/src/main/kotlin/spp/jetbrains/marker/source/mark/api/ExpressionSourceMark.kt index 53dd4a98e..5aa39f836 100644 --- a/marker/src/main/kotlin/spp/jetbrains/marker/source/mark/api/ExpressionSourceMark.kt +++ b/marker/src/main/kotlin/spp/jetbrains/marker/source/mark/api/ExpressionSourceMark.kt @@ -116,6 +116,7 @@ abstract class ExpressionSourceMark( } else { userData.remove(key) } + triggerEvent(SourceMarkEvent(this, SourceMarkEventCode.MARK_USER_DATA_UPDATED, key, value)) } override fun hasUserData(): Boolean = userData.isNotEmpty() From 03c0e03858156f01e1a4700384a8c3efbe193d93 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Thu, 17 Mar 2022 19:37:57 +0100 Subject: [PATCH 22/42] convenience method --- .../spp/jetbrains/marker/source/mark/api/SourceMark.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/marker/src/main/kotlin/spp/jetbrains/marker/source/mark/api/SourceMark.kt b/marker/src/main/kotlin/spp/jetbrains/marker/source/mark/api/SourceMark.kt index f4c062216..3e0223798 100755 --- a/marker/src/main/kotlin/spp/jetbrains/marker/source/mark/api/SourceMark.kt +++ b/marker/src/main/kotlin/spp/jetbrains/marker/source/mark/api/SourceMark.kt @@ -47,10 +47,7 @@ import spp.jetbrains.marker.plugin.SourceInlayHintProvider import spp.jetbrains.marker.source.SourceFileMarker import spp.jetbrains.marker.source.mark.api.component.api.SourceMarkComponent import spp.jetbrains.marker.source.mark.api.config.SourceMarkConfiguration -import spp.jetbrains.marker.source.mark.api.event.SourceMarkEvent -import spp.jetbrains.marker.source.mark.api.event.SourceMarkEventCode -import spp.jetbrains.marker.source.mark.api.event.SourceMarkEventListener -import spp.jetbrains.marker.source.mark.api.event.SynchronousSourceMarkEventListener +import spp.jetbrains.marker.source.mark.api.event.* import spp.jetbrains.marker.source.mark.api.key.SourceKey import spp.jetbrains.marker.source.mark.gutter.GutterMark import spp.jetbrains.marker.source.mark.gutter.event.GutterMarkEventCode @@ -242,6 +239,11 @@ interface SourceMark : JBPopupListener, MouseMotionListener, VisibleAreaListener fun clearEventListeners() fun getEventListeners(): List fun addEventListener(listener: SourceMarkEventListener) + + fun triggerEvent(eventCode: IEventCode, params: List, listen: (() -> Unit)? = null) { + triggerEvent(SourceMarkEvent(this, eventCode, *params.toTypedArray()), listen) + } + fun triggerEvent(event: SourceMarkEvent, listen: (() -> Unit)? = null) { //sync listeners getEventListeners() From f1331999890d87cc8c2615fbdc28c9715752053f Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Thu, 17 Mar 2022 19:38:57 +0100 Subject: [PATCH 23/42] createMethodGutterMark --- .../marker/jvm/JVMArtifactCreationService.kt | 8 +++++ .../jetbrains/marker/source/JVMMarkerUtils.kt | 33 ++++++++++++++++++- .../py/PythonArtifactCreationService.kt | 8 +++++ .../marker/ArtifactCreationService.kt | 6 ++++ 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/jvm/JVMArtifactCreationService.kt b/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/jvm/JVMArtifactCreationService.kt index 7dc6148db..ed6e4d4f8 100644 --- a/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/jvm/JVMArtifactCreationService.kt +++ b/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/jvm/JVMArtifactCreationService.kt @@ -119,6 +119,14 @@ class JVMArtifactCreationService : ArtifactCreationService { } } + override fun createMethodGutterMark( + fileMarker: SourceFileMarker, + element: PsiElement, + autoApply: Boolean + ): MethodGutterMark { + return JVMMarkerUtils.createMethodGutterMark(fileMarker, element, autoApply) + } + override fun createMethodInlayMark( fileMarker: SourceFileMarker, element: PsiElement, diff --git a/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/source/JVMMarkerUtils.kt b/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/source/JVMMarkerUtils.kt index c270d2c78..decc810fd 100755 --- a/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/source/JVMMarkerUtils.kt +++ b/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/source/JVMMarkerUtils.kt @@ -29,6 +29,7 @@ import spp.jetbrains.marker.source.mark.api.SourceMark import spp.jetbrains.marker.source.mark.api.key.SourceKey import spp.jetbrains.marker.source.mark.gutter.ClassGutterMark import spp.jetbrains.marker.source.mark.gutter.ExpressionGutterMark +import spp.jetbrains.marker.source.mark.gutter.MethodGutterMark import spp.jetbrains.marker.source.mark.inlay.ExpressionInlayMark import spp.jetbrains.marker.source.mark.inlay.MethodInlayMark import spp.protocol.artifact.ArtifactQualifiedName @@ -309,6 +310,37 @@ object JVMMarkerUtils { return statementExpression } + /** + * todo: description. + * + * @since 0.4.2 + */ + @JvmStatic + @JvmOverloads + @Synchronized + fun createMethodGutterMark( + fileMarker: SourceFileMarker, + element: PsiElement, + autoApply: Boolean = false + ): MethodGutterMark { + log.trace("createMethodGutterMark: $element") + val gutterMark = fileMarker.createMethodSourceMark( + element.parent as PsiNameIdentifierOwner, + getFullyQualifiedName(element.parent.toUElement() as UMethod), + SourceMark.Type.GUTTER + ) as MethodGutterMark + return if (autoApply) { + if (gutterMark.canApply()) { + gutterMark.apply(true) + gutterMark + } else { + throw IllegalStateException("Could not apply gutter mark: $gutterMark") + } + } else { + gutterMark + } + } + /** * todo: description. * @@ -340,7 +372,6 @@ object JVMMarkerUtils { } } - /** * todo: description. * diff --git a/marker/py-marker/src/main/kotlin/spp/jetbrains/marker/py/PythonArtifactCreationService.kt b/marker/py-marker/src/main/kotlin/spp/jetbrains/marker/py/PythonArtifactCreationService.kt index c3f519a12..b1906d11b 100644 --- a/marker/py-marker/src/main/kotlin/spp/jetbrains/marker/py/PythonArtifactCreationService.kt +++ b/marker/py-marker/src/main/kotlin/spp/jetbrains/marker/py/PythonArtifactCreationService.kt @@ -115,6 +115,14 @@ class PythonArtifactCreationService : ArtifactCreationService { return Optional.empty() } + override fun createMethodGutterMark( + fileMarker: SourceFileMarker, + element: PsiElement, + autoApply: Boolean + ): MethodGutterMark { + TODO("Not yet implemented") + } + override fun createMethodInlayMark( fileMarker: SourceFileMarker, element: PsiElement, diff --git a/marker/src/main/kotlin/spp/jetbrains/marker/ArtifactCreationService.kt b/marker/src/main/kotlin/spp/jetbrains/marker/ArtifactCreationService.kt index c2cad94ce..4bc369ee2 100644 --- a/marker/src/main/kotlin/spp/jetbrains/marker/ArtifactCreationService.kt +++ b/marker/src/main/kotlin/spp/jetbrains/marker/ArtifactCreationService.kt @@ -51,6 +51,12 @@ interface ArtifactCreationService { autoApply: Boolean = false ): Optional + fun createMethodGutterMark( + fileMarker: SourceFileMarker, + element: PsiElement, + autoApply: Boolean = false + ): MethodGutterMark + fun createMethodInlayMark( fileMarker: SourceFileMarker, element: PsiElement, From dee50c03357a8cf76aed3d0a856ababfeddc2ee0 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Fri, 18 Mar 2022 17:48:14 +0100 Subject: [PATCH 24/42] default --- .../spp/jetbrains/monitor/skywalking/bridge/LogsBridge.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monitor/src/main/kotlin/spp/jetbrains/monitor/skywalking/bridge/LogsBridge.kt b/monitor/src/main/kotlin/spp/jetbrains/monitor/skywalking/bridge/LogsBridge.kt index 30a47af17..666a6c5eb 100644 --- a/monitor/src/main/kotlin/spp/jetbrains/monitor/skywalking/bridge/LogsBridge.kt +++ b/monitor/src/main/kotlin/spp/jetbrains/monitor/skywalking/bridge/LogsBridge.kt @@ -127,7 +127,7 @@ class LogsBridge(private val skywalkingClient: SkywalkingClient) : CoroutineVert val serviceId: String? = null, val endpointId: String? = null, val zonedDuration: ZonedDuration, - val orderType: LogOrderType, + val orderType: LogOrderType = LogOrderType.NEWEST_LOGS, val pageNumber: Int = 1, val pageSize: Int = 10 ) From d05af32135869e5a2915662bd37424283eeeb742 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Fri, 18 Mar 2022 17:51:34 +0100 Subject: [PATCH 25/42] lazy changelog --- plugin/build.gradle.kts | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index 94e407c81..11fbeb18d 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -115,12 +115,14 @@ tasks { ) // Get the latest available change notes from the changelog file - val changelog = URL("https://raw.githubusercontent.com/sourceplusplus/live-platform/master/CHANGELOG.md") - .readText() - .substringAfter("### [JetBrains Plugin](https://github.com/sourceplusplus/interface-jetbrains)\n") - .substringBefore("\n### ").substringBefore("\n## ") - .trim() - changeNotes.set(markdownToHTML(changelog)) + changeNotes.set(project.provider { + val changelog = URL("https://raw.githubusercontent.com/sourceplusplus/live-platform/master/CHANGELOG.md") + .readText() + .substringAfter("### [JetBrains Plugin](https://github.com/sourceplusplus/interface-jetbrains)\n") + .substringBefore("\n### ").substringBefore("\n## ") + .trim() + markdownToHTML(changelog) + }) } publishPlugin { @@ -134,12 +136,14 @@ tasks { tasks { register("getPluginChangelog") { - val changelog = URL("https://raw.githubusercontent.com/sourceplusplus/live-platform/master/CHANGELOG.md") - .readText() - .substringAfter("### [JetBrains Plugin](https://github.com/sourceplusplus/interface-jetbrains)\n") - .substringBefore("\n### ").substringBefore("\n## ") - .trim() - println(changelog) + doFirst { + val changelog = URL("https://raw.githubusercontent.com/sourceplusplus/live-platform/master/CHANGELOG.md") + .readText() + .substringAfter("### [JetBrains Plugin](https://github.com/sourceplusplus/interface-jetbrains)\n") + .substringBefore("\n### ").substringBefore("\n## ") + .trim() + println(changelog) + } } test { From 1c7cf7fc8fe7f8e383a52efe075ec05dba7e28b1 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Fri, 18 Mar 2022 17:54:55 +0100 Subject: [PATCH 26/42] move method --- .../command/ControlBarController.kt | 26 +---------------- .../sourcemarker/mark/SourceMarkSearch.kt | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/ControlBarController.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/ControlBarController.kt index a2f9ad5db..56b5c7dd0 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/ControlBarController.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/ControlBarController.kt @@ -205,35 +205,11 @@ object ControlBarController { } private fun handleViewPortalCommand(editor: Editor, command: LiveControlCommand) { - var classSourceMark: ClassSourceMark? = null - val sourceMark = previousControlBar!!.sourceFileMarker.getSourceMarks().find { - if (it is ClassSourceMark) { - classSourceMark = it //todo: probably doesn't handle inner classes well - false - } else if (it is MethodSourceMark) { - if (it.configuration.activateOnKeyboardShortcut) { - //+1 on end offset so match is made even right after method end - val incTextRange = TextRange( - it.getPsiMethod().textRange.startOffset, - it.getPsiMethod().textRange.endOffset + 1 - ) - incTextRange.contains(editor.logicalPositionToOffset(editor.caretModel.logicalPosition)) - } else { - false - } - } else { - false - } - } - + val sourceMark = SourceMarkSearch.getClosestSourceMark(previousControlBar!!.sourceFileMarker, editor) if (sourceMark != null) { sourceMark.triggerEvent(SourceMarkEvent(sourceMark, UPDATE_PORTAL_CONFIG, command)) { sourceMark.triggerEvent(SourceMarkEvent(sourceMark, PORTAL_OPENING)) } - } else if (classSourceMark != null) { - classSourceMark!!.triggerEvent(SourceMarkEvent(classSourceMark!!, UPDATE_PORTAL_CONFIG, command)) { - classSourceMark!!.triggerEvent(SourceMarkEvent(classSourceMark!!, PORTAL_OPENING)) - } } else { log.warn("No source mark found for command: {}", command) } diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/mark/SourceMarkSearch.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/mark/SourceMarkSearch.kt index 0de3b2a37..b3ebd0951 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/mark/SourceMarkSearch.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/mark/SourceMarkSearch.kt @@ -17,7 +17,11 @@ */ package spp.jetbrains.sourcemarker.mark +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.util.TextRange import spp.jetbrains.marker.SourceMarker +import spp.jetbrains.marker.source.SourceFileMarker +import spp.jetbrains.marker.source.mark.api.ClassSourceMark import spp.jetbrains.marker.source.mark.api.ExpressionSourceMark import spp.jetbrains.marker.source.mark.api.MethodSourceMark import spp.jetbrains.marker.source.mark.api.SourceMark @@ -32,6 +36,30 @@ import spp.protocol.artifact.ArtifactType */ object SourceMarkSearch { + fun getClosestSourceMark(sourceFileMarker: SourceFileMarker, editor: Editor): SourceMark? { + var classSourceMark: ClassSourceMark? = null + val sourceMark = sourceFileMarker.getSourceMarks().find { + if (it is ClassSourceMark) { + classSourceMark = it //todo: probably doesn't handle inner classes well + false + } else if (it is MethodSourceMark) { + if (it.configuration.activateOnKeyboardShortcut) { + //+1 on end offset so match is made even right after method end + val incTextRange = TextRange( + it.getPsiMethod().textRange.startOffset, + it.getPsiMethod().textRange.endOffset + 1 + ) + incTextRange.contains(editor.logicalPositionToOffset(editor.caretModel.logicalPosition)) + } else { + false + } + } else { + false + } + } + return sourceMark ?: classSourceMark + } + fun findByEndpointName(endpointName: String): SourceMark? { return SourceMarker.getSourceMarks().firstOrNull { it.getUserData(SourceMarkKeys.ENDPOINT_DETECTOR)?.getEndpointName(it) == endpointName From 318dfeb470d27f55b8c9b02ae6b40953bc48a4e3 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Fri, 18 Mar 2022 19:02:00 +0100 Subject: [PATCH 27/42] impl SWLiveViewService --- .../monitor/skywalking/SkywalkingMonitor.kt | 9 +- .../skywalking/service/SWLiveViewService.kt | 277 ++++++++++++++++ .../sourcemarker/SourceMarkerPlugin.kt | 10 +- .../command/ControlBarController.kt | 2 +- .../portal/PortalEventListener.kt | 305 +++++++++--------- 5 files changed, 445 insertions(+), 158 deletions(-) create mode 100644 monitor/src/main/kotlin/spp/jetbrains/monitor/skywalking/service/SWLiveViewService.kt diff --git a/monitor/src/main/kotlin/spp/jetbrains/monitor/skywalking/SkywalkingMonitor.kt b/monitor/src/main/kotlin/spp/jetbrains/monitor/skywalking/SkywalkingMonitor.kt index 52332b78c..816300922 100644 --- a/monitor/src/main/kotlin/spp/jetbrains/monitor/skywalking/SkywalkingMonitor.kt +++ b/monitor/src/main/kotlin/spp/jetbrains/monitor/skywalking/SkywalkingMonitor.kt @@ -28,6 +28,7 @@ import okhttp3.OkHttpClient import org.slf4j.LoggerFactory import spp.jetbrains.monitor.skywalking.bridge.* import spp.jetbrains.monitor.skywalking.service.SWLiveService +import spp.jetbrains.monitor.skywalking.service.SWLiveViewService import spp.protocol.SourceServices import java.security.SecureRandom import java.security.cert.X509Certificate @@ -46,7 +47,8 @@ class SkywalkingMonitor( private val jwtToken: String? = null, private val certificatePins: List = emptyList(), private val verifyHost: Boolean, - private val currentService: String? = null + private val currentService: String? = null, + private val developerId: String = "system" ) : CoroutineVerticle() { companion object { @@ -121,6 +123,11 @@ class SkywalkingMonitor( vertx.deployVerticle(swLiveService).await() SourceServices.Instance.liveService = swLiveService } + if (SourceServices.Instance.liveView == null) { + val swLiveViewService = SWLiveViewService(developerId) + vertx.deployVerticle(swLiveViewService).await() + SourceServices.Instance.liveView = swLiveViewService + } } } } diff --git a/monitor/src/main/kotlin/spp/jetbrains/monitor/skywalking/service/SWLiveViewService.kt b/monitor/src/main/kotlin/spp/jetbrains/monitor/skywalking/service/SWLiveViewService.kt new file mode 100644 index 000000000..ffe01b6c4 --- /dev/null +++ b/monitor/src/main/kotlin/spp/jetbrains/monitor/skywalking/service/SWLiveViewService.kt @@ -0,0 +1,277 @@ +/* + * Source++, the open-source live coding platform. + * Copyright (C) 2022 CodeBrig, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package spp.jetbrains.monitor.skywalking.service + +import io.vertx.core.Future +import io.vertx.core.eventbus.ReplyException +import io.vertx.core.json.JsonArray +import io.vertx.core.json.JsonObject +import io.vertx.kotlin.coroutines.CoroutineVerticle +import io.vertx.kotlin.coroutines.dispatcher +import kotlinx.coroutines.launch +import kotlinx.datetime.toJavaInstant +import org.slf4j.LoggerFactory +import spp.jetbrains.monitor.skywalking.SkywalkingClient +import spp.jetbrains.monitor.skywalking.bridge.EndpointMetricsBridge +import spp.jetbrains.monitor.skywalking.bridge.EndpointTracesBridge +import spp.jetbrains.monitor.skywalking.bridge.LogsBridge +import spp.jetbrains.monitor.skywalking.bridge.ServiceBridge +import spp.jetbrains.monitor.skywalking.model.GetEndpointMetrics +import spp.jetbrains.monitor.skywalking.model.GetEndpointTraces +import spp.jetbrains.monitor.skywalking.model.ZonedDuration +import spp.protocol.SourceServices.Provide.toLiveViewSubscriberAddress +import spp.protocol.artifact.metrics.MetricType +import spp.protocol.artifact.metrics.MetricType.ServiceLevelAgreement_Average +import spp.protocol.platform.general.Service +import spp.protocol.service.LiveViewService +import spp.protocol.view.LiveViewEvent +import spp.protocol.view.LiveViewSubscription +import java.time.ZoneOffset +import java.time.ZonedDateTime +import java.time.format.DateTimeFormatterBuilder +import java.time.temporal.ChronoUnit +import java.util.* +import java.util.concurrent.ConcurrentHashMap + +/** + * Emulates a subscription-based [LiveViewService] for SkyWalking-standalone installations. + */ +class SWLiveViewService(private val developerId: String) : CoroutineVerticle(), LiveViewService { + + companion object { + private val formatter = DateTimeFormatterBuilder() + .appendPattern("yyyyMMddHHmm") + .toFormatter() + .withZone(ZoneOffset.UTC) + private val log = LoggerFactory.getLogger(SWLiveViewService::class.java) + } + + data class SWLiveViewSubscription( + val subscription: LiveViewSubscription, + val lastMetricsByTimeBucket: ConcurrentHashMap = ConcurrentHashMap() + ) + + private val subscriptionMap = ConcurrentHashMap() + private var currentService: Service? = null + + override suspend fun start() { + vertx.setPeriodic(5_000) { + subscriptionMap.forEach { (_, subscription) -> + launch(vertx.dispatcher()) { + when (subscription.subscription.liveViewConfig.viewName) { + "ACTIVITY" -> sendActivitySubscriptionUpdate(subscription) + "LOGS" -> pullLatestLogs(subscription) + "TRACES" -> sendTracesSubscriptionUpdate(subscription) + else -> TODO("not implemented") + } + } + } + } + + currentService = ServiceBridge.getCurrentService(vertx) + ServiceBridge.currentServiceConsumer(vertx).handler { + currentService = it.body() + } + } + + private suspend fun sendTracesSubscriptionUpdate(swSubscription: SWLiveViewSubscription) { + val subscription = swSubscription.subscription + val endpointId = subscription.artifactQualifiedName.operationName!! //todo: PortalEventListener sets temp + val traceResult = EndpointTracesBridge.getTraces( + GetEndpointTraces( + artifactQualifiedName = subscription.artifactQualifiedName, + endpointId = endpointId, + serviceId = currentService?.id, + zonedDuration = ZonedDuration( + ZonedDateTime.now().minusSeconds(30), + ZonedDateTime.now().plusSeconds(30), + SkywalkingClient.DurationStep.SECOND + ) + ), vertx + ) + + traceResult.traces.forEach { trace -> + val eventData = JsonObject() + .put("type", "TRACES") + .put("multiMetrics", false) + .put("artifactQualifiedName", JsonObject.mapFrom(subscription.artifactQualifiedName)) + .put("entityId", endpointId) + .put("timeBucket", formatter.format(trace.start.toJavaInstant())) + .put("trace", JsonObject.mapFrom(trace)) + val event = LiveViewEvent( + subscription.subscriptionId!!, + endpointId, + subscription.artifactQualifiedName, + formatter.format(trace.start.toJavaInstant()), + subscription.liveViewConfig, + eventData.toString() + ) + vertx.eventBus().publish(toLiveViewSubscriberAddress(developerId), JsonObject.mapFrom(event)) + vertx.eventBus().send(toLiveViewSubscriberAddress(subscription.subscriptionId!!), JsonObject.mapFrom(event)) + } + } + + private suspend fun pullLatestLogs(swSubscription: SWLiveViewSubscription) { + val subscription = swSubscription.subscription + val logsResult = LogsBridge.queryLogs( + LogsBridge.GetEndpointLogs( + serviceId = currentService?.id, + zonedDuration = ZonedDuration( + ZonedDateTime.now().minusSeconds(30), + ZonedDateTime.now().plusSeconds(30), + SkywalkingClient.DurationStep.SECOND + ) + ), vertx + ) + if (logsResult.succeeded()) { + //todo: impl log filtering in skywalking + //todo: send logs in batch + logsResult.result().logs.asReversed().forEach { + if (it.content == subscription.entityIds.first()) { + val viewEvent = LiveViewEvent( + subscription.subscriptionId!!, + "entityId", + subscription.artifactQualifiedName, + formatter.format(it.timestamp.toJavaInstant()), + subscription.liveViewConfig, + JsonObject().put("log", JsonObject.mapFrom(it)).toString() + ) + vertx.eventBus().publish(toLiveViewSubscriberAddress(developerId), JsonObject.mapFrom(viewEvent)) + vertx.eventBus() + .send(toLiveViewSubscriberAddress(subscription.subscriptionId!!), JsonObject.mapFrom(viewEvent)) + } + } + } else { + val replyException = logsResult.cause() as ReplyException + if (replyException.failureCode() == 404) { + log.warn("Failed to fetch logs. Service(s) unavailable") + } else { + log.error("Failed to fetch logs", logsResult.cause()) + } + } + } + + private suspend fun sendActivitySubscriptionUpdate(swSubscription: SWLiveViewSubscription) { + val subscription = swSubscription.subscription + val endpointId = subscription.artifactQualifiedName.operationName!! //todo: PortalEventListener & ActivityQuickStatsIndicator sets temp + val lastMetricsByTimeBucket = swSubscription.lastMetricsByTimeBucket + val endTime = ZonedDateTime.now().plusMinutes(1).truncatedTo(ChronoUnit.MINUTES) //exclusive + val startTime = endTime.minusMinutes(3) + val metricsRequest = GetEndpointMetrics( + subscription.liveViewConfig.viewMetrics, + endpointId, //subscription.entityIds.first(), + ZonedDuration(startTime, endTime, SkywalkingClient.DurationStep.MINUTE) + ) + + val metrics = EndpointMetricsBridge.getMetrics(metricsRequest, vertx) + var i = 0 + var timeBucket = startTime + while (timeBucket.isBefore(endTime)) { + val values = metrics.map { it.values[i] } + if (values.size > 1) { + val jsonArray = JsonArray() + subscription.liveViewConfig.viewMetrics.forEachIndexed { x, metricName -> + val metric = toMetric(subscription, metricName, timeBucket, values[x].value) + jsonArray.add(metric) + } + + if (lastMetricsByTimeBucket[timeBucket.toEpochSecond()] != jsonArray) { + sendActivitySubscriptionUpdate(subscription, timeBucket, jsonArray) + lastMetricsByTimeBucket[timeBucket.toEpochSecond()] = jsonArray + } + } else { + val metricName = subscription.liveViewConfig.viewMetrics.first() + val metric = toMetric(subscription, metricName, timeBucket, values.first().value) + if (lastMetricsByTimeBucket[timeBucket.toEpochSecond()] != JsonArray().add(metric)) { + sendActivitySubscriptionUpdate(subscription, timeBucket, metric) + lastMetricsByTimeBucket[timeBucket.toEpochSecond()] = JsonArray().add(metric) + } + } + + i++ + timeBucket = timeBucket.plusMinutes(1) + } + } + + private fun toMetric( + subscription: LiveViewSubscription, + metricName: String, + timeBucket: ZonedDateTime, + value: Any + ): JsonObject { + return JsonObject() + .put("entityId", subscription.artifactQualifiedName.operationName) //todo: PortalEventListener sets temp + .put("entityName", subscription.entityIds.first()) + .put("serviceId", "todo") + .put("value", value) + .put("total", value) + .apply { + if (MetricType.realValueOf(metricName) == ServiceLevelAgreement_Average) { + put("percentage", value) + } + } + .put("timeBucket", formatter.format(timeBucket)) + .put("lastUpdateTimestamp", 0) + .put("id", "todo") + .put("artifactQualifiedName", JsonObject.mapFrom(subscription.artifactQualifiedName)) + .put("meta", JsonObject().put("metricsName", metricName)) + } + + private fun sendActivitySubscriptionUpdate( + subscription: LiveViewSubscription, + timeBucket: ZonedDateTime, + value: Any + ) { + val event = LiveViewEvent( + subscription.subscriptionId!!, + subscription.entityIds.first(), + subscription.artifactQualifiedName, + formatter.format(timeBucket), + subscription.liveViewConfig, + value.toString() + ) + vertx.eventBus().publish(toLiveViewSubscriberAddress(developerId), JsonObject.mapFrom(event)) + vertx.eventBus().send(toLiveViewSubscriberAddress(subscription.subscriptionId!!), JsonObject.mapFrom(event)) + } + + override fun addLiveViewSubscription(subscription: LiveViewSubscription): Future { + val sub = SWLiveViewSubscription(subscription.copy(subscriptionId = UUID.randomUUID().toString())) + subscriptionMap[sub.subscription.subscriptionId!!] = sub + return Future.succeededFuture(sub.subscription) + } + + override fun removeLiveViewSubscription(subscriptionId: String): Future { + val sub = subscriptionMap.remove(subscriptionId) + ?: return Future.failedFuture(IllegalStateException("Invalid subscription id")) + return Future.succeededFuture(sub.subscription) + } + + override fun getLiveViewSubscriptions(): Future> { + return Future.succeededFuture(subscriptionMap.values.map { it.subscription }) + } + + override fun clearLiveViewSubscriptions(): Future> { + val subscriptions = subscriptionMap.values.toList() + subscriptionMap.clear() + return Future.succeededFuture(subscriptions.map { it.subscription }) + } + + override fun getLiveViewSubscriptionStats(): Future { + return Future.failedFuture(UnsupportedOperationException()) + } +} diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/SourceMarkerPlugin.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/SourceMarkerPlugin.kt index 3b344f970..171faac60 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/SourceMarkerPlugin.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/SourceMarkerPlugin.kt @@ -40,6 +40,7 @@ import io.vertx.core.json.DecodeException import io.vertx.core.json.Json import io.vertx.core.json.JsonObject import io.vertx.core.net.TrustOptions +import io.vertx.ext.auth.impl.jose.JWT import io.vertx.kotlin.coroutines.await import io.vertx.kotlin.coroutines.dispatcher import io.vertx.servicediscovery.ServiceDiscovery @@ -428,6 +429,12 @@ object SourceMarkerPlugin { } private suspend fun initMonitor(config: SourceMarkerConfig) { + var developer = "system" + if (config.serviceToken != null) { + val json = JWT.parse(config.serviceToken) + developer = json.getJsonObject("payload").getString("developer_id") + } + val scheme = if (config.isSsl()) "https" else "http" val skywalkingHost = "$scheme://${config.serviceHostNormalized}:${config.getServicePortNormalized()}/graphql" val certificatePins = mutableListOf() @@ -435,7 +442,8 @@ object SourceMarkerPlugin { deploymentIds.add( vertx.deployVerticle( SkywalkingMonitor( - skywalkingHost, config.serviceToken, certificatePins, config.verifyHost, config.serviceName + skywalkingHost, config.serviceToken, certificatePins, config.verifyHost, config.serviceName, + developer ) ).await() ) diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/ControlBarController.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/ControlBarController.kt index 56b5c7dd0..302ff3574 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/ControlBarController.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/ControlBarController.kt @@ -80,7 +80,7 @@ object ControlBarController { val parentMark = inlayMark.getParentSourceMark() if (parentMark is MethodSourceMark) { val loggerDetector = parentMark.getUserData(SourceMarkKeys.LOGGER_DETECTOR) - if (loggerDetector != null && SourceServices.Instance.liveView != null) { + if (loggerDetector != null) { runBlocking { val detectedLogs = loggerDetector.getOrFindLoggerStatements(parentMark) val logOnCurrentLine = detectedLogs.find { it.lineLocation == inlayMark.lineNumber } diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/portal/PortalEventListener.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/portal/PortalEventListener.kt index 222990ea8..4e1c0624c 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/portal/PortalEventListener.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/portal/PortalEventListener.kt @@ -87,7 +87,6 @@ import spp.jetbrains.sourcemarker.settings.SourceMarkerConfig import spp.protocol.SourceServices.Instance import spp.protocol.SourceServices.Provide.toLiveViewSubscriberAddress import spp.protocol.artifact.ArtifactQualifiedName -import spp.protocol.artifact.ArtifactType import spp.protocol.artifact.QueryTimeFrame import spp.protocol.artifact.exception.LiveStackTraceElement import spp.protocol.artifact.log.Log @@ -295,41 +294,42 @@ class PortalEventListener( } //update subscriptions - if (Instance.liveView != null) { - launch(vertx.dispatcher()) { - val sourceMark = SourceMarker.getSourceMark( - portal.viewingArtifact, SourceMark.Type.GUTTER - ) ?: return@launch - val endpointName = sourceMark.getUserData( - ENDPOINT_DETECTOR - )?.getOrFindEndpointName(sourceMark) ?: return@launch - - Instance.liveView!!.addLiveViewSubscription( - LiveViewSubscription( - null, - listOf(endpointName), - portal.viewingArtifact, - LiveSourceLocation(portal.viewingArtifact.identifier, 0), //todo: fix - LiveViewConfig("ACTIVITY", listOf("endpoint_cpm", "endpoint_avg", "endpoint_sla")) - ) - ).onComplete { - if (it.succeeded()) { - val subscriptionId = it.result().subscriptionId!! - if (portal.configuration.config["subscriptionId"] != null) { - Instance.liveView!!.removeLiveViewSubscription( - portal.configuration.config["subscriptionId"].toString() - ) - } - portal.configuration.config["subscriptionId"] = subscriptionId + launch(vertx.dispatcher()) { + val sourceMark = SourceMarker.getSourceMark( + portal.viewingArtifact, SourceMark.Type.GUTTER + ) ?: return@launch + val endpointName = sourceMark.getUserData( + ENDPOINT_DETECTOR + )?.getOrFindEndpointName(sourceMark) ?: return@launch + val endpointId = sourceMark.getUserData( + ENDPOINT_DETECTOR + )?.getOrFindEndpointId(sourceMark) ?: return@launch + + Instance.liveView!!.addLiveViewSubscription( + LiveViewSubscription( + null, + listOf(endpointName), + portal.viewingArtifact.copy(operationName = endpointId), //todo: only SWLiveViewService uses + LiveSourceLocation(portal.viewingArtifact.identifier, 0), //todo: fix + LiveViewConfig("ACTIVITY", listOf("endpoint_cpm", "endpoint_avg", "endpoint_sla")) + ) + ).onComplete { + if (it.succeeded()) { + val subscriptionId = it.result().subscriptionId!! + if (portal.configuration.config["subscriptionId"] != null) { + Instance.liveView!!.removeLiveViewSubscription( + portal.configuration.config["subscriptionId"].toString() + ) + } + portal.configuration.config["subscriptionId"] = subscriptionId - sourceMark.addEventListener { - if (it.eventCode == SourceMarkEventCode.PORTAL_CLOSED) { - Instance.liveView!!.removeLiveViewSubscription(subscriptionId) - } + sourceMark.addEventListener { + if (it.eventCode == SourceMarkEventCode.PORTAL_CLOSED) { + Instance.liveView!!.removeLiveViewSubscription(subscriptionId) } - } else { - log.error("Failed to add live view subscription", it.cause()) } + } else { + log.error("Failed to add live view subscription", it.cause()) } } } @@ -342,41 +342,42 @@ class PortalEventListener( } //update subscriptions - if (Instance.liveView != null) { - launch(vertx.dispatcher()) { - val sourceMark = SourceMarker.getSourceMark( - portal.viewingArtifact, SourceMark.Type.GUTTER - ) ?: return@launch - val endpointName = sourceMark.getUserData( - ENDPOINT_DETECTOR - )?.getOrFindEndpointName(sourceMark) ?: return@launch - - Instance.liveView!!.addLiveViewSubscription( - LiveViewSubscription( - null, - listOf(endpointName), - portal.viewingArtifact, - LiveSourceLocation(portal.viewingArtifact.identifier, 0), //todo: fix - LiveViewConfig("TRACES", listOf("endpoint_traces")) - ) - ).onComplete { - if (it.succeeded()) { - val subscriptionId = it.result().subscriptionId!! - if (portal.configuration.config["subscriptionId"] != null) { - Instance.liveView!!.removeLiveViewSubscription( - portal.configuration.config["subscriptionId"].toString() - ) - } - portal.configuration.config["subscriptionId"] = subscriptionId + launch(vertx.dispatcher()) { + val sourceMark = SourceMarker.getSourceMark( + portal.viewingArtifact, SourceMark.Type.GUTTER + ) ?: return@launch + val endpointName = sourceMark.getUserData( + ENDPOINT_DETECTOR + )?.getOrFindEndpointName(sourceMark) ?: return@launch + val endpointId = sourceMark.getUserData( + ENDPOINT_DETECTOR + )?.getOrFindEndpointId(sourceMark) ?: return@launch + + Instance.liveView!!.addLiveViewSubscription( + LiveViewSubscription( + null, + listOf(endpointName), + portal.viewingArtifact.copy(operationName = endpointId), //todo: only SWLiveViewService uses + LiveSourceLocation(portal.viewingArtifact.identifier, 0), //todo: fix + LiveViewConfig("TRACES", listOf("endpoint_traces")) + ) + ).onComplete { + if (it.succeeded()) { + val subscriptionId = it.result().subscriptionId!! + if (portal.configuration.config["subscriptionId"] != null) { + Instance.liveView!!.removeLiveViewSubscription( + portal.configuration.config["subscriptionId"].toString() + ) + } + portal.configuration.config["subscriptionId"] = subscriptionId - sourceMark.addEventListener { - if (it.eventCode == SourceMarkEventCode.PORTAL_CLOSED) { - Instance.liveView!!.removeLiveViewSubscription(subscriptionId) - } + sourceMark.addEventListener { + if (it.eventCode == SourceMarkEventCode.PORTAL_CLOSED) { + Instance.liveView!!.removeLiveViewSubscription(subscriptionId) } - } else { - log.error("Failed to add live view subscription", it.cause()) } + } else { + log.error("Failed to add live view subscription", it.cause()) } } } @@ -389,50 +390,48 @@ class PortalEventListener( } //update subscriptions - if (Instance.liveView != null) { - launch(vertx.dispatcher()) { - val sourceMark = SourceMarker.getSourceMark( - portal.viewingArtifact, SourceMark.Type.GUTTER - ) ?: return@launch - val logPatterns = if (sourceMark is ClassSourceMark) { - sourceMark.sourceFileMarker.getSourceMarks().filterIsInstance() - .flatMap { - it.getUserData(SourceMarkKeys.LOGGER_DETECTOR)!! - .getOrFindLoggerStatements(it) - }.map { it.logPattern } - } else if (sourceMark is MethodSourceMark) { - sourceMark.getUserData(SourceMarkKeys.LOGGER_DETECTOR)!! - .getOrFindLoggerStatements(sourceMark).map { it.logPattern } - } else { - throw IllegalStateException("Unsupported source mark type") - } + launch(vertx.dispatcher()) { + val sourceMark = SourceMarker.getSourceMark( + portal.viewingArtifact, SourceMark.Type.GUTTER + ) ?: return@launch + val logPatterns = if (sourceMark is ClassSourceMark) { + sourceMark.sourceFileMarker.getSourceMarks().filterIsInstance() + .flatMap { + it.getUserData(SourceMarkKeys.LOGGER_DETECTOR)!! + .getOrFindLoggerStatements(it) + }.map { it.logPattern } + } else if (sourceMark is MethodSourceMark) { + sourceMark.getUserData(SourceMarkKeys.LOGGER_DETECTOR)!! + .getOrFindLoggerStatements(sourceMark).map { it.logPattern } + } else { + throw IllegalStateException("Unsupported source mark type") + } - Instance.liveView!!.addLiveViewSubscription( - LiveViewSubscription( - null, - logPatterns, - portal.viewingArtifact, - LiveSourceLocation(portal.viewingArtifact.identifier, 0), //todo: fix - LiveViewConfig("LOGS", listOf("endpoint_logs")) - ) - ).onComplete { - if (it.succeeded()) { - val subscriptionId = it.result().subscriptionId!! - if (portal.configuration.config["subscriptionId"] != null) { - Instance.liveView!!.removeLiveViewSubscription( - portal.configuration.config["subscriptionId"].toString() - ) - } - portal.configuration.config["subscriptionId"] = subscriptionId + Instance.liveView!!.addLiveViewSubscription( + LiveViewSubscription( + null, + logPatterns, + portal.viewingArtifact, + LiveSourceLocation(portal.viewingArtifact.identifier, 0), //todo: fix + LiveViewConfig("LOGS", listOf("endpoint_logs")) + ) + ).onComplete { + if (it.succeeded()) { + val subscriptionId = it.result().subscriptionId!! + if (portal.configuration.config["subscriptionId"] != null) { + Instance.liveView!!.removeLiveViewSubscription( + portal.configuration.config["subscriptionId"].toString() + ) + } + portal.configuration.config["subscriptionId"] = subscriptionId - sourceMark.addEventListener { - if (it.eventCode == SourceMarkEventCode.PORTAL_CLOSED) { - Instance.liveView!!.removeLiveViewSubscription(subscriptionId) - } + sourceMark.addEventListener { + if (it.eventCode == SourceMarkEventCode.PORTAL_CLOSED) { + Instance.liveView!!.removeLiveViewSubscription(subscriptionId) } - } else { - log.error("Failed to add live view subscription", it.cause()) } + } else { + log.error("Failed to add live view subscription", it.cause()) } } } @@ -485,24 +484,22 @@ class PortalEventListener( if (sourceMark != null && sourceMark is MethodSourceMark) { val endpointId = sourceMark.getUserData(ENDPOINT_DETECTOR)!!.getOrFindEndpointId(sourceMark) if (endpointId != null) { - launch(vertx.dispatcher()) { - val traceResult = EndpointTracesBridge.getTraces( - GetEndpointTraces( - artifactQualifiedName = portal.viewingArtifact, - endpointId = endpointId, - zonedDuration = ZonedDuration( - ZonedDateTime.now().minusHours(24), - ZonedDateTime.now(), - SkywalkingClient.DurationStep.MINUTE - ), - orderType = portal.tracesView.orderType, - pageSize = portal.tracesView.viewTraceAmount, - pageNumber = portal.tracesView.pageNumber - ), vertx - ) + val traceResult = EndpointTracesBridge.getTraces( + GetEndpointTraces( + artifactQualifiedName = portal.viewingArtifact, + endpointId = endpointId, + zonedDuration = ZonedDuration( + ZonedDateTime.now().minusHours(24), + ZonedDateTime.now(), + SkywalkingClient.DurationStep.MINUTE + ), + orderType = portal.tracesView.orderType, + pageSize = portal.tracesView.viewTraceAmount, + pageNumber = portal.tracesView.pageNumber + ), vertx + ) - handleTraceResult(traceResult, portal, portal.viewingArtifact) - } + handleTraceResult(traceResult, portal, portal.viewingArtifact) } } } @@ -544,42 +541,40 @@ class PortalEventListener( private suspend fun pullLatestLogs(portal: SourcePortal) { if (log.isTraceEnabled) log.trace("Refreshing logs. Portal: {}", portal.portalUuid) val sourceMark = SourceMarker.getSourceMark(portal.viewingArtifact, SourceMark.Type.GUTTER) - launch(vertx.dispatcher()) { - val logsResult = LogsBridge.queryLogs( - GetEndpointLogs( - endpointId = if (sourceMark is MethodSourceMark) { - sourceMark.getUserData(ENDPOINT_DETECTOR)!!.getOrFindEndpointId(sourceMark) - } else null, - zonedDuration = ZonedDuration( - ZonedDateTime.now().minusMinutes(15), //todo: method filtering in skywalking - ZonedDateTime.now(), - SkywalkingClient.DurationStep.MINUTE - ), - orderType = portal.logsView.orderType, - pageSize = portal.logsView.viewLogAmount * 25, //todo: method filtering in skywalking - pageNumber = portal.logsView.pageNumber - ), vertx - ) - if (logsResult.succeeded()) { - //todo: impl method filtering in skywalking - for ((content, logs) in logsResult.result().logs.groupBy { it.content }) { - SourceMarkSearch.findInheritedSourceMarks(content).forEach { - vertx.eventBus().send( - ArtifactLogUpdated, logsResult.result().copy( - artifactQualifiedName = it.artifactQualifiedName, - total = logs.size, - logs = logs, - ) + val logsResult = LogsBridge.queryLogs( + GetEndpointLogs( + endpointId = if (sourceMark is MethodSourceMark) { + sourceMark.getUserData(ENDPOINT_DETECTOR)!!.getOrFindEndpointId(sourceMark) + } else null, + zonedDuration = ZonedDuration( + ZonedDateTime.now().minusMinutes(15), //todo: method filtering in skywalking + ZonedDateTime.now(), + SkywalkingClient.DurationStep.MINUTE + ), + orderType = portal.logsView.orderType, + pageSize = portal.logsView.viewLogAmount * 25, //todo: method filtering in skywalking + pageNumber = portal.logsView.pageNumber + ), vertx + ) + if (logsResult.succeeded()) { + //todo: impl method filtering in skywalking + for ((content, logs) in logsResult.result().logs.groupBy { it.content }) { + SourceMarkSearch.findInheritedSourceMarks(content).forEach { + vertx.eventBus().send( + ArtifactLogUpdated, logsResult.result().copy( + artifactQualifiedName = it.artifactQualifiedName, + total = logs.size, + logs = logs, ) - } + ) } + } + } else { + val replyException = logsResult.cause() as ReplyException + if (replyException.failureCode() == 404) { + log.warn("Failed to fetch logs. Service(s) unavailable") } else { - val replyException = logsResult.cause() as ReplyException - if (replyException.failureCode() == 404) { - log.warn("Failed to fetch logs. Service(s) unavailable") - } else { - log.error("Failed to fetch logs", logsResult.cause()) - } + log.error("Failed to fetch logs", logsResult.cause()) } } } From 10341894b98560bba0701bdb20e00fed4f7ac8a8 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Fri, 18 Mar 2022 19:06:12 +0100 Subject: [PATCH 28/42] allow live view commands --- .../jetbrains/monitor/skywalking/service/SWLiveService.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/monitor/src/main/kotlin/spp/jetbrains/monitor/skywalking/service/SWLiveService.kt b/monitor/src/main/kotlin/spp/jetbrains/monitor/skywalking/service/SWLiveService.kt index b743a45c4..711895517 100644 --- a/monitor/src/main/kotlin/spp/jetbrains/monitor/skywalking/service/SWLiveService.kt +++ b/monitor/src/main/kotlin/spp/jetbrains/monitor/skywalking/service/SWLiveService.kt @@ -23,6 +23,7 @@ import io.vertx.kotlin.coroutines.CoroutineVerticle import io.vertx.kotlin.coroutines.dispatcher import kotlinx.coroutines.launch import spp.jetbrains.monitor.skywalking.bridge.ServiceBridge +import spp.protocol.platform.auth.CommandType import spp.protocol.platform.auth.RolePermission import spp.protocol.platform.developer.Developer import spp.protocol.platform.developer.SelfInfo @@ -37,7 +38,7 @@ class SWLiveService : CoroutineVerticle(), LiveService { SelfInfo( Developer("system"), emptyList(), - RolePermission.values().filter { it.name.startsWith("VIEW_") }, + RolePermission.values().filter { it.commandType == CommandType.LIVE_VIEW }, emptyList() ) ) @@ -53,6 +54,6 @@ class SWLiveService : CoroutineVerticle(), LiveService { } override fun getActiveProbes(): Future> { - TODO("Not yet implemented") + return Future.failedFuture(UnsupportedOperationException("Not implemented")) } } From 681b11eb8c924357396ad4b6223228ab3b859dfe Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Fri, 18 Mar 2022 22:23:23 +0100 Subject: [PATCH 29/42] move code to processor --- .../marker/jvm/JVMVariableSimpleNode.kt | 31 +++++-------------- 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/jvm/JVMVariableSimpleNode.kt b/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/jvm/JVMVariableSimpleNode.kt index 34429d436..de37e9e02 100644 --- a/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/jvm/JVMVariableSimpleNode.kt +++ b/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/jvm/JVMVariableSimpleNode.kt @@ -56,10 +56,6 @@ class JVMVariableSimpleNode(val variable: LiveVariable) : SimpleNode() { "java.lang.Float", "java.lang.Double" ) - private val gsonPrimitives = setOf( - "java.math.BigInteger", - "java.lang.Date" - ) private val scheme = DebuggerUIUtil.getColorScheme(null) override fun getChildren(): Array { @@ -112,28 +108,15 @@ class JVMVariableSimpleNode(val variable: LiveVariable) : SimpleNode() { } presentation.setIcon(AllIcons.Debugger.Db_primitive) } else if (variable.liveClazz != null) { - if (variable.liveClazz == "java.lang.Class") { - presentation.addText( - "{ " + variable.value.toString().substringAfterLast(".") + " }", - SimpleTextAttributes.GRAYED_ATTRIBUTES - ) - presentation.setIcon(AllIcons.Debugger.Value) - } else if (gsonPrimitives.contains(variable.liveClazz)) { - val simpleClassName = variable.liveClazz!!.substringAfterLast(".") - val identity = variable.liveIdentity - presentation.addText("{ $simpleClassName@$identity }", SimpleTextAttributes.GRAYED_ATTRIBUTES) - presentation.addText(" \"" + variable.value + "\"", SimpleTextAttributes.REGULAR_ATTRIBUTES) - presentation.setIcon(AllIcons.Debugger.Db_primitive) + val simpleClassName = variable.liveClazz!!.substringAfterLast(".") + val identity = variable.liveIdentity + if (variable.presentation != null) { + presentation.addText("{ $simpleClassName@$identity } ", SimpleTextAttributes.GRAYED_ATTRIBUTES) + presentation.addText("\"${variable.presentation}\"", SimpleTextAttributes.REGULAR_ATTRIBUTES) } else { - val simpleClassName = variable.liveClazz!!.substringAfterLast(".") - val identity = variable.liveIdentity - if (variable.presentation != null) { - presentation.addText("\"${variable.presentation}\"", SimpleTextAttributes.REGULAR_ATTRIBUTES) - } else { - presentation.addText("{ $simpleClassName@$identity }", SimpleTextAttributes.GRAYED_ATTRIBUTES) - } - presentation.setIcon(AllIcons.Debugger.Value) + presentation.addText("{ $simpleClassName@$identity }", SimpleTextAttributes.GRAYED_ATTRIBUTES) } + presentation.setIcon(AllIcons.Debugger.Value) } else { if (variable.value is Number) { presentation.addText( From 925bfe36b58218de9734066da77ade243c06959d Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Sat, 19 Mar 2022 09:27:24 +0100 Subject: [PATCH 30/42] impl show/hide quick stats --- .../marker/plugin/SourceInlayHintProvider.kt | 38 ++++++++++--- .../mark/api/event/SourceMarkEventCode.kt | 3 +- .../command/ControlBarController.kt | 37 +++++++++++-- .../command/LiveControlCommand.kt | 12 +++++ .../view/ActivityQuickStatsIndicator.kt | 54 ++++++++++--------- 5 files changed, 109 insertions(+), 35 deletions(-) diff --git a/marker/src/main/kotlin/spp/jetbrains/marker/plugin/SourceInlayHintProvider.kt b/marker/src/main/kotlin/spp/jetbrains/marker/plugin/SourceInlayHintProvider.kt index aa6e168c7..82a799cb3 100644 --- a/marker/src/main/kotlin/spp/jetbrains/marker/plugin/SourceInlayHintProvider.kt +++ b/marker/src/main/kotlin/spp/jetbrains/marker/plugin/SourceInlayHintProvider.kt @@ -18,10 +18,7 @@ package spp.jetbrains.marker.plugin import com.intellij.codeInsight.hints.* -import com.intellij.codeInsight.hints.presentation.AttributesTransformerPresentation -import com.intellij.codeInsight.hints.presentation.BasePresentation -import com.intellij.codeInsight.hints.presentation.InlayPresentation -import com.intellij.codeInsight.hints.presentation.MouseButton +import com.intellij.codeInsight.hints.presentation.* import com.intellij.ide.ui.AntialiasingType import com.intellij.lang.Language import com.intellij.openapi.application.ApplicationManager @@ -38,6 +35,7 @@ import com.intellij.ui.paint.EffectPainter import org.slf4j.LoggerFactory import spp.jetbrains.marker.SourceMarker import spp.jetbrains.marker.SourceMarker.getSourceFileMarker +import spp.jetbrains.marker.source.mark.api.event.SourceMarkEventCode.MARK_REMOVED import spp.jetbrains.marker.source.mark.api.key.SourceKey import spp.jetbrains.marker.source.mark.inlay.InlayMark import spp.jetbrains.marker.source.mark.inlay.config.InlayMarkVirtualText @@ -75,6 +73,11 @@ abstract class SourceInlayHintProvider : InlayHintsProvider { ?.getInlineElementsInRange(0, Integer.MAX_VALUE)?.forEach { it.repaint() } + FileEditorManager.getInstance(event.sourceMark.project).selectedTextEditor?.inlayModel + //todo: smaller range + ?.getAfterLineEndElementsInRange(0, Integer.MAX_VALUE)?.forEach { + it.repaint() + } FileEditorManager.getInstance(event.sourceMark.project).selectedTextEditor?.inlayModel //todo: smaller range ?.getBlockElementsInRange(0, Integer.MAX_VALUE)?.forEach { @@ -82,6 +85,28 @@ abstract class SourceInlayHintProvider : InlayHintsProvider { } } } + MARK_REMOVED -> { + ApplicationManager.getApplication().invokeLater { + FileEditorManager.getInstance(event.sourceMark.project).selectedTextEditor?.inlayModel + //todo: smaller range + ?.getBlockElementsInRange(0, Integer.MAX_VALUE)?.forEach { + if (it.renderer is BlockInlayRenderer) { + if ((it.renderer as BlockInlayRenderer).getCachedPresentation() is RecursivelyUpdatingRootPresentation) { + val rootPresentation = (it.renderer as BlockInlayRenderer).getCachedPresentation() as RecursivelyUpdatingRootPresentation + if (rootPresentation.content is StaticDelegatePresentation) { + val delegatePresentation = rootPresentation.content as StaticDelegatePresentation + if (delegatePresentation.presentation is DynamicTextInlayPresentation) { + val dynamicPresentation = delegatePresentation.presentation as DynamicTextInlayPresentation + if (dynamicPresentation.inlayMark == event.sourceMark) { + it.dispose() + } + } + } + } + } + } + } + } } } } @@ -127,7 +152,7 @@ abstract class SourceInlayHintProvider : InlayHintsProvider { virtualText.inlayMark = inlayMark var representation = AttributesTransformerPresentation( - (DynamicTextInlayPresentation(editor, virtualText)) + (DynamicTextInlayPresentation(editor, inlayMark, virtualText)) ) { it.withDefault(editor.colorsScheme.getAttributes(INLINE_PARAMETER_HINT) ?: TextAttributes()) } as InlayPresentation @@ -153,7 +178,8 @@ abstract class SourceInlayHintProvider : InlayHintsProvider { representation: InlayPresentation ) - private inner class DynamicTextInlayPresentation(val editor: Editor, val virtualText: InlayMarkVirtualText) : + private inner class DynamicTextInlayPresentation(val editor: Editor, val inlayMark: InlayMark, + val virtualText: InlayMarkVirtualText) : BasePresentation() { private val font = editor.colorsScheme.getFont(EditorFontType.PLAIN) diff --git a/marker/src/main/kotlin/spp/jetbrains/marker/source/mark/api/event/SourceMarkEventCode.kt b/marker/src/main/kotlin/spp/jetbrains/marker/source/mark/api/event/SourceMarkEventCode.kt index 9c9620d2b..94000788d 100644 --- a/marker/src/main/kotlin/spp/jetbrains/marker/source/mark/api/event/SourceMarkEventCode.kt +++ b/marker/src/main/kotlin/spp/jetbrains/marker/source/mark/api/event/SourceMarkEventCode.kt @@ -35,7 +35,8 @@ enum class SourceMarkEventCode(private val code: Int) : IEventCode { PORTAL_OPENED(1005), PORTAL_CLOSED(1006), UPDATE_PORTAL_CONFIG(1007), - MARK_USER_DATA_UPDATED(1008); + MARK_USER_DATA_UPDATED(1008), + CUSTOM_EVENT(1009); override fun code(): Int { return this.code diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/ControlBarController.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/ControlBarController.kt index 302ff3574..420563dbd 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/ControlBarController.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/ControlBarController.kt @@ -19,14 +19,13 @@ package spp.jetbrains.sourcemarker.command import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.editor.Editor -import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiDocumentManager import io.vertx.kotlin.coroutines.await import kotlinx.coroutines.runBlocking import org.slf4j.LoggerFactory import spp.jetbrains.marker.SourceMarker.creationService +import spp.jetbrains.marker.jvm.psi.EndpointDetector import spp.jetbrains.marker.source.SourceFileMarker -import spp.jetbrains.marker.source.mark.api.ClassSourceMark import spp.jetbrains.marker.source.mark.api.MethodSourceMark import spp.jetbrains.marker.source.mark.api.SourceMark import spp.jetbrains.marker.source.mark.api.component.swing.SwingSourceMarkComponentProvider @@ -37,7 +36,9 @@ import spp.jetbrains.marker.source.mark.inlay.InlayMark import spp.jetbrains.sourcemarker.ControlBar import spp.jetbrains.sourcemarker.command.LiveControlCommand.* import spp.jetbrains.sourcemarker.mark.SourceMarkKeys +import spp.jetbrains.sourcemarker.mark.SourceMarkSearch import spp.jetbrains.sourcemarker.status.LiveStatusManager +import spp.jetbrains.sourcemarker.view.ActivityQuickStatsIndicator import spp.protocol.SourceServices import spp.protocol.instrument.LiveInstrumentType.* import java.awt.BorderLayout @@ -76,7 +77,9 @@ object ControlBarController { runBlocking { syncAvailableCommands() } } - val availableCommandsAtLocation = availableCommands.toMutableList() + val availableCommandsAtLocation = availableCommands.toMutableSet() + availableCommandsAtLocation.remove(SHOW_QUICK_STATS) + val parentMark = inlayMark.getParentSourceMark() if (parentMark is MethodSourceMark) { val loggerDetector = parentMark.getUserData(SourceMarkKeys.LOGGER_DETECTOR) @@ -89,13 +92,27 @@ object ControlBarController { } } } + + if (parentMark.getUserData(EndpointDetector.ENDPOINT_ID) != null) { + val existingQuickStats = parentMark.sourceFileMarker.getSourceMarks().find { + it.artifactQualifiedName == parentMark.artifactQualifiedName + && it.getUserData(ActivityQuickStatsIndicator.SHOWING_QUICK_STATS) == true + } + if (existingQuickStats == null) { + availableCommandsAtLocation.add(SHOW_QUICK_STATS) + } else { + availableCommandsAtLocation.add(HIDE_QUICK_STATS) + } + } } - return availableCommandsAtLocation + return availableCommandsAtLocation.toList() } fun handleCommandInput(input: String, editor: Editor) { log.info("Processing command input: {}", input) when (input) { + SHOW_QUICK_STATS.command -> handleQuickStatsCommand(editor, SHOW_QUICK_STATS) + HIDE_QUICK_STATS.command -> handleQuickStatsCommand(editor, HIDE_QUICK_STATS) VIEW_OVERVIEW.command -> handleViewPortalCommand(editor, VIEW_OVERVIEW) VIEW_ACTIVITY.command -> handleViewPortalCommand(editor, VIEW_ACTIVITY) VIEW_TRACES.command -> handleViewPortalCommand(editor, VIEW_TRACES) @@ -204,6 +221,18 @@ object ControlBarController { } } + private fun handleQuickStatsCommand(editor: Editor, command: LiveControlCommand) { + val sourceMark = SourceMarkSearch.getClosestSourceMark(previousControlBar!!.sourceFileMarker, editor) + if (sourceMark != null) { + sourceMark.triggerEvent(CUSTOM_EVENT, listOf(command)) + } else { + log.warn("No source mark found for command: {}", command) + } + + previousControlBar!!.dispose() + previousControlBar = null + } + private fun handleViewPortalCommand(editor: Editor, command: LiveControlCommand) { val sourceMark = SourceMarkSearch.getClosestSourceMark(previousControlBar!!.sourceFileMarker, editor) if (sourceMark != null) { diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/LiveControlCommand.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/LiveControlCommand.kt index 800b9a1dd..db7ad7f54 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/LiveControlCommand.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/LiveControlCommand.kt @@ -58,6 +58,18 @@ enum class LiveControlCommand( PluginIcons.Command.viewLogsSelected, PluginIcons.Command.viewLogsUnSelected ), + SHOW_QUICK_STATS( + "Show Quick Stats", + "Live View ➛ Quick Stats ➛ Scope: Endpoint", + PluginIcons.Command.viewActivitySelected, + PluginIcons.Command.viewActivityUnSelected + ), + HIDE_QUICK_STATS( + "Hide Quick Stats", + "Live View ➛ Quick Stats ➛ Scope: Endpoint", + PluginIcons.Command.viewActivitySelected, + PluginIcons.Command.viewActivityUnSelected + ), WATCH_LOG( "Watch Log", "Live View ➛ Log ➛ Scope: Expression", diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/view/ActivityQuickStatsIndicator.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/view/ActivityQuickStatsIndicator.kt index c0490dcf5..6e1d3d362 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/view/ActivityQuickStatsIndicator.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/view/ActivityQuickStatsIndicator.kt @@ -19,7 +19,9 @@ package spp.jetbrains.sourcemarker.view import com.intellij.openapi.application.ApplicationManager import com.intellij.ui.JBColor +import io.vertx.core.json.Json import io.vertx.core.json.JsonArray +import io.vertx.core.json.JsonObject import io.vertx.kotlin.coroutines.dispatcher import kotlinx.coroutines.runBlocking import org.slf4j.Logger @@ -29,9 +31,9 @@ import spp.jetbrains.marker.jvm.psi.EndpointDetector import spp.jetbrains.marker.source.mark.api.MethodSourceMark import spp.jetbrains.marker.source.mark.api.event.SourceMarkEvent import spp.jetbrains.marker.source.mark.api.event.SourceMarkEventCode +import spp.jetbrains.marker.source.mark.api.event.SourceMarkEventCode.CUSTOM_EVENT import spp.jetbrains.marker.source.mark.api.event.SourceMarkEventListener import spp.jetbrains.marker.source.mark.api.key.SourceKey -import spp.jetbrains.marker.source.mark.inlay.InlayMark import spp.jetbrains.marker.source.mark.inlay.config.InlayMarkVirtualText import spp.jetbrains.monitor.skywalking.SkywalkingClient import spp.jetbrains.monitor.skywalking.bridge.EndpointMetricsBridge @@ -39,10 +41,10 @@ import spp.jetbrains.monitor.skywalking.model.GetEndpointMetrics import spp.jetbrains.monitor.skywalking.model.ZonedDuration import spp.jetbrains.monitor.skywalking.toProtocol import spp.jetbrains.sourcemarker.SourceMarkerPlugin.vertx -import spp.jetbrains.sourcemarker.mark.SourceMarkKeys.VIEW_SUBSCRIPTION_ID -import spp.jetbrains.sourcemarker.mark.SourceMarkSearch -import spp.jetbrains.sourcemarker.status.LiveStatusManager +import spp.jetbrains.sourcemarker.command.LiveControlCommand.HIDE_QUICK_STATS +import spp.jetbrains.sourcemarker.command.LiveControlCommand.SHOW_QUICK_STATS import spp.protocol.SourceServices +import spp.protocol.SourceServices.Provide.toLiveViewSubscriberAddress import spp.protocol.artifact.QueryTimeFrame import spp.protocol.artifact.metrics.ArtifactMetricResult import spp.protocol.artifact.metrics.MetricType @@ -64,17 +66,12 @@ class ActivityQuickStatsIndicator : SourceMarkEventListener { companion object { private val log: Logger = LoggerFactory.getLogger(ActivityQuickStatsIndicator::class.java) private val inlayForegroundColor = JBColor(Color.decode("#3e464a"), Color.decode("#87939a")) - val ACTIVITY_QUICK_STATS = SourceKey("ACTIVITY_QUICK_STATS") + val SHOWING_QUICK_STATS = SourceKey("SHOWING_QUICK_STATS") } override fun handleEvent(event: SourceMarkEvent) { - if (event.eventCode == SourceMarkEventCode.MARK_USER_DATA_UPDATED) { + if (event.eventCode == CUSTOM_EVENT && event.params.first() == SHOW_QUICK_STATS) { if (event.sourceMark.getUserData(EndpointDetector.ENDPOINT_ID) != null) { - if (event.sourceMark is InlayMark) return - val existingSourceMarks = SourceMarkSearch.findSourceMarks(event.sourceMark.artifactQualifiedName) - if (existingSourceMarks.find { it.getUserData(ACTIVITY_QUICK_STATS) == true } != null) return - - //found a method endpoint to show quick activity stats ApplicationManager.getApplication().runReadAction { val endTime = ZonedDateTime.now().minusMinutes(1).truncatedTo(ChronoUnit.MINUTES) //exclusive val startTime = endTime.minusMinutes(2) @@ -100,34 +97,37 @@ class ActivityQuickStatsIndicator : SourceMarkEventListener { (event.sourceMark as MethodSourceMark).getPsiElement().nameIdentifier!!, false ) - inlay.putUserData(ACTIVITY_QUICK_STATS, true) + inlay.putUserData(SHOWING_QUICK_STATS, true) inlay.configuration.virtualText = InlayMarkVirtualText(inlay, formatMetricResult(metricResult)) inlay.configuration.virtualText!!.textAttributes.foregroundColor = inlayForegroundColor inlay.configuration.activateOnMouseClick = false inlay.apply(true) - val previousMetrics = mutableMapOf() - LiveStatusManager.addViewEventListener(inlay) { - consumeLiveEvent(it, previousMetrics) - - val twoMinAgoValue = previousMetrics[it.timeBucket.toLong() - 2] - if (twoMinAgoValue != null) { - inlay.configuration.virtualText!!.updateVirtualText(twoMinAgoValue) - } - } - SourceServices.Instance.liveView!!.addLiveViewSubscription( LiveViewSubscription( null, listOf(event.sourceMark.getUserData(EndpointDetector.ENDPOINT_NAME)!!), - event.sourceMark.artifactQualifiedName, + event.sourceMark.artifactQualifiedName.copy( + operationName = event.sourceMark.getUserData( + EndpointDetector.ENDPOINT_ID + )!! //todo: only SWLiveViewService uses + ), LiveSourceLocation(event.sourceMark.artifactQualifiedName.identifier, 0), //todo: don't need LiveViewConfig("ACTIVITY", listOf("endpoint_cpm", "endpoint_avg", "endpoint_sla"), -1) ) ).onComplete { if (it.succeeded()) { val subscriptionId = it.result().subscriptionId!! - inlay.putUserData(VIEW_SUBSCRIPTION_ID, subscriptionId) + val previousMetrics = mutableMapOf() + vertx.eventBus().consumer(toLiveViewSubscriberAddress(subscriptionId)) { + val viewEvent = Json.decodeValue(it.body().toString(), LiveViewEvent::class.java) + consumeLiveEvent(viewEvent, previousMetrics) + + val twoMinAgoValue = previousMetrics[viewEvent.timeBucket.toLong() - 2] + if (twoMinAgoValue != null) { + inlay.configuration.virtualText!!.updateVirtualText(twoMinAgoValue) + } + } inlay.addEventListener { if (it.eventCode == SourceMarkEventCode.MARK_REMOVED) { SourceServices.Instance.liveView!!.removeLiveViewSubscription(subscriptionId) @@ -139,6 +139,12 @@ class ActivityQuickStatsIndicator : SourceMarkEventListener { } } } + } else if (event.eventCode == CUSTOM_EVENT && event.params.first() == HIDE_QUICK_STATS) { + val existingQuickStats = event.sourceMark.sourceFileMarker.getSourceMarks().find { + it.artifactQualifiedName == event.sourceMark.artifactQualifiedName + && it.getUserData(SHOWING_QUICK_STATS) == true + } + existingQuickStats?.dispose() } } From 2794e7c37117b30a54c84421a26b9ad64b9b4b9a Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Sat, 19 Mar 2022 09:34:40 +0100 Subject: [PATCH 31/42] todo --- .../spp/jetbrains/sourcemarker/command/ControlBarController.kt | 2 +- .../spp/jetbrains/sourcemarker/portal/PortalController.kt | 2 +- .../spp/jetbrains/sourcemarker/service/LiveViewManager.kt | 1 + .../spp/jetbrains/sourcemarker/status/LiveStatusManager.kt | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/ControlBarController.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/ControlBarController.kt index 420563dbd..a7eff4dae 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/ControlBarController.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/ControlBarController.kt @@ -69,7 +69,7 @@ object ControlBarController { @Suppress("UselessCallOnCollection") //unknown enums are null selfInfo.permissions.filterNotNull().map { it.name }.contains(it.name) }) - //availableCommands.add(VIEW_OVERVIEW) //todo: remove after v0.4.2 + //availableCommands.add(VIEW_OVERVIEW) //todo: remove after v0.4.3 } private fun determineAvailableCommandsAtLocation(inlayMark: ExpressionInlayMark): List { diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/portal/PortalController.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/portal/PortalController.kt index c500c02fa..9e8e31f4d 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/portal/PortalController.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/portal/PortalController.kt @@ -57,7 +57,7 @@ class PortalController(private val markerConfig: SourceMarkerConfig) : Coroutine vertx.deployVerticle(portalServer).await() vertx.deployVerticle(PortalEventListener(markerConfig)).await() -// //todo: remove after v0.4.2 +// //todo: remove after v0.4.3 // vertx.eventBus().registerDefaultCodec(ArtifactQualifiedName::class.java, LocalMessageCodec()) SourceMarker.addGlobalSourceMarkEventListener { diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/service/LiveViewManager.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/service/LiveViewManager.kt index 30b02957e..9a77d9c7d 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/service/LiveViewManager.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/service/LiveViewManager.kt @@ -52,6 +52,7 @@ class LiveViewManager(private val pluginConfig: SourceMarkerConfig) : CoroutineV return@consumer } + //todo: remove in favor of sending events to individual subscribers SourceMarkSearch.findBySubscriptionId(event.subscriptionId) ?.getUserData(SourceMarkKeys.VIEW_EVENT_LISTENERS)?.forEach { it.accept(event) } } diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/status/LiveStatusManager.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/status/LiveStatusManager.kt index 76e434856..39485a941 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/status/LiveStatusManager.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/status/LiveStatusManager.kt @@ -81,7 +81,7 @@ object LiveStatusManager : SourceMarkEventListener { when (event.eventCode) { SourceMarkEventCode.MARK_ADDED -> { if (event.sourceMark !is MethodSourceMark) return - //todo: shouldn't need to wait for method mark added to add inlay marks + //todo: shouldn't need to wait for method mark added to add inlay/gutter marks // should have events that just mean a method is visible ApplicationManager.getApplication().runReadAction { From 5a34119025e728e2f6cddfe23d4e148fef4f6fb5 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Sat, 19 Mar 2022 09:35:27 +0100 Subject: [PATCH 32/42] accept events to indiv subscriber --- .../sourcemarker/status/LiveStatusManager.kt | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/status/LiveStatusManager.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/status/LiveStatusManager.kt index 39485a941..c3fdfb882 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/status/LiveStatusManager.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/status/LiveStatusManager.kt @@ -23,6 +23,7 @@ import com.intellij.openapi.editor.Editor import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.psi.PsiDocumentManager import io.vertx.core.json.Json +import io.vertx.core.json.JsonObject import kotlinx.coroutines.runBlocking import org.slf4j.LoggerFactory import spp.jetbrains.marker.SourceMarker.creationService @@ -37,6 +38,7 @@ import spp.jetbrains.marker.source.mark.api.event.SourceMarkEvent import spp.jetbrains.marker.source.mark.api.event.SourceMarkEventCode import spp.jetbrains.marker.source.mark.api.event.SourceMarkEventListener import spp.jetbrains.marker.source.mark.inlay.InlayMark +import spp.jetbrains.sourcemarker.SourceMarkerPlugin.vertx import spp.jetbrains.sourcemarker.icons.SourceMarkerIcons.LIVE_METER_COUNT_ICON import spp.jetbrains.sourcemarker.icons.SourceMarkerIcons.LIVE_METER_GAUGE_ICON import spp.jetbrains.sourcemarker.icons.SourceMarkerIcons.LIVE_METER_HISTOGRAM_ICON @@ -50,11 +52,13 @@ import spp.jetbrains.sourcemarker.service.ViewEventListener import spp.jetbrains.sourcemarker.settings.SourceMarkerConfig import spp.jetbrains.sourcemarker.status.util.CircularList import spp.protocol.SourceServices +import spp.protocol.SourceServices.Provide.toLiveViewSubscriberAddress import spp.protocol.artifact.ArtifactQualifiedName import spp.protocol.artifact.ArtifactType import spp.protocol.instrument.* import spp.protocol.instrument.meter.MeterType import spp.protocol.view.LiveViewConfig +import spp.protocol.view.LiveViewEvent import spp.protocol.view.LiveViewSubscription import java.awt.BorderLayout import java.awt.Dimension @@ -172,6 +176,21 @@ object LiveStatusManager : SourceMarkEventListener { val wrapperPanel = JPanel() wrapperPanel.layout = BorderLayout() + val config = Json.decodeValue( + PropertiesComponent.getInstance(editor.project!!).getValue("sourcemarker_plugin_config"), + SourceMarkerConfig::class.java + ) + val statusBar = LogStatusBar( + LiveSourceLocation( + namingService.getClassQualifiedNames(fileMarker.psiFile)[0].identifier, + lineNumber, + service = config.serviceName + ), + if (watchExpression) emptyList() else scopeService.getScopeVariables(fileMarker, lineNumber), + inlayMark, + watchExpression + ) + if (watchExpression) { val logPatterns = mutableListOf() val parentMark = inlayMark.getParentSourceMark() @@ -207,6 +226,9 @@ object LiveStatusManager : SourceMarkEventListener { if (it.succeeded()) { val subscriptionId = it.result().subscriptionId!! inlayMark.putUserData(VIEW_SUBSCRIPTION_ID, subscriptionId) + vertx.eventBus().consumer(toLiveViewSubscriberAddress(subscriptionId)) { + statusBar.accept(Json.decodeValue(it.body().toString(), LiveViewEvent::class.java)) + } inlayMark.addEventListener { event -> if (event.eventCode == SourceMarkEventCode.MARK_REMOVED) { SourceServices.Instance.liveView!!.removeLiveViewSubscription(subscriptionId) @@ -218,20 +240,6 @@ object LiveStatusManager : SourceMarkEventListener { } } - val config = Json.decodeValue( - PropertiesComponent.getInstance(editor.project!!).getValue("sourcemarker_plugin_config"), - SourceMarkerConfig::class.java - ) - val statusBar = LogStatusBar( - LiveSourceLocation( - namingService.getClassQualifiedNames(fileMarker.psiFile)[0].identifier, - lineNumber, - service = config.serviceName - ), - if (watchExpression) emptyList() else scopeService.getScopeVariables(fileMarker, lineNumber), - inlayMark, - watchExpression - ) inlayMark.putUserData(SourceMarkKeys.STATUS_BAR, statusBar) statusBar.setWrapperPanel(wrapperPanel) wrapperPanel.add(statusBar) From 72fc955dca046ddee1d9f0f9874dfa1129946de6 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Sat, 19 Mar 2022 09:46:49 +0100 Subject: [PATCH 33/42] bump --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 432c178ca..0addd6acb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ kotlin.code.style=official pluginGroup = spp.jetbrains pluginName = Source++ -projectVersion=0.4.2 +projectVersion=0.4.3 pluginSinceBuild = 202.4357 # Plugin Verifier integration -> https://github.com/JetBrains/gradle-intellij-plugin#plugin-verifier-dsl # See https://jb.gg/intellij-platform-builds-list for available build versions From 55d5f14d1917b4b038ac9d03463c582c1f5c498a Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Sat, 19 Mar 2022 10:05:43 +0100 Subject: [PATCH 34/42] don't need --- .../spp/jetbrains/sourcemarker/portal/PortalController.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/portal/PortalController.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/portal/PortalController.kt index 9e8e31f4d..698812541 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/portal/PortalController.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/portal/PortalController.kt @@ -57,9 +57,6 @@ class PortalController(private val markerConfig: SourceMarkerConfig) : Coroutine vertx.deployVerticle(portalServer).await() vertx.deployVerticle(PortalEventListener(markerConfig)).await() -// //todo: remove after v0.4.3 -// vertx.eventBus().registerDefaultCodec(ArtifactQualifiedName::class.java, LocalMessageCodec()) - SourceMarker.addGlobalSourceMarkEventListener { if (it.eventCode == SourceMarkEventCode.MARK_BEFORE_ADDED && it.sourceMark is GutterMark) { //register portal for source mark From 5fd681f799f58582980b977636a5d62b257ab801 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Sat, 19 Mar 2022 10:47:43 +0100 Subject: [PATCH 35/42] Update JVMMarkerUtils.kt --- .../main/kotlin/spp/jetbrains/marker/source/JVMMarkerUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/source/JVMMarkerUtils.kt b/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/source/JVMMarkerUtils.kt index decc810fd..4870bf08d 100755 --- a/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/source/JVMMarkerUtils.kt +++ b/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/source/JVMMarkerUtils.kt @@ -313,7 +313,7 @@ object JVMMarkerUtils { /** * todo: description. * - * @since 0.4.2 + * @since 0.4.3 */ @JvmStatic @JvmOverloads From 10d0cb5ba352f8474aacb9ed32f557efcaa60733 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Sat, 19 Mar 2022 15:38:12 +0100 Subject: [PATCH 36/42] auto-display endpoint quick stats setting --- .../settings/PluginConfigurationPanel.form | 10 +- .../settings/PluginConfigurationPanel.java | 28 ++-- .../settings/SourceMarkerConfig.kt | 3 +- .../view/ActivityQuickStatsIndicator.kt | 143 ++++++++++-------- .../messages/PluginBundle.properties | 3 +- .../messages/PluginBundle_zh.properties | 3 +- 6 files changed, 107 insertions(+), 83 deletions(-) diff --git a/plugin/src/main/java/spp/jetbrains/sourcemarker/settings/PluginConfigurationPanel.form b/plugin/src/main/java/spp/jetbrains/sourcemarker/settings/PluginConfigurationPanel.form index 7e9c4c09e..6cf92fd10 100644 --- a/plugin/src/main/java/spp/jetbrains/sourcemarker/settings/PluginConfigurationPanel.form +++ b/plugin/src/main/java/spp/jetbrains/sourcemarker/settings/PluginConfigurationPanel.form @@ -21,7 +21,7 @@ - + @@ -74,6 +74,14 @@ + + + + + + + + diff --git a/plugin/src/main/java/spp/jetbrains/sourcemarker/settings/PluginConfigurationPanel.java b/plugin/src/main/java/spp/jetbrains/sourcemarker/settings/PluginConfigurationPanel.java index 4a3971224..a91401675 100644 --- a/plugin/src/main/java/spp/jetbrains/sourcemarker/settings/PluginConfigurationPanel.java +++ b/plugin/src/main/java/spp/jetbrains/sourcemarker/settings/PluginConfigurationPanel.java @@ -37,6 +37,7 @@ public class PluginConfigurationPanel { private JComboBox serviceComboBox; private JCheckBox verifyHostCheckBox; private JLabel verifyHostLabel; + private JCheckBox autoDisplayEndpointQuickStatCheckBox; private SourceMarkerConfig config; private CertificatePinPanel myCertificatePins; @@ -45,19 +46,17 @@ public PluginConfigurationPanel(SourceMarkerConfig config) { myServiceSettingsPanel.setBorder(IdeBorderFactory.createTitledBorder(message("service_settings"))); myGlobalSettingsPanel.setBorder(IdeBorderFactory.createTitledBorder(message("plugin_settings"))); - if (INSTANCE.getLiveService() != null) { - INSTANCE.getLiveService().getServices().onComplete(it -> { - if (it.succeeded()) { - it.result().forEach(service -> serviceComboBox.addItem(service.getName())); + INSTANCE.getLiveService().getServices().onComplete(it -> { + if (it.succeeded()) { + it.result().forEach(service -> serviceComboBox.addItem(service.getName())); - if (config.getServiceName() != null) { - serviceComboBox.setSelectedItem(config.getServiceName()); - } - } else { - it.cause().printStackTrace(); + if (config.getServiceName() != null) { + serviceComboBox.setSelectedItem(config.getServiceName()); } - }); - } + } else { + it.cause().printStackTrace(); + } + }); } public JComponent getContentPane() { @@ -89,6 +88,9 @@ boolean isModified() { if (!Objects.equals(serviceComboBox.getSelectedItem(), config.getServiceName())) { return config.getServiceName() != null || serviceComboBox.getSelectedItem() != "All Services"; } + if (!Objects.equals(autoDisplayEndpointQuickStatCheckBox.isSelected(), config.getAutoDisplayEndpointQuickStats())) { + return true; + } return false; } @@ -108,7 +110,8 @@ public SourceMarkerConfig getPluginConfig() { new ArrayList<>(Collections.list(myCertificatePins.listModel.elements())), null, verifyHostCheckBox.isSelected(), - currentService + currentService, + autoDisplayEndpointQuickStatCheckBox.isSelected() ); } @@ -120,6 +123,7 @@ public void applySourceMarkerConfig(SourceMarkerConfig config) { serviceHostTextField.setText(config.getServiceHost()); accessTokenTextField.setText(config.getAccessToken()); verifyHostCheckBox.setSelected(config.getVerifyHost()); + autoDisplayEndpointQuickStatCheckBox.setSelected(config.getAutoDisplayEndpointQuickStats()); myCertificatePins = new CertificatePinPanel(); myCertificatePins.listModel.addAll(config.getCertificatePins()); diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/settings/SourceMarkerConfig.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/settings/SourceMarkerConfig.kt index 0327ddd19..849977eeb 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/settings/SourceMarkerConfig.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/settings/SourceMarkerConfig.kt @@ -33,7 +33,8 @@ data class SourceMarkerConfig( var certificatePins: List = emptyList(), var serviceToken: String? = null, var verifyHost: Boolean = true, - val serviceName: String? = null + val serviceName: String? = null, + var autoDisplayEndpointQuickStats: Boolean = true, ) { companion object { const val DEFAULT_SERVICE_PORT = 5445 diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/view/ActivityQuickStatsIndicator.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/view/ActivityQuickStatsIndicator.kt index 6e1d3d362..69ebe9af8 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/view/ActivityQuickStatsIndicator.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/view/ActivityQuickStatsIndicator.kt @@ -29,6 +29,7 @@ import org.slf4j.LoggerFactory import spp.jetbrains.marker.SourceMarker import spp.jetbrains.marker.jvm.psi.EndpointDetector import spp.jetbrains.marker.source.mark.api.MethodSourceMark +import spp.jetbrains.marker.source.mark.api.SourceMark import spp.jetbrains.marker.source.mark.api.event.SourceMarkEvent import spp.jetbrains.marker.source.mark.api.event.SourceMarkEventCode import spp.jetbrains.marker.source.mark.api.event.SourceMarkEventCode.CUSTOM_EVENT @@ -43,6 +44,8 @@ import spp.jetbrains.monitor.skywalking.toProtocol import spp.jetbrains.sourcemarker.SourceMarkerPlugin.vertx import spp.jetbrains.sourcemarker.command.LiveControlCommand.HIDE_QUICK_STATS import spp.jetbrains.sourcemarker.command.LiveControlCommand.SHOW_QUICK_STATS +import spp.jetbrains.sourcemarker.mark.SourceMarkSearch +import spp.jetbrains.sourcemarker.settings.SourceMarkerConfig import spp.protocol.SourceServices import spp.protocol.SourceServices.Provide.toLiveViewSubscriberAddress import spp.protocol.artifact.QueryTimeFrame @@ -61,7 +64,7 @@ import java.time.temporal.ChronoUnit * Adds activity quick stats as inlay marks above recognized endpoint methods. * Uses a two-minute delay to ensure metrics have been fully collected. */ -class ActivityQuickStatsIndicator : SourceMarkEventListener { +class ActivityQuickStatsIndicator(val config: SourceMarkerConfig) : SourceMarkEventListener { companion object { private val log: Logger = LoggerFactory.getLogger(ActivityQuickStatsIndicator::class.java) @@ -70,74 +73,16 @@ class ActivityQuickStatsIndicator : SourceMarkEventListener { } override fun handleEvent(event: SourceMarkEvent) { - if (event.eventCode == CUSTOM_EVENT && event.params.first() == SHOW_QUICK_STATS) { + if (config.autoDisplayEndpointQuickStats && event.eventCode == SourceMarkEventCode.MARK_USER_DATA_UPDATED) { if (event.sourceMark.getUserData(EndpointDetector.ENDPOINT_ID) != null) { - ApplicationManager.getApplication().runReadAction { - val endTime = ZonedDateTime.now().minusMinutes(1).truncatedTo(ChronoUnit.MINUTES) //exclusive - val startTime = endTime.minusMinutes(2) - val metricsRequest = GetEndpointMetrics( - listOf("endpoint_cpm", "endpoint_avg", "endpoint_sla"), - event.sourceMark.getUserData(EndpointDetector.ENDPOINT_ID)!!, - ZonedDuration(startTime, endTime, SkywalkingClient.DurationStep.MINUTE) - ) + val existingMarks = SourceMarkSearch.findSourceMarks(event.sourceMark.artifactQualifiedName) + if (existingMarks.find { it.getUserData(SHOWING_QUICK_STATS) == true } != null) return - val currentMetrics = runBlocking(vertx.dispatcher()) { - EndpointMetricsBridge.getMetrics(metricsRequest, vertx) - } - val metricResult = toProtocol( - event.sourceMark.artifactQualifiedName, - QueryTimeFrame.LAST_15_MINUTES, //todo: don't need - MetricType.ResponseTime_Average, //todo: dont need - metricsRequest, - currentMetrics - ) - - val inlay = SourceMarker.creationService.createMethodInlayMark( - event.sourceMark.sourceFileMarker, - (event.sourceMark as MethodSourceMark).getPsiElement().nameIdentifier!!, - false - ) - inlay.putUserData(SHOWING_QUICK_STATS, true) - inlay.configuration.virtualText = InlayMarkVirtualText(inlay, formatMetricResult(metricResult)) - inlay.configuration.virtualText!!.textAttributes.foregroundColor = inlayForegroundColor - inlay.configuration.activateOnMouseClick = false - inlay.apply(true) - - SourceServices.Instance.liveView!!.addLiveViewSubscription( - LiveViewSubscription( - null, - listOf(event.sourceMark.getUserData(EndpointDetector.ENDPOINT_NAME)!!), - event.sourceMark.artifactQualifiedName.copy( - operationName = event.sourceMark.getUserData( - EndpointDetector.ENDPOINT_ID - )!! //todo: only SWLiveViewService uses - ), - LiveSourceLocation(event.sourceMark.artifactQualifiedName.identifier, 0), //todo: don't need - LiveViewConfig("ACTIVITY", listOf("endpoint_cpm", "endpoint_avg", "endpoint_sla"), -1) - ) - ).onComplete { - if (it.succeeded()) { - val subscriptionId = it.result().subscriptionId!! - val previousMetrics = mutableMapOf() - vertx.eventBus().consumer(toLiveViewSubscriberAddress(subscriptionId)) { - val viewEvent = Json.decodeValue(it.body().toString(), LiveViewEvent::class.java) - consumeLiveEvent(viewEvent, previousMetrics) - - val twoMinAgoValue = previousMetrics[viewEvent.timeBucket.toLong() - 2] - if (twoMinAgoValue != null) { - inlay.configuration.virtualText!!.updateVirtualText(twoMinAgoValue) - } - } - inlay.addEventListener { - if (it.eventCode == SourceMarkEventCode.MARK_REMOVED) { - SourceServices.Instance.liveView!!.removeLiveViewSubscription(subscriptionId) - } - } - } else { - log.error("Failed to add live view subscription", it.cause()) - } - } - } + displayQuickStatsInlay(event.sourceMark) + } + } else if (event.eventCode == CUSTOM_EVENT && event.params.first() == SHOW_QUICK_STATS) { + if (event.sourceMark.getUserData(EndpointDetector.ENDPOINT_ID) != null) { + displayQuickStatsInlay(event.sourceMark) } } else if (event.eventCode == CUSTOM_EVENT && event.params.first() == HIDE_QUICK_STATS) { val existingQuickStats = event.sourceMark.sourceFileMarker.getSourceMarks().find { @@ -148,6 +93,70 @@ class ActivityQuickStatsIndicator : SourceMarkEventListener { } } + private fun displayQuickStatsInlay(sourceMark: SourceMark) = ApplicationManager.getApplication().runReadAction { + log.info("Displaying quick stats inlay for {}", sourceMark.artifactQualifiedName.identifier) + val endTime = ZonedDateTime.now().minusMinutes(1).truncatedTo(ChronoUnit.MINUTES) //exclusive + val startTime = endTime.minusMinutes(2) + val metricsRequest = GetEndpointMetrics( + listOf("endpoint_cpm", "endpoint_avg", "endpoint_sla"), + sourceMark.getUserData(EndpointDetector.ENDPOINT_ID)!!, + ZonedDuration(startTime, endTime, SkywalkingClient.DurationStep.MINUTE) + ) + + val currentMetrics = runBlocking(vertx.dispatcher()) { EndpointMetricsBridge.getMetrics(metricsRequest, vertx) } + val metricResult = toProtocol( + sourceMark.artifactQualifiedName, + QueryTimeFrame.LAST_15_MINUTES, //todo: don't need + MetricType.ResponseTime_Average, //todo: dont need + metricsRequest, + currentMetrics + ) + + val inlay = SourceMarker.creationService.createMethodInlayMark( + sourceMark.sourceFileMarker, + (sourceMark as MethodSourceMark).getPsiElement().nameIdentifier!!, + false + ) + inlay.putUserData(SHOWING_QUICK_STATS, true) + inlay.configuration.virtualText = InlayMarkVirtualText(inlay, formatMetricResult(metricResult)) + inlay.configuration.virtualText!!.textAttributes.foregroundColor = inlayForegroundColor + inlay.configuration.activateOnMouseClick = false + inlay.apply(true) + + SourceServices.Instance.liveView!!.addLiveViewSubscription( + LiveViewSubscription( + null, + listOf(sourceMark.getUserData(EndpointDetector.ENDPOINT_NAME)!!), + sourceMark.artifactQualifiedName.copy( + operationName = sourceMark.getUserData(EndpointDetector.ENDPOINT_ID)!! //todo: only SWLiveViewService uses + ), + LiveSourceLocation(sourceMark.artifactQualifiedName.identifier, 0), //todo: don't need + LiveViewConfig("ACTIVITY", listOf("endpoint_cpm", "endpoint_avg", "endpoint_sla"), -1) + ) + ).onComplete { + if (it.succeeded()) { + val subscriptionId = it.result().subscriptionId!! + val previousMetrics = mutableMapOf() + vertx.eventBus().consumer(toLiveViewSubscriberAddress(subscriptionId)) { + val viewEvent = Json.decodeValue(it.body().toString(), LiveViewEvent::class.java) + consumeLiveEvent(viewEvent, previousMetrics) + + val twoMinAgoValue = previousMetrics[viewEvent.timeBucket.toLong() - 2] + if (twoMinAgoValue != null) { + inlay.configuration.virtualText!!.updateVirtualText(twoMinAgoValue) + } + } + inlay.addEventListener { + if (it.eventCode == SourceMarkEventCode.MARK_REMOVED) { + SourceServices.Instance.liveView!!.removeLiveViewSubscription(subscriptionId) + } + } + } else { + log.error("Failed to add live view subscription", it.cause()) + } + } + } + private fun formatMetricResult(result: ArtifactMetricResult): String { val sb = StringBuilder() val resp = result.artifactMetrics.find { it.metricType == MetricType.Throughput_Average }!! diff --git a/plugin/src/main/resources/messages/PluginBundle.properties b/plugin/src/main/resources/messages/PluginBundle.properties index df4591f7d..de2aa3a8e 100644 --- a/plugin/src/main/resources/messages/PluginBundle.properties +++ b/plugin/src/main/resources/messages/PluginBundle.properties @@ -44,4 +44,5 @@ report.error.connection.failure=Could not communicate with GitHub git.issue.title=[auto-generated:{0}] {1} git.issue.text=Created issue {1}. Thanks for your feedback, please comment (to further discuss with us) if possible! git.issue.duplicate.text=A similar issue was already reported (#{1}). Thanks for your feedback! -access_token=Access Token \ No newline at end of file +access_token=Access Token +auto_display_endpoint_quick_stats=Auto-display endpoint quick stats \ No newline at end of file diff --git a/plugin/src/main/resources/messages/PluginBundle_zh.properties b/plugin/src/main/resources/messages/PluginBundle_zh.properties index e67134ca3..d92b9f888 100644 --- a/plugin/src/main/resources/messages/PluginBundle_zh.properties +++ b/plugin/src/main/resources/messages/PluginBundle_zh.properties @@ -43,4 +43,5 @@ report.error.connection.failure=无法与GitHub的沟通 git.issue.title=[auto-generated:{0}] {1} git.issue.text=已创建的问题 {1}. 感谢您的反馈,如果可能,请发表评论(与我们进一步讨论)! git.issue.duplicate.text=已经报告了类似的问题 (#{1}). 感谢您的反馈意见! -access_token=访问令牌 \ No newline at end of file +access_token=访问令牌 +auto_display_endpoint_quick_stats=自动显示端点快速统计 \ No newline at end of file From 0459a94306e13a56f6a91e8b299a5a15e49c60c2 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Sat, 19 Mar 2022 15:38:27 +0100 Subject: [PATCH 37/42] auto-display endpoint quick stats setting --- .../kotlin/spp/jetbrains/sourcemarker/SourceMarkerPlugin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/SourceMarkerPlugin.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/SourceMarkerPlugin.kt index 171faac60..f98dc1360 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/SourceMarkerPlugin.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/SourceMarkerPlugin.kt @@ -456,7 +456,7 @@ object SourceMarkerPlugin { private fun initMarker(config: SourceMarkerConfig, project: Project) { log.info("Initializing marker") SourceMarker.addGlobalSourceMarkEventListener(PluginSourceMarkEventListener()) - SourceMarker.addGlobalSourceMarkEventListener(ActivityQuickStatsIndicator()) + SourceMarker.addGlobalSourceMarkEventListener(ActivityQuickStatsIndicator(config)) val gutterMarkConfig = GutterMarkConfiguration() gutterMarkConfig.activateOnMouseHover = false From 0b509f5270a9c104f6d09b80144b9ce87eb41363 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Sat, 19 Mar 2022 15:38:40 +0100 Subject: [PATCH 38/42] change default --- .../spp/jetbrains/sourcemarker/settings/SourceMarkerConfig.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/settings/SourceMarkerConfig.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/settings/SourceMarkerConfig.kt index 849977eeb..323f19456 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/settings/SourceMarkerConfig.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/settings/SourceMarkerConfig.kt @@ -25,7 +25,7 @@ package spp.jetbrains.sourcemarker.settings */ data class SourceMarkerConfig( var rootSourcePackages: List = emptyList(), - var autoResolveEndpointNames: Boolean = false, + var autoResolveEndpointNames: Boolean = true, var localMentorEnabled: Boolean = true, var pluginConsoleEnabled: Boolean = false, var serviceHost: String? = null, From e2d72e23e3d35c5fceecf211cb353594981d20c1 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Sat, 19 Mar 2022 15:59:08 +0100 Subject: [PATCH 39/42] impl auto-resolve for SWLiveService --- .../portal/PortalEventListener.kt | 56 +++++++++---------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/portal/PortalEventListener.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/portal/PortalEventListener.kt index 4e1c0624c..97ce93ea9 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/portal/PortalEventListener.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/portal/PortalEventListener.kt @@ -498,44 +498,36 @@ class PortalEventListener( pageNumber = portal.tracesView.pageNumber ), vertx ) - - handleTraceResult(traceResult, portal, portal.viewingArtifact) + vertx.eventBus().send(ArtifactTracesUpdated, traceResult) + autoResolveEndpointNamesIfNecessary(traceResult, portal) } } } - private fun handleTraceResult( - traceResult: TraceResult, - portal: SourcePortal, - artifactQualifiedName: ArtifactQualifiedName - ) { - //todo: rename {GET} to [GET] in skywalking + private suspend fun autoResolveEndpointNamesIfNecessary(traceResult: TraceResult, portal: SourcePortal) { if (markerConfig.autoResolveEndpointNames) { - launch(vertx.dispatcher()) { - //todo: only try to auto resolve endpoint names with dynamic ids - //todo: support multiple operationsNames/traceIds - traceResult.traces.forEach { - if (!portal.tracesView.resolvedEndpointNames.containsKey(it.traceIds[0])) { - val traceStack = EndpointTracesBridge.getTraceStack(it.traceIds[0], vertx) - val entrySpan: TraceSpan? = traceStack.traceSpans.firstOrNull { it.type == "Entry" } - if (entrySpan != null) { - val url = entrySpan.tags["url"] - val httpMethod = entrySpan.tags["http.method"] - if (url != null && httpMethod != null) { - val updatedEndpointName = "{$httpMethod}${URI(url).path}" - vertx.eventBus().send( - TraceSpanUpdated, entrySpan.copy( - endpointName = updatedEndpointName, - artifactQualifiedName = artifactQualifiedName - ) + //todo: only try to auto resolve endpoint names with dynamic ids + //todo: support multiple operationsNames/traceIds + traceResult.traces.forEach { + if (!portal.tracesView.resolvedEndpointNames.containsKey(it.traceIds[0])) { + val traceStack = EndpointTracesBridge.getTraceStack(it.traceIds[0], vertx) + val entrySpan: TraceSpan? = traceStack.traceSpans.firstOrNull { it.type == "Entry" } + if (entrySpan != null) { + val url = entrySpan.tags["url"] + val httpMethod = entrySpan.tags["http.method"] + if (url != null && httpMethod != null) { + val updatedEndpointName = "$httpMethod:${URI(url).path}" + vertx.eventBus().send( + TraceSpanUpdated, entrySpan.copy( + endpointName = updatedEndpointName, + artifactQualifiedName = portal.viewingArtifact ) - } + ) } } } } } - vertx.eventBus().send(ArtifactTracesUpdated, traceResult) } private suspend fun pullLatestLogs(portal: SourcePortal) { @@ -740,17 +732,23 @@ class PortalEventListener( ) vertx.eventBus().send(ArtifactTracesUpdated, traceResult) + //S++ adds trace meta to avoid additional query for auto-resolve endpoints val url = trace.meta["url"] val httpMethod = trace.meta["http.method"] - if (url != null && httpMethod != null) { + val entrySpanJson = trace.meta["entrySpan"] + if (url != null && httpMethod != null && entrySpanJson != null) { val updatedEndpointName = "$httpMethod:${URI(url).path}" - val entrySpan = Json.decodeValue(trace.meta["entrySpan"], TraceSpan::class.java) + val entrySpan = Json.decodeValue(entrySpanJson, TraceSpan::class.java) vertx.eventBus().send( TraceSpanUpdated, entrySpan.copy( endpointName = updatedEndpointName, artifactQualifiedName = event.artifactQualifiedName ) ) + } else { + launch(vertx.dispatcher()) { + autoResolveEndpointNamesIfNecessary(traceResult, portal) + } } } From cdb202d1bb77c4e9045f2d2a4ef8689087f4f0ab Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Sat, 19 Mar 2022 16:52:17 +0100 Subject: [PATCH 40/42] fix compatibility issues --- .../jvm/psi/endpoint/SpringMVCEndpoint.kt | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/jvm/psi/endpoint/SpringMVCEndpoint.kt b/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/jvm/psi/endpoint/SpringMVCEndpoint.kt index f219ee4a0..d9c4f8cc8 100644 --- a/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/jvm/psi/endpoint/SpringMVCEndpoint.kt +++ b/marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/jvm/psi/endpoint/SpringMVCEndpoint.kt @@ -28,7 +28,7 @@ import org.jetbrains.uast.java.JavaUSimpleNameReferenceExpression import org.jetbrains.uast.kotlin.KotlinStringULiteralExpression import org.jetbrains.uast.kotlin.KotlinUQualifiedReferenceExpression import org.jetbrains.uast.kotlin.KotlinUSimpleReferenceExpression -import org.jetbrains.uast.kotlin.expressions.KotlinUCollectionLiteralExpression +import org.jooq.tools.reflect.Reflect import spp.jetbrains.marker.jvm.psi.EndpointDetector import spp.jetbrains.marker.jvm.psi.EndpointDetector.DetectedEndpoint import java.util.* @@ -206,12 +206,12 @@ class SpringMVCEndpoint : EndpointDetector.EndpointNameDeterminer { } val methodExpr = annotation.attributeValues.find { it.name == "method" }!!.expression - var value = if (endpointNameExpr is KotlinUCollectionLiteralExpression) { - endpointNameExpr.valueArguments[0].evaluate() + var value = if (endpointNameExpr?.javaClass?.simpleName?.equals("KotlinUCollectionLiteralExpression") == true) { + getField>(endpointNameExpr, "valueArguments")[0].evaluate() } else { endpointNameExpr?.evaluate() ?: "" } - val valueArg = (methodExpr as KotlinUCollectionLiteralExpression).valueArguments[0] + val valueArg = getField>(methodExpr, "valueArguments")[0] val method = if (valueArg is KotlinUSimpleReferenceExpression) { valueArg.resolvedName } else if (valueArg is KotlinUQualifiedReferenceExpression) { @@ -224,8 +224,8 @@ class SpringMVCEndpoint : EndpointDetector.EndpointNameDeterminer { } else { var valueExpr = annotation.findAttributeValue("value") if (valueExpr == null) valueExpr = annotation.findAttributeValue("path") - var value = if (valueExpr is KotlinUCollectionLiteralExpression) { - valueExpr.valueArguments[0].evaluate() + var value = if (valueExpr?.javaClass?.simpleName?.equals("KotlinUCollectionLiteralExpression") == true) { + getField>(valueExpr, "valueArguments")[0].evaluate() } else if (valueExpr != null) { valueExpr.evaluate() } else { @@ -276,8 +276,8 @@ class SpringMVCEndpoint : EndpointDetector.EndpointNameDeterminer { if (valueExpr is UastEmptyExpression) valueExpr = annotation.findAttributeValue("path") //todo: have to call this twice??? if (valueExpr is UastEmptyExpression) valueExpr = null - var value = if (valueExpr is KotlinUCollectionLiteralExpression) { - valueExpr.valueArguments[0].evaluate() + var value = if (valueExpr?.javaClass?.simpleName?.equals("KotlinUCollectionLiteralExpression") == true) { + getField>(valueExpr, "valueArguments")[0].evaluate() } else if (valueExpr != null) { valueExpr.evaluate() } else { @@ -289,4 +289,20 @@ class SpringMVCEndpoint : EndpointDetector.EndpointNameDeterminer { return Optional.of(DetectedEndpoint("$method:$value", false, value.toString(), method)) } } + + private fun getField(value: Any, name: String): T { + val fields = Reflect.on(value).fields() + return if (fields.containsKey(name)) { + fields[name]!!.get() + } else if (fields.containsKey("$name\$delegate")) { + val value = fields["$name\$delegate"]!!.get() + return if (value is Lazy<*>) { + value.value as T + } else { + value as T + } + } else { + throw IllegalArgumentException("Field $name not found") + } + } } From 19277b8044118e3ade8a51cf345201f16120789a Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Sat, 19 Mar 2022 17:01:51 +0100 Subject: [PATCH 41/42] fix compatibility issues --- plugin/build.gradle.kts | 1 - .../activities/PluginSourceMarkerStartupActivity.kt | 13 ------------- 2 files changed, 14 deletions(-) diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index 6e91d031c..a62b0e0d6 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -40,7 +40,6 @@ intellij { } tasks.getByName("buildSearchableOptions").onlyIf { false } //todo: figure out how to remove tasks.getByName("runIde") { - systemProperty("sourcemarker.debug.capture_logs", true) systemProperty("ide.enable.slow.operations.in.edt", false) systemProperty("ide.browser.jcef.contextMenu.devTools.enabled", true) } diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/activities/PluginSourceMarkerStartupActivity.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/activities/PluginSourceMarkerStartupActivity.kt index 2cc4ae22c..b8ceecdff 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/activities/PluginSourceMarkerStartupActivity.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/activities/PluginSourceMarkerStartupActivity.kt @@ -24,9 +24,6 @@ import com.intellij.openapi.application.ApplicationInfo import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.project.Project import kotlinx.coroutines.runBlocking -import org.apache.log4j.FileAppender -import org.apache.log4j.Logger -import org.apache.log4j.PatternLayout import spp.jetbrains.marker.plugin.SourceMarkerStartupActivity import spp.jetbrains.sourcemarker.PluginBundle import spp.jetbrains.sourcemarker.SourceMarkerPlugin @@ -48,16 +45,6 @@ class PluginSourceMarkerStartupActivity : SourceMarkerStartupActivity() { val SUPPORTED_PRODUCT_CODES = PYCHARM_PRODUCT_CODES + INTELLIJ_PRODUCT_CODES } - init { - if (System.getProperty("sourcemarker.debug.capture_logs", "false")!!.toBoolean()) { - val fa = FileAppender() - fa.file = "/tmp/sourcemarker.log" - fa.layout = PatternLayout("%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n") - fa.activateOptions() - Logger.getLogger("spp.jetbrains").addAppender(fa) - } - } - override fun runActivity(project: Project) { if (ApplicationManager.getApplication().isUnitTestMode) { return //tests manually set up necessary components From 4d38574318ee415fff0f5d2fcf510763abc97506 Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Sat, 19 Mar 2022 17:38:15 +0100 Subject: [PATCH 42/42] fix compatibility issues --- .../jetbrains/marker/plugin/SourceInlayHintProvider.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/marker/src/main/kotlin/spp/jetbrains/marker/plugin/SourceInlayHintProvider.kt b/marker/src/main/kotlin/spp/jetbrains/marker/plugin/SourceInlayHintProvider.kt index 82a799cb3..f824e1024 100644 --- a/marker/src/main/kotlin/spp/jetbrains/marker/plugin/SourceInlayHintProvider.kt +++ b/marker/src/main/kotlin/spp/jetbrains/marker/plugin/SourceInlayHintProvider.kt @@ -32,6 +32,7 @@ import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.ui.paint.EffectPainter +import org.joor.Reflect import org.slf4j.LoggerFactory import spp.jetbrains.marker.SourceMarker import spp.jetbrains.marker.SourceMarker.getSourceFileMarker @@ -91,10 +92,10 @@ abstract class SourceInlayHintProvider : InlayHintsProvider { //todo: smaller range ?.getBlockElementsInRange(0, Integer.MAX_VALUE)?.forEach { if (it.renderer is BlockInlayRenderer) { - if ((it.renderer as BlockInlayRenderer).getCachedPresentation() is RecursivelyUpdatingRootPresentation) { - val rootPresentation = (it.renderer as BlockInlayRenderer).getCachedPresentation() as RecursivelyUpdatingRootPresentation - if (rootPresentation.content is StaticDelegatePresentation) { - val delegatePresentation = rootPresentation.content as StaticDelegatePresentation + val cachedPresentation = Reflect.on(it.renderer).field("cachedPresentation").get() + if (cachedPresentation is RecursivelyUpdatingRootPresentation) { + if (cachedPresentation.content is StaticDelegatePresentation) { + val delegatePresentation = cachedPresentation.content as StaticDelegatePresentation if (delegatePresentation.presentation is DynamicTextInlayPresentation) { val dynamicPresentation = delegatePresentation.presentation as DynamicTextInlayPresentation if (dynamicPresentation.inlayMark == event.sourceMark) {