Always create events log when profiling (#8337)

Changelog:
- update: always create an event log next to the profiling file when the engine is started with the `--profiling-path` flag
- remove: `--profiling-events-log-path` flag
This commit is contained in:
Dmitry Bushev 2023-11-20 16:01:25 +00:00 committed by GitHub
parent 705d6f192c
commit 53d1f727da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 44 additions and 94 deletions

View File

@ -15,7 +15,7 @@ Start `project-manager` with following options to record first 20s of the Enso
engine startup sequence:
```
$ project-manager --profiling-events-log-path=start.log --profiling-path=start.npss --profiling-time=20
$ project-manager --profiling-path=start.npss --profiling-time=20
```
Let the IDE connect to just launched `project-manager` - e.g. start the IDE with

View File

@ -171,7 +171,7 @@ class MainModule(serverConfig: LanguageServerConfig, logLevel: Level) {
)
val runtimeEventsMonitor =
languageServerConfig.profiling.runtimeEventsLogPath match {
languageServerConfig.profiling.profilingEventsLogPath match {
case Some(path) =>
val out = new PrintStream(path.toFile, StandardCharsets.UTF_8)
new RuntimeEventsMonitor(out)

View File

@ -1,18 +1,41 @@
package org.enso.languageserver.boot
import org.apache.commons.io.FilenameUtils
import java.nio.file.Path
import scala.concurrent.duration.FiniteDuration
/** Application profiling configuration.
*
* @param runtimeEventsLogPath the path to the runtime events log file
* @param profilingPath the path to the profiling output file
* @param profilingTime limit the profiling duration, as an infinite profiling
* duration may cause out-of-memory errors.
*/
case class ProfilingConfig(
runtimeEventsLogPath: Option[Path] = None,
profilingPath: Option[Path] = None,
profilingTime: Option[FiniteDuration] = None
)
) {
/** Creates the path to the runtime events log with the same name as
* `profilingPath` but with the `.log` extension.
*
* @return the path to the runtime events log file
*/
def profilingEventsLogPath: Option[Path] =
profilingPath.map { path =>
val profilingDirectory = path.getParent
val profilingFileName = path.getFileName.toString
val profilingFileExtension = FilenameUtils.getExtension(profilingFileName)
val eventsLogFileName =
profilingFileName.stripSuffix(
profilingFileExtension
) + ProfilingConfig.EventsLogExtension
profilingDirectory.resolve(eventsLogFileName)
}
}
object ProfilingConfig {
private val EventsLogExtension = "log"
}

View File

@ -54,8 +54,6 @@ object Main {
private val PROFILING_PATH = "profiling-path"
private val PROFILING_TIME = "profiling-time"
private val LANGUAGE_SERVER_OPTION = "server"
private val LANGUAGE_SERVER_PROFILING_EVENTS_LOG_PATH =
"server-profiling-events-log-path"
private val DAEMONIZE_OPTION = "daemon"
private val INTERFACE_OPTION = "interface"
private val RPC_PORT_OPTION = "rpc-port"
@ -201,16 +199,9 @@ object Main {
.longOpt(PROFILING_TIME)
.desc("The duration in seconds limiting the profiling time.")
.build()
val lsProfilingEventsLogPathOption = CliOption.builder
.hasArg(true)
.numberOfArgs(1)
.argName("file")
.longOpt(LANGUAGE_SERVER_PROFILING_EVENTS_LOG_PATH)
.desc("The path to the runtime events log file.")
.build()
val deamonizeOption = CliOption.builder
.longOpt(DAEMONIZE_OPTION)
.desc("Deamonize Language Server")
.desc("Daemonize Language Server")
.build()
val interfaceOption = CliOption.builder
.longOpt(INTERFACE_OPTION)
@ -427,7 +418,6 @@ object Main {
.addOption(lsOption)
.addOption(lsProfilingPathOption)
.addOption(lsProfilingTimeOption)
.addOption(lsProfilingEventsLogPathOption)
.addOption(deamonizeOption)
.addOption(interfaceOption)
.addOption(rpcPortOption)
@ -1026,16 +1016,7 @@ object Main {
profilingTime <- Either
.catchNonFatal(profilingTimeStr.map(_.toInt.seconds))
.leftMap(_ => "Profiling time should be an integer")
profilingEventsLogPathStr =
Option(line.getOptionValue(LANGUAGE_SERVER_PROFILING_EVENTS_LOG_PATH))
profilingEventsLogPath <- Either
.catchNonFatal(profilingEventsLogPathStr.map(Paths.get(_)))
.leftMap(_ => "Profiling events log path is invalid")
} yield ProfilingConfig(
profilingEventsLogPath,
profilingPath,
profilingTime
)
} yield ProfilingConfig(profilingPath, profilingTime)
}
/** Prints the version of the Enso executable.

View File

@ -7,14 +7,13 @@ import scala.util.Try
object Cli {
val JSON_OPTION = "json"
val HELP_OPTION = "help"
val NO_LOG_MASKING = "no-log-masking"
val VERBOSE_OPTION = "verbose"
val VERSION_OPTION = "version"
val PROFILING_PATH = "profiling-path"
val PROFILING_TIME = "profiling-time"
val PROFILING_EVENTS_LOG_PATH = "profiling-events-log-path"
val JSON_OPTION = "json"
val HELP_OPTION = "help"
val NO_LOG_MASKING = "no-log-masking"
val VERBOSE_OPTION = "verbose"
val VERSION_OPTION = "version"
val PROFILING_PATH = "profiling-path"
val PROFILING_TIME = "profiling-time"
object option {
@ -64,16 +63,6 @@ object Cli {
.longOpt(PROFILING_TIME)
.desc("The duration in seconds limiting the application profiling time.")
.build()
val profilingEventsLogPath: cli.Option = cli.Option.builder
.hasArg(true)
.numberOfArgs(1)
.argName("file")
.longOpt(PROFILING_EVENTS_LOG_PATH)
.desc(
"The path to the runtime events log file. Enables the runtime events logging."
)
.build()
}
val options: cli.Options =
@ -85,7 +74,6 @@ object Cli {
.addOption(option.noLogMasking)
.addOption(option.profilingPath)
.addOption(option.profilingTime)
.addOption(option.profilingEventsLogPath)
/** Parse the command line options. */
def parse(args: Array[String]): Either[String, cli.CommandLine] = {

View File

@ -189,37 +189,10 @@ object ProjectManager extends ZIOAppDefault with LazyLogging {
)
}
val parseProfilingEventsLogPath = ZIO
.attempt {
Option(options.getOptionValue(Cli.PROFILING_EVENTS_LOG_PATH))
.map(Paths.get(_).toAbsolutePath)
}
.flatMap {
case pathOpt @ Some(path) =>
ZIO.ifZIO(ZIO.attempt(Files.isDirectory(path)))(
onTrue = printLineError(
s"Error: ${Cli.PROFILING_EVENTS_LOG_PATH} is a directory: $path"
) *>
ZIO.fail(new FileAlreadyExistsException(path.toString)),
onFalse = ZIO.succeed(pathOpt)
)
case None =>
ZIO.succeed(None)
}
.catchAll { err =>
printLineError(s"Invalid ${Cli.PROFILING_EVENTS_LOG_PATH} argument.") *>
ZIO.fail(err)
}
for {
profilingEventsLogPath <- parseProfilingEventsLogPath
profilingPath <- parseProfilingPath
profilingTime <- parseProfilingTime
} yield ProjectManagerOptions(
profilingEventsLogPath,
profilingPath,
profilingTime
)
profilingPath <- parseProfilingPath
profilingTime <- parseProfilingTime
} yield ProjectManagerOptions(profilingPath, profilingTime)
}
/** The main function of the application, which will be passed the command-line
@ -240,7 +213,6 @@ object ProjectManager extends ZIOAppDefault with LazyLogging {
logLevel <- setupLogging(verbosity, logMasking)
procConf = MainProcessConfig(
logLevel,
opts.profilingRuntimeEventsLog,
opts.profilingPath,
opts.profilingTime
)
@ -271,7 +243,7 @@ object ProjectManager extends ZIOAppDefault with LazyLogging {
()
}
.catchAll { exception =>
printLineError(s"Failed to setup logger: ${exception.getMessage()}")
printLineError(s"Failed to setup logger: ${exception.getMessage}")
}
.as(level)
}

View File

@ -6,12 +6,10 @@ import scala.concurrent.duration.FiniteDuration
/** The runtime options.
*
* @param profilingRuntimeEventsLog the path to the runtime events log file
* @param profilingPath the path to the profiling output file
* @param profilingTime the time limiting the profiling duration
*/
case class ProjectManagerOptions(
profilingRuntimeEventsLog: Option[Path],
profilingPath: Option[Path],
profilingTime: Option[FiniteDuration]
)

View File

@ -12,13 +12,11 @@ object configuration {
* main project manager process.
*
* @param logLevel the logging level
* @param profilingEventsLogPath the path to the runtime events log file
* @param profilingPath the path to the profiling out file
* @param profilingTime the time limiting the profiling duration
*/
case class MainProcessConfig(
logLevel: Level,
profilingEventsLogPath: Option[Path],
profilingPath: Option[Path],
profilingTime: Option[FiniteDuration]
)

View File

@ -107,18 +107,12 @@ object ExecutorWithUnlimitedPool extends LanguageServerExecutor {
val profilingTimeArguments =
descriptor.profilingTime.toSeq
.flatMap(time => Seq("--profiling-time", time.toSeconds.toString))
val profilingEventsLogPathArguments =
descriptor.profilingEventsLogPath.toSeq
.flatMap(path =>
Seq("--server-profiling-events-log-path", path.toString)
)
val startupArgs =
if (descriptor.skipGraalVMUpdater) Seq("--skip-graalvm-updater")
else Seq()
val additionalArguments =
profilingPathArguments ++
profilingTimeArguments ++
profilingEventsLogPathArguments ++
startupArgs
val runSettings = runner
.startLanguageServer(

View File

@ -86,7 +86,6 @@ class LanguageServerController(
engineVersion = engineVersion,
jvmSettings = distributionConfiguration.defaultJVMSettings,
discardOutput = distributionConfiguration.shouldDiscardChildOutput,
profilingEventsLogPath = processConfig.profilingEventsLogPath,
profilingPath = processConfig.profilingPath,
profilingTime = processConfig.profilingTime,
deferredLoggingServiceEndpoint = loggingServiceDescriptor.getEndpoint,

View File

@ -24,7 +24,6 @@ import scala.concurrent.duration.FiniteDuration
* @param jvmSettings settings to use for the JVM that will host the engine
* @param discardOutput specifies if the process output should be discarded or
* printed to parent's streams
* @param profilingEventsLogPath the path to the runtime events log file
* @param profilingPath the language server profiling file path
* @param profilingTime the time limiting the profiling duration
* @param deferredLoggingServiceEndpoint a future that is completed once the
@ -44,7 +43,6 @@ case class LanguageServerDescriptor(
engineVersion: SemVer,
jvmSettings: JVMSettings,
discardOutput: Boolean,
profilingEventsLogPath: Option[Path],
profilingPath: Option[Path],
profilingTime: Option[FiniteDuration],
deferredLoggingServiceEndpoint: Future[Option[URI]],

View File

@ -87,10 +87,9 @@ class BaseServerSpec extends JsonRpcServerTestKit with BeforeAndAfterAll {
val processConfig: MainProcessConfig =
MainProcessConfig(
logLevel = if (debugLogs) Level.TRACE else Level.ERROR,
profilingPath = profilingPath,
profilingTime = None,
profilingEventsLogPath = None
logLevel = if (debugLogs) Level.TRACE else Level.ERROR,
profilingPath = profilingPath,
profilingTime = None
)
val testClock =