diff --git a/build.gradle.kts b/build.gradle.kts index 78612e3a6d..d46b7efca3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -57,6 +57,7 @@ allprojects { // this is useful if you debug in docker // testLogging.showStandardStreams = true // testLogging.showStackTraces = true + // set heap size for the test JVM(s) minHeapSize = "128m" maxHeapSize = "3072m" diff --git a/docs/InterProcessLogging.md b/docs/InterProcessLogging.md new file mode 100644 index 0000000000..dd5207fa1d --- /dev/null +++ b/docs/InterProcessLogging.md @@ -0,0 +1,229 @@ +# Interprocess logging + +This document described how logging is performed across all 3 different processes: IDEA, Engine and Instrumented. + +## Architecture + +All logging relies on log4j2. +When UtBot is used as IDEA plugin - [`utbot-intellij/log4j2.xml`](../utbot-intellij/src/main/resources/log4j2.xml) +is used as configuration file. +In other cases(`ContestEstimator`, `Gradle/Maven` tasks, `CLI`, tests) it searches for the first `log4j2.xml` in resources in classpath. + +### IDE process +IDEA part of UtBot write logs to `idea.log`. +Log configuration file is used as is, so if you want to configure logs in IDEA part - use it straight. +If you want to change log configuration in already built plugin - +use `Help > Diagnostic Tools > Debug Log Settings...` to change `log4j2.xml` configuration for plugin. + + +### UtBot plugin + + +UtBot plugin creates log directory `org.utbot.intellij.plugin.process.EngineProcessKt.engineProcessLogDirectory` +where places log files. + +### Engine process +Things are a bit more complicated here. There are cases - Engine process started from IDEA, and Engine process started separately. + +#### Engine process started from IDEA + +As plugin does not support multiple generation processes at a time - logs from any Engine process are written to the same file. + +Default log file directory is `%user_temp%/UtBot/rdEngineProcessLogs`. + +[`utbot-intellij/log4j2.xml`](../utbot-intellij/src/main/resources/log4j2.xml) is copied in +UtBot temporary directory - `org.utbot.intellij.plugin.process.EngineProcessKt.engineProcessLogConfigurationsDirectory`, +and then provided to Engine process via following CLI switch: + ``` + -Dlog4j2.configurationFile=%configuration_file% + ``` + +where `%configuration_file%` will be either: +1. Modified copy of [`utbot-intellij/log4j2.xml`](../utbot-intellij/src/main/resources/log4j2.xml) at UtBot temp directory. + + More precisely, there are 2 appenders in configuration file: + ```xml + + + + + ``` + By default `IdeaAppender` is used everywhere in file, which is used in IDEA plugin. + + When working as Engine process - temporary `log4j2.`xml would be created, in which + substring `ref="IdeaAppender"` will be replaced with `ref="EngineProcessAppender"`, + thus changing all appenders and log pattern, but preserving same categories and log levels for loggers. + + After that, logs will be written by `RollingFileAppender` in `utbot-engine-current.log` file with rolling over + after file reaches 20MB size. Previous log files are named `utbot-engine-%i.log`. Log file with + maximal index is the last one rolled. For example, `utbot-engine-1.log` is created earlier than `utbot-engine-10.log`. + + In IDEA log following lines are printed each time Engine process started: + ``` + | UtBot - EngineProcess | Engine process started with PID = 4172 + | UtBot - EngineProcess | Engine process log directory - C:\Users\user_name\AppData\Local\Temp\UTBot\rdEngineProcessLogs + | UtBot - EngineProcess | Engine process log file - C:\Users\user_name\AppData\Local\Temp\UTBot\rdEngineProcessLogs\utbot-engine-current.log + ``` + +2. Path from `UtSettings.engineProcessLogConfigFile`. + + This option allows to provide path to external Log4j2 configuration file instead of [`utbot-intellij/log4j2.xml`](../utbot-intellij/src/main/resources/log4j2.xml). + At `~/.utbot/settings.properties` you can set path to custom configuration file, + which would apply for engine process, for example: + ``` + engineProcessLogConfigFile=C:\wrk\UTBotJava\engineProcessLog4j2.xml + ``` + This allows you to configure logs for Engine process even for already built plugin, + you need only to restart IDE. + +#### Engine process started separately + +This is the case for `ContestEstimator`, `Gradle/Maven` tasks, `CLI`, tests, etc. +Configuration is taken from `log4j2.xml` in resources from the first `log4j2.xml` in resources in classpath. + +### Instrumented process + +Instrumented process sends its logs to the parent Engine process. +Logs are sent via corresponding RD model: `org.utbot.rd.models.LoggerModel`. +See `org.utbot.instrumentation.rd.InstrumentedProcess.Companion.invoke` and +`org.utbot.instrumentation.process.InstrumentedProcessMainKt.main`. + +## RD logs +Rd has its own logging system, based on `com.jetbrains.rd.util.Logger` interface. It is convenient to use +RD logging as default logging system in instrumented process because log4j2 classes in utbot would be confused +at concrete execution with log4j2 classes in tested project - we will have duplicated versions of log4j2 libs, +this would break instrumentation and coverage statistics. + +You should always override default RD logging strategy as by default it writes to stdout/stderr - use `com.jetbrains.rd.util.Logger.Companion.set` method to provide custom +`com.jetbrains.rd.util.ILoggerFactory`. Already created loggers will be automatically reinstantiated to obtain +new logger from provided factory. You can obtain logger via `com.jetbrains.rd.util.getLogger` function. +Check `EngineProcessMain` for RD logging example. + +For available RD factories see `org.utbot.rd.loggers` package - it contains useful implemented factories, +which log message in the same format as described in `utbot-intellij/src/main/resources/log4j2.xml`. + +## Implementation details + +### Additivity + +Sometimes same log entry might be written to log multiple times. At log you will see something like: +``` +13:55:41.204 | INFO | AnalyticsConfigureUtil | PathSelectorType: INHERITORS_SELECTOR +13:55:41.204 | INFO | AnalyticsConfigureUtil | PathSelectorType: INHERITORS_SELECTOR +``` + +This is because of loggers *additivity* - their full names defines tree structure, and events from children +are visible for parents. For example, following `log4j2.xml` configuration in IDEA will produce such problem: +```xml +... + + + + + + + + +... +``` + +This happens because `org.utbot` logger is parent for `org.utbot.intellij`, and all events from +`org.utbot.intellij` are also transferred to parent. This is called `additivity`. + +The solution is to manually add ```additivity="false"``` tag to all loggers: +```xml +... + + + + + + + + +... +``` + +Consider this problem when you manually configure log level and appender for logger. + +More information is available [here](https://logging.apache.org/log4j/2.x/manual/configuration.html#Additivity). + +### Useful +See auxiliary methods to work with logs at `UtRdLogUtil.kt` and `Logging.kt`. +If you want to trace how long execution took - use `org.utbot.common.LoggingKt.logMeasure` +method with corresponding log level scope. + +In the Engine process log entries from Instrumented process are logged by `org.utbot.instrumentation.rd.InstrumentedProcessKt.rdLogger`. + +## How to use log4j2 loggers + +See related document - [How to use loggers](../HowToUseLoggers.md). + +## Miscellaneous + +### Performance considerations + +`Debug` level is preferred in the most cases for developing. `Info` is sufficient for release. + +`Trace` log level for RD loggers(for ex. if you specify `Trace` for all loggers, or as default level for root logger) +will enable logging all technical send/receive event from protocol, +causing ~50mb additional logs per generation and ***heavily*** polluting log. This might be useful +when troubleshooting inter-process communication, but in all other cases prefer `Debug` level or +specify `Trace` level per logger explicitly. + +If your `Debug` level log message requires heavy string interpolation - wrap it in lambda, for example: +```kotlin +val someVeryBigDataStructure = VeryBigDataStructure() + +logger.debug("data structure representation - $someVeryBigDataStructure") // <---- interpolation +``` +In that code even though message uses `Debug` level, interpolation will always occur because +message is passed as a parameter, which are evaluated at call site. +In case logger is configured to `Info` level or higher - this means message will be built, but not logged, +resulting in unnecessary work, possibly causing performance issue. +Consider using lambdas: +```kotlin +// message will be created only if debug log level is available +logger.debug { "data structure representation - $someVeryBigDataStructure"} +``` + +Although now logs are sent from one process to another - performance penalties were not noticed. +Additional performance can be achieved playing with `bufferedIO` and `immediateFlush` properties in `log4j2.xml`. +For example, you can make following changes in `utbot-intellij`: +```xml + +``` + +This will reduce number of IO operations and use log4j2 buffer more efficiently. The cost it that +when process terminates - log4j2 terminates logging service before buffer is flushed, and +you will lose last portion of logs. This might be undesired behaviour in tests and debugging, +but probably acceptable in release. + +### Docker and Gradle + +To see logs in Gradle from console, Docker and CI - add following `build.gradle.kts`: +```kotlin +allprojects { + tasks { + withType { + testLogging.showStandardStreams = true + testLogging.showStackTraces = true + } + } +} +``` + +## Links + +Related topics: +1. [Multiprocess architecture](RD%20for%20UnitTestBot.md) +2. [Inter process debugging](./contributing/InterProcessDebugging.md) + +Log4j2: +2. [Architecture](https://logging.apache.org/log4j/2.x/manual/architecture.html) - overall log4j2 description. +2. [Layouts](https://logging.apache.org/log4j/2.x/manual/layouts.html) - how to format log messages. +UtBot uses `Pattern layout` everywhere. +3. [Appenders](https://logging.apache.org/log4j/2.x/manual/appenders.html) - about different ways to store log entries, +different storages for log entries and how to configure them. UtBot uses `Console`, `File` and `RollingFile` appenders. +4. [Configuration](https://logging.apache.org/log4j/2.x/manual/configuration.html) - what you can write in configuration file, +precise algorithm which file is used and many other useful info. It is **highly advised** to read `Additivity` part. \ No newline at end of file diff --git a/docs/RD for UnitTestBot.md b/docs/RD for UnitTestBot.md index c0827b9c96..3becab04da 100644 --- a/docs/RD for UnitTestBot.md +++ b/docs/RD for UnitTestBot.md @@ -228,7 +228,7 @@ Sometimes the _Instrumented process_ may unexpectedly die due to concrete execut - **Important**: do not add [`Rdgen`](https://mvnrepository.com/artifact/com.jetbrains.rd/rd-gen) as an implementation dependency — it breaks some JAR files as it contains `kotlin-compiler-embeddable`. 5. Logging & debugging: - - [Interprocess logging](./contributing/InterProcessLogging.md) + - [Interprocess logging](./InterProcessLogging.md) - [Interprocess debugging](./contributing/InterProcessDebugging.md) 6. Custom protocol marshaling types: do not spend time on it until `UtModels` get simpler, e.g. compatible with `kotlinx.serialization`. diff --git a/docs/contributing/InterProcessDebugging.md b/docs/contributing/InterProcessDebugging.md index a104cef082..864a14e865 100644 --- a/docs/contributing/InterProcessDebugging.md +++ b/docs/contributing/InterProcessDebugging.md @@ -35,7 +35,7 @@ To debug the _Engine process_ and the _Instrumented process_, you need to enable * **Discouraged**: you can change the options in the source file, but this will involve moderate project recompilation. -4. You can set additional options for the Java Debug Wire Protocol (JDWP) agent if debugging is enabled: +3. You can set additional options for the Java Debug Wire Protocol (JDWP) agent if debugging is enabled: * `engineProcessDebugPort` and `instrumentedProcessDebugPort` are the ports for debugging. Default values: @@ -62,7 +62,7 @@ To debug the _Engine process_ and the _Instrumented process_, you need to enable "-agentlib:jdwp=transport=dt_socket,server=n,suspend=n,quiet=y,address=12345" ``` See `org.utbot.intellij.plugin.process.EngineProcess.Companion.debugArgument` for switch implementation. -5. For information about logs, refer to the [Interprocess logging](InterProcessLogging.md) guide. +4. For information about logs, refer to the [Interprocess logging](../InterProcessLogging.md) guide. ### Run configurations for debugging the Engine process diff --git a/docs/contributing/InterProcessLogging.md b/docs/contributing/InterProcessLogging.md deleted file mode 100644 index 7377b09bbb..0000000000 --- a/docs/contributing/InterProcessLogging.md +++ /dev/null @@ -1,129 +0,0 @@ -# Logging of UnitTestBot Java - -## Table of content -- [IDE and Engine processes logs](#ide-and-engine-processes-logs) -- [RD logs](#rd-logs) -- [Instrumented process logs](#instrumented-process-logs) -- [Useful & misc](#useful--misc) - -## IDE and Engine processes logs - -Logging for both IDE and engine processes are based on [`utbot-intellij/log4j2.xml`](../../utbot-intellij/src/main/resources/log4j2.xml). - -### IDE process -Log configuration file is used as is, so if you want to configure logs in IDEA part - use it straight. -If you want to change log configuration in already built plugin - -use `Help > Diagnostic Tools > Debug Log Settings...` to change `log4j2.xml` configuration for plugin. - -### Engine process -Things are a bit more complicated here. -[`utbot-intellij/log4j2.xml`](../../utbot-intellij/src/main/resources/log4j2.xml) is copied in -UtBot temporary directory - `org.utbot.common.FileUtilKt.getUtBotTempDirectory`, -and then provided to JVM via following CLI switch: - ``` - -Dlog4j2.configurationFile=%configuration_file% - ``` - -where `%configuration_file%` will be either: -1. Modified copy of [`utbot-intellij/log4j2.xml`](../../utbot-intellij/src/main/resources/log4j2.xml) at UtBot temp directory. - - More precisely, there are 2 appenders in configuration file: - ```xml - - - - - - - - - ``` - By default `IdeaAppender` is used everywhere in file. - Idea catches plugin stdout log and wraps with own format, so in IDE log only `%msg` is logged. - - When working as engine process - temporary `log4j2.`xml would be created, in which - substring `ref="IdeaAppender"` will be replaced with `ref="EngineProcessAppender"`, - thus changing all appenders and log pattern, but preserving same categories and log level. - -2. Path from `UtSettings.engineProcessLogConfigFile`. - - This option allows to provide path to external Log4j2 configuration file instead of [`utbot-intellij/log4j2.xml`](../../utbot-intellij/src/main/resources/log4j2.xml). - At `~/.utbot/settings.properties` you can set path to custom configuration file, - which would apply for engine process, for example: - ``` - engineProcessLogConfigFile=C:\wrk\UTBotJava\engineProcessLog4j2.xml - ``` - This allows you to configure logs even for already built plugin, - you need only to restart IDE. - -## RD logs - -RD has its own logging system with different interface for logging, -see `com.jetbrains.rd.util.Logger`. - -Obtain logger via global function `getLogger()` from `rd-core.jar`. -By default, logger writes to `stderr` messages with `Warn` or higher log level, -and stdout for others. - -You can set which logger you want RD to use via `com.jetbrains.rd.util.ILoggerFactory` interface. -To set factory use `Logger.set(Lifetime, ILoggerFactory)` method, -for example this code overrides RD logs with `KotlinLogging`: - -```kotlin -Logger.set(object: ILoggerFactory { - override fun getLogger(category: String): Logger { - return KotlinLogging.logger(category) - } -}) -``` - -There are already 2 factories: -1. `UtRdConsoleLoggeFactory` - allows to write stdin/stdout in a format compatible with IDEA `logj42` configuration. -2. `UtRdKLoggerFactory` - smart adapter from RD to KotlinLogger loggers. - -### Details -Setup logger factory before any RD logs occurred, as you might lose some at RD start when loggers are configured to stdout. -The only way to configure RD logs - programmatically. There are no configuration files and/or services. - -Rd logger dynamically reconfigures as new logger factories arrive, see `com.jetbrains.rd.util.SwitchLogger` for -more details. - -Although RD produce ___A LOT OF LOGS___ - for 2-3 test generation logs -file will contain ~800mb of text related to logs, nearly all RD logs has `Trace` log level. You `Trace` with care! - -## Instrumented process logs - -Instrumented process have different logging due to class mocking limitation: -in some cases we want to mock loggers, and for that we would need to mock static function like `getLogger` etc. -In that case if we use that logger in UtBot - we might get incorrect version which in fact is mock. - -Instead, you should use hand-made logging based on RD as described in [RD logs section](#rd-logs). - -To configure instrumented process log level - use `UtSettings.instrumentedProcessLogLevel` property, -for example add in settings.properties: - -```kotlin -instrumentedProcessLogLevel=Debug -``` - -## Useful & misc - -### Log4j2 - -Sometimes your log entries might duplicate when using log4j or similar. -One of the reason might be *additivity*, read [here](https://logging.apache.org/log4j/2.x/manual/configuration.html#Additivity) -about how to solve it. - -Also, log4j2 automatically reconfigures when detects changes in log file. Default check timeout - 30s. - -### Output files for processes - -In `idea.log` there will be a path to engine process log file: -``` -Engine process log file - %path-to-engine-process-log% -``` - -And similarly in engine process log file will be entry: -``` -Instrumented process log file: %path-to-instrumented-process-log% -``` \ No newline at end of file diff --git a/utbot-cli/src/main/kotlin/org/utbot/cli/GenerateTestsAbstractCommand.kt b/utbot-cli/src/main/kotlin/org/utbot/cli/GenerateTestsAbstractCommand.kt index 3b789d25a8..db5831a382 100644 --- a/utbot-cli/src/main/kotlin/org/utbot/cli/GenerateTestsAbstractCommand.kt +++ b/utbot-cli/src/main/kotlin/org/utbot/cli/GenerateTestsAbstractCommand.kt @@ -32,7 +32,7 @@ import org.utbot.framework.plugin.api.TestCaseGenerator import org.utbot.framework.plugin.api.TreatOverflowAsError import org.utbot.framework.plugin.api.UtMethodTestSet import org.utbot.framework.plugin.services.JdkInfoDefaultProvider -import org.utbot.summary.summarize +import org.utbot.summary.summarizeAll import java.io.File import java.net.URLClassLoader import java.nio.file.Files @@ -161,8 +161,8 @@ abstract class GenerateTestsAbstractCommand(name: String, help: String) : mockStrategy, chosenClassesToMockAlways, generationTimeout - ).map { - if (sourceCodeFile != null) it.summarize(searchDirectory, sourceCodeFile.toFile()) else it + ).let { + if (sourceCodeFile != null) it.summarizeAll(searchDirectory, sourceCodeFile.toFile()) else it } diff --git a/utbot-core/src/main/kotlin/org/utbot/common/Logging.kt b/utbot-core/src/main/kotlin/org/utbot/common/Logging.kt index 99d1b7a7a2..bb24c9142c 100644 --- a/utbot-core/src/main/kotlin/org/utbot/common/Logging.kt +++ b/utbot-core/src/main/kotlin/org/utbot/common/Logging.kt @@ -6,11 +6,11 @@ import java.time.format.DateTimeFormatter val timeFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss.SSS") val dateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy_HH-mm-ss") -class LoggerWithLogMethod(val logger: KLogger, val logMethod: (() -> Any?) -> Unit) +class LoggerWithLogMethod(val logMethod: (() -> Any?) -> Unit) -fun KLogger.info(): LoggerWithLogMethod = LoggerWithLogMethod(this, this::info) -fun KLogger.debug(): LoggerWithLogMethod = LoggerWithLogMethod(this, this::debug) -fun KLogger.trace(): LoggerWithLogMethod = LoggerWithLogMethod(this, this::trace) +fun KLogger.info(): LoggerWithLogMethod = LoggerWithLogMethod(this::info) +fun KLogger.debug(): LoggerWithLogMethod = LoggerWithLogMethod(this::debug) +fun KLogger.trace(): LoggerWithLogMethod = LoggerWithLogMethod(this::trace) fun elapsedSecFrom(startNano: Long): String { val elapsedNano = System.nanoTime() - startNano @@ -35,16 +35,22 @@ fun elapsedSecFrom(startNano: Long): String { * You can use [closingComment] to add some result-depending comment to "Finished:" message. Special "" comment * is added if non local return happened in [block] */ -inline fun LoggerWithLogMethod.bracket( - msg: String, +inline fun LoggerWithLogMethod.measureTime( + crossinline msgBlock: () -> String, crossinline closingComment: (Result) -> Any? = { "" }, block: () -> T ): T { - logMethod { "Started: $msg" } + var msg = "" + + logMethod { + msg = msgBlock() + "Started: $msg" + } + val startNano = System.nanoTime() var alreadyLogged = false - var res : Maybe = Maybe.empty() + var res: Maybe = Maybe.empty() try { // Note: don't replace this one with runCatching, otherwise return from lambda breaks "finished" logging. res = Maybe(block()) @@ -63,20 +69,28 @@ inline fun LoggerWithLogMethod.bracket( } } -inline fun KLogger.catchException(block: () -> T): T? { +inline fun KLogger.catchException(message: String = "Isolated", block: () -> T): T? { return try { block() } catch (e: Throwable) { - this.error(e) { "Isolated" } + this.error(message, e) null } } -inline fun KLogger.logException(block: () -> T): T { +inline fun KLogger.logException(message: String = "Exception occurred", block: () -> T): T { return try { block() } catch (e: Throwable) { - this.error("Exception occurred", e) + this.error(message, e) throw e } +} + +inline fun silent(block: () -> T): T? { + return try { + block() + } catch (_: Throwable) { + null + } } \ No newline at end of file diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt index 35800bbe2a..5c1c66a637 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt @@ -1,6 +1,5 @@ package org.utbot.framework -import com.jetbrains.rd.util.LogLevel import java.io.File import mu.KotlinLogging import org.utbot.common.AbstractSettings @@ -324,11 +323,6 @@ object UtSettings : AbstractSettings(logger, defaultKeyForSettingsPath, defaultS * @see [org.utbot.instrumentation.process.InstrumentedProcessRunner.cmds] */ var runInstrumentedProcessWithDebug by getBooleanProperty(false) - - /** - * Log level for instrumented process. - */ - var instrumentedProcessLogLevel by getEnumProperty(LogLevel.Info) // endregion /** diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/UtExecutionResult.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/UtExecutionResult.kt index f2c50278ca..c269af107e 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/UtExecutionResult.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/UtExecutionResult.kt @@ -1,8 +1,6 @@ package org.utbot.framework.plugin.api import org.utbot.framework.plugin.api.visible.UtStreamConsumingException -import java.io.File -import java.util.LinkedList sealed class UtExecutionResult @@ -38,8 +36,11 @@ data class UtStreamConsumingFailure( /** * unexpectedFail (when exceptions such as NPE, IOBE, etc. appear, but not thrown by a user, applies both for function under test and nested calls ) + * * expectedCheckedThrow (when function under test or nested call explicitly says that checked exception could be thrown and throws it) + * * expectedUncheckedThrow (when there is a throw statement for unchecked exception inside of function under test) + * * unexpectedUncheckedThrow (in case when there is unchecked exception thrown from nested call) */ data class UtExplicitlyThrownException( @@ -60,25 +61,13 @@ data class UtTimeoutException(override val exception: TimeoutException) : UtExec * Indicates failure in concrete execution. * For now it is explicitly throwing by ConcreteExecutor in case instrumented process death. */ -class InstrumentedProcessDeathException(cause: Throwable, errorFile: File, val processStdout: List) : +class InstrumentedProcessDeathException(cause: Throwable) : Exception( buildString { appendLine() appendLine("----------------------------------------") appendLine("The instrumented process is dead") appendLine("Cause:\n${cause.message}") - appendLine("Last 1000 lines of the error log ${errorFile.absolutePath}:") - appendLine("----------------------------------------") - errorFile.useLines { lines -> - val lastLines = LinkedList() - for (line in lines) { - lastLines.add(line) - if (lastLines.size > 1000) { - lastLines.removeFirst() - } - } - lastLines.forEach { appendLine(it) } - } appendLine("----------------------------------------") }, cause @@ -105,4 +94,4 @@ inline fun UtExecutionResult.onFailure(action: (exception: Throwable) -> Unit): fun UtExecutionResult.exceptionOrNull(): Throwable? = when (this) { is UtExecutionFailure -> rootCauseException is UtExecutionSuccess -> null -} +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt index f7fc5ca2cf..ef6202d621 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt @@ -8,7 +8,7 @@ import org.utbot.analytics.EngineAnalyticsContext import org.utbot.analytics.FeatureProcessor import org.utbot.analytics.Predictors import org.utbot.api.exception.UtMockAssumptionViolatedException -import org.utbot.common.bracket +import org.utbot.common.measureTime import org.utbot.common.debug import org.utbot.engine.MockStrategy.NO_MOCKS import org.utbot.engine.pc.* @@ -230,7 +230,7 @@ class UtBotSymbolicEngine( logger.trace { "executing $state concretely..." } - logger.debug().bracket("concolicStrategy<$methodUnderTest>: execute concretely") { + logger.debug().measureTime({ "concolicStrategy<$methodUnderTest>: execute concretely"} ) { val resolver = Resolver( hierarchy, state.memory, @@ -252,7 +252,7 @@ class UtBotSymbolicEngine( if (concreteExecutionResult.violatesUtMockAssumption()) { logger.debug { "Generated test case violates the UtMock assumption: $concreteExecutionResult" } - return@bracket + return@measureTime } val concreteUtExecution = UtSymbolicExecution( @@ -511,7 +511,7 @@ class UtBotSymbolicEngine( //It's possible that symbolic and concrete stateAfter/results are diverged. //So we trust concrete results more. try { - logger.debug().bracket("processResult<$methodUnderTest>: concrete execution") { + logger.debug().measureTime({ "processResult<$methodUnderTest>: concrete execution" } ) { //this can throw CancellationException val concreteExecutionResult = concreteExecutor.executeConcretely( diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/pc/UtSolver.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/pc/UtSolver.kt index 1297636146..7d98030f0c 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/pc/UtSolver.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/pc/UtSolver.kt @@ -3,7 +3,7 @@ package org.utbot.engine.pc import org.utbot.analytics.IncrementalData import org.utbot.analytics.Predictors import org.utbot.analytics.learnOn -import org.utbot.common.bracket +import org.utbot.common.measureTime import org.utbot.common.md5 import org.utbot.common.trace import org.utbot.engine.Eq @@ -222,7 +222,7 @@ data class UtSolver constructor( val translatedAssumes = assumption.constraints.translate() - val statusHolder = logger.trace().bracket("High level check(): ", { it }) { + val statusHolder = logger.trace().measureTime({ "High level check(): " }, { it }) { Predictors.smtIncremental.learnOn(IncrementalData(constraints.hard, hardConstraintsNotYetAddedToZ3Solver)) { hardConstraintsNotYetAddedToZ3Solver.forEach { z3Solver.add(translator.translate(it) as BoolExpr) } @@ -255,7 +255,7 @@ data class UtSolver constructor( val assumptionsInUnsatCore = mutableListOf() while (true) { - val res = logger.trace().bracket("Low level check(): ", { it }) { + val res = logger.trace().measureTime({ "Low level check(): " }, { it }) { val constraintsToCheck = translatedSoft.keys + translatedAssumptions.keys z3Solver.check(*constraintsToCheck.toTypedArray()) } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgMethodConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgMethodConstructor.kt index e3eff3556b..fba77160ec 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgMethodConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgMethodConstructor.kt @@ -1899,22 +1899,6 @@ open class CgMethodConstructor(val context: CgContext) : CgContextOwner by conte methodType = this@CgMethodConstructor.methodType val docComment = currentExecution?.summary?.map { convertDocToCg(it) }?.toMutableList() ?: mutableListOf() - // add JVM crash report path if exists - if (result is UtConcreteExecutionFailure) { - result.extractJvmReportPathOrNull()?.let { - val jvmReportDocumentation = CgDocRegularStmt(getJvmReportDocumentation(it)) - val lastTag = docComment.lastOrNull() - // if the last statement is a
 tag, put the path inside it
-                    if (lastTag == null || lastTag !is CgDocPreTagStatement) {
-                        docComment += jvmReportDocumentation
-                    } else {
-                        val tagContent = lastTag.content
-                        docComment.removeLast()
-                        docComment += CgDocPreTagStatement(tagContent + jvmReportDocumentation)
-                    }
-                }
-            }
-
             documentation = CgDocumentationComment(docComment)
             documentation = if (parameterized) {
                 CgDocumentationComment(text = null)
@@ -1970,18 +1954,6 @@ open class CgMethodConstructor(val context: CgContext) : CgContextOwner by conte
         return CgSimpleRegion("Errors report for ${executable.name}", listOf(errorTestMethod))
     }
 
