diff --git a/mapper/build.gradle.kts b/mapper/build.gradle.kts index f3f7d362c..cb2c10937 100644 --- a/mapper/build.gradle.kts +++ b/mapper/build.gradle.kts @@ -24,7 +24,7 @@ repositories { } dependencies { - implementation("com.github.sourceplusplus.protocol:protocol:473051b4e5") + implementation("com.github.sourceplusplus.protocol:protocol:2bd4bea9ad") implementation("com.github.sh5i:git-stein:v0.5.0") implementation("org.apache.commons:commons-lang3:3.12.0") implementation("org.eclipse.jgit:org.eclipse.jgit:6.0.0.202111291000-r") diff --git a/marker/build.gradle.kts b/marker/build.gradle.kts index a55dc3b0e..6ed34f049 100644 --- a/marker/build.gradle.kts +++ b/marker/build.gradle.kts @@ -30,7 +30,7 @@ dependencies { val intellijVersion = "213.6777.52" compileOnly("org.jooq:joor:$joorVersion") - compileOnly("com.github.sourceplusplus.protocol:protocol:473051b4e5") + compileOnly("com.github.sourceplusplus.protocol:protocol:2bd4bea9ad") compileOnly("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinVersion") compileOnly("org.jetbrains.kotlin:kotlin-stdlib-jdk8") compileOnly("com.google.guava:guava:31.0.1-jre") diff --git a/marker/jvm-marker/build.gradle.kts b/marker/jvm-marker/build.gradle.kts index 5373d0151..4aaa44cad 100644 --- a/marker/jvm-marker/build.gradle.kts +++ b/marker/jvm-marker/build.gradle.kts @@ -21,7 +21,7 @@ dependencies { compileOnly(project(":marker")) compileOnly(project(":monitor")) } - compileOnly("com.github.sourceplusplus.protocol:protocol:473051b4e5") + compileOnly("com.github.sourceplusplus.protocol:protocol:2bd4bea9ad") val intellijVersion = "213.6777.52" implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinVersion") diff --git a/marker/py-marker/build.gradle.kts b/marker/py-marker/build.gradle.kts index f7a8a588f..005753418 100644 --- a/marker/py-marker/build.gradle.kts +++ b/marker/py-marker/build.gradle.kts @@ -18,7 +18,7 @@ dependencies { } else { compileOnly(project(":marker")) } - compileOnly("com.github.sourceplusplus.protocol:protocol:473051b4e5") + compileOnly("com.github.sourceplusplus.protocol:protocol:2bd4bea9ad") val intellijVersion = "213.6777.52" implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinVersion") 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 0ccc6ef2c..53dd4a98e 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 @@ -21,6 +21,7 @@ import com.intellij.openapi.Disposable import com.intellij.openapi.editor.Editor import com.intellij.psi.PsiElement import com.intellij.psi.PsiInvalidElementAccessException +import spp.jetbrains.marker.SourceMarker import spp.jetbrains.marker.SourceMarker.namingService import spp.jetbrains.marker.source.SourceFileMarker import spp.jetbrains.marker.source.mark.api.component.api.SourceMarkComponent @@ -31,6 +32,7 @@ import spp.jetbrains.marker.source.mark.api.key.SourceKey import spp.jetbrains.marker.source.mark.gutter.GutterMark import spp.jetbrains.marker.source.mark.inlay.InlayMark import spp.protocol.artifact.ArtifactQualifiedName +import spp.protocol.artifact.ArtifactType import java.util.* /** @@ -96,6 +98,16 @@ abstract class ExpressionSourceMark( super.dispose(removeFromMarker, assertRemoval) } + fun getParentSourceMark(): SourceMark? { + return SourceMarker.getSourceMark( + artifactQualifiedName.copy( + identifier = artifactQualifiedName.identifier.substringBefore("#"), + type = ArtifactType.METHOD + ), + SourceMark.Type.GUTTER + ) + } + private val userData = HashMap() override fun getUserData(key: SourceKey): T? = userData[key] as T? override fun putUserData(key: SourceKey, value: T?) { diff --git a/monitor/build.gradle.kts b/monitor/build.gradle.kts index 50c85c418..b81cb760d 100644 --- a/monitor/build.gradle.kts +++ b/monitor/build.gradle.kts @@ -10,7 +10,7 @@ val projectVersion: String by project val slf4jVersion: String by project dependencies { - implementation("com.github.sourceplusplus.protocol:protocol:473051b4e5") + implementation("com.github.sourceplusplus.protocol:protocol:2bd4bea9ad") implementation("org.slf4j:slf4j-api:$slf4jVersion") implementation("com.apollographql.apollo3:apollo-runtime:$apolloVersion") api("com.apollographql.apollo3:apollo-api:$apolloVersion") diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index 1506c850e..deb6c620d 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -65,7 +65,7 @@ dependencies { implementation(project(":marker:py-marker")) implementation(project(":monitor")) implementation("com.github.sourceplusplus.interface-portal:portal-jvm:$projectVersion") { isTransitive = false } - implementation("com.github.sourceplusplus.protocol:protocol:473051b4e5") + implementation("com.github.sourceplusplus.protocol:protocol:2bd4bea9ad") } implementation("org.jooq:joor:$joorVersion") 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 579c4f5b1..c56bfa771 100644 --- a/plugin/src/main/java/spp/jetbrains/sourcemarker/status/LogStatusBar.java +++ b/plugin/src/main/java/spp/jetbrains/sourcemarker/status/LogStatusBar.java @@ -13,11 +13,13 @@ import com.intellij.util.ui.ListTableModel; import com.intellij.util.ui.UIUtil; import io.vertx.core.json.JsonObject; +import io.vertx.core.json.JsonObject; import net.miginfocom.swing.MigLayout; import org.jetbrains.annotations.NotNull; import spp.jetbrains.marker.source.mark.inlay.InlayMark; import spp.jetbrains.sourcemarker.PluginIcons; import spp.jetbrains.sourcemarker.PluginUI; +import spp.jetbrains.sourcemarker.SourceMarkerPlugin; import spp.jetbrains.sourcemarker.command.AutocompleteFieldRow; import spp.jetbrains.sourcemarker.mark.SourceMarkKeys; import spp.jetbrains.sourcemarker.service.InstrumentEventListener; @@ -26,11 +28,13 @@ import spp.jetbrains.sourcemarker.settings.LiveLogConfigurationPanel; import spp.jetbrains.sourcemarker.status.util.AutocompleteField; import spp.protocol.artifact.log.Log; +import spp.protocol.artifact.log.LogResult; import spp.protocol.instrument.LiveInstrument; import spp.protocol.instrument.LiveLog; import spp.protocol.instrument.LiveSourceLocation; import spp.protocol.instrument.event.LiveInstrumentEvent; import spp.protocol.instrument.event.LiveInstrumentRemoved; +import spp.protocol.instrument.event.LiveLogHit; import spp.protocol.instrument.throttle.InstrumentThrottle; import spp.protocol.instrument.throttle.ThrottleStep; @@ -57,6 +61,7 @@ import static spp.jetbrains.marker.SourceMarker.conditionParser; import static spp.jetbrains.sourcemarker.PluginUI.*; import static spp.jetbrains.sourcemarker.status.util.ViewUtils.addRecursiveMouseListener; +import static spp.protocol.ProtocolAddress.Global.ArtifactLogUpdated; import static spp.protocol.marshall.ProtocolMarshaller.deserializeLiveInstrumentRemoved; import static spp.protocol.SourceServices.Instance.INSTANCE; import static spp.protocol.instrument.event.LiveInstrumentEventType.LOG_HIT; @@ -76,6 +81,7 @@ public class LogStatusBar extends JPanel implements StatusBar, VisibleAreaListen private final List scopeVars; private final Function> lookup; private final String placeHolderText; + private final boolean watchExpression; private EditorImpl editor; private LiveLog liveLog; private Instant latestTime; @@ -97,7 +103,8 @@ public class LogStatusBar extends JPanel implements StatusBar, VisibleAreaListen new ArrayList<>(), 0, SortOrder.DESCENDING); private final Pattern varPattern; - public LogStatusBar(LiveSourceLocation sourceLocation, List scopeVars, InlayMark inlayMark) { + public LogStatusBar(LiveSourceLocation sourceLocation, List scopeVars, InlayMark inlayMark, + boolean watchExpression) { this.sourceLocation = sourceLocation; this.scopeVars = scopeVars.stream().map(it -> new AutocompleteFieldRow() { public String getText() { @@ -133,16 +140,49 @@ public Icon getIcon() { varPattern = VariableParser.createPattern(scopeVars, "$", true, false); this.inlayMark = inlayMark; + this.watchExpression = watchExpression; - placeHolderText = "Input log message (use $ for variables)"; + if (watchExpression) { + placeHolderText = WAITING_FOR_LIVE_LOG_DATA; + } else { + placeHolderText = "Input log message (use $ for variables)"; + } initComponents(); setupComponents(); - showEditableMode(); - liveLogTextField.setEditMode(true); + if (watchExpression) { + liveLogTextField.setCanShowSaveButton(false); + liveLogTextField.setEditMode(false); + removeActiveDecorations(); + configDropdownLabel.setVisible(false); + displayTimeField(); + addExpandButton(); - liveLogTextField.addSaveListener(this::saveLiveLog); + SourceMarkerPlugin.INSTANCE.getVertx().eventBus().consumer(ArtifactLogUpdated, event -> { + LogResult logResult = (LogResult) event.body(); + if (!inlayMark.getArtifactQualifiedName().equals(logResult.getArtifactQualifiedName())) { + return; + } + Log latestLog = logResult.getLogs().get(0); + setLatestLog(Instant.now(), latestLog); + + JsonObject logJson = JsonObject.mapFrom(new LiveLogHit( //todo: real hit info + "-1", latestLog.getTimestamp(), "null", "null", logResult + )); + logJson.getJsonObject("logResult").getJsonArray("logs").forEach(it -> { + JsonObject log = (JsonObject) it; + log.remove("formattedMessage"); + }); + + LiveInstrumentEvent liveInstrumentEvent = new LiveInstrumentEvent(LOG_HIT, logJson.toString()); + commandModel.insertRow(0, liveInstrumentEvent); + }); + } else { + showEditableMode(); + liveLogTextField.setEditMode(true); + liveLogTextField.addSaveListener(this::saveLiveLog); + } } public void setLiveInstrument(LiveInstrument liveInstrument) { @@ -164,14 +204,14 @@ public void setWrapperPanel(JPanel wrapperPanel) { @Override public void visibleAreaChanged(@NotNull VisibleAreaEvent e) { liveLogTextField.hideAutocompletePopup(); - if(popup != null) { + if (popup != null) { popup.dispose(); popup = null; } } public void setLatestLog(Instant time, Log latestLog) { - if (liveLog == null) return; + if (liveLog == null && !watchExpression) return; this.latestTime = time; this.latestLog = latestLog; @@ -373,7 +413,7 @@ public void keyTyped(KeyEvent e) { liveLogTextField.addFocusListener(new FocusAdapter() { @Override public void focusGained(FocusEvent e) { - if (errored || liveLogTextField.getEditMode()) return; + if (watchExpression || errored || liveLogTextField.getEditMode()) return; liveLogTextField.setEditMode(true); if (liveLog != null) { @@ -405,7 +445,7 @@ public void mouseClicked(MouseEvent e) { @Override public void mouseEntered(MouseEvent mouseEvent) { - if (!errored && !removed) showEditableMode(); + if (!watchExpression && !errored && !removed) showEditableMode(); } @Override @@ -454,7 +494,7 @@ public void mouseReleased(MouseEvent e) { configPanel.addMouseMotionListener(new MouseAdapter() { @Override public void mouseMoved(MouseEvent e) { - if (!errored && !removed) configPanel.setBackground(CNFG_PANEL_FOCUS_COLOR); + if (!watchExpression && !errored && !removed) configPanel.setBackground(CNFG_PANEL_FOCUS_COLOR); } }); @@ -462,7 +502,8 @@ public void mouseMoved(MouseEvent e) { addRecursiveMouseListener(configPanel, new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { - if (!errored && !removed && System.currentTimeMillis() - popupLastOpened.get() > 200) { + if (!watchExpression && !errored && !removed + && System.currentTimeMillis() - popupLastOpened.get() > 200) { ApplicationManager.getApplication().runWriteAction(() -> showConfigurationPopup(popupLastOpened)); } } 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 6ca38a637..8185036eb 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/ControlBarController.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/ControlBarController.kt @@ -32,6 +32,7 @@ import spp.jetbrains.marker.source.mark.api.SourceMark import spp.jetbrains.marker.source.mark.api.component.swing.SwingSourceMarkComponentProvider import spp.jetbrains.marker.source.mark.api.event.SourceMarkEvent import spp.jetbrains.marker.source.mark.api.event.SourceMarkEventCode +import spp.jetbrains.marker.source.mark.inlay.ExpressionInlayMark import spp.jetbrains.marker.source.mark.inlay.InlayMark import spp.jetbrains.sourcemarker.ControlBar import spp.jetbrains.sourcemarker.SourceMarkerPlugin @@ -66,12 +67,40 @@ object ControlBarController { } } + private fun determineAvailableCommands(inlayMark: ExpressionInlayMark): List { + val availableCommandsAtLocation = availableCommands.toMutableList() + val parentMark = inlayMark.getParentSourceMark() + if (parentMark is MethodSourceMark) { + val loggerDetector = parentMark.getUserData(SourceMarkKeys.LOGGER_DETECTOR) + if (loggerDetector != null) { + runBlocking { + val detectedLogs = loggerDetector.getOrFindLoggerStatements(parentMark) + val logOnCurrentLine = detectedLogs.find { it.lineLocation == inlayMark.lineNumber } + if (logOnCurrentLine != null) { + availableCommandsAtLocation.add(WATCH_LOG) + } + } + } + } + return availableCommandsAtLocation + } + fun handleCommandInput(input: String, editor: Editor) { log.info("Processing command input: {}", input) when (input) { VIEW_ACTIVITY.command -> handleViewPortalCommand(editor, VIEW_ACTIVITY) VIEW_TRACES.command -> handleViewPortalCommand(editor, VIEW_TRACES) VIEW_LOGS.command -> handleViewPortalCommand(editor, VIEW_LOGS) + WATCH_LOG.command -> { + //replace command inlay with log status inlay + val prevCommandBar = previousControlBar!! + previousControlBar!!.dispose() + previousControlBar = null + + ApplicationManager.getApplication().runWriteAction { + LiveStatusManager.showLogStatusBar(editor, prevCommandBar.lineNumber, true) + } + } ADD_LIVE_BREAKPOINT.command -> { //replace command inlay with breakpoint status inlay val prevCommandBar = previousControlBar!! @@ -89,7 +118,7 @@ object ControlBarController { previousControlBar = null ApplicationManager.getApplication().runWriteAction { - LiveStatusManager.showLogStatusBar(editor, prevCommandBar.lineNumber) + LiveStatusManager.showLogStatusBar(editor, prevCommandBar.lineNumber, false) } } ADD_LIVE_METER.command -> { @@ -253,7 +282,7 @@ object ControlBarController { val wrapperPanel = JPanel() wrapperPanel.layout = BorderLayout() - val controlBar = ControlBar(editor, inlayMark, availableCommands) + val controlBar = ControlBar(editor, inlayMark, determineAvailableCommands(inlayMark)) wrapperPanel.add(controlBar) editor.scrollingModel.addVisibleAreaListener(controlBar) 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 e24fc939b..94f34358b 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/LiveControlCommand.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/command/LiveControlCommand.kt @@ -52,6 +52,12 @@ enum class LiveControlCommand( PluginIcons.Command.viewLogsSelected, PluginIcons.Command.viewLogsUnSelected ), + WATCH_LOG( + "Watch Log", + "Live View ➛ Log ➛ Scope: Expression", + PluginIcons.Command.viewLogsSelected, + PluginIcons.Command.viewLogsUnSelected + ), WATCH_VARIABLE( "watch", "Manual Tracing ➛ Watched Variables ➛ Scope: Local / Add *variable* to watched variables" diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/discover/TCPServiceDiscoveryBackend.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/discover/TCPServiceDiscoveryBackend.kt index 736abc47e..ddc5a709b 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/discover/TCPServiceDiscoveryBackend.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/discover/TCPServiceDiscoveryBackend.kt @@ -166,21 +166,10 @@ class TCPServiceDiscoveryBackend : ServiceDiscoveryBackend { } } - override fun store(record: Record, resultHandler: Handler>) { - TODO("Not yet implemented") - } - - override fun remove(record: Record, resultHandler: Handler>) { - TODO("Not yet implemented") - } - - override fun remove(uuid: String, resultHandler: Handler>) { - TODO("Not yet implemented") - } - - override fun update(record: Record, resultHandler: Handler>) { - TODO("Not yet implemented") - } + override fun store(record: Record, resultHandler: Handler>) = Unit + override fun remove(record: Record, resultHandler: Handler>) = Unit + override fun remove(uuid: String, resultHandler: Handler>) = Unit + override fun update(record: Record, resultHandler: Handler>) = Unit override fun getRecords(resultHandler: Handler>>) { if (setupFuture.isComplete) { @@ -212,9 +201,6 @@ class TCPServiceDiscoveryBackend : ServiceDiscoveryBackend { } } - override fun getRecord(uuid: String, resultHandler: Handler>) { - TODO("Not yet implemented") - } - + override fun getRecord(uuid: String, resultHandler: Handler>) = Unit override fun name() = "tcp-service-discovery" } diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/search/SourceMarkSearch.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/search/SourceMarkSearch.kt index ca5f36334..48f94aab8 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/search/SourceMarkSearch.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/search/SourceMarkSearch.kt @@ -40,27 +40,6 @@ object SourceMarkSearch { } } - fun findByMeterId(meterId: String): SourceMark? { - return SourceMarker.getSourceMarks() - .firstOrNull { - it.getUserData(SourceMarkKeys.METER_ID) == meterId - } - } - - fun findByLogId(logId: String): SourceMark? { - return SourceMarker.getSourceMarks() - .firstOrNull { - it.getUserData(SourceMarkKeys.LOG_ID) == logId - } - } - - fun findByBreakpointId(breakpointId: String): SourceMark? { - return SourceMarker.getSourceMarks() - .firstOrNull { - it.getUserData(SourceMarkKeys.BREAKPOINT_ID) == breakpointId - } - } - fun findByInstrumentId(instrumentId: String): SourceMark? { return SourceMarker.getSourceMarks() .firstOrNull { @@ -73,7 +52,8 @@ object SourceMarkSearch { suspend fun findSourceMark(artifact: ArtifactQualifiedName): SourceMark? { return when (artifact.type) { ArtifactType.ENDPOINT -> findEndpointSourceMark(artifact) - ArtifactType.STATEMENT -> findExpressionAdvice(artifact) + ArtifactType.STATEMENT -> findExpressionSourceMark(artifact) + ArtifactType.EXPRESSION -> findExpressionSourceMark(artifact) else -> TODO("impl") } } @@ -120,7 +100,11 @@ object SourceMarkSearch { } } - private fun findExpressionAdvice(artifact: ArtifactQualifiedName): ExpressionSourceMark? { + private fun findExpressionSourceMark(artifact: ArtifactQualifiedName): ExpressionSourceMark? { + if (artifact.type == ArtifactType.EXPRESSION) { + return SourceMarker.getSourceMarks().find { it.artifactQualifiedName == artifact } as ExpressionSourceMark? + } + val qualifiedClassName = artifact.identifier.substring(0, artifact.identifier.lastIndexOf(".")) val fileMarker = SourceMarker.getSourceFileMarker(qualifiedClassName) return if (fileMarker != null) { diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/service/LiveInstrumentManager.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/service/LiveInstrumentManager.kt index f4903f7f9..944a9d0e5 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/service/LiveInstrumentManager.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/service/LiveInstrumentManager.kt @@ -37,7 +37,6 @@ import spp.jetbrains.sourcemarker.service.breakpoint.BreakpointTriggerListener import spp.jetbrains.sourcemarker.settings.SourceMarkerConfig import spp.jetbrains.sourcemarker.status.LiveStatusManager import spp.protocol.ProtocolAddress.Global.ArtifactLogUpdated -import spp.protocol.marshall.ProtocolMarshaller.deserializeLiveInstrumentRemoved import spp.protocol.SourceServices.Instance import spp.protocol.SourceServices.Provide.toLiveInstrumentSubscriberAddress import spp.protocol.instrument.LiveBreakpoint @@ -46,6 +45,7 @@ import spp.protocol.instrument.event.LiveInstrumentEvent import spp.protocol.instrument.event.LiveInstrumentEventType import spp.protocol.instrument.event.LiveLogHit import spp.protocol.marshall.ProtocolMarshaller +import spp.protocol.marshall.ProtocolMarshaller.deserializeLiveInstrumentRemoved /** * todo: description. @@ -79,9 +79,9 @@ class LiveInstrumentManager( LiveInstrumentEventType.LOG_HIT -> handleLogHitEvent(liveEvent) LiveInstrumentEventType.BREAKPOINT_HIT -> handleBreakpointHitEvent(liveEvent) LiveInstrumentEventType.BREAKPOINT_ADDED -> handleBreakpointAddedEvent(liveEvent) - LiveInstrumentEventType.BREAKPOINT_REMOVED -> handleBreakpointRemovedEvent(liveEvent) + LiveInstrumentEventType.BREAKPOINT_REMOVED -> handleInstrumentRemovedEvent(liveEvent) LiveInstrumentEventType.LOG_ADDED -> handleLogAddedEvent(liveEvent) - LiveInstrumentEventType.LOG_REMOVED -> handleLogRemovedEvent(liveEvent) + LiveInstrumentEventType.LOG_REMOVED -> handleInstrumentRemovedEvent(liveEvent) else -> log.warn("Un-implemented event type: {}", liveEvent.eventType) } } @@ -105,19 +105,6 @@ class LiveInstrumentManager( } } - private fun handleLogRemovedEvent(liveEvent: LiveInstrumentEvent) { - val logRemoved = deserializeLiveInstrumentRemoved(JsonObject(liveEvent.data)) - ApplicationManager.getApplication().invokeLater { - val inlayMark = SourceMarkSearch.findByLogId(logRemoved.liveInstrument.id!!) - if (inlayMark != null) { - val eventListeners = inlayMark.getUserData(SourceMarkKeys.INSTRUMENT_EVENT_LISTENERS) - if (eventListeners?.isNotEmpty() == true) { - eventListeners.forEach { it.accept(liveEvent) } - } - } - } - } - private fun handleLogAddedEvent(liveEvent: LiveInstrumentEvent) { if (!SourceMarker.enabled) { log.debug("SourceMarker disabled. Ignored log added") @@ -151,10 +138,10 @@ class LiveInstrumentManager( } } - private fun handleBreakpointRemovedEvent(liveEvent: LiveInstrumentEvent) { - val bpRemoved = deserializeLiveInstrumentRemoved(JsonObject(liveEvent.data)) + private fun handleInstrumentRemovedEvent(liveEvent: LiveInstrumentEvent) { + val instrumentRemoved = deserializeLiveInstrumentRemoved(JsonObject(liveEvent.data)) ApplicationManager.getApplication().invokeLater { - val inlayMark = SourceMarkSearch.findByBreakpointId(bpRemoved.liveInstrument.id!!) + val inlayMark = SourceMarkSearch.findByInstrumentId(instrumentRemoved.liveInstrument.id!!) if (inlayMark != null) { val eventListeners = inlayMark.getUserData(SourceMarkKeys.INSTRUMENT_EVENT_LISTENERS) if (eventListeners?.isNotEmpty() == true) { @@ -170,7 +157,7 @@ class LiveInstrumentManager( val project = ProjectManager.getInstance().openProjects[0] BreakpointHitWindowService.getInstance(project).addBreakpointHit(bpHit) - val inlayMark = SourceMarkSearch.findByBreakpointId(bpHit.breakpointId) + val inlayMark = SourceMarkSearch.findByInstrumentId(bpHit.breakpointId) if (inlayMark != null) { val eventListeners = inlayMark.getUserData(SourceMarkKeys.INSTRUMENT_EVENT_LISTENERS) if (eventListeners?.isNotEmpty() == true) { @@ -189,7 +176,7 @@ class LiveInstrumentManager( //todo: can get log hit without log added (race) try open val logHit = Json.decodeValue(liveEvent.data, LiveLogHit::class.java) ApplicationManager.getApplication().invokeLater { - val inlayMark = SourceMarkSearch.findByLogId(logHit.logId) + val inlayMark = SourceMarkSearch.findByInstrumentId(logHit.logId) if (inlayMark != null) { val eventListeners = inlayMark.getUserData(SourceMarkKeys.INSTRUMENT_EVENT_LISTENERS) if (eventListeners?.isNotEmpty() == true) { 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 099464c68..ab347a4fb 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/service/LiveViewManager.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/service/LiveViewManager.kt @@ -29,6 +29,7 @@ import kotlinx.coroutines.launch import kotlinx.datetime.toJavaInstant import kotlinx.datetime.toKotlinInstant import org.slf4j.LoggerFactory +import spp.jetbrains.marker.SourceMarker import spp.jetbrains.marker.source.mark.api.SourceMark import spp.jetbrains.portal.SourcePortal import spp.jetbrains.sourcemarker.discover.TCPServiceDiscoveryBackend @@ -40,6 +41,7 @@ import spp.protocol.ProtocolAddress.Global.ArtifactMetricsUpdated import spp.protocol.ProtocolAddress.Global.ArtifactTracesUpdated import spp.protocol.ProtocolAddress.Global.TraceSpanUpdated import spp.protocol.SourceServices.Provide.toLiveViewSubscriberAddress +import spp.protocol.artifact.ArtifactType import spp.protocol.artifact.QueryTimeFrame import spp.protocol.artifact.log.Log import spp.protocol.artifact.log.LogOrderType @@ -80,6 +82,10 @@ class LiveViewManager(private val pluginConfig: SourceMarkerConfig) : CoroutineV vertx.eventBus().consumer(toLiveViewSubscriberAddress(developer)) { val event = Json.decodeValue(it.body().toString(), LiveViewEvent::class.java) if (log.isTraceEnabled) log.trace("Received live event: {}", event) + if (!SourceMarker.enabled) { + log.warn("SourceMarker is not enabled, ignoring live event: {}", event) + return@consumer + } when (event.viewConfig.viewName) { "LIVE_METER" -> launch(vertx.dispatcher()) { consumeLiveMeterEvent(event) } @@ -116,7 +122,7 @@ class LiveViewManager(private val pluginConfig: SourceMarkerConfig) : CoroutineV val meterTypeStr = event.entityId.substringAfter("spp_").substringBefore("_").toUpperCase() val meterType = MeterType.valueOf(meterTypeStr) val meterId = event.entityId.substringAfter(meterType.name.toLowerCase() + "_").replace("_", "-") - val meterMark = SourceMarkSearch.findByMeterId(meterId) + val meterMark = SourceMarkSearch.findByInstrumentId(meterId) if (meterMark == null) { log.info("Could not find source mark for: " + event.entityId) return @@ -140,16 +146,23 @@ class LiveViewManager(private val pluginConfig: SourceMarkerConfig) : CoroutineV Int.MAX_VALUE ) - for ((content, logs) in logsResult.logs.groupBy { it.content }) { - SourceMarkSearch.findInheritedSourceMarks(content).forEach { - vertx.eventBus().send( - ProtocolAddress.Global.ArtifactLogUpdated, - logsResult.copy( - artifactQualifiedName = it.artifactQualifiedName, - total = logs.size, - logs = logs, + if (event.artifactQualifiedName.type == ArtifactType.EXPRESSION) { + val expressionMark = SourceMarkSearch.findSourceMark(event.artifactQualifiedName) + if (expressionMark != null) { + vertx.eventBus().send(ProtocolAddress.Global.ArtifactLogUpdated, logsResult) + } + } else { + for ((content, logs) in logsResult.logs.groupBy { it.content }) { + SourceMarkSearch.findInheritedSourceMarks(content).forEach { + vertx.eventBus().send( + ProtocolAddress.Global.ArtifactLogUpdated, + logsResult.copy( + artifactQualifiedName = it.artifactQualifiedName, + total = logs.size, + logs = logs, + ) ) - ) + } } } } diff --git a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/service/LogCountIndicators.kt b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/service/LogCountIndicators.kt index 155040e3a..35a68ce2d 100644 --- a/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/service/LogCountIndicators.kt +++ b/plugin/src/main/kotlin/spp/jetbrains/sourcemarker/service/LogCountIndicators.kt @@ -63,7 +63,7 @@ class LogCountIndicators : CoroutineVerticle() { val fileLogPatterns = fileMarker.getSourceMarks().filterIsInstance().flatMap { it.getUserData(LOGGER_DETECTOR)!!.getOrFindLoggerStatements(it) } - Instance.logCountIndicator!!.getPatternOccurrences( + val occurrences = Instance.logCountIndicator!!.getPatternOccurrences( fileLogPatterns.map { it.logPattern }, config.serviceName, Clock.System.now().minus(15, DateTimeUnit.MINUTE), @@ -103,8 +103,6 @@ class LogCountIndicators : CoroutineVerticle() { } } } - } else { - log.error("Failed to get log pattern occurrences", it.cause()) } } } 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 14aade941..b581c9441 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 kotlinx.coroutines.runBlocking import org.slf4j.LoggerFactory import spp.jetbrains.marker.SourceMarker.creationService import spp.jetbrains.marker.SourceMarker.namingService @@ -161,7 +162,7 @@ object LiveStatusManager : SourceMarkEventListener { /** * Invoked via control bar. Force visible. */ - fun showLogStatusBar(editor: Editor, lineNumber: Int) { + fun showLogStatusBar(editor: Editor, lineNumber: Int, watchExpression: Boolean) { val fileMarker = PsiDocumentManager.getInstance(editor.project!!).getPsiFile(editor.document)!! .getUserData(SourceFileMarker.KEY) if (fileMarker == null) { @@ -174,17 +175,69 @@ object LiveStatusManager : SourceMarkEventListener { val wrapperPanel = JPanel() wrapperPanel.layout = BorderLayout() + if (watchExpression) { + val logPatterns = mutableListOf() + val parentMark = inlayMark.getParentSourceMark() + if (parentMark is MethodSourceMark) { + val loggerDetector = parentMark.getUserData(SourceMarkKeys.LOGGER_DETECTOR) + if (loggerDetector != null) { + runBlocking { + val detectedLogs = loggerDetector.getOrFindLoggerStatements(parentMark) + val logOnCurrentLine = detectedLogs.find { it.lineLocation == inlayMark.lineNumber } + if (logOnCurrentLine != null) { + logPatterns.add(logOnCurrentLine.logPattern) + } + } + } + } + + SourceServices.Instance.liveView!!.addLiveViewSubscription( + LiveViewSubscription( + null, + logPatterns, + ArtifactQualifiedName( + inlayMark.artifactQualifiedName.identifier, + lineNumber = inlayMark.artifactQualifiedName.lineNumber, + type = ArtifactType.EXPRESSION + ), + LiveSourceLocation( + inlayMark.artifactQualifiedName.identifier, + line = inlayMark.artifactQualifiedName.lineNumber!! + ), + LiveViewConfig("LOGS", listOf("endpoint_logs")) + ) + ).onComplete { + if (it.succeeded()) { + inlayMark.addEventListener { event -> + if (event.eventCode == SourceMarkEventCode.MARK_REMOVED) { + SourceServices.Instance.liveView!!.removeLiveViewSubscription( + it.result().subscriptionId!! + ).onComplete { + if (it.failed()) { + log.error("Failed to remove subscription: {}", it.cause()) + } + } + } + } + } else { + log.error("Failed to add live view subscription", it.cause()) + } + } + } + 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, + namingService.getClassQualifiedNames(fileMarker.psiFile)[0].identifier, + lineNumber, service = config.serviceName ), - scopeService.getScopeVariables(fileMarker, lineNumber), - inlayMark + if (watchExpression) emptyList() else scopeService.getScopeVariables(fileMarker, lineNumber), + inlayMark, + watchExpression ) inlayMark.putUserData(SourceMarkKeys.STATUS_BAR, statusBar) statusBar.setWrapperPanel(wrapperPanel) @@ -203,14 +256,14 @@ object LiveStatusManager : SourceMarkEventListener { sourcePortal.configuration.currentPage = PageType.LOGS sourcePortal.configuration.statusBar = true - SourceMarkerPlugin.vertx.eventBus().consumer(DisplayLogs(sourcePortal.portalUuid)) { - val latestLog = it.body().logs.first() - statusBar.setLatestLog( - Instant.ofEpochMilli(latestLog.timestamp.toEpochMilliseconds()), latestLog - ) - } + if (!watchExpression) { + SourceMarkerPlugin.vertx.eventBus().consumer(DisplayLogs(sourcePortal.portalUuid)) { + val latestLog = it.body().logs.first() + statusBar.setLatestLog(Instant.ofEpochMilli(latestLog.timestamp.toEpochMilliseconds()), latestLog) + } - statusBar.focus() + statusBar.focus() + } } } @@ -359,7 +412,8 @@ object LiveStatusManager : SourceMarkEventListener { val statusBar = LogStatusBar( liveLog.location, emptyList(), - inlayMark + inlayMark, + false ) inlayMark.putUserData(SourceMarkKeys.STATUS_BAR, statusBar) statusBar.setWrapperPanel(wrapperPanel) diff --git a/plugin/src/main/resources/plugin-configuration.json b/plugin/src/main/resources/plugin-configuration.json index 6bf445836..b736dabda 100644 --- a/plugin/src/main/resources/plugin-configuration.json +++ b/plugin/src/main/resources/plugin-configuration.json @@ -6,7 +6,6 @@ "service_port": 5445, "tcp_service_port": 5455, "services": { - "local_tracing": false, "log_count_indicator": false, "live_instrument": true, "live_view": true