--attach-debugger to start LS with debugger

This change adds a simple cli parameter to start Language Server with
remote debugging capabilities. Whenever I needed to attach the debbugger
a) I had to lookup the non-trivial `agentlib` options b) figure out
where to add it and build the whole distribution again.
This commit is contained in:
Hubert Plociniczak 2024-05-23 22:02:41 +02:00
parent 094076a9e8
commit 95d2638dca
13 changed files with 74 additions and 24 deletions

View File

@ -307,6 +307,7 @@ case class Launcher(cliOptions: GlobalCLIOptions) {
versionOverride,
logLevel,
logMasking = cliOptions.internalOptions.logMasking,
attachDebugger = false,
additionalArguments
)
.get,

View File

@ -68,7 +68,8 @@ class LauncherRunner(
version,
arguments ++ setLogLevelArgs(logLevel, logMasking)
++ additionalArguments,
connectLoggerIfAvailable = true
connectLoggerIfAvailable = true,
attachDebugger = false
)
}
@ -127,7 +128,8 @@ class LauncherRunner(
version,
arguments ++ setLogLevelArgs(logLevel, logMasking)
++ additionalArguments,
connectLoggerIfAvailable = true
connectLoggerIfAvailable = true,
attachDebugger = false
)
}
@ -148,6 +150,7 @@ class LauncherRunner(
versionOverride: Option[SemVer],
logLevel: Level,
logMasking: Boolean,
attachDebugger: Boolean,
additionalArguments: Seq[String]
): Try[RunSettings] =
for {
@ -158,6 +161,7 @@ class LauncherRunner(
versionOverride,
logLevel,
logMasking,
attachDebugger,
additionalArguments
)
} yield runSettings
@ -190,7 +194,12 @@ class LauncherRunner(
}
(
RunSettings(version, arguments, connectLoggerIfAvailable = false),
RunSettings(
version,
arguments,
connectLoggerIfAvailable = false,
attachDebugger = false
),
whichEngine
)
}
@ -239,7 +248,8 @@ class LauncherRunner(
version,
arguments ++ setLogLevelArgs(logLevel, logMasking)
++ additionalArguments,
connectLoggerIfAvailable = true
connectLoggerIfAvailable = true,
attachDebugger = false
)
}
@ -286,7 +296,8 @@ class LauncherRunner(
version,
arguments ++ setLogLevelArgs(logLevel, logMasking)
++ additionalArguments,
connectLoggerIfAvailable = true
connectLoggerIfAvailable = true,
attachDebugger = false
)
}
}

View File

@ -64,7 +64,8 @@ class LauncherRunnerSpec extends RuntimeVersionManagerTest with FlakySpec {
val runSettings = RunSettings(
SemVer.of(0, 0, 0),
Seq("arg1", "--flag2"),
connectLoggerIfAvailable = true
connectLoggerIfAvailable = true,
attachDebugger = false
)
val jvmOptions = Seq(("locally-added-options", "value1"))
@ -299,7 +300,8 @@ class LauncherRunnerSpec extends RuntimeVersionManagerTest with FlakySpec {
versionOverride = None,
additionalArguments = Seq("additional"),
logLevel = Level.INFO,
logMasking = true
logMasking = true,
attachDebugger = false
)
.get
@ -321,7 +323,8 @@ class LauncherRunnerSpec extends RuntimeVersionManagerTest with FlakySpec {
versionOverride = Some(overridden),
additionalArguments = Seq(),
logLevel = Level.INFO,
logMasking = true
logMasking = true,
attachDebugger = false
)
.get
.engineVersion shouldEqual overridden

View File

@ -14,6 +14,7 @@ object Cli {
val VERSION_OPTION = "version"
val PROFILING_PATH = "profiling-path"
val PROFILING_TIME = "profiling-time"
val ATTACH_DEBUGGER = "attach-debugger"
val PROJECTS_DIRECTORY = "projects-directory"
val PROJECT_LIST = "project-list"
@ -137,6 +138,12 @@ object Cli {
.longOpt(FILESYSTEM_WRITE_PATH)
.desc("Write data from stdin to the provided file")
.build()
val attachDebugger: cli.Option = cli.Option.builder
.hasArg(false)
.longOpt(ATTACH_DEBUGGER)
.desc("Enables remote debugging capabilities")
.build()
}
val options: cli.Options =
@ -148,6 +155,7 @@ object Cli {
.addOption(option.noLogMasking)
.addOption(option.profilingPath)
.addOption(option.profilingTime)
.addOption(option.attachDebugger)
.addOption(option.projectsDirectory)
.addOption(option.projectList)
.addOption(option.filesystemList)

View File

@ -201,10 +201,14 @@ object ProjectManager extends ZIOAppDefault with LazyLogging {
)
}
val parseAttachDebugger =
ZIO.attempt(options.hasOption(Cli.ATTACH_DEBUGGER))
for {
profilingPath <- parseProfilingPath
profilingTime <- parseProfilingTime
} yield ProjectManagerOptions(profilingPath, profilingTime)
attachDebugger <- parseAttachDebugger
} yield ProjectManagerOptions(profilingPath, profilingTime, attachDebugger)
}
/** The main function of the application, which will be passed the command-line
@ -277,7 +281,8 @@ object ProjectManager extends ZIOAppDefault with LazyLogging {
procConf = MainProcessConfig(
logLevel,
opts.profilingPath,
opts.profilingTime
opts.profilingTime,
opts.attachDebugger
)
exitCode <- mainProcess(procConf).fold(
th => {

View File

@ -11,5 +11,6 @@ import scala.concurrent.duration.FiniteDuration
*/
case class ProjectManagerOptions(
profilingPath: Option[Path],
profilingTime: Option[FiniteDuration]
profilingTime: Option[FiniteDuration],
attachDebugger: Boolean
)