-    private fun getJvmReportDocumentation(jvmReportPath: String): String {
-        val pureJvmReportPath = jvmReportPath.substringAfter("# ")
-
-        // \n is here because IntellijIdea cannot process other separators
-        return PathUtil.toHtmlLinkTag(PathUtil.replaceSeparator(pureJvmReportPath), fileName = "JVM crash report") + "\n"
-    }
-
-    private fun UtConcreteExecutionFailure.extractJvmReportPathOrNull(): String? =
-        exception.processStdout.singleOrNull {
-            "hs_err_pid" in it
-        }
-
     private fun CgExecutableCall.wrapReflectiveCall() {
         +tryBlock {
             +this@wrapReflectiveCall
diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/TestCaseGenerator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/TestCaseGenerator.kt
index f3e04bd7b6..454c3e5865 100644
--- a/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/TestCaseGenerator.kt
+++ b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/TestCaseGenerator.kt
@@ -10,7 +10,7 @@ import kotlinx.coroutines.launch
 import kotlinx.coroutines.yield
 import mu.KLogger
 import mu.KotlinLogging
-import org.utbot.common.bracket
+import org.utbot.common.measureTime
 import org.utbot.common.runBlockingWithCancellationPredicate
 import org.utbot.common.runIgnoringCancellationException
 import org.utbot.common.trace
@@ -79,7 +79,7 @@ open class TestCaseGenerator(
                 System.setProperty(kotlinx.coroutines.DEBUG_PROPERTY_NAME, kotlinx.coroutines.DEBUG_PROPERTY_VALUE_OFF)
             }
 
-            timeoutLogger.trace().bracket("Soot initialization") {
+            timeoutLogger.trace().measureTime({ "Soot initialization"} ) {
                 SootUtils.runSoot(buildDirs, classpath, forceSootReload, jdkInfo)
             }
 
diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/sarif/GenerateTestsAndSarifReportFacade.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/sarif/GenerateTestsAndSarifReportFacade.kt
index 616c8a871d..f870126799 100644
--- a/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/sarif/GenerateTestsAndSarifReportFacade.kt
+++ b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/sarif/GenerateTestsAndSarifReportFacade.kt
@@ -9,7 +9,7 @@ import org.utbot.framework.plugin.api.UtMethodTestSet
 import org.utbot.framework.plugin.api.util.id
 import org.utbot.sarif.SarifReport
 import org.utbot.sarif.SourceFindingStrategy
-import org.utbot.summary.summarize
+import org.utbot.summary.summarizeAll
 import java.io.File
 import java.nio.file.Path
 
@@ -59,9 +59,7 @@ class GenerateTestsAndSarifReportFacade(
                 sarifProperties.mockStrategy,
                 sarifProperties.classesToMockAlways,
                 sarifProperties.generationTimeout
-            ).map {
-                it.summarize(workingDirectory, targetClass.sourceCodeFile)
-            }
+            ).summarizeAll(workingDirectory, targetClass.sourceCodeFile)
 
     private fun generateTestCode(targetClass: TargetClassWrapper, testSets: List): String =
         initializeCodeGenerator(targetClass)
diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt
index 01c880caea..49fc11bab7 100644
--- a/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt
+++ b/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt
@@ -6,10 +6,7 @@ import com.jetbrains.rd.util.lifetime.Lifetime
 import kotlinx.coroutines.runBlocking
 import mu.KotlinLogging
 import org.utbot.analytics.AnalyticsConfigureUtil
-import org.utbot.common.AbstractSettings
-import org.utbot.common.allNestedClasses
-import org.utbot.common.appendHtmlLine
-import org.utbot.common.nameOfPackage
+import org.utbot.common.*
 import org.utbot.engine.util.mockListeners.ForceMockListener
 import org.utbot.engine.util.mockListeners.ForceStaticMockListener
 import org.utbot.framework.codegen.*
@@ -40,7 +37,7 @@ import org.utbot.rd.generated.settingsModel
 import org.utbot.rd.loggers.UtRdKLoggerFactory
 import org.utbot.sarif.RdSourceFindingStrategyFacade
 import org.utbot.sarif.SarifReport
-import org.utbot.summary.summarize
+import org.utbot.summary.summarizeAll
 import java.io.File
 import java.net.URLClassLoader
 import java.nio.file.Paths
@@ -50,21 +47,25 @@ import kotlin.time.Duration.Companion.seconds
 private val messageFromMainTimeoutMillis = 120.seconds
 private val logger = KotlinLogging.logger {}
 
+@Suppress("unused")
+object EngineProcessMain
+
 // use log4j2.configurationFile property to set log4j configuration
 suspend fun main(args: Array) = runBlocking {
+    Logger.set(Lifetime.Eternal, UtRdKLoggerFactory(logger))
+
+    logger.info("-----------------------------------------------------------------------")
+    logger.info("-------------------NEW ENGINE PROCESS STARTED--------------------------")
+    logger.info("-----------------------------------------------------------------------")
     // 0 - auto port for server, should not be used here
     val port = findRdPort(args)
 
-    Logger.set(Lifetime.Eternal, UtRdKLoggerFactory(logger))
 
     ClientProtocolBuilder().withProtocolTimeout(messageFromMainTimeoutMillis).start(port) {
         AbstractSettings.setupFactory(RdSettingsContainerFactory(protocol.settingsModel))
         val kryoHelper = KryoHelper(lifetime)
         engineProcessModel.setup(kryoHelper, it, protocol)
     }
-    logger.info { "runBlocking ending" }
-}.also {
-    logger.info { "runBlocking ended" }
 }
 
 private lateinit var testGenerator: TestCaseGenerator
@@ -74,12 +75,12 @@ private var idCounter: Long = 0
 
 private fun EngineProcessModel.setup(kryoHelper: KryoHelper, watchdog: IdleWatchdog, realProtocol: IProtocol) {
     val model = this
-    watchdog.wrapActiveCall(setupUtContext) { params ->
+    watchdog.measureTimeForActiveCall(setupUtContext, "UtContext setup") { params ->
         UtContext.setUtContext(UtContext(URLClassLoader(params.classpathForUrlsClassloader.map {
             File(it).toURI().toURL()
         }.toTypedArray())))
     }
-    watchdog.wrapActiveCall(createTestGenerator) { params ->
+    watchdog.measureTimeForActiveCall(createTestGenerator, "Creating Test Generator") { params ->
         AnalyticsConfigureUtil.configureML()
         Instrumenter.adapter = RdInstrumenter(realProtocol.rdInstrumenterAdapter)
         testGenerator = TestCaseGenerator(buildDirs = params.buildDir.map { Paths.get(it) },
@@ -92,37 +93,38 @@ private fun EngineProcessModel.setup(kryoHelper: KryoHelper, watchdog: IdleWatch
                 }
             })
     }
-    watchdog.wrapActiveCall(generate) { params ->
-        val mockFrameworkInstalled = params.mockInstalled
-        val conflictTriggers = ConflictTriggers(kryoHelper.readObject(params.conflictTriggers))
-        if (!mockFrameworkInstalled) {
-            ForceMockListener.create(testGenerator, conflictTriggers, cancelJob = true)
-        }
-        val staticsMockingConfigured = params.staticsMockingIsConfigureda
-        if (!staticsMockingConfigured) {
-            ForceStaticMockListener.create(testGenerator, conflictTriggers, cancelJob = true)
-        }
-        val result = testGenerator.generate(kryoHelper.readObject(params.methods),
-            MockStrategyApi.valueOf(params.mockStrategy),
-            kryoHelper.readObject(params.chosenClassesToMockAlways),
-            params.timeout,
-            generate = testFlow {
-                generationTimeout = params.generationTimeout
-                isSymbolicEngineEnabled = params.isSymbolicEngineEnabled
-                isFuzzingEnabled = params.isFuzzingEnabled
-                fuzzingValue = params.fuzzingValue
-            })
-            .apply { logger.info("generation ended, starting summarization, result size: ${this.size}") }
-            .map { it.summarize(Paths.get(params.searchDirectory), sourceFile = null) }
-            .apply { logger.info("summarization ended") }
-            .filterNot { it.executions.isEmpty() && it.errors.isEmpty() }
+    watchdog.measureTimeForActiveCall(generate, "Generating tests") { params ->
+        val methods: List = kryoHelper.readObject(params.methods)
+        logger.debug().measureTime({ "starting generation for ${methods.size} methods, starting with ${methods.first()}" }) {
+            val mockFrameworkInstalled = params.mockInstalled
+            val conflictTriggers = ConflictTriggers(kryoHelper.readObject(params.conflictTriggers))
+            if (!mockFrameworkInstalled) {
+                ForceMockListener.create(testGenerator, conflictTriggers, cancelJob = true)
+            }
+            val staticsMockingConfigured = params.staticsMockingIsConfigureda
+            if (!staticsMockingConfigured) {
+                ForceStaticMockListener.create(testGenerator, conflictTriggers, cancelJob = true)
+            }
+            val result = testGenerator.generate(methods,
+                MockStrategyApi.valueOf(params.mockStrategy),
+                kryoHelper.readObject(params.chosenClassesToMockAlways),
+                params.timeout,
+                generate = testFlow {
+                    generationTimeout = params.generationTimeout
+                    isSymbolicEngineEnabled = params.isSymbolicEngineEnabled
+                    isFuzzingEnabled = params.isFuzzingEnabled
+                    fuzzingValue = params.fuzzingValue
+                })
+                .summarizeAll(Paths.get(params.searchDirectory), null)
+                .filterNot { it.executions.isEmpty() && it.errors.isEmpty() }
 
-        val id = ++idCounter
+            val id = ++idCounter
 
-        testSets[id] = result
-        GenerateResult(result.size, id)
+            testSets[id] = result
+            GenerateResult(result.size, id)
+        }
     }
-    watchdog.wrapActiveCall(render) { params ->
+    watchdog.measureTimeForActiveCall(render, "Rendering tests") { params ->
         val testFramework = testFrameworkByName(params.testFramework)
         val staticMocking = if (params.staticsMocking.startsWith("No")) {
             NoStaticMocking
@@ -147,37 +149,32 @@ private fun EngineProcessModel.setup(kryoHelper: KryoHelper, watchdog: IdleWatch
             enableTestsTimeout = params.enableTestsTimeout,
             testClassPackageName = params.testClassPackageName
         )
-        codeGenerator.generateAsStringWithTestReport(testSets[testSetsId]!!)
-            .let {
-                testGenerationReports.add(it.testsGenerationReport)
-                RenderResult(it.generatedCode, it.utilClassKind?.javaClass?.simpleName)
-            }
+        codeGenerator.generateAsStringWithTestReport(testSets[testSetsId]!!).let {
+            testGenerationReports.add(it.testsGenerationReport)
+            RenderResult(it.generatedCode, it.utilClassKind?.javaClass?.simpleName)
+        }
     }
-    watchdog.wrapActiveCall(stopProcess) { watchdog.stopProtocol() }
-    watchdog.wrapActiveCall(obtainClassId) { canonicalName ->
+    watchdog.measureTimeForActiveCall(obtainClassId, "Obtain class id in UtContext") { canonicalName ->
         kryoHelper.writeObject(UtContext.currentContext()!!.classLoader.loadClass(canonicalName).id)
     }
-    watchdog.wrapActiveCall(findMethodsInClassMatchingSelected) { params ->
+    watchdog.measureTimeForActiveCall(findMethodsInClassMatchingSelected, "Find methods in Class") { params ->
         val classId = kryoHelper.readObject(params.classId)
         val selectedMethodDescriptions =
             params.methodDescriptions.map { MethodDescription(it.name, it.containingClass, it.parametersTypes) }
         FindMethodsInClassMatchingSelectedResult(kryoHelper.writeObject(classId.jClass.allNestedClasses.flatMap { clazz ->
             clazz.id.allMethods.mapNotNull { it.method.kotlinFunction }
                 .sortedWith(compareBy { selectedMethodDescriptions.indexOf(it.methodDescription()) })
-                .filter { it.methodDescription().normalized() in selectedMethodDescriptions }
-                .map { it.executableId }
+                .filter { it.methodDescription().normalized() in selectedMethodDescriptions }.map { it.executableId }
         }))
     }
-    watchdog.wrapActiveCall(findMethodParamNames) { params ->
+    watchdog.measureTimeForActiveCall(findMethodParamNames, "Find method parameters names") { params ->
         val classId = kryoHelper.readObject(params.classId)
         val byMethodDescription = kryoHelper.readObject>>(params.bySignature)
-        FindMethodParamNamesResult(kryoHelper.writeObject(
-            classId.jClass.allNestedClasses.flatMap { clazz -> clazz.id.allMethods.mapNotNull { it.method.kotlinFunction } }
-                .mapNotNull { method -> byMethodDescription[method.methodDescription()]?.let { params -> method.executableId to params } }
-                .toMap()
-        ))
+        FindMethodParamNamesResult(kryoHelper.writeObject(classId.jClass.allNestedClasses.flatMap { clazz -> clazz.id.allMethods.mapNotNull { it.method.kotlinFunction } }
+            .mapNotNull { method -> byMethodDescription[method.methodDescription()]?.let { params -> method.executableId to params } }
+            .toMap()))
     }
-    watchdog.wrapActiveCall(writeSarifReport) { params ->
+    watchdog.measureTimeForActiveCall(writeSarifReport, "Writing Sarif report") { params ->
         val reportFilePath = Paths.get(params.reportFilePath)
         reportFilePath.parent.toFile().mkdirs()
         val sarifReport = SarifReport(
@@ -188,12 +185,12 @@ private fun EngineProcessModel.setup(kryoHelper: KryoHelper, watchdog: IdleWatch
         reportFilePath.toFile().writeText(sarifReport)
         sarifReport
     }
-    watchdog.wrapActiveCall(generateTestReport) { params ->
+    watchdog.measureTimeForActiveCall(generateTestReport, "Generating test report") { params ->
         val eventLogMessage = params.eventLogMessage
         val testPackageName: String? = params.testPackageName
         var hasWarnings = false
         val reports = testGenerationReports
-        if (reports.isEmpty()) return@wrapActiveCall GenerateTestReportResult("No tests were generated", null, true)
+        if (reports.isEmpty()) return@measureTimeForActiveCall GenerateTestReportResult("No tests were generated", null, true)
         val isMultiPackage = params.isMultiPackage
         val (notifyMessage, statistics) = if (reports.size == 1) {
             val report = reports.first()
@@ -202,15 +199,13 @@ private fun EngineProcessModel.setup(kryoHelper: KryoHelper, watchdog: IdleWatch
             val message = buildString {
                 appendHtmlLine(report.toString(isShort = true))
 
-                val classUnderTestPackageName =
-                    report.classUnderTest.java.nameOfPackage
+                val classUnderTestPackageName = report.classUnderTest.java.nameOfPackage
 
-                destinationWarningMessage(testPackageName, classUnderTestPackageName)
-                    ?.let {
-                        hasWarnings = true
-                        appendHtmlLine(it)
-                        appendHtmlLine()
-                    }
+                destinationWarningMessage(testPackageName, classUnderTestPackageName)?.let {
+                    hasWarnings = true
+                    appendHtmlLine(it)
+                    appendHtmlLine()
+                }
                 eventLogMessage?.let {
                     appendHtmlLine(it)
                 }
@@ -232,13 +227,11 @@ private fun EngineProcessModel.setup(kryoHelper: KryoHelper, watchdog: IdleWatch
                 // TODO maybe add statistics info here
 
                 for (report in reports) {
-                    val classUnderTestPackageName =
-                        report.classUnderTest.java.nameOfPackage
+                    val classUnderTestPackageName = report.classUnderTest.java.nameOfPackage
 
                     hasWarnings = hasWarnings || report.hasWarnings
                     if (!isMultiPackage) {
-                        val destinationWarning =
-                            destinationWarningMessage(testPackageName, classUnderTestPackageName)
+                        val destinationWarning = destinationWarningMessage(testPackageName, classUnderTestPackageName)
                         if (destinationWarning != null) {
                             hasWarnings = true
                             appendHtmlLine(destinationWarning)
diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessModel.Generated.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessModel.Generated.kt
index dc49b4d12e..76ac332ac6 100644
--- a/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessModel.Generated.kt
+++ b/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessModel.Generated.kt
@@ -15,7 +15,7 @@ import kotlin.jvm.JvmStatic
 
 
 /**
- * #### Generated from [EngineProcessModel.kt:30]
+ * #### Generated from [EngineProcessModel.kt:31]
  */
 class EngineProcessModel private constructor(
     private val _setupUtContext: RdCall,
@@ -23,7 +23,6 @@ class EngineProcessModel private constructor(
     private val _isCancelled: RdCall,
     private val _generate: RdCall,
     private val _render: RdCall,
-    private val _stopProcess: RdCall,
     private val _obtainClassId: RdCall,
     private val _findMethodsInClassMatchingSelected: RdCall,
     private val _findMethodParamNames: RdCall,
@@ -71,9 +70,9 @@ class EngineProcessModel private constructor(
                 bind(lifetime, protocol, "EngineProcessModel")
             }
         }
-
-
-        const val serializationHash = -6219345436129699239L
+        
+        
+        const val serializationHash = 5025678608993948804L
         
     }
     override val serializersOwner: ISerializersOwner get() = EngineProcessModel
@@ -85,7 +84,6 @@ class EngineProcessModel private constructor(
     val isCancelled: RdCall get() = _isCancelled
     val generate: RdCall get() = _generate
     val render: RdCall get() = _render
-    val stopProcess: RdCall get() = _stopProcess
     val obtainClassId: RdCall get() = _obtainClassId
     val findMethodsInClassMatchingSelected: RdCall get() = _findMethodsInClassMatchingSelected
     val findMethodParamNames: RdCall get() = _findMethodParamNames
@@ -99,7 +97,6 @@ class EngineProcessModel private constructor(
         _isCancelled.async = true
         _generate.async = true
         _render.async = true
-        _stopProcess.async = true
         _obtainClassId.async = true
         _findMethodsInClassMatchingSelected.async = true
         _findMethodParamNames.async = true
@@ -113,7 +110,6 @@ class EngineProcessModel private constructor(
         bindableChildren.add("isCancelled" to _isCancelled)
         bindableChildren.add("generate" to _generate)
         bindableChildren.add("render" to _render)
-        bindableChildren.add("stopProcess" to _stopProcess)
         bindableChildren.add("obtainClassId" to _obtainClassId)
         bindableChildren.add("findMethodsInClassMatchingSelected" to _findMethodsInClassMatchingSelected)
         bindableChildren.add("findMethodParamNames" to _findMethodParamNames)
@@ -129,7 +125,6 @@ class EngineProcessModel private constructor(
         RdCall(FrameworkMarshallers.Void, FrameworkMarshallers.Bool),
         RdCall(GenerateParams, GenerateResult),
         RdCall(RenderParams, RenderResult),
-        RdCall(FrameworkMarshallers.Void, FrameworkMarshallers.Void),
         RdCall(FrameworkMarshallers.String, FrameworkMarshallers.ByteArray),
         RdCall(FindMethodsInClassMatchingSelectedArguments, FindMethodsInClassMatchingSelectedResult),
         RdCall(FindMethodParamNamesArguments, FindMethodParamNamesResult),
@@ -148,7 +143,6 @@ class EngineProcessModel private constructor(
             print("isCancelled = "); _isCancelled.print(printer); println()
             print("generate = "); _generate.print(printer); println()
             print("render = "); _render.print(printer); println()
-            print("stopProcess = "); _stopProcess.print(printer); println()
             print("obtainClassId = "); _obtainClassId.print(printer); println()
             print("findMethodsInClassMatchingSelected = "); _findMethodsInClassMatchingSelected.print(printer); println()
             print("findMethodParamNames = "); _findMethodParamNames.print(printer); println()
@@ -165,7 +159,6 @@ class EngineProcessModel private constructor(
             _isCancelled.deepClonePolymorphic(),
             _generate.deepClonePolymorphic(),
             _render.deepClonePolymorphic(),
-            _stopProcess.deepClonePolymorphic(),
             _obtainClassId.deepClonePolymorphic(),
             _findMethodsInClassMatchingSelected.deepClonePolymorphic(),
             _findMethodParamNames.deepClonePolymorphic(),
@@ -180,7 +173,7 @@ val IProtocol.engineProcessModel get() = getOrCreateExtension(EngineProcessModel
 
 
 /**
- * #### Generated from [EngineProcessModel.kt:100]
+ * #### Generated from [EngineProcessModel.kt:101]
  */
 data class FindMethodParamNamesArguments (
     val classId: ByteArray,
@@ -243,7 +236,7 @@ data class FindMethodParamNamesArguments (
 
 
 /**
- * #### Generated from [EngineProcessModel.kt:104]
+ * #### Generated from [EngineProcessModel.kt:105]
  */
 data class FindMethodParamNamesResult (
     val paramNames: ByteArray
@@ -300,7 +293,7 @@ data class FindMethodParamNamesResult (
 
 
 /**
- * #### Generated from [EngineProcessModel.kt:93]
+ * #### Generated from [EngineProcessModel.kt:94]
  */
 data class FindMethodsInClassMatchingSelectedArguments (
     val classId: ByteArray,
@@ -312,7 +305,7 @@ data class FindMethodsInClassMatchingSelectedArguments (
         override val _type: KClass = FindMethodsInClassMatchingSelectedArguments::class
         
         @Suppress("UNCHECKED_CAST")
-        override fun read(ctx: SerializationCtx, buffer: AbstractBuffer): FindMethodsInClassMatchingSelectedArguments {
+        override fun read(ctx: SerializationCtx, buffer: AbstractBuffer): FindMethodsInClassMatchingSelectedArguments  {
             val classId = buffer.readByteArray()
             val methodDescriptions = buffer.readList { MethodDescription.read(ctx, buffer) }
             return FindMethodsInClassMatchingSelectedArguments(classId, methodDescriptions)
@@ -335,7 +328,7 @@ data class FindMethodsInClassMatchingSelectedArguments (
         if (other == null || other::class != this::class) return false
         
         other as FindMethodsInClassMatchingSelectedArguments
-
+        
         if (!(classId contentEquals other.classId)) return false
         if (methodDescriptions != other.methodDescriptions) return false
         
@@ -344,8 +337,8 @@ data class FindMethodsInClassMatchingSelectedArguments (
     //hash code trait
     override fun hashCode(): Int  {
         var __r = 0
-        __r = __r * 31 + classId.contentHashCode()
-        __r = __r * 31 + methodDescriptions.hashCode()
+        __r = __r*31 + classId.contentHashCode()
+        __r = __r*31 + methodDescriptions.hashCode()
         return __r
     }
     //pretty print
@@ -363,7 +356,7 @@ data class FindMethodsInClassMatchingSelectedArguments (
 
 
 /**
- * #### Generated from [EngineProcessModel.kt:97]
+ * #### Generated from [EngineProcessModel.kt:98]
  */
 data class FindMethodsInClassMatchingSelectedResult (
     val executableIds: ByteArray
@@ -420,7 +413,7 @@ data class FindMethodsInClassMatchingSelectedResult (
 
 
 /**
- * #### Generated from [EngineProcessModel.kt:42]
+ * #### Generated from [EngineProcessModel.kt:43]
  */
 data class GenerateParams (
     val mockInstalled: Boolean,
@@ -543,7 +536,7 @@ data class GenerateParams (
 
 
 /**
- * #### Generated from [EngineProcessModel.kt:60]
+ * #### Generated from [EngineProcessModel.kt:61]
  */
 data class GenerateResult (
     val notEmptyCases: Int,
@@ -606,7 +599,7 @@ data class GenerateResult (
 
 
 /**
- * #### Generated from [EngineProcessModel.kt:112]
+ * #### Generated from [EngineProcessModel.kt:113]
  */
 data class GenerateTestReportArgs (
     val eventLogMessage: String?,
@@ -699,7 +692,7 @@ data class GenerateTestReportArgs (
 
 
 /**
- * #### Generated from [EngineProcessModel.kt:121]
+ * #### Generated from [EngineProcessModel.kt:122]
  */
 data class GenerateTestReportResult (
     val notifyMessage: String,
@@ -768,7 +761,7 @@ data class GenerateTestReportResult (
 
 
 /**
- * #### Generated from [EngineProcessModel.kt:31]
+ * #### Generated from [EngineProcessModel.kt:32]
  */
 data class JdkInfo (
     val path: String,
@@ -831,64 +824,61 @@ data class JdkInfo (
 
 
 /**
- * #### Generated from [EngineProcessModel.kt:88]
+ * #### Generated from [EngineProcessModel.kt:89]
  */
-data class MethodDescription(
+data class MethodDescription (
     val name: String,
     val containingClass: String?,
     val parametersTypes: List
 ) : IPrintable {
     //companion
-
+    
     companion object : IMarshaller {
         override val _type: KClass = MethodDescription::class
-
+        
         @Suppress("UNCHECKED_CAST")
-        override fun read(ctx: SerializationCtx, buffer: AbstractBuffer): MethodDescription {
+        override fun read(ctx: SerializationCtx, buffer: AbstractBuffer): MethodDescription  {
             val name = buffer.readString()
             val containingClass = buffer.readNullable { buffer.readString() }
             val parametersTypes = buffer.readList { buffer.readNullable { buffer.readString() } }
             return MethodDescription(name, containingClass, parametersTypes)
         }
-
-        override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: MethodDescription) {
+        
+        override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: MethodDescription)  {
             buffer.writeString(value.name)
             buffer.writeNullable(value.containingClass) { buffer.writeString(it) }
             buffer.writeList(value.parametersTypes) { v -> buffer.writeNullable(v) { buffer.writeString(it) } }
         }
-
-
+        
+        
     }
-
     //fields
     //methods
     //initializer
     //secondary constructor
     //equals trait
-    override fun equals(other: Any?): Boolean {
+    override fun equals(other: Any?): Boolean  {
         if (this === other) return true
         if (other == null || other::class != this::class) return false
-
+        
         other as MethodDescription
-
+        
         if (name != other.name) return false
         if (containingClass != other.containingClass) return false
         if (parametersTypes != other.parametersTypes) return false
-
+        
         return true
     }
-
     //hash code trait
-    override fun hashCode(): Int {
+    override fun hashCode(): Int  {
         var __r = 0
-        __r = __r * 31 + name.hashCode()
-        __r = __r * 31 + if (containingClass != null) containingClass.hashCode() else 0
-        __r = __r * 31 + parametersTypes.hashCode()
+        __r = __r*31 + name.hashCode()
+        __r = __r*31 + if (containingClass != null) containingClass.hashCode() else 0
+        __r = __r*31 + parametersTypes.hashCode()
         return __r
     }
-
     //pretty print
-    override fun print(printer: PrettyPrinter) {
+    override fun print(printer: PrettyPrinter)  {
         printer.println("MethodDescription (")
         printer.indent {
             print("name = "); name.print(printer); println()
@@ -903,9 +893,9 @@ data class MethodDescription(
 
 
 /**
- * #### Generated from [EngineProcessModel.kt:64]
+ * #### Generated from [EngineProcessModel.kt:65]
  */
-data class RenderParams(
+data class RenderParams (
     val testSetsId: Long,
     val classUnderTest: ByteArray,
     val paramNames: ByteArray,
@@ -1044,7 +1034,7 @@ data class RenderParams(
 
 
 /**
- * #### Generated from [EngineProcessModel.kt:81]
+ * #### Generated from [EngineProcessModel.kt:82]
  */
 data class RenderResult (
     val generatedCode: String,
@@ -1107,7 +1097,7 @@ data class RenderResult (
 
 
 /**
- * #### Generated from [EngineProcessModel.kt:85]
+ * #### Generated from [EngineProcessModel.kt:86]
  */
 data class SetupContextParams (
     val classpathForUrlsClassloader: List
@@ -1164,7 +1154,7 @@ data class SetupContextParams (
 
 
 /**
- * #### Generated from [EngineProcessModel.kt:36]
+ * #### Generated from [EngineProcessModel.kt:37]
  */
 data class TestGeneratorParams (
     val buildDir: Array,
@@ -1239,7 +1229,7 @@ data class TestGeneratorParams (
 
 
 /**
- * #### Generated from [EngineProcessModel.kt:107]
+ * #### Generated from [EngineProcessModel.kt:108]
  */
 data class WriteSarifReportArguments (
     val testSetsId: Long,
diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessRoot.Generated.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessRoot.Generated.kt
index 0b333c3a50..dd4a221774 100644
--- a/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessRoot.Generated.kt
+++ b/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessRoot.Generated.kt
@@ -15,7 +15,7 @@ import kotlin.jvm.JvmStatic
 
 
 /**
- * #### Generated from [EngineProcessModel.kt:5]
+ * #### Generated from [EngineProcessModel.kt:6]
  */
 class EngineProcessRoot private constructor(
 ) : RdExtBase() {
diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/RdInstrumenterAdapter.Generated.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/RdInstrumenterAdapter.Generated.kt
index f4fbc6f17d..c9c56ee162 100644
--- a/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/RdInstrumenterAdapter.Generated.kt
+++ b/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/RdInstrumenterAdapter.Generated.kt
@@ -15,7 +15,7 @@ import kotlin.jvm.JvmStatic
 
 
 /**
- * #### Generated from [EngineProcessModel.kt:7]
+ * #### Generated from [EngineProcessModel.kt:8]
  */
 class RdInstrumenterAdapter private constructor(
     private val _computeSourceFileByClass: RdCall
@@ -97,7 +97,7 @@ val IProtocol.rdInstrumenterAdapter get() = getOrCreateExtension(RdInstrumenterA
 
 
 /**
- * #### Generated from [EngineProcessModel.kt:8]
+ * #### Generated from [EngineProcessModel.kt:9]
  */
 data class ComputeSourceFileByClassArguments (
     val canonicalClassName: String
diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/RdSourceFindingStrategy.Generated.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/RdSourceFindingStrategy.Generated.kt
index 598ae1e086..11324e77f2 100644
--- a/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/RdSourceFindingStrategy.Generated.kt
+++ b/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/RdSourceFindingStrategy.Generated.kt
@@ -15,7 +15,7 @@ import kotlin.jvm.JvmStatic
 
 
 /**
- * #### Generated from [EngineProcessModel.kt:16]
+ * #### Generated from [EngineProcessModel.kt:17]
  */
 class RdSourceFindingStrategy private constructor(
     private val _testsRelativePath: RdCall,
@@ -111,7 +111,7 @@ val IProtocol.rdSourceFindingStrategy get() = getOrCreateExtension(RdSourceFindi
 
 
 /**
- * #### Generated from [EngineProcessModel.kt:17]
+ * #### Generated from [EngineProcessModel.kt:18]
  */
 data class SourceStrategyMethodArgs (
     val testSetId: Long,
diff --git a/utbot-gradle/src/main/kotlin/org/utbot/gradle/plugin/GenerateTestsAndSarifReportTask.kt b/utbot-gradle/src/main/kotlin/org/utbot/gradle/plugin/GenerateTestsAndSarifReportTask.kt
index 2f7bac2262..1e5081a6ba 100644
--- a/utbot-gradle/src/main/kotlin/org/utbot/gradle/plugin/GenerateTestsAndSarifReportTask.kt
+++ b/utbot-gradle/src/main/kotlin/org/utbot/gradle/plugin/GenerateTestsAndSarifReportTask.kt
@@ -1,137 +1,137 @@
-package org.utbot.gradle.plugin
-
-import mu.KLogger
-import org.gradle.api.DefaultTask
-import org.gradle.api.tasks.TaskAction
-import org.utbot.common.bracket
-import org.utbot.common.debug
-import org.utbot.framework.plugin.api.TestCaseGenerator
-import org.utbot.framework.plugin.api.util.UtContext
-import org.utbot.framework.plugin.api.util.withUtContext
-import org.utbot.framework.plugin.sarif.GenerateTestsAndSarifReportFacade
-import org.utbot.gradle.plugin.extension.SarifGradleExtensionProvider
-import org.utbot.gradle.plugin.wrappers.GradleProjectWrapper
-import org.utbot.gradle.plugin.wrappers.SourceFindingStrategyGradle
-import org.utbot.gradle.plugin.wrappers.SourceSetWrapper
-import org.utbot.framework.plugin.sarif.TargetClassWrapper
-import org.utbot.framework.plugin.services.JdkInfoDefaultProvider
-import java.io.File
-import java.net.URLClassLoader
-import javax.inject.Inject
-
-/**
- * The main class containing the entry point [generateTestsAndSarifReport].
- *
- * [Documentation](https://docs.gradle.org/current/userguide/custom_tasks.html)
- */
-open class GenerateTestsAndSarifReportTask @Inject constructor(
-    private val sarifProperties: SarifGradleExtensionProvider
-) : DefaultTask() {
-
-    init {
-        group = "utbot"
-        description = "Generate a SARIF report"
-    }
-
-    /**
-     * Entry point: called when the user starts this gradle task.
-     */
-    @TaskAction
-    fun generateTestsAndSarifReport() {
-        // the user specifies the parameters using "-Pname=value"
-        sarifProperties.taskParameters = project.gradle.startParameter.projectProperties
-        val rootGradleProject = try {
-            GradleProjectWrapper(project, sarifProperties)
-        } catch (t: Throwable) {
-            logger.error(t) { "Unexpected error while configuring the gradle task" }
-            return
-        }
-        try {
-
-            generateForProjectRecursively(rootGradleProject)
-            GenerateTestsAndSarifReportFacade.mergeReports(
-                sarifReports = rootGradleProject.collectReportsRecursively(),
-                mergedSarifReportFile = rootGradleProject.sarifReportFile
-            )
-        } catch (t: Throwable) {
-            logger.error(t) { "Unexpected error while generating SARIF report" }
-            return
-        }
-    }
-
-    // internal
-
-    // overwriting the getLogger() function from the DefaultTask
-    private val logger: KLogger = org.utbot.gradle.plugin.logger
-
-    private val dependencyPaths by lazy {
-        val thisClassLoader = this::class.java.classLoader as? URLClassLoader
-            ?: return@lazy System.getProperty("java.class.path")
-        thisClassLoader.urLs.joinToString(File.pathSeparator) { it.path }
-    }
-
-    /**
-     * Generates tests and a SARIF report for classes in the [gradleProject] and in all its child projects.
-     */
-    private fun generateForProjectRecursively(gradleProject: GradleProjectWrapper) {
-        gradleProject.sourceSets.forEach { sourceSet ->
-            generateForSourceSet(sourceSet)
-        }
-        gradleProject.childProjects.forEach { childProject ->
-            generateForProjectRecursively(childProject)
-        }
-    }
-
-    /**
-     * Generates tests and a SARIF report for classes in the [sourceSet].
-     */
-    private fun generateForSourceSet(sourceSet: SourceSetWrapper) {
-        logger.debug().bracket("Generating tests for the '${sourceSet.sourceSet.name}' source set") {
-            withUtContext(UtContext(sourceSet.classLoader)) {
-                val testCaseGenerator =
-                    TestCaseGenerator(
-                        listOf(sourceSet.workingDirectory),
-                        sourceSet.runtimeClasspath,
-                        dependencyPaths,
-                        JdkInfoDefaultProvider().info
-                    )
-                sourceSet.targetClasses.forEach { targetClass ->
-                    generateForClass(sourceSet, targetClass, testCaseGenerator)
-                }
-            }
-        }
-    }
-
-    /**
-     * Generates tests and a SARIF report for the class [targetClass].
-     */
-    private fun generateForClass(
-        sourceSet: SourceSetWrapper,
-        targetClass: TargetClassWrapper,
-        testCaseGenerator: TestCaseGenerator,
-    ) {
-        logger.debug().bracket("Generating tests for the $targetClass") {
-            val sourceFindingStrategy = SourceFindingStrategyGradle(sourceSet, targetClass.testsCodeFile.path)
-            GenerateTestsAndSarifReportFacade(sarifProperties, sourceFindingStrategy, testCaseGenerator)
-                .generateForClass(targetClass, sourceSet.workingDirectory)
-        }
-    }
-
-    /**
-     * Returns SARIF reports created for this [GradleProjectWrapper] and for all its child projects.
-     */
-    private fun GradleProjectWrapper.collectReportsRecursively(): List =
-        this.sourceSets.flatMap { sourceSetWrapper ->
-            sourceSetWrapper.collectReports()
-        } + this.childProjects.flatMap { childProject ->
-            childProject.collectReportsRecursively()
-        }
-
-    /**
-     * Returns SARIF reports created for this [SourceSetWrapper].
-     */
-    private fun SourceSetWrapper.collectReports(): List =
-        this.targetClasses.map { targetClass ->
-            targetClass.sarifReportFile.readText()
-        }
-}
+package org.utbot.gradle.plugin
+
+import mu.KLogger
+import org.gradle.api.DefaultTask
+import org.gradle.api.tasks.TaskAction
+import org.utbot.common.measureTime
+import org.utbot.common.debug
+import org.utbot.framework.plugin.api.TestCaseGenerator
+import org.utbot.framework.plugin.api.util.UtContext
+import org.utbot.framework.plugin.api.util.withUtContext
+import org.utbot.framework.plugin.sarif.GenerateTestsAndSarifReportFacade
+import org.utbot.gradle.plugin.extension.SarifGradleExtensionProvider
+import org.utbot.gradle.plugin.wrappers.GradleProjectWrapper
+import org.utbot.gradle.plugin.wrappers.SourceFindingStrategyGradle
+import org.utbot.gradle.plugin.wrappers.SourceSetWrapper
+import org.utbot.framework.plugin.sarif.TargetClassWrapper
+import org.utbot.framework.plugin.services.JdkInfoDefaultProvider
+import java.io.File
+import java.net.URLClassLoader
+import javax.inject.Inject
+
+/**
+ * The main class containing the entry point [generateTestsAndSarifReport].
+ *
+ * [Documentation](https://docs.gradle.org/current/userguide/custom_tasks.html)
+ */
+open class GenerateTestsAndSarifReportTask @Inject constructor(
+    private val sarifProperties: SarifGradleExtensionProvider
+) : DefaultTask() {
+
+    init {
+        group = "utbot"
+        description = "Generate a SARIF report"
+    }
+
+    /**
+     * Entry point: called when the user starts this gradle task.
+     */
+    @TaskAction
+    fun generateTestsAndSarifReport() {
+        // the user specifies the parameters using "-Pname=value"
+        sarifProperties.taskParameters = project.gradle.startParameter.projectProperties
+        val rootGradleProject = try {
+            GradleProjectWrapper(project, sarifProperties)
+        } catch (t: Throwable) {
+            logger.error(t) { "Unexpected error while configuring the gradle task" }
+            return
+        }
+        try {
+
+            generateForProjectRecursively(rootGradleProject)
+            GenerateTestsAndSarifReportFacade.mergeReports(
+                sarifReports = rootGradleProject.collectReportsRecursively(),
+                mergedSarifReportFile = rootGradleProject.sarifReportFile
+            )
+        } catch (t: Throwable) {
+            logger.error(t) { "Unexpected error while generating SARIF report" }
+            return
+        }
+    }
+
+    // internal
+
+    // overwriting the getLogger() function from the DefaultTask
+    private val logger: KLogger = org.utbot.gradle.plugin.logger
+
+    private val dependencyPaths by lazy {
+        val thisClassLoader = this::class.java.classLoader as? URLClassLoader
+            ?: return@lazy System.getProperty("java.class.path")
+        thisClassLoader.urLs.joinToString(File.pathSeparator) { it.path }
+    }
+
+    /**
+     * Generates tests and a SARIF report for classes in the [gradleProject] and in all its child projects.
+     */
+    private fun generateForProjectRecursively(gradleProject: GradleProjectWrapper) {
+        gradleProject.sourceSets.forEach { sourceSet ->
+            generateForSourceSet(sourceSet)
+        }
+        gradleProject.childProjects.forEach { childProject ->
+            generateForProjectRecursively(childProject)
+        }
+    }
+
+    /**
+     * Generates tests and a SARIF report for classes in the [sourceSet].
+     */
+    private fun generateForSourceSet(sourceSet: SourceSetWrapper) {
+        logger.debug().measureTime({ "Generating tests for the '${sourceSet.sourceSet.name}' source set" }) {
+            withUtContext(UtContext(sourceSet.classLoader)) {
+                val testCaseGenerator =
+                    TestCaseGenerator(
+                        listOf(sourceSet.workingDirectory),
+                        sourceSet.runtimeClasspath,
+                        dependencyPaths,
+                        JdkInfoDefaultProvider().info
+                    )
+                sourceSet.targetClasses.forEach { targetClass ->
+                    generateForClass(sourceSet, targetClass, testCaseGenerator)
+                }
+            }
+        }
+    }
+
+    /**
+     * Generates tests and a SARIF report for the class [targetClass].
+     */
+    private fun generateForClass(
+        sourceSet: SourceSetWrapper,
+        targetClass: TargetClassWrapper,
+        testCaseGenerator: TestCaseGenerator,
+    ) {
+        logger.debug().measureTime({ "Generating tests for the $targetClass" }) {
+            val sourceFindingStrategy = SourceFindingStrategyGradle(sourceSet, targetClass.testsCodeFile.path)
+            GenerateTestsAndSarifReportFacade(sarifProperties, sourceFindingStrategy, testCaseGenerator)
+                .generateForClass(targetClass, sourceSet.workingDirectory)
+        }
+    }
+
+    /**
+     * Returns SARIF reports created for this [GradleProjectWrapper] and for all its child projects.
+     */
+    private fun GradleProjectWrapper.collectReportsRecursively(): List =
+        this.sourceSets.flatMap { sourceSetWrapper ->
+            sourceSetWrapper.collectReports()
+        } + this.childProjects.flatMap { childProject ->
+            childProject.collectReportsRecursively()
+        }
+
+    /**
+     * Returns SARIF reports created for this [SourceSetWrapper].
+     */
+    private fun SourceSetWrapper.collectReports(): List =
+        this.targetClasses.map { targetClass ->
+            targetClass.sarifReportFile.readText()
+        }
+}
diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/ConcreteExecutor.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/ConcreteExecutor.kt
index 422a0bd069..07abbdb850 100644
--- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/ConcreteExecutor.kt
+++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/ConcreteExecutor.kt
@@ -1,6 +1,8 @@
 package org.utbot.instrumentation
 
+import com.jetbrains.rd.util.ILoggerFactory
 import com.jetbrains.rd.util.Logger
+import com.jetbrains.rd.util.Statics
 import com.jetbrains.rd.util.lifetime.Lifetime
 import com.jetbrains.rd.util.lifetime.LifetimeDefinition
 import com.jetbrains.rd.util.lifetime.isAlive
@@ -20,6 +22,7 @@ import kotlinx.coroutines.sync.Mutex
 import kotlinx.coroutines.sync.withLock
 import mu.KotlinLogging
 import org.utbot.framework.plugin.api.InstrumentedProcessDeathException
+import org.utbot.common.logException
 import org.utbot.framework.plugin.api.FieldId
 import org.utbot.framework.plugin.api.util.UtContext
 import org.utbot.framework.plugin.api.util.signature
@@ -29,7 +32,9 @@ import org.utbot.instrumentation.process.generated.ComputeStaticFieldParams
 import org.utbot.instrumentation.process.generated.InvokeMethodCommandParams
 import org.utbot.instrumentation.rd.InstrumentedProcess
 import org.utbot.instrumentation.util.InstrumentedProcessError
+import org.utbot.rd.generated.synchronizationModel
 import org.utbot.rd.loggers.UtRdKLoggerFactory
+import org.utbot.rd.loggers.overrideDefaultRdLoggerFactoryWithKLogger
 
 private val logger = KotlinLogging.logger {}
 
@@ -120,7 +125,7 @@ class ConcreteExecutor> p
         val defaultPool = ConcreteExecutorPool()
 
         init {
-            Logger.set(Lifetime.Eternal, UtRdKLoggerFactory(logger))
+            overrideDefaultRdLoggerFactoryWithKLogger(logger)
         }
 
         /**
@@ -178,14 +183,7 @@ class ConcreteExecutor> p
     suspend fun  withProcess(exclusively: Boolean = false, block: suspend InstrumentedProcess.() -> T): T {
         fun throwConcreteIfDead(e: Throwable, proc: InstrumentedProcess?) {
             if (proc?.lifetime?.isAlive != true) {
-                throw InstrumentedProcessDeathException(e,
-                    instrumentedProcessRunner.errorLogFile,
-                    try {
-                        proc?.run { process.inputStream.bufferedReader().lines().toList() } ?: emptyList()
-                    } catch (e: Exception) {
-                        emptyList()
-                    }
-                )
+                throw InstrumentedProcessDeathException(e)
             }
         }
 
@@ -229,18 +227,15 @@ class ConcreteExecutor> p
         signature: String,
         arguments: Array,
         parameters: Any?
-    ): TIResult = try {
+    ): TIResult = logger.logException("executeAsync, response(ERROR)") {
         withProcess {
             val argumentsByteArray = kryoHelper.writeObject(arguments.asList())
             val parametersByteArray = kryoHelper.writeObject(parameters)
             val params = InvokeMethodCommandParams(className, signature, argumentsByteArray, parametersByteArray)
 
-            val ba = instrumentedProcessModel.invokeMethodCommand.startSuspending(lifetime, params).result
-            kryoHelper.readObject(ba)
+            val result = instrumentedProcessModel.invokeMethodCommand.startSuspending(lifetime, params).result
+            kryoHelper.readObject(result)
         }
-    } catch (e: Throwable) {
-        logger.trace { "executeAsync, response(ERROR): $e" }
-        throw e
     }
 
     /**
@@ -275,7 +270,7 @@ class ConcreteExecutor> p
                 if (alive) {
                     try {
                         processInstance?.run {
-                            instrumentedProcessModel.stopProcess.start(lifetime, Unit)
+                            protocol.synchronizationModel.stopProcess.fire(Unit)
                         }
                     } catch (_: Exception) {}
                     processInstance = null
diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/agent/DynamicClassTransformer.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/agent/DynamicClassTransformer.kt
index 5ab16b1db9..28607220e3 100644
--- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/agent/DynamicClassTransformer.kt
+++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/agent/DynamicClassTransformer.kt
@@ -11,7 +11,7 @@ import java.security.ProtectionDomain
 import kotlin.io.path.absolutePathString
 
 
-private val logger = getLogger("DynamicClassTransformer")
+private val logger = getLogger()
 
 /**
  * Transformer, which will transform only classes with certain names.
diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/ExecutionPhase.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/ExecutionPhase.kt
index bcff67b0f8..7c64275b07 100644
--- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/ExecutionPhase.kt
+++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/ExecutionPhase.kt
@@ -1,10 +1,11 @@
 package org.utbot.instrumentation.instrumentation.execution.phases
 
 import com.jetbrains.rd.util.getLogger
+import org.utbot.common.measureTime
 import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult
-import org.utbot.rd.logMeasure
+import org.utbot.rd.loggers.debug
 
-private val logger = getLogger("ExecutionPhase")
+private val logger = getLogger()
 
 abstract class ExecutionPhaseException(override val message: String) : Exception()
 
@@ -20,7 +21,7 @@ interface ExecutionPhase {
 
 fun  T.start(block: T.() -> R): R =
     try {
-        logger.logMeasure(this.javaClass.simpleName) {
+        logger.debug().measureTime({ this.javaClass.simpleName } ) {
             this.block()
         }
     } catch (e: ExecutionPhaseStop) {
diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/InstrumentedProcessMain.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/InstrumentedProcessMain.kt
index 96db99322a..0e1af9c98c 100644
--- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/InstrumentedProcessMain.kt
+++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/InstrumentedProcessMain.kt
@@ -2,6 +2,7 @@ package org.utbot.instrumentation.process
 
 import com.jetbrains.rd.util.*
 import com.jetbrains.rd.util.lifetime.Lifetime
+import com.jetbrains.rd.util.reactive.adviseOnce
 import kotlinx.coroutines.*
 import org.mockito.Mockito
 import org.utbot.common.*
@@ -18,14 +19,16 @@ import org.utbot.rd.IdleWatchdog
 import org.utbot.rd.ClientProtocolBuilder
 import org.utbot.rd.RdSettingsContainerFactory
 import org.utbot.rd.findRdPort
+import org.utbot.rd.generated.loggerModel
 import org.utbot.rd.generated.settingsModel
-import org.utbot.rd.loggers.UtRdConsoleLoggerFactory
+import org.utbot.rd.generated.synchronizationModel
+import org.utbot.rd.loggers.UtRdRemoteLoggerFactory
 import java.io.File
+import java.io.IOException
 import java.io.OutputStream
 import java.io.PrintStream
 import java.net.URLClassLoader
 import java.security.AllPermission
-import kotlin.system.measureTimeMillis
 import kotlin.time.Duration
 import kotlin.time.Duration.Companion.seconds
 
@@ -56,12 +59,24 @@ internal object HandlerClassesLoader : URLClassLoader(emptyArray()) {
  * Command-line option to disable the sandbox
  */
 const val DISABLE_SANDBOX_OPTION = "--disable-sandbox"
-const val ENABLE_LOGS_OPTION = "--enable-logs"
-private val logger = getLogger("InstrumentedProcess")
+private val logger = getLogger()
 private val messageFromMainTimeout: Duration = 120.seconds
 
-fun logLevelArgument(level: LogLevel): String {
-    return "$ENABLE_LOGS_OPTION=$level"
+private fun closeStandardStreams() {
+    // we should change out/err streams as not to spend time on user output
+    // and also because rd default logging system writes some initial values to stdout, polluting it as well
+    val tmpStream = PrintStream(object : OutputStream() {
+        override fun write(b: Int) {}
+    })
+    val prevOut = System.out
+    val prevError = System.err
+    System.setOut(tmpStream)
+    System.setErr(tmpStream)
+    // stdin/stderr should be closed as not to leave hanging descriptors
+    // and we cannot log any exceptions here as rd remote logging is still not configured
+    // so we pass any exceptions
+    silent { prevOut.close() }
+    silent { prevError.close() }
 }
 
 interface DummyForMockitoWarmup {
@@ -74,27 +89,21 @@ interface DummyForMockitoWarmup {
  */
 fun warmupMockito() {
     try {
-        val unused = Mockito.mock(DummyForMockitoWarmup::class.java)
-    } catch (ignored: Throwable) {
+        Mockito.mock(DummyForMockitoWarmup::class.java)
+    } catch (e: Throwable) {
+        logger.warn { "Exception during mockito warmup: ${e.stackTraceToString()}" }
     }
 }
 
-private fun findLogLevel(args: Array): LogLevel {
-    val logArgument = args.find{ it.contains(ENABLE_LOGS_OPTION) } ?: return LogLevel.Fatal
-
-    return enumValueOf(logArgument.split("=").last())
-}
+@Suppress("unused")
+object InstrumentedProcessMain
 
 /**
  * It should be compiled into separate jar file (instrumented_process.jar) and be run with an agent (agent.jar) option.
  */
 fun main(args: Array) = runBlocking {
     // We don't want user code to litter the standard output, so we redirect it.
-    val tmpStream = PrintStream(object : OutputStream() {
-        override fun write(b: Int) {}
-    })
-
-    System.setOut(tmpStream)
+    closeStandardStreams()
 
     if (!args.contains(DISABLE_SANDBOX_OPTION)) {
         permissions {
@@ -104,14 +113,14 @@ fun main(args: Array) = runBlocking {
         }
     }
 
-    val logLevel: LogLevel = findLogLevel(args)
-    Logger.set(Lifetime.Eternal, UtRdConsoleLoggerFactory(logLevel, System.err))
-
     val port = findRdPort(args)
 
     try {
         ClientProtocolBuilder().withProtocolTimeout(messageFromMainTimeout).start(port) {
-            this.protocol.scheduler.queue { warmupMockito() }
+            synchronizationModel.initRemoteLogging.adviseOnce(lifetime) {
+                Logger.set(Lifetime.Eternal, UtRdRemoteLoggerFactory(loggerModel))
+                this.protocol.scheduler.queue { warmupMockito() }
+            }
             val kryoHelper = KryoHelper(lifetime)
             logger.info { "setup started" }
             AbstractSettings.setupFactory(RdSettingsContainerFactory(protocol.settingsModel))
@@ -121,9 +130,6 @@ fun main(args: Array) = runBlocking {
     } catch (e: Throwable) {
         logger.error { "Terminating process because exception occurred: ${e.stackTraceToString()}" }
     }
-    logger.info { "runBlocking ending" }
-}.also {
-    logger.info { "runBlocking ended" }
 }
 
 private lateinit var pathsToUserClasses: Set
@@ -132,20 +138,15 @@ private lateinit var instrumentation: Instrumentation<*>
 private var warmupDone = false
 
 private fun InstrumentedProcessModel.setup(kryoHelper: KryoHelper, watchdog: IdleWatchdog) {
-    watchdog.wrapActiveCall(warmup) {
-        logger.info { "received warmup request" }
+    watchdog.measureTimeForActiveCall(warmup, "Classloader warmup request") {
         if (!warmupDone) {
-            val time = measureTimeMillis {
-                HandlerClassesLoader.scanForClasses("").toList() // here we transform classes
-            }
-            logger.info { "warmup finished in $time ms" }
+            HandlerClassesLoader.scanForClasses("").toList() // here we transform classes
             warmupDone = true
         } else {
             logger.info { "warmup already happened" }
         }
     }
-    watchdog.wrapActiveCall(invokeMethodCommand) { params ->
-        logger.debug { "received invokeMethod request: ${params.classname}, ${params.signature}" }
+    watchdog.measureTimeForActiveCall(invokeMethodCommand, "Invoke method request") { params ->
         val clazz = HandlerClassesLoader.loadClass(params.classname)
         val res = kotlin.runCatching {
             instrumentation.invoke(
@@ -156,35 +157,26 @@ private fun InstrumentedProcessModel.setup(kryoHelper: KryoHelper, watchdog: Idl
             )
         }
         res.fold({
-            logger.debug { "invokeMethod success" }
             InvokeMethodCommandResult(kryoHelper.writeObject(it))
         }) {
-            logger.debug { "invokeMethod failure" }
-            logger.error(it)
             throw it
         }
     }
-    watchdog.wrapActiveCall(setInstrumentation) { params ->
+    watchdog.measureTimeForActiveCall(setInstrumentation, "Instrumentation setup") { params ->
         logger.debug { "setInstrumentation request" }
         instrumentation = kryoHelper.readObject(params.instrumentation)
-        logger.trace { "instrumentation - ${instrumentation.javaClass.name} " }
+        logger.debug { "instrumentation - ${instrumentation.javaClass.name} " }
         Agent.dynamicClassTransformer.transformer = instrumentation // classTransformer is set
         Agent.dynamicClassTransformer.addUserPaths(pathsToUserClasses)
         instrumentation.init(pathsToUserClasses)
     }
-    watchdog.wrapActiveCall(addPaths) { params ->
-        logger.debug { "addPaths request" }
+    watchdog.measureTimeForActiveCall(addPaths, "User and dependency classpath setup") { params ->
         pathsToUserClasses = params.pathsToUserClasses.split(File.pathSeparatorChar).toSet()
         HandlerClassesLoader.addUrls(pathsToUserClasses)
         kryoHelper.setKryoClassLoader(HandlerClassesLoader) // Now kryo will use our classloader when it encounters unregistered class.
         UtContext.setUtContext(UtContext(HandlerClassesLoader))
     }
-    watchdog.wrapActiveCall(stopProcess) {
-        logger.debug { "stop request" }
-        watchdog.stopProtocol()
-    }
-    watchdog.wrapActiveCall(collectCoverage) { params ->
-        logger.debug { "collect coverage request" }
+    watchdog.measureTimeForActiveCall(collectCoverage, "Coverage") { params ->
         val anyClass: Class<*> = kryoHelper.readObject(params.clazz)
         logger.debug { "class - ${anyClass.name}" }
         val result = (instrumentation as CoverageInstrumentation).collectCoverageInfo(anyClass)
diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/InstrumentedProcessRunner.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/InstrumentedProcessRunner.kt
index 327ef53437..8d06d98128 100644
--- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/InstrumentedProcessRunner.kt
+++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/InstrumentedProcessRunner.kt
@@ -11,7 +11,6 @@ import org.utbot.framework.process.OpenModulesContainer
 import org.utbot.instrumentation.agent.DynamicClassTransformer
 import org.utbot.rd.rdPortArgument
 import java.io.File
-import java.time.LocalDateTime
 
 private val logger = KotlinLogging.logger {}
 
@@ -27,34 +26,29 @@ class InstrumentedProcessRunner {
             listOf("-javaagent:$jarFile", "-ea", "-jar", "$jarFile")
     }
 
-    var errorLogFile: File = NULL_FILE
-
     fun start(rdPort: Int): Process {
         val portArgument = rdPortArgument(rdPort)
 
         logger.debug { "Starting instrumented process: ${cmds.joinToString(" ")} $portArgument" }
 
-        UT_BOT_TEMP_DIR.mkdirs()
-        val formatted = dateTimeFormatter.format(LocalDateTime.now())
-        errorLogFile = File(UT_BOT_TEMP_DIR, "$formatted.log")
-
         val directory = WorkingDirService.provide().toFile()
         val commandsWithOptions = buildList {
             addAll(cmds)
             if (!UtSettings.useSandbox) {
                 add(DISABLE_SANDBOX_OPTION)
             }
-            add(logLevelArgument(UtSettings.instrumentedProcessLogLevel))
             add(portArgument)
         }
 
         val processBuilder = ProcessBuilder(commandsWithOptions)
-            .redirectError(errorLogFile)
             .directory(directory)
 
         return processBuilder.start().also {
-            logger.info { "Instrumented process started with PID=${it.getPid}" }
-            logger.info { "Instrumented process log file: ${errorLogFile.absolutePath}" }
+            logger.info {
+                "------------------------------------------------------------------\n" +
+                "--------Instrumented process started with PID=${it.getPid}--------\n" +
+                "------------------------------------------------------------------"
+            }
         }
     }
 
@@ -62,13 +56,10 @@ class InstrumentedProcessRunner {
         private fun suspendValue(): String = if (UtSettings.suspendInstrumentedProcessExecutionInDebugMode) "y" else "n"
 
         private const val UTBOT_INSTRUMENTATION = "utbot-instrumentation"
-        private const val ERRORS_FILE_PREFIX = "utbot-instrumentedprocess-errors"
         private const val INSTRUMENTATION_LIB = "lib"
 
         private val DEBUG_RUN_CMD = "-agentlib:jdwp=transport=dt_socket,server=n,suspend=${suspendValue()},quiet=y,address=${UtSettings.instrumentedProcessDebugPort}"
 
-        private val UT_BOT_TEMP_DIR: File = File(utBotTempDirectory.toFile(), ERRORS_FILE_PREFIX)
-
         private val NULL_FILE_PATH: String = if (System.getProperty("os.name").startsWith("Windows")) {
             "NUL"
         } else {
@@ -85,7 +76,7 @@ class InstrumentedProcessRunner {
          * in the gradle configuration of the project which depends on utbot-instrumentation module.
          */
         private val jarFile: File by lazy {
-            logger.debug().bracket("Finding $UTBOT_INSTRUMENTATION jar") {
+            logger.debug().measureTime({ "Finding $UTBOT_INSTRUMENTATION jar" } ) {
                 run {
                     logger.debug("Trying to find jar in the resources.")
                     val tempDir = utBotTempDirectory.toFile()
diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/rd/InstrumentedProcess.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/rd/InstrumentedProcess.kt
index 8008030f82..973c79a597 100644
--- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/rd/InstrumentedProcess.kt
+++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/rd/InstrumentedProcess.kt
@@ -12,13 +12,20 @@ import org.utbot.instrumentation.process.generated.instrumentedProcessModel
 import org.utbot.instrumentation.util.KryoHelper
 import org.utbot.rd.ProcessWithRdServer
 import org.utbot.rd.exceptions.InstantProcessDeathException
+import org.utbot.rd.generated.LoggerModel
+import org.utbot.rd.generated.loggerModel
+import org.utbot.rd.generated.synchronizationModel
+import org.utbot.rd.loggers.UtRdKLogger
+import org.utbot.rd.loggers.UtRdRemoteLogger
 import org.utbot.rd.onSchedulerBlocking
 import org.utbot.rd.startUtProcessWithRdServer
 import org.utbot.rd.terminateOnException
 
-private val logger = KotlinLogging.logger {}
+private val logger = KotlinLogging.logger { }
+private val rdLogger = UtRdKLogger(logger, "")
 
-class InstrumentedProcessInstantDeathException: InstantProcessDeathException(UtSettings.instrumentedProcessDebugPort, UtSettings.runInstrumentedProcessWithDebug)
+class InstrumentedProcessInstantDeathException :
+    InstantProcessDeathException(UtSettings.instrumentedProcessDebugPort, UtSettings.runInstrumentedProcessWithDebug)
 
 /**
  * Main goals of this class:
@@ -33,6 +40,7 @@ class InstrumentedProcess private constructor(
         classLoader?.let { setKryoClassLoader(it) }
     }
     val instrumentedProcessModel: InstrumentedProcessModel = onSchedulerBlocking { protocol.instrumentedProcessModel }
+    val loggerModel: LoggerModel = onSchedulerBlocking { protocol.loggerModel }
 
     companion object {
         suspend operator fun > invoke(
@@ -54,10 +62,22 @@ class InstrumentedProcess private constructor(
 
             logger.trace("rd process started")
 
-            val proc = InstrumentedProcess(
-                classLoader,
-                rdProcess
-            )
+            val proc = InstrumentedProcess(classLoader, rdProcess)
+
+            // currently we do not specify log level for different categories in instrumented process
+            // though it is possible with some additional map on categories -> consider performance
+            proc.loggerModel.getCategoryMinimalLogLevel.set { _ ->
+                // this logLevel is obtained from KotlinLogger
+                rdLogger.logLevel.ordinal
+            }
+
+            proc.loggerModel.log.advise(proc.lifetime) {
+                val logLevel = UtRdRemoteLogger.logLevelValues[it.logLevelOrdinal]
+                // assume throwable already in message
+                rdLogger.log(logLevel, it.message, null)
+            }
+
+            rdProcess.protocol.synchronizationModel.initRemoteLogging.fire(Unit)
 
             proc.lifetime.onTermination {
                 logger.trace { "process is terminating" }
diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/rd/generated/InstrumentedProcessModel.Generated.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/rd/generated/InstrumentedProcessModel.Generated.kt
index 812ad77951..6718640e3e 100644
--- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/rd/generated/InstrumentedProcessModel.Generated.kt
+++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/rd/generated/InstrumentedProcessModel.Generated.kt
@@ -22,7 +22,6 @@ class InstrumentedProcessModel private constructor(
     private val _warmup: RdCall,
     private val _setInstrumentation: RdCall,
     private val _invokeMethodCommand: RdCall,
-    private val _stopProcess: RdCall,
     private val _collectCoverage: RdCall,
     private val _computeStaticField: RdCall
 ) : RdExtBase() {
@@ -62,7 +61,7 @@ class InstrumentedProcessModel private constructor(
         }
         
         
-        const val serializationHash = 7371522075001495459L
+        const val serializationHash = 2443784041000581664L
         
     }
     override val serializersOwner: ISerializersOwner get() = InstrumentedProcessModel
@@ -92,11 +91,6 @@ class InstrumentedProcessModel private constructor(
      */
     val invokeMethodCommand: RdCall get() = _invokeMethodCommand
     
-    /**
-     * This command tells the instrumented process to stop
-     */
-    val stopProcess: RdCall get() = _stopProcess
-    
     /**
      * This command is sent to the instrumented process from the [ConcreteExecutor] if user wants to collect coverage for the
     [clazz]
@@ -115,7 +109,6 @@ class InstrumentedProcessModel private constructor(
         _warmup.async = true
         _setInstrumentation.async = true
         _invokeMethodCommand.async = true
-        _stopProcess.async = true
         _collectCoverage.async = true
         _computeStaticField.async = true
     }
@@ -125,7 +118,6 @@ class InstrumentedProcessModel private constructor(
         bindableChildren.add("warmup" to _warmup)
         bindableChildren.add("setInstrumentation" to _setInstrumentation)
         bindableChildren.add("invokeMethodCommand" to _invokeMethodCommand)
-        bindableChildren.add("stopProcess" to _stopProcess)
         bindableChildren.add("collectCoverage" to _collectCoverage)
         bindableChildren.add("computeStaticField" to _computeStaticField)
     }
@@ -137,7 +129,6 @@ class InstrumentedProcessModel private constructor(
         RdCall(FrameworkMarshallers.Void, FrameworkMarshallers.Void),
         RdCall(SetInstrumentationParams, FrameworkMarshallers.Void),
         RdCall(InvokeMethodCommandParams, InvokeMethodCommandResult),
-        RdCall(FrameworkMarshallers.Void, FrameworkMarshallers.Void),
         RdCall(CollectCoverageParams, CollectCoverageResult),
         RdCall(ComputeStaticFieldParams, ComputeStaticFieldResult)
     )
@@ -152,7 +143,6 @@ class InstrumentedProcessModel private constructor(
             print("warmup = "); _warmup.print(printer); println()
             print("setInstrumentation = "); _setInstrumentation.print(printer); println()
             print("invokeMethodCommand = "); _invokeMethodCommand.print(printer); println()
-            print("stopProcess = "); _stopProcess.print(printer); println()
             print("collectCoverage = "); _collectCoverage.print(printer); println()
             print("computeStaticField = "); _computeStaticField.print(printer); println()
         }
@@ -165,7 +155,6 @@ class InstrumentedProcessModel private constructor(
             _warmup.deepClonePolymorphic(),
             _setInstrumentation.deepClonePolymorphic(),
             _invokeMethodCommand.deepClonePolymorphic(),
-            _stopProcess.deepClonePolymorphic(),
             _collectCoverage.deepClonePolymorphic(),
             _computeStaticField.deepClonePolymorphic()
         )
diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt
index eef1a9608b..c63682b2b5 100644
--- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt
+++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt
@@ -10,7 +10,9 @@ import com.intellij.psi.impl.file.impl.JavaFileManager
 import com.intellij.psi.search.GlobalSearchScope
 import com.intellij.refactoring.util.classMembers.MemberInfo
 import com.jetbrains.rd.util.ConcurrentHashMap
+import com.jetbrains.rd.util.ILoggerFactory
 import com.jetbrains.rd.util.Logger
+import com.jetbrains.rd.util.Statics
 import com.jetbrains.rd.util.lifetime.Lifetime
 import com.jetbrains.rd.util.lifetime.LifetimeDefinition
 import kotlinx.coroutines.runBlocking
@@ -41,21 +43,25 @@ import org.utbot.rd.generated.SettingsModel
 import org.utbot.rd.generated.settingsModel
 import org.utbot.rd.generated.synchronizationModel
 import org.utbot.rd.loggers.UtRdKLoggerFactory
+import org.utbot.rd.loggers.overrideDefaultRdLoggerFactoryWithKLogger
 import org.utbot.sarif.SourceFindingStrategy
 import java.io.File
 import java.nio.charset.Charset
 import java.nio.file.Files
 import java.nio.file.Path
 import java.nio.file.StandardCopyOption
-import java.time.LocalDateTime
 import kotlin.io.path.pathString
 import kotlin.reflect.KProperty1
 import kotlin.reflect.full.memberProperties
 
-private val engineProcessLogConfigurations = utBotTempDirectory.toFile().resolve("rdEngineProcessLogConfigurations")
+private val engineProcessLogConfigurationsDirectory = utBotTempDirectory.toFile().resolve("rdEngineProcessLogConfigurations")
 private val logger = KotlinLogging.logger {}
 private val engineProcessLogDirectory = utBotTempDirectory.toFile().resolve("rdEngineProcessLogs")
 
+private const val configurationFileDeleteKey = "delete_this_comment_key"
+private const val deleteOpenComment = ""
+
 data class RdTestGenerationResult(val notEmptyCases: Int, val testSetsId: Long)
 
 class EngineProcessInstantDeathException :
@@ -68,19 +74,20 @@ class EngineProcess private constructor(val project: Project, private val classN
 
         init {
             engineProcessLogDirectory.mkdirs()
-            engineProcessLogConfigurations.mkdirs()
-            Logger.set(Lifetime.Eternal, UtRdKLoggerFactory(logger))
+            engineProcessLogConfigurationsDirectory.mkdirs()
+            overrideDefaultRdLoggerFactoryWithKLogger(logger)
 
             val customFile = File(UtSettings.engineProcessLogConfigFile)
 
             if (customFile.exists()) {
                 log4j2ConfigFile = customFile
             } else {
-                log4j2ConfigFile = Files.createTempFile(engineProcessLogConfigurations.toPath(), null, ".xml").toFile()
-                log4j2ConfigFile.deleteOnExit()
+                log4j2ConfigFile = Files.createTempFile(engineProcessLogConfigurationsDirectory.toPath(), null, ".xml").toFile()
                 this.javaClass.classLoader.getResourceAsStream("log4j2.xml")?.use { logConfig ->
                     val resultConfig = logConfig.readBytes().toString(Charset.defaultCharset())
+                        .replace(Regex("$deleteOpenComment|$deleteCloseComment"), "")
                         .replace("ref=\"IdeaAppender\"", "ref=\"EngineProcessAppender\"")
+                        .replace("\${env:UTBOT_LOG_DIR}", engineProcessLogDirectory.canonicalPath.trimEnd(File.separatorChar) + File.separatorChar)
                     Files.copy(
                         resultConfig.byteInputStream(),
                         log4j2ConfigFile.toPath(),
@@ -133,16 +140,12 @@ class EngineProcess private constructor(val project: Project, private val classN
                     val cmd = obtainEngineProcessCommandLine(port)
                     val directory = WorkingDirService.provide().toFile()
                     val builder = ProcessBuilder(cmd).directory(directory)
-                    val formatted = dateTimeFormatter.format(LocalDateTime.now())
-                    val logFile = File(engineProcessLogDirectory, "$formatted.log")
-
-                    builder.redirectOutput(logFile)
-                    builder.redirectError(logFile)
-
                     val process = builder.start()
 
                     logger.info { "Engine process started with PID = ${process.getPid}" }
-                    logger.info { "Engine process log file - ${logFile.canonicalPath}" }
+                    logger.info { "Engine process log directory - ${engineProcessLogDirectory.canonicalPath}" }
+                    logger.info { "Engine process log file - ${engineProcessLogDirectory.resolve("utbot-engine-current.log")}" }
+                    logger.info { "Log4j2 configuration file path - ${log4j2ConfigFile.canonicalPath}" }
 
                     if (!process.isAlive) {
                         throw EngineProcessInstantDeathException()
@@ -398,7 +401,7 @@ class EngineProcess private constructor(val project: Project, private val classN
 
     init {
         lifetime.onTermination {
-            engineModel.stopProcess.start(Unit)
+            protocol.synchronizationModel.stopProcess.fire(Unit)
         }
         settingsModel.settingFor.set { params ->
             SettingForResult(AbstractSettings.allSettings[params.key]?.let { settings: AbstractSettings ->
diff --git a/utbot-intellij/src/main/resources/log4j2.xml b/utbot-intellij/src/main/resources/log4j2.xml
index 58caefe205..6a9ae540c8 100644
--- a/utbot-intellij/src/main/resources/log4j2.xml
+++ b/utbot-intellij/src/main/resources/log4j2.xml
@@ -1 +1,34 @@
-

    

        
            
        


        
            
        
    
    
        
            
        
        
            
        
        
            
        
    

\ No newline at end of file
+
+
+    
+        
+        
+            
+        
+        
+        
+        
+        
+        
+        
+    
+    
+        
+            
+        
+        
+            
+        
+        
+            
+        
+    
+
\ No newline at end of file
diff --git a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/Contest.kt b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/Contest.kt
index cba7acaef4..d3f7b6a8cd 100644
--- a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/Contest.kt
+++ b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/Contest.kt
@@ -3,7 +3,7 @@ package org.utbot.contest
 import mu.KotlinLogging
 import org.objectweb.asm.Type
 import org.utbot.common.FileUtil
-import org.utbot.common.bracket
+import org.utbot.common.measureTime
 import org.utbot.common.filterWhen
 import org.utbot.common.info
 import org.utbot.common.isAbstract
@@ -57,7 +57,7 @@ import org.utbot.framework.minimization.minimizeExecutions
 import org.utbot.framework.plugin.api.*
 import org.utbot.framework.plugin.api.util.isSynthetic
 import org.utbot.framework.util.jimpleBody
-import org.utbot.summary.summarize
+import org.utbot.summary.summarizeAll
 
 internal const val junitVersion = 4
 private val logger = KotlinLogging.logger {}
@@ -118,7 +118,7 @@ fun main(args: Array) {
         // This saves the time budget for real work instead of soot initialization.
         TestCaseGenerator(listOf(classfileDir), classpathString, dependencyPath, JdkInfoService.provide())
 
-        logger.info().bracket("warmup: kotlin reflection :: init") {
+        logger.info().measureTime({ "warmup: kotlin reflection :: init" }) {
             prepareClass(ConcreteExecutorPool::class.java, "")
             prepareClass(Warmup::class.java, "")
         }
@@ -198,10 +198,10 @@ fun runGeneration(
     if (runFromEstimator) {
         setOptions()
         //will not be executed in real contest
-        logger.info().bracket("warmup: 1st optional soot initialization and executor warmup (not to be counted in time budget)") {
+        logger.info().measureTime({ "warmup: 1st optional soot initialization and executor warmup (not to be counted in time budget)" }) {
             TestCaseGenerator(listOf(cut.classfileDir.toPath()), classpathString, dependencyPath, JdkInfoService.provide(), forceSootReload = false)
         }
-        logger.info().bracket("warmup (first): kotlin reflection :: init") {
+        logger.info().measureTime({ "warmup (first): kotlin reflection :: init" }) {
             prepareClass(ConcreteExecutorPool::class.java, "")
             prepareClass(Warmup::class.java, "")
         }
@@ -228,9 +228,9 @@ fun runGeneration(
             cgLanguageAssistant = CgLanguageAssistant.getByCodegenLanguage(CodegenLanguage.defaultItem),
         )
 
-    logger.info().bracket("class ${cut.fqn}", { statsForClass }) {
+    logger.info().measureTime({ "class ${cut.fqn}" }, { statsForClass }) {
 
-        val filteredMethods = logger.info().bracket("preparation class ${cut.clazz}: kotlin reflection :: run") {
+        val filteredMethods = logger.info().measureTime({ "preparation class ${cut.clazz}: kotlin reflection :: run" }) {
             prepareClass(cut.clazz, methodNameFilter)
         }
 
@@ -240,7 +240,7 @@ fun runGeneration(
         if (filteredMethods.isEmpty()) return@runBlocking statsForClass
 
         val testCaseGenerator =
-            logger.info().bracket("2nd optional soot initialization") {
+            logger.info().measureTime({ "2nd optional soot initialization" }) {
                 TestCaseGenerator(listOf(cut.classfileDir.toPath()), classpathString, dependencyPath, JdkInfoService.provide(), forceSootReload = false)
             }
 
@@ -313,7 +313,7 @@ fun runGeneration(
 
 
                     var testsCounter = 0
-                    logger.info().bracket("method $method", { statsForMethod }) {
+                    logger.info().measureTime({ "method $method" }, { statsForMethod }) {
                         logger.info {
                             " -- Remaining time budget: $remainingBudget ms, " +
                                     "#remaining_methods: $remainingMethodsCount, " +
@@ -403,10 +403,9 @@ fun runGeneration(
 
         val testSets = testsByMethod.map { (method, executions) ->
             UtMethodTestSet(method, minimizeExecutions(executions), jimpleBody(method))
-                .summarize(cut.classfileDir.toPath(), sourceFile = null)
-        }
+        }.summarizeAll(cut.classfileDir.toPath(), sourceFile = null)
 
-        logger.info().bracket("Flushing tests for [${cut.simpleName}] on disk") {
+        logger.info().measureTime({ "Flushing tests for [${cut.simpleName}] on disk" }) {
             writeTestClass(cut, codeGenerator.generateAsString(testSets))
         }
         //write classes
diff --git a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/ContestEstimator.kt b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/ContestEstimator.kt
index 199bae753b..d1271f70c2 100644
--- a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/ContestEstimator.kt
+++ b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/ContestEstimator.kt
@@ -14,7 +14,7 @@ import mu.KotlinLogging
 import org.utbot.analytics.EngineAnalyticsContext
 import org.utbot.analytics.Predictors
 import org.utbot.common.FileUtil
-import org.utbot.common.bracket
+import org.utbot.common.measureTime
 import org.utbot.common.getPid
 import org.utbot.common.info
 import org.utbot.contest.Paths.classesLists
@@ -166,7 +166,7 @@ enum class Tool {
                 val testClass = cut.generatedTestFile
                 classStats.testClassFile = testClass
 
-                logger.info().bracket("Compiling class ${testClass.absolutePath}") {
+                logger.info().measureTime({ "Compiling class ${testClass.absolutePath}" }) {
                     val exitCode = compileClass(
                         compiledTestDir.absolutePath,
                         project.compileClasspathString,
diff --git a/utbot-junit-contest/src/main/kotlin/org/utbot/monitoring/StatisticsMonitoring.kt b/utbot-junit-contest/src/main/kotlin/org/utbot/monitoring/StatisticsMonitoring.kt
index ab4c1ff718..5af270f045 100644
--- a/utbot-junit-contest/src/main/kotlin/org/utbot/monitoring/StatisticsMonitoring.kt
+++ b/utbot-junit-contest/src/main/kotlin/org/utbot/monitoring/StatisticsMonitoring.kt
@@ -7,7 +7,7 @@ import kotlinx.serialization.encodeToString
 import kotlinx.serialization.json.Json
 import mu.KotlinLogging
 import org.utbot.common.ThreadBasedExecutor
-import org.utbot.common.bracket
+import org.utbot.common.measureTime
 import org.utbot.common.info
 import org.utbot.contest.ContestEstimatorJdkInfoProvider
 import org.utbot.contest.ContextManager
@@ -50,7 +50,7 @@ fun main(args: Array) {
             Paths.moduleTestDir
         )
 
-        logger.info().bracket("Run UTBot generation [fuzzing ratio = $fuzzingRatio]") {
+        logger.info().measureTime({ "Run UTBot generation [fuzzing ratio = $fuzzingRatio]" }) {
             val start = System.nanoTime()
 
             executor.invokeWithTimeout(runTimeout) {
diff --git a/utbot-maven/src/main/kotlin/org/utbot/maven/plugin/GenerateTestsAndSarifReportMojo.kt b/utbot-maven/src/main/kotlin/org/utbot/maven/plugin/GenerateTestsAndSarifReportMojo.kt
index 94cb050950..1a016c98cb 100644
--- a/utbot-maven/src/main/kotlin/org/utbot/maven/plugin/GenerateTestsAndSarifReportMojo.kt
+++ b/utbot-maven/src/main/kotlin/org/utbot/maven/plugin/GenerateTestsAndSarifReportMojo.kt
@@ -1,228 +1,228 @@
-package org.utbot.maven.plugin
-
-import mu.KotlinLogging
-import org.apache.maven.plugin.AbstractMojo
-import org.apache.maven.plugins.annotations.Execute
-import org.apache.maven.plugins.annotations.LifecyclePhase
-import org.apache.maven.plugins.annotations.Mojo
-import org.apache.maven.plugins.annotations.Parameter
-import org.apache.maven.project.MavenProject
-import org.utbot.common.bracket
-import org.utbot.common.debug
-import org.utbot.framework.plugin.api.TestCaseGenerator
-import org.utbot.framework.plugin.api.util.UtContext
-import org.utbot.framework.plugin.api.util.withUtContext
-import org.utbot.framework.plugin.sarif.GenerateTestsAndSarifReportFacade
-import org.utbot.framework.plugin.sarif.TargetClassWrapper
-import org.utbot.framework.plugin.services.JdkInfoService
-import org.utbot.maven.plugin.extension.SarifMavenConfigurationProvider
-import org.utbot.maven.plugin.wrappers.MavenProjectWrapper
-import org.utbot.maven.plugin.wrappers.SourceFindingStrategyMaven
-import java.io.File
-import java.net.URLClassLoader
-
-internal val logger = KotlinLogging.logger {}
-
-/**
- * The main class containing the entry point [execute].
- *
- * [Documentation](https://maven.apache.org/guides/plugin/guide-java-plugin-development.html)
- */
-@Mojo(
-    name = "generateTestsAndSarifReport",
-    defaultPhase = LifecyclePhase.GENERATE_TEST_SOURCES
-)
-@Execute(
-    phase = LifecyclePhase.GENERATE_TEST_SOURCES
-)
-class GenerateTestsAndSarifReportMojo : AbstractMojo() {
-
-    /**
-     * The maven project for which we are creating a SARIF report.
-     */
-    @Parameter(defaultValue = "\${project}", readonly = true)
-    lateinit var mavenProject: MavenProject
-
-    /**
-     * Classes for which the SARIF report will be created.
-     * Uses all classes from the user project if this list is empty.
-     */
-    @Parameter(defaultValue = "")
-    internal var targetClasses: List = listOf()
-
-    /**
-     * Absolute path to the root of the relative paths in the SARIF report.
-     */
-    @Parameter(defaultValue = "\${project.basedir}")
-    internal lateinit var projectRoot: File
-
-    /**
-     * Relative path (against module root) to the root of the generated tests.
-     */
-    @Parameter(defaultValue = "target/generated/test")
-    internal lateinit var generatedTestsRelativeRoot: String
-
-    /**
-     * Relative path (against module root) to the root of the SARIF reports.
-     */
-    @Parameter(defaultValue = "target/generated/sarif")
-    internal lateinit var sarifReportsRelativeRoot: String
-
-    /**
-     * Mark the directory with generated tests as `test sources root` or not.
-     */
-    @Parameter(defaultValue = "true")
-    internal var markGeneratedTestsDirectoryAsTestSourcesRoot: Boolean = true
-
-    /**
-     * Generate tests for private methods or not.
-     */
-    @Parameter(defaultValue = "false")
-    internal var testPrivateMethods: Boolean = false
-
-    /**
-     * Can be one of: 'junit4', 'junit5', 'testng'.
-     */
-    @Parameter(defaultValue = "junit5")
-    internal lateinit var testFramework: String
-
-    /**
-     * Can be one of: 'mockito'.
-     */
-    @Parameter(defaultValue = "mockito")
-    internal lateinit var mockFramework: String
-
-    /**
-     * Maximum tests generation time for one class (in milliseconds).
-     */
-    @Parameter
-    internal var generationTimeout: Long = 60 * 1000L
-
-    /**
-     * Can be one of: 'java', 'kotlin'.
-     */
-    @Parameter(defaultValue = "java")
-    internal lateinit var codegenLanguage: String
-
-    /**
-     * Can be one of: 'no-mocks', 'other-packages', 'other-classes'.
-     */
-    @Parameter(defaultValue = "no-mocks")
-    internal lateinit var mockStrategy: String
-
-    /**
-     * Can be one of: 'do-not-mock-statics', 'mock-statics'.
-     */
-    @Parameter(defaultValue = "do-not-mock-statics")
-    internal lateinit var staticsMocking: String
-
-    /**
-     * Can be one of: 'force', 'do-not-force'.
-     */
-    @Parameter(defaultValue = "force")
-    internal lateinit var forceStaticMocking: String
-
-    /**
-     * Classes to force mocking theirs static methods and constructors.
-     */
-    @Parameter(defaultValue = "")
-    internal var classesToMockAlways: List = listOf()
-
-    /**
-     * Provides configuration needed to create a SARIF report.
-     */
-    val sarifProperties: SarifMavenConfigurationProvider
-        get() = SarifMavenConfigurationProvider(this)
-
-    /**
-     * Contains information about the maven project for which we are creating a SARIF report.
-     */
-    lateinit var rootMavenProjectWrapper: MavenProjectWrapper
-
-    private val dependencyPaths by lazy {
-        val thisClassLoader = this::class.java.classLoader as? URLClassLoader
-            ?: return@lazy System.getProperty("java.class.path")
-        thisClassLoader.urLs.joinToString(File.pathSeparator) { it.path }
-    }
-
-    /**
-     * Entry point: called when the user starts this maven task.
-     */
-    override fun execute() {
-        try {
-            rootMavenProjectWrapper = MavenProjectWrapper(mavenProject, sarifProperties)
-        } catch (t: Throwable) {
-            logger.error(t) { "Unexpected error while configuring the maven task" }
-            return
-        }
-        try {
-            generateForProjectRecursively(rootMavenProjectWrapper)
-            GenerateTestsAndSarifReportFacade.mergeReports(
-                sarifReports = rootMavenProjectWrapper.collectReportsRecursively(),
-                mergedSarifReportFile = rootMavenProjectWrapper.sarifReportFile
-            )
-        } catch (t: Throwable) {
-            logger.error(t) { "Unexpected error while generating SARIF report" }
-            return
-        }
-    }
-
-    // internal
-
-    /**
-     * Generates tests and a SARIF report for classes in the [mavenProjectWrapper] and in all its child projects.
-     */
-    private fun generateForProjectRecursively(mavenProjectWrapper: MavenProjectWrapper) {
-        logger.debug().bracket("Generating tests for the '${mavenProjectWrapper.mavenProject.name}' source set") {
-            withUtContext(UtContext(mavenProjectWrapper.classLoader)) {
-                val testCaseGenerator =
-                    TestCaseGenerator(
-                        listOf(mavenProjectWrapper.workingDirectory),
-                        mavenProjectWrapper.runtimeClasspath,
-                        dependencyPaths,
-                        JdkInfoService.provide()
-                    )
-                mavenProjectWrapper.targetClasses.forEach { targetClass ->
-                    generateForClass(mavenProjectWrapper, targetClass, testCaseGenerator)
-                }
-            }
-        }
-        mavenProjectWrapper.childProjects.forEach { childProject ->
-            generateForProjectRecursively(childProject)
-        }
-    }
-
-    /**
-     * Generates tests and a SARIF report for the class [targetClass].
-     */
-    private fun generateForClass(
-        mavenProjectWrapper: MavenProjectWrapper,
-        targetClass: TargetClassWrapper,
-        testCaseGenerator: TestCaseGenerator,
-    ) {
-        logger.debug().bracket("Generating tests for the $targetClass") {
-            val sourceFindingStrategy =
-                SourceFindingStrategyMaven(mavenProjectWrapper, targetClass.testsCodeFile.path)
-            val generateTestsAndSarifReportFacade =
-                GenerateTestsAndSarifReportFacade(sarifProperties, sourceFindingStrategy, testCaseGenerator)
-            generateTestsAndSarifReportFacade
-                .generateForClass(targetClass, mavenProjectWrapper.workingDirectory)
-        }
-    }
-
-    /**
-     * Returns SARIF reports created for this [MavenProjectWrapper] and for all its child projects.
-     */
-    private fun MavenProjectWrapper.collectReportsRecursively(): List =
-        this.childProjects.flatMap { childProject ->
-            childProject.collectReportsRecursively()
-        } + this.collectReports()
-
-    /**
-     * Returns SARIF reports created for this [MavenProjectWrapper].
-     */
-    private fun MavenProjectWrapper.collectReports(): List =
-        this.targetClasses.map { targetClass ->
-            targetClass.sarifReportFile.readText()
-        }
-}
+package org.utbot.maven.plugin
+
+import mu.KotlinLogging
+import org.apache.maven.plugin.AbstractMojo
+import org.apache.maven.plugins.annotations.Execute
+import org.apache.maven.plugins.annotations.LifecyclePhase
+import org.apache.maven.plugins.annotations.Mojo
+import org.apache.maven.plugins.annotations.Parameter
+import org.apache.maven.project.MavenProject
+import org.utbot.common.measureTime
+import org.utbot.common.debug
+import org.utbot.framework.plugin.api.TestCaseGenerator
+import org.utbot.framework.plugin.api.util.UtContext
+import org.utbot.framework.plugin.api.util.withUtContext
+import org.utbot.framework.plugin.sarif.GenerateTestsAndSarifReportFacade
+import org.utbot.framework.plugin.sarif.TargetClassWrapper
+import org.utbot.framework.plugin.services.JdkInfoService
+import org.utbot.maven.plugin.extension.SarifMavenConfigurationProvider
+import org.utbot.maven.plugin.wrappers.MavenProjectWrapper
+import org.utbot.maven.plugin.wrappers.SourceFindingStrategyMaven
+import java.io.File
+import java.net.URLClassLoader
+
+internal val logger = KotlinLogging.logger {}
+
+/**
+ * The main class containing the entry point [execute].
+ *
+ * [Documentation](https://maven.apache.org/guides/plugin/guide-java-plugin-development.html)
+ */
+@Mojo(
+    name = "generateTestsAndSarifReport",
+    defaultPhase = LifecyclePhase.GENERATE_TEST_SOURCES
+)
+@Execute(
+    phase = LifecyclePhase.GENERATE_TEST_SOURCES
+)
+class GenerateTestsAndSarifReportMojo : AbstractMojo() {
+
+    /**
+     * The maven project for which we are creating a SARIF report.
+     */
+    @Parameter(defaultValue = "\${project}", readonly = true)
+    lateinit var mavenProject: MavenProject
+
+    /**
+     * Classes for which the SARIF report will be created.
+     * Uses all classes from the user project if this list is empty.
+     */
+    @Parameter(defaultValue = "")
+    internal var targetClasses: List = listOf()
+
+    /**
+     * Absolute path to the root of the relative paths in the SARIF report.
+     */
+    @Parameter(defaultValue = "\${project.basedir}")
+    internal lateinit var projectRoot: File
+
+    /**
+     * Relative path (against module root) to the root of the generated tests.
+     */
+    @Parameter(defaultValue = "target/generated/test")
+    internal lateinit var generatedTestsRelativeRoot: String
+
+    /**
+     * Relative path (against module root) to the root of the SARIF reports.
+     */
+    @Parameter(defaultValue = "target/generated/sarif")
+    internal lateinit var sarifReportsRelativeRoot: String
+
+    /**
+     * Mark the directory with generated tests as `test sources root` or not.
+     */
+    @Parameter(defaultValue = "true")
+    internal var markGeneratedTestsDirectoryAsTestSourcesRoot: Boolean = true
+
+    /**
+     * Generate tests for private methods or not.
+     */
+    @Parameter(defaultValue = "false")
+    internal var testPrivateMethods: Boolean = false
+
+    /**
+     * Can be one of: 'junit4', 'junit5', 'testng'.
+     */
+    @Parameter(defaultValue = "junit5")
+    internal lateinit var testFramework: String
+
+    /**
+     * Can be one of: 'mockito'.
+     */
+    @Parameter(defaultValue = "mockito")
+    internal lateinit var mockFramework: String
+
+    /**
+     * Maximum tests generation time for one class (in milliseconds).
+     */
+    @Parameter
+    internal var generationTimeout: Long = 60 * 1000L
+
+    /**
+     * Can be one of: 'java', 'kotlin'.
+     */
+    @Parameter(defaultValue = "java")
+    internal lateinit var codegenLanguage: String
+
+    /**
+     * Can be one of: 'no-mocks', 'other-packages', 'other-classes'.
+     */
+    @Parameter(defaultValue = "no-mocks")
+    internal lateinit var mockStrategy: String
+
+    /**
+     * Can be one of: 'do-not-mock-statics', 'mock-statics'.
+     */
+    @Parameter(defaultValue = "do-not-mock-statics")
+    internal lateinit var staticsMocking: String
+
+    /**
+     * Can be one of: 'force', 'do-not-force'.
+     */
+    @Parameter(defaultValue = "force")
+    internal lateinit var forceStaticMocking: String
+
+    /**
+     * Classes to force mocking theirs static methods and constructors.
+     */
+    @Parameter(defaultValue = "")
+    internal var classesToMockAlways: List = listOf()
+
+    /**
+     * Provides configuration needed to create a SARIF report.
+     */
+    val sarifProperties: SarifMavenConfigurationProvider
+        get() = SarifMavenConfigurationProvider(this)
+
+    /**
+     * Contains information about the maven project for which we are creating a SARIF report.
+     */
+    lateinit var rootMavenProjectWrapper: MavenProjectWrapper
+
+    private val dependencyPaths by lazy {
+        val thisClassLoader = this::class.java.classLoader as? URLClassLoader
+            ?: return@lazy System.getProperty("java.class.path")
+        thisClassLoader.urLs.joinToString(File.pathSeparator) { it.path }
+    }
+
+    /**
+     * Entry point: called when the user starts this maven task.
+     */
+    override fun execute() {
+        try {
+            rootMavenProjectWrapper = MavenProjectWrapper(mavenProject, sarifProperties)
+        } catch (t: Throwable) {
+            logger.error(t) { "Unexpected error while configuring the maven task" }
+            return
+        }
+        try {
+            generateForProjectRecursively(rootMavenProjectWrapper)
+            GenerateTestsAndSarifReportFacade.mergeReports(
+                sarifReports = rootMavenProjectWrapper.collectReportsRecursively(),
+                mergedSarifReportFile = rootMavenProjectWrapper.sarifReportFile
+            )
+        } catch (t: Throwable) {
+            logger.error(t) { "Unexpected error while generating SARIF report" }
+            return
+        }
+    }
+
+    // internal
+
+    /**
+     * Generates tests and a SARIF report for classes in the [mavenProjectWrapper] and in all its child projects.
+     */
+    private fun generateForProjectRecursively(mavenProjectWrapper: MavenProjectWrapper) {
+        logger.debug().measureTime({ "Generating tests for the '${mavenProjectWrapper.mavenProject.name}' source set" }) {
+            withUtContext(UtContext(mavenProjectWrapper.classLoader)) {
+                val testCaseGenerator =
+                    TestCaseGenerator(
+                        listOf(mavenProjectWrapper.workingDirectory),
+                        mavenProjectWrapper.runtimeClasspath,
+                        dependencyPaths,
+                        JdkInfoService.provide()
+                    )
+                mavenProjectWrapper.targetClasses.forEach { targetClass ->
+                    generateForClass(mavenProjectWrapper, targetClass, testCaseGenerator)
+                }
+            }
+        }
+        mavenProjectWrapper.childProjects.forEach { childProject ->
+            generateForProjectRecursively(childProject)
+        }
+    }
+
+    /**
+     * Generates tests and a SARIF report for the class [targetClass].
+     */
+    private fun generateForClass(
+        mavenProjectWrapper: MavenProjectWrapper,
+        targetClass: TargetClassWrapper,
+        testCaseGenerator: TestCaseGenerator,
+    ) {
+        logger.debug().measureTime({ "Generating tests for the $targetClass" }) {
+            val sourceFindingStrategy =
+                SourceFindingStrategyMaven(mavenProjectWrapper, targetClass.testsCodeFile.path)
+            val generateTestsAndSarifReportFacade =
+                GenerateTestsAndSarifReportFacade(sarifProperties, sourceFindingStrategy, testCaseGenerator)
+            generateTestsAndSarifReportFacade
+                .generateForClass(targetClass, mavenProjectWrapper.workingDirectory)
+        }
+    }
+
+    /**
+     * Returns SARIF reports created for this [MavenProjectWrapper] and for all its child projects.
+     */
+    private fun MavenProjectWrapper.collectReportsRecursively(): List =
+        this.childProjects.flatMap { childProject ->
+            childProject.collectReportsRecursively()
+        } + this.collectReports()
+
+    /**
+     * Returns SARIF reports created for this [MavenProjectWrapper].
+     */
+    private fun MavenProjectWrapper.collectReports(): List =
+        this.targetClasses.map { targetClass ->
+            targetClass.sarifReportFile.readText()
+        }
+}
diff --git a/utbot-rd/build.gradle b/utbot-rd/build.gradle
index 6097d21dcd..01ac9574df 100644
--- a/utbot-rd/build.gradle
+++ b/utbot-rd/build.gradle
@@ -181,6 +181,15 @@ task generateCommonModels(type: RdGenTask) {
         directory = generatedOutputDir.canonicalPath
         namespace = "org.utbot.rd.generated"
     }
+
+    rdParams.generator {
+        language = "kotlin"
+        transform = "symmetric"
+        root = "org.utbot.rd.models.LoggerRoot"
+
+        directory = generatedOutputDir.canonicalPath
+        namespace = "org.utbot.rd.generated"
+    }
 }
 
 task generateCSharpModels(type: RdGenTask) {
diff --git a/utbot-rd/src/main/kotlin/org/utbot/rd/ClientProcessUtil.kt b/utbot-rd/src/main/kotlin/org/utbot/rd/ClientProcessUtil.kt
index fb35913d02..a9b3d23bc0 100644
--- a/utbot-rd/src/main/kotlin/org/utbot/rd/ClientProcessUtil.kt
+++ b/utbot-rd/src/main/kotlin/org/utbot/rd/ClientProcessUtil.kt
@@ -3,12 +3,14 @@ package org.utbot.rd
 import com.jetbrains.rd.framework.*
 import com.jetbrains.rd.framework.impl.RdCall
 import com.jetbrains.rd.framework.util.launch
+import com.jetbrains.rd.util.LogLevel
 import com.jetbrains.rd.util.getLogger
 import com.jetbrains.rd.util.info
 import com.jetbrains.rd.util.lifetime.Lifetime
 import com.jetbrains.rd.util.lifetime.LifetimeDefinition
 import com.jetbrains.rd.util.lifetime.isAlive
 import com.jetbrains.rd.util.lifetime.plusAssign
+import com.jetbrains.rd.util.reactive.adviseEternal
 import com.jetbrains.rd.util.threading.SingleThreadScheduler
 import com.jetbrains.rd.util.trace
 import kotlinx.coroutines.CancellationException
@@ -17,6 +19,7 @@ import kotlinx.coroutines.channels.trySendBlocking
 import kotlinx.coroutines.withTimeoutOrNull
 import org.utbot.common.*
 import org.utbot.rd.generated.synchronizationModel
+import org.utbot.rd.loggers.withLevel
 import java.io.File
 import kotlin.time.Duration
 
@@ -98,6 +101,21 @@ class IdleWatchdog(private val ldef: LifetimeDefinition, val timeout: Duration)
         }
     }
 
+    /**
+     * Adds callback to RdCall with indicating that during this activity process should not die.
+     * After block ended - idle timer restarts.
+     * Also additonally logs
+     */
+    fun  measureTimeForActiveCall(call: RdCall, requestName: String, level: LogLevel = LogLevel.Debug, block: (T) -> R) {
+        call.set { it ->
+            logger.withLevel(level).measureTime({ requestName }) {
+                wrapActive {
+                    block(it)
+                }
+            }
+        }
+    }
+
     suspend fun setupTimeout() {
         ldef.launch {
             var lastState = State.ENDED
@@ -162,6 +180,7 @@ class ClientProtocolBuilder {
                 clientProtocol.synchronizationModel.suspendTimeoutTimer.set { param ->
                     watchdog.suspendTimeout = param
                 }
+                clientProtocol.synchronizationModel.stopProcess.adviseEternal { _ -> watchdog.stopProtocol() }
                 clientProtocol.block(watchdog)
             }
 
diff --git a/utbot-rd/src/main/kotlin/org/utbot/rd/ProcessWithRdServer.kt b/utbot-rd/src/main/kotlin/org/utbot/rd/ProcessWithRdServer.kt
index e2f28119b3..a6321f1e18 100644
--- a/utbot-rd/src/main/kotlin/org/utbot/rd/ProcessWithRdServer.kt
+++ b/utbot-rd/src/main/kotlin/org/utbot/rd/ProcessWithRdServer.kt
@@ -11,6 +11,7 @@ import com.jetbrains.rd.util.lifetime.throwIfNotAlive
 import com.jetbrains.rd.util.trace
 import kotlinx.coroutines.delay
 import org.utbot.common.getPid
+import org.utbot.common.silent
 import org.utbot.rd.generated.synchronizationModel
 import java.io.File
 import java.nio.file.Files
@@ -90,6 +91,13 @@ class ProcessWithRdServerImpl private constructor(
 ) : ProcessWithRdServer, LifetimedProcess by child {
     override val protocol = serverFactory(lifetime)
 
+    override fun terminate() {
+        silent {
+            protocol.synchronizationModel.stopProcess.fire(Unit)
+        }
+        child.terminate()
+    }
+
     companion object {
         suspend operator fun invoke(
             child: LifetimedProcess, serverFactory: (Lifetime) -> Protocol
diff --git a/utbot-rd/src/main/kotlin/org/utbot/rd/UtRdUtil.kt b/utbot-rd/src/main/kotlin/org/utbot/rd/UtRdUtil.kt
index 535c294032..4dabe27c7b 100644
--- a/utbot-rd/src/main/kotlin/org/utbot/rd/UtRdUtil.kt
+++ b/utbot-rd/src/main/kotlin/org/utbot/rd/UtRdUtil.kt
@@ -3,8 +3,7 @@ package org.utbot.rd
 import com.jetbrains.rd.framework.*
 import com.jetbrains.rd.framework.util.NetUtils
 import com.jetbrains.rd.framework.util.synchronizeWith
-import com.jetbrains.rd.util.Logger
-import com.jetbrains.rd.util.debug
+import com.jetbrains.rd.util.*
 import com.jetbrains.rd.util.lifetime.Lifetime
 import com.jetbrains.rd.util.lifetime.LifetimeDefinition
 import com.jetbrains.rd.util.lifetime.throwIfNotAlive
@@ -14,6 +13,7 @@ import com.jetbrains.rd.util.threading.SingleThreadScheduler
 import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.Deferred
 import kotlinx.coroutines.runBlocking
+import org.utbot.common.LoggerWithLogMethod
 
 suspend fun  ProcessWithRdServer.onScheduler(block: () -> T): T {
     val deffered = CompletableDeferred()
@@ -124,19 +124,4 @@ suspend fun startUtProcessWithRdServer(
             it
         )
     }
-}
-
-inline fun  Logger.logMeasure(tag: String = "", block: () -> T): T {
-    val start = System.currentTimeMillis()
-    this.debug { "started evaluating $tag" }
-    try {
-        return block()
-    }
-    catch (e: Throwable) {
-        this.debug { "exception during evaluating $tag: ${e.stackTraceToString()}" }
-        throw e
-    }
-    finally {
-        this.debug { "evaluating $tag took ${System.currentTimeMillis() - start} ms" }
-    }
 }
\ No newline at end of file
diff --git a/utbot-rd/src/main/kotlin/org/utbot/rd/generated/LoggerModel.Generated.kt b/utbot-rd/src/main/kotlin/org/utbot/rd/generated/LoggerModel.Generated.kt
new file mode 100644
index 0000000000..d8f0f59f87
--- /dev/null
+++ b/utbot-rd/src/main/kotlin/org/utbot/rd/generated/LoggerModel.Generated.kt
@@ -0,0 +1,177 @@
+@file:Suppress("EXPERIMENTAL_API_USAGE","EXPERIMENTAL_UNSIGNED_LITERALS","PackageDirectoryMismatch","UnusedImport","unused","LocalVariableName","CanBeVal","PropertyName","EnumEntryName","ClassName","ObjectPropertyName","UnnecessaryVariable","SpellCheckingInspection")
+package org.utbot.rd.generated
+
+import com.jetbrains.rd.framework.*
+import com.jetbrains.rd.framework.base.*
+import com.jetbrains.rd.framework.impl.*
+
+import com.jetbrains.rd.util.lifetime.*
+import com.jetbrains.rd.util.reactive.*
+import com.jetbrains.rd.util.string.*
+import com.jetbrains.rd.util.*
+import kotlin.reflect.KClass
+import kotlin.jvm.JvmStatic
+
+
+
+/**
+ * #### Generated from [LoggerModel.kt:8]
+ */
+class LoggerModel private constructor(
+    private val _log: RdSignal,
+    private val _getCategoryMinimalLogLevel: RdCall
+) : RdExtBase() {
+    //companion
+    
+    companion object : ISerializersOwner {
+        
+        override fun registerSerializersCore(serializers: ISerializers)  {
+            serializers.register(LogArguments)
+        }
+        
+        
+        @JvmStatic
+        @JvmName("internalCreateModel")
+        @Deprecated("Use create instead", ReplaceWith("create(lifetime, protocol)"))
+        internal fun createModel(lifetime: Lifetime, protocol: IProtocol): LoggerModel  {
+            @Suppress("DEPRECATION")
+            return create(lifetime, protocol)
+        }
+        
+        @JvmStatic
+        @Deprecated("Use protocol.loggerModel or revise the extension scope instead", ReplaceWith("protocol.loggerModel"))
+        fun create(lifetime: Lifetime, protocol: IProtocol): LoggerModel  {
+            LoggerRoot.register(protocol.serializers)
+            
+            return LoggerModel().apply {
+                identify(protocol.identity, RdId.Null.mix("LoggerModel"))
+                bind(lifetime, protocol, "LoggerModel")
+            }
+        }
+        
+        
+        const val serializationHash = -6259198217478203203L
+        
+    }
+    override val serializersOwner: ISerializersOwner get() = LoggerModel
+    override val serializationHash: Long get() = LoggerModel.serializationHash
+    
+    //fields
+    val log: IAsyncSignal get() = _log
+    
+    /**
+     * Parameter - log category.
+    Result - integer value for com.jetbrains.rd.util.LogLevel.
+     */
+    val getCategoryMinimalLogLevel: RdCall get() = _getCategoryMinimalLogLevel
+    //methods
+    //initializer
+    init {
+        _log.async = true
+        _getCategoryMinimalLogLevel.async = true
+    }
+    
+    init {
+        bindableChildren.add("log" to _log)
+        bindableChildren.add("getCategoryMinimalLogLevel" to _getCategoryMinimalLogLevel)
+    }
+    
+    //secondary constructor
+    private constructor(
+    ) : this(
+        RdSignal(LogArguments),
+        RdCall(FrameworkMarshallers.String, FrameworkMarshallers.Int)
+    )
+    
+    //equals trait
+    //hash code trait
+    //pretty print
+    override fun print(printer: PrettyPrinter)  {
+        printer.println("LoggerModel (")
+        printer.indent {
+            print("log = "); _log.print(printer); println()
+            print("getCategoryMinimalLogLevel = "); _getCategoryMinimalLogLevel.print(printer); println()
+        }
+        printer.print(")")
+    }
+    //deepClone
+    override fun deepClone(): LoggerModel   {
+        return LoggerModel(
+            _log.deepClonePolymorphic(),
+            _getCategoryMinimalLogLevel.deepClonePolymorphic()
+        )
+    }
+    //contexts
+}
+val IProtocol.loggerModel get() = getOrCreateExtension(LoggerModel::class) { @Suppress("DEPRECATION") LoggerModel.create(lifetime, this) }
+
+
+
+/**
+ * @property logLevelOrdinal Integer value for com.jetbrains.rd.util.LogLevel
+ * #### Generated from [LoggerModel.kt:9]
+ */
+data class LogArguments (
+    val category: String,
+    val logLevelOrdinal: Int,
+    val message: String
+) : IPrintable {
+    //companion
+    
+    companion object : IMarshaller {
+        override val _type: KClass = LogArguments::class
+        
+        @Suppress("UNCHECKED_CAST")
+        override fun read(ctx: SerializationCtx, buffer: AbstractBuffer): LogArguments  {
+            val category = buffer.readString()
+            val logLevelOrdinal = buffer.readInt()
+            val message = buffer.readString()
+            return LogArguments(category, logLevelOrdinal, message)
+        }
+        
+        override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: LogArguments)  {
+            buffer.writeString(value.category)
+            buffer.writeInt(value.logLevelOrdinal)
+            buffer.writeString(value.message)
+        }
+        
+        
+    }
+    //fields
+    //methods
+    //initializer
+    //secondary constructor
+    //equals trait
+    override fun equals(other: Any?): Boolean  {
+        if (this === other) return true
+        if (other == null || other::class != this::class) return false
+        
+        other as LogArguments
+        
+        if (category != other.category) return false
+        if (logLevelOrdinal != other.logLevelOrdinal) return false
+        if (message != other.message) return false
+        
+        return true
+    }
+    //hash code trait
+    override fun hashCode(): Int  {
+        var __r = 0
+        __r = __r*31 + category.hashCode()
+        __r = __r*31 + logLevelOrdinal.hashCode()
+        __r = __r*31 + message.hashCode()
+        return __r
+    }
+    //pretty print
+    override fun print(printer: PrettyPrinter)  {
+        printer.println("LogArguments (")
+        printer.indent {
+            print("category = "); category.print(printer); println()
+            print("logLevelOrdinal = "); logLevelOrdinal.print(printer); println()
+            print("message = "); message.print(printer); println()
+        }
+        printer.print(")")
+    }
+    //deepClone
+    //contexts
+}
diff --git a/utbot-rd/src/main/kotlin/org/utbot/rd/generated/LoggerRoot.Generated.kt b/utbot-rd/src/main/kotlin/org/utbot/rd/generated/LoggerRoot.Generated.kt
new file mode 100644
index 0000000000..64503c5452
--- /dev/null
+++ b/utbot-rd/src/main/kotlin/org/utbot/rd/generated/LoggerRoot.Generated.kt
@@ -0,0 +1,58 @@
+@file:Suppress("EXPERIMENTAL_API_USAGE","EXPERIMENTAL_UNSIGNED_LITERALS","PackageDirectoryMismatch","UnusedImport","unused","LocalVariableName","CanBeVal","PropertyName","EnumEntryName","ClassName","ObjectPropertyName","UnnecessaryVariable","SpellCheckingInspection")
+package org.utbot.rd.generated
+
+import com.jetbrains.rd.framework.*
+import com.jetbrains.rd.framework.base.*
+import com.jetbrains.rd.framework.impl.*
+
+import com.jetbrains.rd.util.lifetime.*
+import com.jetbrains.rd.util.reactive.*
+import com.jetbrains.rd.util.string.*
+import com.jetbrains.rd.util.*
+import kotlin.reflect.KClass
+import kotlin.jvm.JvmStatic
+
+
+
+/**
+ * #### Generated from [LoggerModel.kt:7]
+ */
+class LoggerRoot private constructor(
+) : RdExtBase() {
+    //companion
+    
+    companion object : ISerializersOwner {
+        
+        override fun registerSerializersCore(serializers: ISerializers)  {
+            LoggerRoot.register(serializers)
+            LoggerModel.register(serializers)
+        }
+        
+        
+        
+        
+        
+        const val serializationHash = -3743703762234585836L
+        
+    }
+    override val serializersOwner: ISerializersOwner get() = LoggerRoot
+    override val serializationHash: Long get() = LoggerRoot.serializationHash
+    
+    //fields
+    //methods
+    //initializer
+    //secondary constructor
+    //equals trait
+    //hash code trait
+    //pretty print
+    override fun print(printer: PrettyPrinter)  {
+        printer.println("LoggerRoot (")
+        printer.print(")")
+    }
+    //deepClone
+    override fun deepClone(): LoggerRoot   {
+        return LoggerRoot(
+        )
+    }
+    //contexts
+}
diff --git a/utbot-rd/src/main/kotlin/org/utbot/rd/generated/SynchronizationModel.Generated.kt b/utbot-rd/src/main/kotlin/org/utbot/rd/generated/SynchronizationModel.Generated.kt
index 066be03fb1..e520a29383 100644
--- a/utbot-rd/src/main/kotlin/org/utbot/rd/generated/SynchronizationModel.Generated.kt
+++ b/utbot-rd/src/main/kotlin/org/utbot/rd/generated/SynchronizationModel.Generated.kt
@@ -19,7 +19,9 @@ import kotlin.jvm.JvmStatic
  */
 class SynchronizationModel private constructor(
     private val _suspendTimeoutTimer: RdCall,
-    private val _synchronizationSignal: RdSignal
+    private val _initRemoteLogging: RdSignal,
+    private val _synchronizationSignal: RdSignal,
+    private val _stopProcess: RdSignal
 ) : RdExtBase() {
     //companion
     
@@ -49,7 +51,7 @@ class SynchronizationModel private constructor(
         }
         
         
-        const val serializationHash = 3813608056984691311L
+        const val serializationHash = 5881306106692642003L
         
     }
     override val serializersOwner: ISerializersOwner get() = SynchronizationModel
@@ -57,24 +59,36 @@ class SynchronizationModel private constructor(
     
     //fields
     val suspendTimeoutTimer: RdCall get() = _suspendTimeoutTimer
+    val initRemoteLogging: IAsyncSignal get() = _initRemoteLogging
     val synchronizationSignal: IAsyncSignal get() = _synchronizationSignal
+    
+    /**
+     * This command tells the instrumented process to stop
+     */
+    val stopProcess: IAsyncSignal get() = _stopProcess
     //methods
     //initializer
     init {
         _suspendTimeoutTimer.async = true
+        _initRemoteLogging.async = true
         _synchronizationSignal.async = true
+        _stopProcess.async = true
     }
     
     init {
         bindableChildren.add("suspendTimeoutTimer" to _suspendTimeoutTimer)
+        bindableChildren.add("initRemoteLogging" to _initRemoteLogging)
         bindableChildren.add("synchronizationSignal" to _synchronizationSignal)
+        bindableChildren.add("stopProcess" to _stopProcess)
     }
     
     //secondary constructor
     private constructor(
     ) : this(
         RdCall(FrameworkMarshallers.Bool, FrameworkMarshallers.Void),
-        RdSignal(FrameworkMarshallers.String)
+        RdSignal(FrameworkMarshallers.Void),
+        RdSignal(FrameworkMarshallers.String),
+        RdSignal(FrameworkMarshallers.Void)
     )
     
     //equals trait
@@ -84,7 +98,9 @@ class SynchronizationModel private constructor(
         printer.println("SynchronizationModel (")
         printer.indent {
             print("suspendTimeoutTimer = "); _suspendTimeoutTimer.print(printer); println()
+            print("initRemoteLogging = "); _initRemoteLogging.print(printer); println()
             print("synchronizationSignal = "); _synchronizationSignal.print(printer); println()
+            print("stopProcess = "); _stopProcess.print(printer); println()
         }
         printer.print(")")
     }
@@ -92,7 +108,9 @@ class SynchronizationModel private constructor(
     override fun deepClone(): SynchronizationModel   {
         return SynchronizationModel(
             _suspendTimeoutTimer.deepClonePolymorphic(),
-            _synchronizationSignal.deepClonePolymorphic()
+            _initRemoteLogging.deepClonePolymorphic(),
+            _synchronizationSignal.deepClonePolymorphic(),
+            _stopProcess.deepClonePolymorphic()
         )
     }
     //contexts
diff --git a/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdConsoleLogger.kt b/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdConsoleLogger.kt
index 648f17bf41..b696b5f55c 100644
--- a/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdConsoleLogger.kt
+++ b/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdConsoleLogger.kt
@@ -8,7 +8,7 @@ import java.time.LocalDateTime
 class UtRdConsoleLogger(
     private val loggersLevel: LogLevel,
     private val streamToWrite: PrintStream,
-    private val category: String = ""
+    private val category: String
 ) : Logger {
     override fun isEnabled(level: LogLevel): Boolean {
         return level >= loggersLevel
@@ -16,7 +16,8 @@ class UtRdConsoleLogger(
 
     private fun format(category: String, level: LogLevel, message: Any?, throwable: Throwable?) : String {
         val throwableToPrint = if (level < LogLevel.Error) throwable  else throwable ?: Exception() //to print stacktrace
-        return "${LocalDateTime.now().format(timeFormatter)} | ${level.toString().uppercase().padEnd(5)} | ${category.substringAfterLast('.').padEnd(25)} | ${message?.toString()?:""} ${throwableToPrint?.getThrowableText()?.let { "| $it" }?:""}"
+        val rdCategory = if (category.isNotEmpty()) "RdCategory: ${category.substringAfterLast('.').padEnd(25)} | " else ""
+        return "${LocalDateTime.now().format(timeFormatter)} | ${level.toString().uppercase().padEnd(5)} | $rdCategory${message?.toString()?:""} ${throwableToPrint?.getThrowableText()?.let { "| $it" }?:""}"
     }
 
     override fun log(level: LogLevel, message: Any?, throwable: Throwable?) {
diff --git a/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdConsoleLoggerFactory.kt b/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdConsoleLoggerFactory.kt
index c34e6a3788..ad2d02a8a1 100644
--- a/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdConsoleLoggerFactory.kt
+++ b/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdConsoleLoggerFactory.kt
@@ -5,6 +5,10 @@ import com.jetbrains.rd.util.LogLevel
 import com.jetbrains.rd.util.Logger
 import java.io.PrintStream
 
+/**
+ * Creates loggers with predefined log level, that writes to provided stream.
+ * Create logger category is added to message.
+ */
 class UtRdConsoleLoggerFactory(
     private val loggersLevel: LogLevel,
     private val streamToWrite: PrintStream
diff --git a/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdKLogger.kt b/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdKLogger.kt
index 64c2ded59c..b706757690 100644
--- a/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdKLogger.kt
+++ b/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdKLogger.kt
@@ -3,25 +3,34 @@ package org.utbot.rd.loggers
 import com.jetbrains.rd.util.*
 import mu.KLogger
 
-class UtRdKLogger(private val realLogger: KLogger): Logger {
-    override fun isEnabled(level: LogLevel): Boolean {
-        return when (level) {
-            LogLevel.Trace -> realLogger.isTraceEnabled
-            LogLevel.Debug -> realLogger.isDebugEnabled
-            LogLevel.Info -> realLogger.isInfoEnabled
-            LogLevel.Warn -> realLogger.isWarnEnabled
-            LogLevel.Error -> realLogger.isErrorEnabled
-            LogLevel.Fatal -> realLogger.isErrorEnabled
+/**
+ * Adapter from RD Logger to KLogger
+ */
+class UtRdKLogger(private val realLogger: KLogger, val category: String) : Logger {
+    val logLevel: LogLevel
+        get() {
+            return when {
+                realLogger.isTraceEnabled -> LogLevel.Trace
+                realLogger.isDebugEnabled -> LogLevel.Debug
+                realLogger.isInfoEnabled -> LogLevel.Info
+                realLogger.isWarnEnabled -> LogLevel.Warn
+                realLogger.isErrorEnabled -> LogLevel.Error
+                else -> LogLevel.Fatal
+            }
         }
+
+    override fun isEnabled(level: LogLevel): Boolean {
+        return level >= logLevel
     }
 
     private fun format(level: LogLevel, message: Any?, throwable: Throwable?): String {
         val throwableToPrint = if (level < LogLevel.Error) throwable else throwable ?: Exception() //to print stacktrace
-        return "${message?.toString() ?: ""} ${throwableToPrint?.getThrowableText()?.let { "| $it" } ?: ""}"
+        val rdCategory = if (category.isNotEmpty()) "RdCategory: ${category.substringAfterLast('.').padEnd(25)} | " else ""
+        return "$rdCategory${message?.toString() ?: ""} ${throwableToPrint?.getThrowableText()?.let { "| $it" } ?: ""}"
     }
 
     override fun log(level: LogLevel, message: Any?, throwable: Throwable?) {
-        if (!isEnabled(level))
+        if (!isEnabled(level) || (message == null && throwable == null))
             return
 
         val msg = format(level, message, throwable)
diff --git a/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdKLoggerFactory.kt b/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdKLoggerFactory.kt
index 2d0c4ee194..7982c963f3 100644
--- a/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdKLoggerFactory.kt
+++ b/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdKLoggerFactory.kt
@@ -4,8 +4,13 @@ import com.jetbrains.rd.util.ILoggerFactory
 import com.jetbrains.rd.util.Logger
 import mu.KLogger
 
+/**
+ * Creates RD loggers that writes to provided KLogger.
+ *
+ * Created logger category is added to message.
+ */
 class UtRdKLoggerFactory(private val realLogger: KLogger) : ILoggerFactory {
     override fun getLogger(category: String): Logger {
-        return UtRdKLogger(realLogger)
+        return UtRdKLogger(realLogger, category)
     }
 }
\ No newline at end of file
diff --git a/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdLogUtil.kt b/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdLogUtil.kt
new file mode 100644
index 0000000000..9aae485486
--- /dev/null
+++ b/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdLogUtil.kt
@@ -0,0 +1,27 @@
+package org.utbot.rd.loggers
+
+import com.jetbrains.rd.util.*
+import com.jetbrains.rd.util.lifetime.Lifetime
+import mu.KLogger
+import org.utbot.common.LoggerWithLogMethod
+
+
+fun Logger.withLevel(logLevel: LogLevel): LoggerWithLogMethod = LoggerWithLogMethod {
+    this.log(logLevel, it)
+}
+
+fun Logger.info(): LoggerWithLogMethod = LoggerWithLogMethod {
+    this.info(it)
+}
+fun Logger.debug(): LoggerWithLogMethod = LoggerWithLogMethod {
+    this.debug(it)
+}
+fun Logger.trace(): LoggerWithLogMethod = LoggerWithLogMethod {
+    this.trace(it)
+}
+
+fun overrideDefaultRdLoggerFactoryWithKLogger(logger: KLogger) {
+    if (Statics().get() !is UtRdKLoggerFactory) {
+        Logger.set(Lifetime.Eternal, UtRdKLoggerFactory(logger))
+    }
+}
\ No newline at end of file
diff --git a/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdRemoteLogger.kt b/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdRemoteLogger.kt
new file mode 100644
index 0000000000..08b397c350
--- /dev/null
+++ b/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdRemoteLogger.kt
@@ -0,0 +1,62 @@
+package org.utbot.rd.loggers
+
+import com.jetbrains.rd.util.LogLevel
+import com.jetbrains.rd.util.Logger
+import com.jetbrains.rd.util.collections.CountingSet
+import com.jetbrains.rd.util.getThrowableText
+import com.jetbrains.rd.util.threadLocalWithInitial
+import org.utbot.rd.generated.LogArguments
+import org.utbot.rd.generated.LoggerModel
+import org.utbot.rd.startBlocking
+
+class UtRdRemoteLogger(
+    private val loggerModel: LoggerModel,
+    private val category: String
+) : Logger {
+    private val logLevel: LogLevel = logLevelValues[loggerModel.getCategoryMinimalLogLevel.startBlocking(category)]
+
+    companion object {
+        val logLevelValues = LogLevel.values()
+        private val threadLocalExecutingBackingFiled: ThreadLocal> =
+            threadLocalWithInitial { CountingSet() }
+
+        internal val threadLocalExecuting get() = threadLocalExecutingBackingFiled.get()
+    }
+
+    override fun isEnabled(level: LogLevel): Boolean {
+        // On every protocol sends/receives event RD to its own loggers.
+        // They will be redirected here, and then sent via RD to another process,
+        // producing new log event again thus causing infinite recursion.
+        // The solution is to prohibit writing any logs from inside logger.
+        // This is implemented via thread local counter per logger,
+        // which will be incremented when this logger fires event to another process,
+        // and deny all following log events until previous log event is delivered.
+        if (threadLocalExecuting[this] > 0)
+            return false
+
+        return level >= logLevel
+    }
+
+    private fun format(message: Any?, throwable: Throwable?): String {
+        val rdCategory = if (category.isNotEmpty()) "RdCategory: ${category.substringAfterLast('.').padEnd(25)} | " else ""
+        return "$rdCategory${message?.toString() ?: ""}${
+            throwable?.getThrowableText()?.let { "${message?.let { " | " } ?: ""}$it" } ?: ""
+        }"
+    }
+
+    override fun log(level: LogLevel, message: Any?, throwable: Throwable?) {
+        if (!isEnabled(level) || message == null && throwable == null)
+            return
+
+        threadLocalExecuting.add(this, +1)
+        try {
+            val renderedMsg = format(message, throwable)
+            val args = LogArguments(category, level.ordinal, renderedMsg)
+
+            loggerModel.log.fire(args)
+        } finally {
+            threadLocalExecuting.add(this, -1)
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdRemoteLoggerFactory.kt b/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdRemoteLoggerFactory.kt
new file mode 100644
index 0000000000..e2024376a3
--- /dev/null
+++ b/utbot-rd/src/main/kotlin/org/utbot/rd/loggers/UtRdRemoteLoggerFactory.kt
@@ -0,0 +1,17 @@
+package org.utbot.rd.loggers
+
+import com.jetbrains.rd.util.ILoggerFactory
+import com.jetbrains.rd.util.Logger
+import org.utbot.rd.generated.LoggerModel
+
+/**
+ * Creates loggers that are mapped to the remote counter-part.
+ * Category is added to message
+*/
+class UtRdRemoteLoggerFactory(
+    private val loggerModel: LoggerModel
+) : ILoggerFactory {
+    override fun getLogger(category: String): Logger {
+        return UtRdRemoteLogger(loggerModel, category)
+    }
+}
\ No newline at end of file
diff --git a/utbot-rd/src/main/rdgen/org/utbot/rd/models/EngineProcessModel.kt b/utbot-rd/src/main/rdgen/org/utbot/rd/models/EngineProcessModel.kt
index 1c89ef0312..532962d55b 100644
--- a/utbot-rd/src/main/rdgen/org/utbot/rd/models/EngineProcessModel.kt
+++ b/utbot-rd/src/main/rdgen/org/utbot/rd/models/EngineProcessModel.kt
@@ -130,7 +130,6 @@ object EngineProcessModel : Ext(EngineProcessRoot) {
         call("isCancelled", PredefinedType.void, PredefinedType.bool).async
         call("generate", generateParams, generateResult).async
         call("render", renderParams, renderResult).async
-        call("stopProcess", PredefinedType.void, PredefinedType.void).async
         call("obtainClassId", PredefinedType.string, array(PredefinedType.byte)).async
         call("findMethodsInClassMatchingSelected", findMethodsInClassMatchingSelectedArguments, findMethodsInClassMatchingSelectedResult).async
         call("findMethodParamNames", findMethodParamNamesArguments, findMethodParamNamesResult).async
diff --git a/utbot-rd/src/main/rdgen/org/utbot/rd/models/InstrumentedProcessModel.kt b/utbot-rd/src/main/rdgen/org/utbot/rd/models/InstrumentedProcessModel.kt
index 205b95d75f..f66a2a990b 100644
--- a/utbot-rd/src/main/rdgen/org/utbot/rd/models/InstrumentedProcessModel.kt
+++ b/utbot-rd/src/main/rdgen/org/utbot/rd/models/InstrumentedProcessModel.kt
@@ -64,11 +64,6 @@ object InstrumentedProcessModel : Ext(InstrumentedProcessRoot) {
                     "which declaring class's name is [className].\n" +
                     "@property parameters are the parameters needed for an execution, e.g. static environment"
         }
-        call("StopProcess", PredefinedType.void, PredefinedType.void).apply {
-            async
-            documentation =
-                "This command tells the instrumented process to stop"
-        }
         call("CollectCoverage", CollectCoverageParams, CollectCoverageResult).apply {
             async
             documentation =
diff --git a/utbot-rd/src/main/rdgen/org/utbot/rd/models/LoggerModel.kt b/utbot-rd/src/main/rdgen/org/utbot/rd/models/LoggerModel.kt
new file mode 100644
index 0000000000..7ca4d8e6b7
--- /dev/null
+++ b/utbot-rd/src/main/rdgen/org/utbot/rd/models/LoggerModel.kt
@@ -0,0 +1,23 @@
+@file:Suppress("unused")
+
+package org.utbot.rd.models
+
+import com.jetbrains.rd.generator.nova.*
+
+object LoggerRoot : Root()
+object LoggerModel : Ext(LoggerRoot) {
+    val logArguments = structdef {
+        field("category", PredefinedType.string)
+        field("logLevelOrdinal", PredefinedType.int).doc("Integer value for com.jetbrains.rd.util.LogLevel")
+        field("message", PredefinedType.string)
+    }
+
+    init {
+        signal("log", logArguments).async
+        call(
+            "getCategoryMinimalLogLevel",
+            PredefinedType.string,
+            PredefinedType.int
+        ).async.doc("Parameter - log category.\nResult - integer value for com.jetbrains.rd.util.LogLevel.")
+    }
+}
\ No newline at end of file
diff --git a/utbot-rd/src/main/rdgen/org/utbot/rd/models/SynchronizationModel.kt b/utbot-rd/src/main/rdgen/org/utbot/rd/models/SynchronizationModel.kt
index 15fa71a260..077173ba23 100644
--- a/utbot-rd/src/main/rdgen/org/utbot/rd/models/SynchronizationModel.kt
+++ b/utbot-rd/src/main/rdgen/org/utbot/rd/models/SynchronizationModel.kt
@@ -8,6 +8,12 @@ object SynchronizationRoot: Root()
 object SynchronizationModel: Ext(SynchronizationRoot) {
     init {
         call("suspendTimeoutTimer", PredefinedType.bool, PredefinedType.void).async
+        signal("initRemoteLogging", PredefinedType.void).async
         signal("synchronizationSignal", PredefinedType.string).async
+        signal("StopProcess", PredefinedType.void).apply {
+            async
+            documentation =
+                "This command tells the instrumented process to stop"
+        }
     }
 }
\ No newline at end of file
diff --git a/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt b/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt
index 5a7ab647e8..88edc7308c 100644
--- a/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt
+++ b/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt
@@ -3,16 +3,14 @@ package examples
 import org.junit.jupiter.api.*
 import org.utbot.common.WorkaroundReason
 import org.utbot.common.workaround
-import org.utbot.framework.SummariesGenerationType
 import org.utbot.framework.UtSettings.checkNpeInNestedMethods
 import org.utbot.framework.UtSettings.checkNpeInNestedNotPrivateMethods
 import org.utbot.framework.UtSettings.checkSolverTimeoutMillis
-import org.utbot.framework.UtSettings.summaryGenerationType
 import org.utbot.framework.plugin.api.*
 import org.utbot.framework.plugin.api.util.UtContext
 import org.utbot.framework.plugin.api.util.executableId
 import org.utbot.summary.comment.nextSynonyms
-import org.utbot.summary.summarize
+import org.utbot.summary.summarizeAll
 import org.utbot.testing.CoverageMatcher
 import org.utbot.testing.TestExecution
 import org.utbot.testing.UtValueTestCaseChecker
@@ -60,7 +58,7 @@ open class SummaryTestCaseGeneratorTest(
             checkNpeInNestedNotPrivateMethods = true
         }
         val testSet = executionsModel(method.executableId, mockStrategy)
-        val testSetWithSummarization = testSet.summarize(searchDirectory, sourceFile = null)
+        val testSetWithSummarization = listOf(testSet).summarizeAll(searchDirectory, sourceFile = null).single()
 
         testSetWithSummarization.executions.checkMatchersWithTextSummary(summaryKeys)
         testSetWithSummarization.executions.checkMatchersWithMethodNames(methodNames)
diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt
index a2b0cc6111..d53f59b766 100644
--- a/utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt
+++ b/utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt
@@ -16,6 +16,8 @@ import org.utbot.summary.name.SimpleNameBuilder
 import java.io.File
 import java.nio.file.Path
 import mu.KotlinLogging
+import org.utbot.common.measureTime
+import org.utbot.common.info
 import org.utbot.framework.SummariesGenerationType.*
 import org.utbot.framework.UtSettings.enableClusterCommentsGeneration
 import org.utbot.framework.UtSettings.enableJavaDocGeneration
@@ -36,7 +38,17 @@ import soot.SootMethod
 
 private val logger = KotlinLogging.logger {}
 
-fun UtMethodTestSet.summarize(searchDirectory: Path, sourceFile: File?): UtMethodTestSet {
+fun Collection.summarizeAll(searchDirectory: Path, sourceFile: File?): List = logger.info().measureTime({
+    "----------------------------------------------------------------------------------------\n" +
+    "-------------------Summarization started for ${this.size} test cases--------------------\n" +
+    "----------------------------------------------------------------------------------------"
+    }) {
+    this.map {
+        it.summarizeOne(searchDirectory, sourceFile)
+    }
+}
+
+private fun UtMethodTestSet.summarizeOne(searchDirectory: Path, sourceFile: File?): UtMethodTestSet = logger.info().measureTime({ "Summarization for ${this.method}"} ){
     if (summaryGenerationType == NONE) return this
 
     val sourceFileToAnalyze = sourceFile
@@ -46,34 +58,29 @@ fun UtMethodTestSet.summarize(searchDirectory: Path, sourceFile: File?): UtMetho
             NONE -> null
         }
 
-    return try {
-        makeDiverseExecutions(this)
+    makeDiverseExecutions(this)
 
-        // HACK: we avoid calling [invokeDescriptions] method to save time, it is useless in Contest
-        val invokeDescriptions = when (summaryGenerationType) {
-            FULL -> invokeDescriptions(this, searchDirectory)
-            LIGHT,
-            NONE -> emptyList()
-        }
+    // HACK: we avoid calling [invokeDescriptions] method to save time, it is useless in Contest
+    val invokeDescriptions = when (summaryGenerationType) {
+        FULL -> invokeDescriptions(this, searchDirectory)
+        LIGHT,
+        NONE -> emptyList()
+    }
 
-        // every cluster has summary and list of executions
-        val executionClusters = Summarization(sourceFileToAnalyze, invokeDescriptions).fillSummaries(this)
-        val updatedExecutions = executionClusters.flatMap { it.executions }
-        var pos = 0
-        val clustersInfo = executionClusters.map {
-            val clusterSize = it.executions.size
-            val indices = pos until (pos + clusterSize)
-            pos += clusterSize
-            it.clusterInfo to indices
-        }
-        this.copy(
+    // every cluster has summary and list of executions
+    val executionClusters = Summarization(sourceFileToAnalyze, invokeDescriptions).fillSummaries(this)
+    val updatedExecutions = executionClusters.flatMap { it.executions }
+    var pos = 0
+    val clustersInfo = executionClusters.map {
+        val clusterSize = it.executions.size
+        val indices = pos until (pos + clusterSize)
+        pos += clusterSize
+        it.clusterInfo to indices
+    }
+    return this.copy(
             executions = updatedExecutions,
             clustersInfo = clustersInfo
         ) // TODO: looks weird and don't create the real copy
-    } catch (e: Throwable) {
-        logger.info(e) { "Summary generation error: ${e.message}" }
-        this
-    }
 }
 
 class Summarization(val sourceFile: File?, val invokeDescriptions: List) {
diff --git a/utbot-testing/src/main/kotlin/org/utbot/testing/TestCodeGeneratorPipeline.kt b/utbot-testing/src/main/kotlin/org/utbot/testing/TestCodeGeneratorPipeline.kt
index 82194912f0..571dce5112 100644
--- a/utbot-testing/src/main/kotlin/org/utbot/testing/TestCodeGeneratorPipeline.kt
+++ b/utbot-testing/src/main/kotlin/org/utbot/testing/TestCodeGeneratorPipeline.kt
@@ -3,7 +3,7 @@ package org.utbot.testing
 import mu.KotlinLogging
 import org.junit.jupiter.api.Assertions.assertTrue
 import org.utbot.common.FileUtil
-import org.utbot.common.bracket
+import org.utbot.common.measureTime
 import org.utbot.common.info
 import org.utbot.framework.codegen.CodeGenerator
 import org.utbot.framework.codegen.CodeGeneratorResult
@@ -49,7 +49,7 @@ class TestCodeGeneratorPipeline(private val testFrameworkConfiguration: TestFram
 
         logger
             .info()
-            .bracket("Executing code generation tests for [$classesPipelinesNames]") {
+            .measureTime({ "Executing code generation tests for [$classesPipelinesNames]" }) {
                 CodeGeneration.filterPipelines(classesPipelines).forEach {
                     withUtContext(UtContext(it.stageContext.classUnderTest.java.classLoader)) {
                         processCodeGenerationStage(it)
diff --git a/utbot-testing/src/main/kotlin/org/utbot/testing/UtValueTestCaseChecker.kt b/utbot-testing/src/main/kotlin/org/utbot/testing/UtValueTestCaseChecker.kt
index 9b64a53c2f..d78e29ee7d 100644
--- a/utbot-testing/src/main/kotlin/org/utbot/testing/UtValueTestCaseChecker.kt
+++ b/utbot-testing/src/main/kotlin/org/utbot/testing/UtValueTestCaseChecker.kt
@@ -42,7 +42,7 @@ import org.utbot.framework.plugin.api.util.kClass
 import org.utbot.framework.plugin.api.util.withUtContext
 import org.utbot.framework.util.Conflict
 import org.utbot.framework.util.toValueTestCase
-import org.utbot.summary.summarize
+import org.utbot.summary.summarizeAll
 import org.utbot.testcheckers.ExecutionsNumberMatcher
 import java.io.File
 import java.nio.file.Path
@@ -1730,7 +1730,7 @@ abstract class UtValueTestCaseChecker(
             } else {
                 walk(executableId, mockStrategy, additionalDependenciesClassPath)
             }
-            testSet.summarize(searchDirectory, sourceFile = null)
+            listOf(testSet).summarizeAll(searchDirectory, sourceFile = null)
             val valueTestCase = testSet.toValueTestCase()
 
             assertTrue(testSet.errors.isEmpty()) {