From 9592fceda629e300fb4d4df1fefdf50c99646f4f Mon Sep 17 00:00:00 2001 From: Alexey Merkulov Date: Tue, 9 Jul 2024 18:00:03 +0200 Subject: [PATCH] [debugger] Implement additional logging for flaky tests GitOrigin-RevId: ec1eb573ee756dc0d16ee0dcada086db0625e277 --- .../debugger/engine/DebugProcessEvents.java | 21 ++++++++++++--- .../debugger/ui/breakpoints/Breakpoint.java | 13 +++++++++- .../InternalDebugLoggingRequestor.java | 12 +++++++++ .../stepping/CoroutineBreakpointFacility.kt | 3 +-- .../debugger/test/util/BreakpointCreator.kt | 26 +++++++++++++++---- .../stepOver/stepThroughCoroutineScope.kt | 10 ++++++- .../stepOver/stepThroughCoroutineScope.out | 11 ++++---- 7 files changed, 78 insertions(+), 18 deletions(-) create mode 100644 java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/InternalDebugLoggingRequestor.java diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java index 3b68939323db..58d126b6ec08 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java @@ -18,10 +18,7 @@ import com.intellij.debugger.requests.Requestor; import com.intellij.debugger.settings.DebuggerSettings; import com.intellij.debugger.statistics.DebuggerStatistics; import com.intellij.debugger.statistics.StatisticsStorage; -import com.intellij.debugger.ui.breakpoints.Breakpoint; -import com.intellij.debugger.ui.breakpoints.InstrumentationTracker; -import com.intellij.debugger.ui.breakpoints.StackCapturingLineBreakpoint; -import com.intellij.debugger.ui.breakpoints.SyntheticBreakpoint; +import com.intellij.debugger.ui.breakpoints.*; import com.intellij.debugger.ui.overhead.OverheadProducer; import com.intellij.debugger.ui.overhead.OverheadTimings; import com.intellij.ide.BrowserUtil; @@ -646,6 +643,22 @@ public class DebugProcessEvents extends DebugProcessImpl { final SuspendManager suspendManager = getSuspendManager(); final LocatableEventRequestor requestor = (LocatableEventRequestor)RequestManagerImpl.findRequestor(event.request()); + + boolean isDebugLogBreakpoint = requestor instanceof InternalDebugLoggingRequestor dReq && dReq.isDebugLogBreakpoint(); + + if (isDebugLogBreakpoint) { + String firstArgument; + try { + firstArgument = suspendContext.getEventThread().frame(0).getArgumentValues().get(0).toString(); + } + catch (Throwable e) { + firstArgument = e.getMessage(); + } + LOG.debug("Debug log breakpoint: " + firstArgument); + suspendManager.voteResume(suspendContext); + return; + } + ThreadReferenceProxyImpl threadProxy = suspendContext.getThread(); boolean isEvaluationOnCurrentThread = threadProxy != null && threadProxy.isEvaluating(); if ((isEvaluationOnCurrentThread || myThreadBlockedMonitor.isInResumeAllMode()) && diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java index ea1ca3b78d1d..93a57a6562f1 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java @@ -75,7 +75,7 @@ import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Stream; -public abstract class Breakpoint

implements FilteredRequestor, ClassPrepareRequestor, OverheadProducer { +public abstract class Breakpoint

implements FilteredRequestor, ClassPrepareRequestor, OverheadProducer, InternalDebugLoggingRequestor { public static final Key> DATA_KEY = Key.create("JavaBreakpoint"); private static final Key HIT_COUNTER = Key.create("HIT_COUNTER"); @@ -86,6 +86,8 @@ public abstract class Breakpoint

implements @NonNls private static final String LOG_MESSAGE_OPTION_NAME = "LOG_MESSAGE"; protected boolean myCachedVerifiedState = false; + private boolean myIsDebugLogBreakpoint; + protected Breakpoint(@NotNull Project project, XBreakpoint

xBreakpoint) { myProject = project; myXBreakpoint = xBreakpoint; @@ -810,4 +812,13 @@ public abstract class Breakpoint

implements protected void fireBreakpointChanged() { ((XBreakpointBase)myXBreakpoint).fireBreakpointChanged(); } + + public void setIsDebugLogBreakpoint(boolean isDebugLogBreakpoint) { + myIsDebugLogBreakpoint = isDebugLogBreakpoint; + } + + @Override + public boolean isDebugLogBreakpoint() { + return myIsDebugLogBreakpoint; + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/InternalDebugLoggingRequestor.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/InternalDebugLoggingRequestor.java new file mode 100644 index 000000000000..8cc58ce2ad5a --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/InternalDebugLoggingRequestor.java @@ -0,0 +1,12 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.debugger.ui.breakpoints; + +import org.jetbrains.annotations.ApiStatus; + +/** It is used to investigate flaky test behavior in complex cases */ +@ApiStatus.Internal +public interface InternalDebugLoggingRequestor { + default boolean isDebugLogBreakpoint() { + return false; + } +} diff --git a/plugins/kotlin/jvm-debugger/core/src/org/jetbrains/kotlin/idea/debugger/core/stepping/CoroutineBreakpointFacility.kt b/plugins/kotlin/jvm-debugger/core/src/org/jetbrains/kotlin/idea/debugger/core/stepping/CoroutineBreakpointFacility.kt index f1f25d368a37..36870170e971 100644 --- a/plugins/kotlin/jvm-debugger/core/src/org/jetbrains/kotlin/idea/debugger/core/stepping/CoroutineBreakpointFacility.kt +++ b/plugins/kotlin/jvm-debugger/core/src/org/jetbrains/kotlin/idea/debugger/core/stepping/CoroutineBreakpointFacility.kt @@ -106,8 +106,7 @@ object CoroutineBreakpointFacility { breakpoint.createRequest(debugProcess) debugProcess.setSteppingBreakpoint(breakpoint) - val filterThread = debugProcess.requestsManager.filterThread - thisLogger().debug("Resume breakpoint for $method in thread $filterThread") + thisLogger().debug("Resume breakpoint for $method in context $context") return true } diff --git a/plugins/kotlin/jvm-debugger/test/test/org/jetbrains/kotlin/idea/debugger/test/util/BreakpointCreator.kt b/plugins/kotlin/jvm-debugger/test/test/org/jetbrains/kotlin/idea/debugger/test/util/BreakpointCreator.kt index 4db24f82a2bb..3020cc1dfb4d 100644 --- a/plugins/kotlin/jvm-debugger/test/test/org/jetbrains/kotlin/idea/debugger/test/util/BreakpointCreator.kt +++ b/plugins/kotlin/jvm-debugger/test/test/org/jetbrains/kotlin/idea/debugger/test/util/BreakpointCreator.kt @@ -2,16 +2,14 @@ package org.jetbrains.kotlin.idea.debugger.test.util -import com.intellij.debugger.DebuggerInvocationUtil import com.intellij.debugger.engine.evaluation.CodeFragmentKind import com.intellij.debugger.engine.evaluation.TextWithImportsImpl import com.intellij.debugger.ui.breakpoints.Breakpoint import com.intellij.debugger.ui.breakpoints.BreakpointManager import com.intellij.debugger.ui.breakpoints.JavaLineBreakpointType import com.intellij.debugger.ui.breakpoints.LineBreakpoint -import com.intellij.openapi.application.ModalityState import com.intellij.openapi.application.runReadAction -import com.intellij.openapi.application.runWriteAction +import com.intellij.openapi.diagnostic.thisLogger import com.intellij.openapi.project.Project import com.intellij.openapi.util.io.FileUtilRt import com.intellij.openapi.vfs.VirtualFile @@ -27,6 +25,7 @@ import com.intellij.xdebugger.breakpoints.XBreakpointType import com.intellij.xdebugger.breakpoints.XLineBreakpointType import org.jetbrains.java.debugger.breakpoints.properties.JavaBreakpointProperties import org.jetbrains.java.debugger.breakpoints.properties.JavaLineBreakpointProperties +import org.jetbrains.kotlin.idea.base.test.InTextDirectivesUtils.findLinesWithPrefixesRemoved import org.jetbrains.kotlin.idea.debugger.breakpoints.KotlinFieldBreakpointType import org.jetbrains.kotlin.idea.debugger.breakpoints.KotlinLineBreakpointType import org.jetbrains.kotlin.idea.debugger.core.DebuggerUtils.isKotlinSourceFile @@ -35,9 +34,7 @@ import org.jetbrains.kotlin.idea.debugger.core.breakpoints.KotlinFunctionBreakpo import org.jetbrains.kotlin.idea.debugger.core.breakpoints.KotlinFunctionBreakpointType import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferenceKeys import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferences -import org.jetbrains.kotlin.idea.base.test.InTextDirectivesUtils.findLinesWithPrefixesRemoved import java.util.* -import javax.swing.SwingUtilities internal class BreakpointCreator( private val project: Project, @@ -94,6 +91,9 @@ internal class BreakpointCreator( comment.startsWith("//FunctionBreakpoint!") -> { createFunctionBreakpoint(breakpointManager, file, lineIndex, false) } + comment.startsWith("//LogFirstArgumentBreakpoint!") -> { + createLogFirstArgumentBreakpoint(breakpointManager, file, lineIndex) + } else -> throw AssertionError("Cannot create breakpoint at line ${lineIndex + 1}") } } @@ -171,6 +171,22 @@ internal class BreakpointCreator( } } + private fun createLogFirstArgumentBreakpoint(breakpointManager: XBreakpointManager, file: PsiFile, lineIndex: Int) { + val kotlinLineBreakpointType = findBreakpointType(KotlinLineBreakpointType::class.java) + val javaBreakpoint = createBreakpointOfType( + breakpointManager, + kotlinLineBreakpointType, + lineIndex, + file.virtualFile, + null, + false, + ) + javaBreakpoint?.setIsDebugLogBreakpoint(true) + if (javaBreakpoint is LineBreakpoint<*>) { + thisLogger().debug("LogFirstArgumentBreakpoint created at ${file.virtualFile.name}:${lineIndex + 1}") + } + } + private fun createLineBreakpoint( breakpointManager: XBreakpointManager, file: PsiFile, diff --git a/plugins/kotlin/jvm-debugger/test/testData/evaluation/singleBreakpoint/coroutines/stepOver/stepThroughCoroutineScope.kt b/plugins/kotlin/jvm-debugger/test/testData/evaluation/singleBreakpoint/coroutines/stepOver/stepThroughCoroutineScope.kt index 45af75b5031d..21b997bbfeb7 100644 --- a/plugins/kotlin/jvm-debugger/test/testData/evaluation/singleBreakpoint/coroutines/stepOver/stepThroughCoroutineScope.kt +++ b/plugins/kotlin/jvm-debugger/test/testData/evaluation/singleBreakpoint/coroutines/stepOver/stepThroughCoroutineScope.kt @@ -5,10 +5,12 @@ import kotlinx.coroutines.* suspend fun foo(i: Int) { println("Start foo") coroutineScope { + trackExecution("Start for $i") if (i == 25) { //Breakpoint! startMethod(i) } + trackExecution("Middle for $i") delay(1) // EXPRESSION: i // RESULT: 25: I @@ -39,7 +41,13 @@ fun main() { } } -// STEP_OVER: 3 +fun trackExecution(s: String) { + //LogFirstArgumentBreakpoint! + s.toString() +} + + +// STEP_OVER: 4 // REGISTRY: debugger.filter.breakpoints.by.coroutine.id=true // REGISTRY: debugger.always.suspend.thread.before.switch=true // REGISTRY: debugger.log.jdi.in.unit.tests=true diff --git a/plugins/kotlin/jvm-debugger/test/testData/evaluation/singleBreakpoint/coroutines/stepOver/stepThroughCoroutineScope.out b/plugins/kotlin/jvm-debugger/test/testData/evaluation/singleBreakpoint/coroutines/stepOver/stepThroughCoroutineScope.out index 8b6858582e7d..6533b9c4ec34 100644 --- a/plugins/kotlin/jvm-debugger/test/testData/evaluation/singleBreakpoint/coroutines/stepOver/stepThroughCoroutineScope.out +++ b/plugins/kotlin/jvm-debugger/test/testData/evaluation/singleBreakpoint/coroutines/stepOver/stepThroughCoroutineScope.out @@ -1,10 +1,11 @@ -LineBreakpoint created at stepThroughCoroutineScope.kt:10 +LineBreakpoint created at stepThroughCoroutineScope.kt:11 Run Java Connected to the target VM -stepThroughCoroutineScope.kt:10 -stepThroughCoroutineScope.kt:12 -stepThroughCoroutineScope.kt:15 -stepThroughCoroutineScope.kt:16 +stepThroughCoroutineScope.kt:11 +stepThroughCoroutineScope.kt:13 +stepThroughCoroutineScope.kt:14 +stepThroughCoroutineScope.kt:17 +stepThroughCoroutineScope.kt:18 Compile bytecode for i Disconnected from the target VM