View File

@ -18,7 +18,8 @@ object configuration {
case class MainProcessConfig(
logLevel: Level,
profilingPath: Option[Path],
profilingTime: Option[FiniteDuration]
profilingTime: Option[FiniteDuration],
attachDebugger: Boolean
)
/** A configuration object for properties of the Project Manager.

View File

@ -122,6 +122,7 @@ object ExecutorWithUnlimitedPool extends LanguageServerExecutor {
version = descriptor.engineVersion,
logLevel = inheritedLogLevel,
logMasking = Masking.isMaskingEnabled,
attachDebugger = descriptor.attachDebugger,
additionalArguments = additionalArguments
)
.get

View File

@ -88,6 +88,7 @@ class LanguageServerController(
discardOutput = distributionConfiguration.shouldDiscardChildOutput,
profilingPath = processConfig.profilingPath,
profilingTime = processConfig.profilingTime,
attachDebugger = processConfig.attachDebugger,
deferredLoggingServiceEndpoint = loggingServiceDescriptor.getEndpoint,
skipGraalVMUpdater = bootloaderConfig.skipGraalVMUpdater
)

View File

@ -26,6 +26,7 @@ import scala.concurrent.duration.FiniteDuration
* printed to parent's streams
* @param profilingPath the language server profiling file path
* @param profilingTime the time limiting the profiling duration
* @param attachDebugger if true, language server will be started with remote debugging capabilities
* @param deferredLoggingServiceEndpoint a future that is completed once the
* logging service has been fully set-up;
* if the child component should connect
@ -45,6 +46,7 @@ case class LanguageServerDescriptor(
discardOutput: Boolean,
profilingPath: Option[Path],
profilingTime: Option[FiniteDuration],
attachDebugger: Boolean,
deferredLoggingServiceEndpoint: Future[Option[URI]],
skipGraalVMUpdater: Boolean
)

View File

@ -90,7 +90,8 @@ class BaseServerSpec extends JsonRpcServerTestKit with BeforeAndAfterAll {
MainProcessConfig(
logLevel = if (debugLogs) Level.TRACE else Level.ERROR,
profilingPath = profilingPath,
profilingTime = None
profilingTime = None,
attachDebugger = false
)
val testClock =

View File

@ -8,9 +8,11 @@ import org.enso.semver.SemVer
* @param runnerArguments arguments that should be passed to the runner
* @param connectLoggerIfAvailable specifies if the ran component should
* connect to launcher's logging service
* @param attachDebugger if true, indicates that the runner should be started with remote debugging capabilities
*/
case class RunSettings(
engineVersion: SemVer,
runnerArguments: Seq[String],
connectLoggerIfAvailable: Boolean
connectLoggerIfAvailable: Boolean,
attachDebugger: Boolean
)

View File

@ -79,7 +79,12 @@ class Runner(
engineVersion
)
}
RunSettings(engineVersion, arguments, connectLoggerIfAvailable = false)
RunSettings(
engineVersion,
arguments,
connectLoggerIfAvailable = false,
attachDebugger = false
)
}
/** Creates [[RunSettings]] for launching the Language Server. */
@ -89,6 +94,7 @@ class Runner(
versionOverride: Option[SemVer],
logLevel: Level,
logMasking: Boolean,
attachDebugger: Boolean,
additionalArguments: Seq[String]
): Try[RunSettings] = {
val version = resolveVersion(versionOverride, Some(project))
@ -99,6 +105,7 @@ class Runner(
version,
logLevel,
logMasking,
attachDebugger,
additionalArguments
)
}
@ -110,6 +117,7 @@ class Runner(
version: SemVer,
logLevel: Level,
logMasking: Boolean,
attachDebugger: Boolean,
additionalArguments: Seq[String]
): Try[RunSettings] =
Try {
@ -137,7 +145,8 @@ class Runner(
RunSettings(
version,
arguments ++ additionalArguments,
connectLoggerIfAvailable = true
connectLoggerIfAvailable = true,
attachDebugger = attachDebugger
)
}
@ -221,9 +230,13 @@ class Runner(
forceLoggerConnectionArguments()
else Seq()
val command = Seq(
javaCommand.executableName
) ++ jvmArguments ++ loggingConnectionArguments ++ runSettings.runnerArguments
val command = Seq(javaCommand.executableName) ++
(if (runSettings.attachDebugger)
Seq(
"-agentlib:jdwp=transport=dt_socket,server=y,address=localhost:5005,suspend=y"
)
else Seq()) ++
jvmArguments ++ loggingConnectionArguments ++ runSettings.runnerArguments
val distributionSettings =
distributionManager.getEnvironmentToInheritSettings