mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:19:59 +07:00
[platform] IJPL-148733: Unify logging for warmup and qodana
GitOrigin-RevId: 2d18e232718583f93230dd2cd91b453d24c28e04
This commit is contained in:
committed by
intellij-monorepo-bot
parent
a758147396
commit
432cee2d40
@@ -26,5 +26,6 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.backend.workspace" />
|
||||
<orderEntry type="module" module-name="intellij.platform.diagnostic" />
|
||||
<orderEntry type="library" name="hash4j" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.backend.observation" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -28883,8 +28883,6 @@ f:com.intellij.util.PatternValuesIndex
|
||||
- <init>():V
|
||||
- s:buildStringIndex(java.util.Collection):java.util.Set
|
||||
- s:processStringValues(java.util.Collection,com.intellij.util.PairProcessor):Z
|
||||
f:com.intellij.util.ProjectConfigurationUtil
|
||||
- sf:awaitCompleteProjectConfiguration(com.intellij.openapi.project.Project,kotlin.jvm.functions.Function1,kotlin.coroutines.Continuation):java.lang.Object
|
||||
a:com.intellij.util.TextFieldCompletionProvider
|
||||
- com.intellij.openapi.project.PossiblyDumbAware
|
||||
- com.intellij.util.textCompletion.TextCompletionProvider
|
||||
|
||||
@@ -1411,17 +1411,6 @@ com.intellij.ide.warmup.WarmupConfigurator
|
||||
- a:runWarmup(com.intellij.openapi.project.Project,kotlin.coroutines.Continuation):java.lang.Object
|
||||
f:com.intellij.ide.warmup.WarmupConfigurator$Companion
|
||||
- f:getEP_NAME():com.intellij.openapi.extensions.ExtensionPointName
|
||||
com.intellij.ide.warmup.WarmupLogger
|
||||
- sf:Companion:com.intellij.ide.warmup.WarmupLogger$Companion
|
||||
- a:logError(java.lang.String,java.lang.Throwable):V
|
||||
- a:logFatalError(java.lang.String,java.lang.Throwable):V
|
||||
- a:logInfo(java.lang.String):V
|
||||
f:com.intellij.ide.warmup.WarmupLogger$Companion
|
||||
- f:error(java.lang.String,java.lang.Throwable):V
|
||||
- bs:error$default(com.intellij.ide.warmup.WarmupLogger$Companion,java.lang.String,java.lang.Throwable,I,java.lang.Object):V
|
||||
- f:fatalError(java.lang.String,java.lang.Throwable):V
|
||||
- bs:fatalError$default(com.intellij.ide.warmup.WarmupLogger$Companion,java.lang.String,java.lang.Throwable,I,java.lang.Object):V
|
||||
- f:message(java.lang.String):V
|
||||
com.intellij.ide.warmup.WarmupStatus
|
||||
- sf:Companion:com.intellij.ide.warmup.WarmupStatus$Companion
|
||||
f:com.intellij.ide.warmup.WarmupStatus$Companion
|
||||
@@ -3494,6 +3483,71 @@ a:com.intellij.openapi.project.ProjectReloadState
|
||||
- s:getInstance(com.intellij.openapi.project.Project):com.intellij.openapi.project.ProjectReloadState
|
||||
- a:isAfterAutomaticReload():Z
|
||||
- a:onBeforeAutomaticProjectReload():V
|
||||
f:com.intellij.openapi.project.configuration.HeadlessLogging
|
||||
- sf:INSTANCE:com.intellij.openapi.project.configuration.HeadlessLogging
|
||||
- f:logFatalError(java.lang.String):V
|
||||
- f:logFatalError(java.lang.Throwable):V
|
||||
- f:logMessage(java.lang.String):V
|
||||
- f:logWarning(java.lang.String):V
|
||||
- f:logWarning(java.lang.Throwable):V
|
||||
- f:loggingFlow():kotlinx.coroutines.flow.SharedFlow
|
||||
com.intellij.openapi.project.configuration.HeadlessLogging$HeadlessLoggingService
|
||||
- sf:Companion:com.intellij.openapi.project.configuration.HeadlessLogging$HeadlessLoggingService$Companion
|
||||
- a:logEntry(com.intellij.openapi.project.configuration.HeadlessLogging$LogEntry):V
|
||||
- a:loggingFlow():kotlinx.coroutines.flow.SharedFlow
|
||||
f:com.intellij.openapi.project.configuration.HeadlessLogging$HeadlessLoggingService$Companion
|
||||
- f:getInstance():com.intellij.openapi.project.configuration.HeadlessLogging$HeadlessLoggingService
|
||||
f:com.intellij.openapi.project.configuration.HeadlessLogging$LogEntry
|
||||
- <init>(com.intellij.openapi.project.configuration.HeadlessLogging$SeverityKind,com.intellij.openapi.project.configuration.HeadlessLogging$Message):V
|
||||
- f:component1():com.intellij.openapi.project.configuration.HeadlessLogging$SeverityKind
|
||||
- f:component2():com.intellij.openapi.project.configuration.HeadlessLogging$Message
|
||||
- f:copy(com.intellij.openapi.project.configuration.HeadlessLogging$SeverityKind,com.intellij.openapi.project.configuration.HeadlessLogging$Message):com.intellij.openapi.project.configuration.HeadlessLogging$LogEntry
|
||||
- bs:copy$default(com.intellij.openapi.project.configuration.HeadlessLogging$LogEntry,com.intellij.openapi.project.configuration.HeadlessLogging$SeverityKind,com.intellij.openapi.project.configuration.HeadlessLogging$Message,I,java.lang.Object):com.intellij.openapi.project.configuration.HeadlessLogging$LogEntry
|
||||
- equals(java.lang.Object):Z
|
||||
- f:getMessage():com.intellij.openapi.project.configuration.HeadlessLogging$Message
|
||||
- f:getSeverity():com.intellij.openapi.project.configuration.HeadlessLogging$SeverityKind
|
||||
- hashCode():I
|
||||
- toString():java.lang.String
|
||||
com.intellij.openapi.project.configuration.HeadlessLogging$Message
|
||||
- a:representation():java.lang.String
|
||||
f:com.intellij.openapi.project.configuration.HeadlessLogging$Message$Exception
|
||||
- com.intellij.openapi.project.configuration.HeadlessLogging$Message
|
||||
- bsf:box-impl(java.lang.Throwable):com.intellij.openapi.project.configuration.HeadlessLogging$Message$Exception
|
||||
- s:constructor-impl(java.lang.Throwable):java.lang.Throwable
|
||||
- equals(java.lang.Object):Z
|
||||
- s:equals-impl(java.lang.Throwable,java.lang.Object):Z
|
||||
- sf:equals-impl0(java.lang.Throwable,java.lang.Throwable):Z
|
||||
- f:getException():java.lang.Throwable
|
||||
- hashCode():I
|
||||
- s:hashCode-impl(java.lang.Throwable):I
|
||||
- representation():java.lang.String
|
||||
- s:representation-impl(java.lang.Throwable):java.lang.String
|
||||
- toString():java.lang.String
|
||||
- s:toString-impl(java.lang.Throwable):java.lang.String
|
||||
- bf:unbox-impl():java.lang.Throwable
|
||||
f:com.intellij.openapi.project.configuration.HeadlessLogging$Message$Plain
|
||||
- com.intellij.openapi.project.configuration.HeadlessLogging$Message
|
||||
- bsf:box-impl(java.lang.String):com.intellij.openapi.project.configuration.HeadlessLogging$Message$Plain
|
||||
- s:constructor-impl(java.lang.String):java.lang.String
|
||||
- equals(java.lang.Object):Z
|
||||
- s:equals-impl(java.lang.String,java.lang.Object):Z
|
||||
- sf:equals-impl0(java.lang.String,java.lang.String):Z
|
||||
- f:getMessage():java.lang.String
|
||||
- hashCode():I
|
||||
- s:hashCode-impl(java.lang.String):I
|
||||
- representation():java.lang.String
|
||||
- s:representation-impl(java.lang.String):java.lang.String
|
||||
- toString():java.lang.String
|
||||
- s:toString-impl(java.lang.String):java.lang.String
|
||||
- bf:unbox-impl():java.lang.String
|
||||
e:com.intellij.openapi.project.configuration.HeadlessLogging$SeverityKind
|
||||
- java.lang.Enum
|
||||
- sf:Fatal:com.intellij.openapi.project.configuration.HeadlessLogging$SeverityKind
|
||||
- sf:Info:com.intellij.openapi.project.configuration.HeadlessLogging$SeverityKind
|
||||
- sf:Warning:com.intellij.openapi.project.configuration.HeadlessLogging$SeverityKind
|
||||
- s:getEntries():kotlin.enums.EnumEntries
|
||||
- s:valueOf(java.lang.String):com.intellij.openapi.project.configuration.HeadlessLogging$SeverityKind
|
||||
- s:values():com.intellij.openapi.project.configuration.HeadlessLogging$SeverityKind[]
|
||||
com.intellij.openapi.project.impl.ProjectLifecycleListener
|
||||
- sf:TOPIC:com.intellij.util.messages.Topic
|
||||
- afterProjectClosed(com.intellij.openapi.project.Project):V
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.ide.warmup
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
|
||||
/**
|
||||
* This class is used when warmup decides to relay important information to the user.
|
||||
*/
|
||||
interface WarmupLogger {
|
||||
|
||||
/**
|
||||
* Allows reporting information messages.
|
||||
*/
|
||||
fun logInfo(message: String)
|
||||
|
||||
/**
|
||||
* Allows reporting error messages to the user.
|
||||
* Use this if there is an important error, which is still recoverable.
|
||||
*/
|
||||
fun logError(message: String, throwable: Throwable?)
|
||||
|
||||
/**
|
||||
* Allows aborting the process of warmup if something non-recoverable happens.
|
||||
*/
|
||||
fun logFatalError(message: String, throwable: Throwable?)
|
||||
|
||||
companion object {
|
||||
private val EP_NAME: ExtensionPointName<WarmupLogger> = ExtensionPointName("com.intellij.warmupLogger")
|
||||
|
||||
fun message(message: String) {
|
||||
for (warmupLogger in EP_NAME.extensionList) {
|
||||
warmupLogger.logInfo(message)
|
||||
}
|
||||
}
|
||||
|
||||
fun error(message: String, throwable: Throwable? = null) {
|
||||
for (warmupLogger in EP_NAME.extensionList) {
|
||||
warmupLogger.logError(message, throwable)
|
||||
}
|
||||
}
|
||||
|
||||
fun fatalError(message: String, throwable: Throwable? = null) {
|
||||
for (warmupLogger in EP_NAME.extensionList) {
|
||||
warmupLogger.logFatalError(message, throwable)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.ide.warmup
|
||||
|
||||
import com.intellij.openapi.application.Application
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.util.Key
|
||||
import org.jetbrains.annotations.ApiStatus.Internal
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.openapi.project.configuration
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.project.configuration.HeadlessLogging.Message.Plain
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import javax.print.attribute.standard.Severity
|
||||
|
||||
/**
|
||||
* A sink for information that may be useful during command-line execution of the IDE.
|
||||
*
|
||||
* Each subsystem can use the methods in this class to send some information that may be of value to the end user.
|
||||
*
|
||||
* We do not provide a distinction between the severity levels here, as all the reported messages are of interest for the user.
|
||||
* Severity differentiation makes sense for investigation of internal problems, and for this reason we have internal logging.
|
||||
*/
|
||||
object HeadlessLogging {
|
||||
|
||||
/**
|
||||
* Reports an informational message about the IDE.
|
||||
*
|
||||
* This kind of messages is important to keep track of progress and to assure the user that the execution is not stuck.
|
||||
*/
|
||||
fun logMessage(message: String) = HeadlessLoggingService.getInstance().logEntry(LogEntry(SeverityKind.Info, Plain(message)))
|
||||
|
||||
/**
|
||||
* Reports a warning message.
|
||||
*
|
||||
* The collector of the message can decide to react differently to warnings, i.e., print them in different colors in the console,
|
||||
* or collect and report them batched at the end of the configuration.
|
||||
*/
|
||||
fun logWarning(message: String) = HeadlessLoggingService.getInstance().logEntry(LogEntry(SeverityKind.Warning, Plain(message)))
|
||||
|
||||
/**
|
||||
* Reports a non-fatal exception. An exception is non-fatal if the IDE can recover from it.
|
||||
*
|
||||
* This kind of error does not stop the execution of the IDE.
|
||||
*/
|
||||
fun logWarning(exception: Throwable) = HeadlessLoggingService.getInstance().logEntry(LogEntry(SeverityKind.Warning, Message.Exception(exception)))
|
||||
|
||||
/**
|
||||
* Reports a fatal error during the execution. An error is fatal if the user's actions are required in order to fix the problem.
|
||||
*
|
||||
* This kind of errors **has influence on control flow**: once the IDE reports a fatal error,
|
||||
* the headless execution may stop. An example of this error is a failure in the build system import.
|
||||
* This
|
||||
*/
|
||||
fun logFatalError(exception: Throwable) = HeadlessLoggingService.getInstance().logEntry(LogEntry(SeverityKind.Fatal, Message.Exception(exception)))
|
||||
fun logFatalError(message: String) = HeadlessLoggingService.getInstance().logEntry(LogEntry(SeverityKind.Fatal, Plain(message)))
|
||||
|
||||
/**
|
||||
* Retrieves a hot flow with messages about the IDE.
|
||||
*/
|
||||
fun loggingFlow(): SharedFlow<LogEntry> = HeadlessLoggingService.getInstance().loggingFlow()
|
||||
|
||||
enum class SeverityKind {
|
||||
Info,
|
||||
Warning,
|
||||
Fatal
|
||||
}
|
||||
|
||||
sealed interface Message {
|
||||
fun representation(): String
|
||||
|
||||
@JvmInline
|
||||
value class Plain(val message: String) : Message {
|
||||
override fun representation(): String = message
|
||||
}
|
||||
|
||||
@JvmInline
|
||||
value class Exception(val exception: Throwable) : Message {
|
||||
override fun representation(): String = exception.toString()
|
||||
}
|
||||
}
|
||||
|
||||
data class LogEntry(val severity: SeverityKind, val message: Message)
|
||||
|
||||
interface HeadlessLoggingService {
|
||||
companion object {
|
||||
fun getInstance(): HeadlessLoggingService {
|
||||
return ApplicationManager.getApplication().getService(HeadlessLoggingService::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
fun logEntry(logEntry: LogEntry)
|
||||
fun loggingFlow(): SharedFlow<LogEntry>
|
||||
}
|
||||
}
|
||||
@@ -18065,6 +18065,29 @@ f:com.intellij.openapi.project.ScanningTracker
|
||||
- awaitConfiguration(com.intellij.openapi.project.Project,kotlin.coroutines.Continuation):java.lang.Object
|
||||
- getPresentableName():java.lang.String
|
||||
- isInProgress(com.intellij.openapi.project.Project,kotlin.coroutines.Continuation):java.lang.Object
|
||||
f:com.intellij.openapi.project.configuration.ChannelingProgressIndicator
|
||||
- com.intellij.openapi.progress.util.ProgressIndicatorBase
|
||||
- <init>(java.lang.String):V
|
||||
- setFraction(D):V
|
||||
- setIndeterminate(Z):V
|
||||
- setText(java.lang.String):V
|
||||
- setText2(java.lang.String):V
|
||||
f:com.intellij.openapi.project.configuration.EmptyLoggingService
|
||||
- com.intellij.openapi.project.configuration.HeadlessLogging$HeadlessLoggingService
|
||||
- <init>():V
|
||||
- logEntry(com.intellij.openapi.project.configuration.HeadlessLogging$LogEntry):V
|
||||
- loggingFlow():kotlinx.coroutines.flow.SharedFlow
|
||||
f:com.intellij.openapi.project.configuration.HeadlessLoggingServiceImpl
|
||||
- com.intellij.openapi.project.configuration.HeadlessLogging$HeadlessLoggingService
|
||||
- <init>():V
|
||||
- logEntry(com.intellij.openapi.project.configuration.HeadlessLogging$LogEntry):V
|
||||
- loggingFlow():kotlinx.coroutines.flow.SharedFlow
|
||||
f:com.intellij.openapi.project.configuration.HeadlessProgressListener
|
||||
- <init>():V
|
||||
- afterTaskFinished(com.intellij.openapi.progress.Task):V
|
||||
- beforeTaskStart(com.intellij.openapi.progress.Task,com.intellij.openapi.progress.ProgressIndicator):V
|
||||
f:com.intellij.openapi.project.configuration.ProjectConfigurationUtil
|
||||
- sf:awaitCompleteProjectConfiguration(com.intellij.openapi.project.Project,kotlin.jvm.functions.Function1,kotlin.coroutines.Continuation):java.lang.Object
|
||||
a:com.intellij.openapi.project.impl.DefaultProjectTimed
|
||||
- com.intellij.util.TimedReference
|
||||
- dispose():V
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -17,7 +18,9 @@ import java.util.function.Predicate;
|
||||
/**
|
||||
* Extension point that helps prepare project for opening in headless or automated environments.
|
||||
* Implementation must be stateless.
|
||||
* Consider using com.intellij.platform.backend.observation.ActivityTracker
|
||||
*/
|
||||
@ApiStatus.Obsolete(since = "2024.1")
|
||||
public interface CommandLineInspectionProjectConfigurator {
|
||||
ExtensionPointName<CommandLineInspectionProjectConfigurator> EP_NAME = ExtensionPointName.create("com.intellij.commandLineInspectionProjectConfigurator");
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ import com.fasterxml.jackson.databind.type.CollectionType
|
||||
import com.intellij.ide.environment.EnvironmentKey
|
||||
import com.intellij.ide.environment.EnvironmentService
|
||||
import com.intellij.ide.environment.description
|
||||
import com.intellij.ide.warmup.WarmupLogger
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.project.configuration.HeadlessLogging
|
||||
import kotlinx.coroutines.*
|
||||
import java.io.IOException
|
||||
|
||||
@@ -22,7 +22,8 @@ class HeadlessEnvironmentService(scope: CoroutineScope) : BaseEnvironmentService
|
||||
return getEnvironmentValueOrNull(key)
|
||||
?: run {
|
||||
val throwable = MissingEnvironmentKeyException(key)
|
||||
WarmupLogger.fatalError("Insufficient project configuration", MissingEnvironmentKeyException(key))
|
||||
LOG.error(throwable)
|
||||
HeadlessLogging.logFatalError(MissingEnvironmentKeyException(key))
|
||||
throw throwable
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.openapi.project.configuration
|
||||
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorBase
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
class ChannelingProgressIndicator(private val prefix: String) : ProgressIndicatorBase() {
|
||||
override fun setIndeterminate(indeterminate: Boolean) {
|
||||
super.setIndeterminate(indeterminate)
|
||||
}
|
||||
|
||||
private val lastState = AtomicReference(0.0)
|
||||
|
||||
override fun setFraction(fraction: Double) {
|
||||
super.setFraction(fraction)
|
||||
val lastStateValue = lastState.get()
|
||||
if (fraction - lastStateValue > 0.2) {
|
||||
// we debounce the messages by 20%
|
||||
if (lastState.compareAndSet(lastStateValue, fraction)) {
|
||||
offerState()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun setText(text: String?) {
|
||||
super.setText(text)
|
||||
super.setText2("")
|
||||
offerState()
|
||||
}
|
||||
|
||||
override fun setText2(text: String?) {
|
||||
super.setText2(text)
|
||||
}
|
||||
|
||||
private fun trimProgressTextAndNullize(s: String?) = s?.trim()?.trimEnd('.', '\u2026', ' ')?.takeIf { it.isNotBlank() }
|
||||
|
||||
private fun progressStateText(fraction: Double?, text: String?, details: String?): String? {
|
||||
val text = trimProgressTextAndNullize(text)
|
||||
val text2 = trimProgressTextAndNullize(details)
|
||||
if (text.isNullOrBlank() && text2.isNullOrBlank()) {
|
||||
return null
|
||||
}
|
||||
|
||||
val shortText = text ?: ""
|
||||
val verboseText = shortText + (text2?.let { " ($it)" } ?: "")
|
||||
if (shortText.isBlank() || fraction == null) {
|
||||
return verboseText
|
||||
}
|
||||
|
||||
val v = (100.0 * fraction).toInt()
|
||||
val total = 18
|
||||
val completed = (total * fraction).toInt().coerceAtLeast(0)
|
||||
val d = ".".repeat(completed).padEnd(total, ' ')
|
||||
val verboseReport = verboseText.take(100).padEnd(105) + "$d $v%"
|
||||
return verboseReport
|
||||
}
|
||||
|
||||
private fun offerState() {
|
||||
val progressState = progressStateText(
|
||||
fraction = if (isIndeterminate) null else fraction,
|
||||
text = text,
|
||||
details = text2,
|
||||
) ?: return
|
||||
val actualPrefix = if (prefix.isEmpty()) "" else "[$prefix]: "
|
||||
HeadlessLogging.logMessage(actualPrefix + progressState)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.openapi.project.configuration
|
||||
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
|
||||
class EmptyLoggingService : HeadlessLogging.HeadlessLoggingService {
|
||||
private val emptyFlow = MutableSharedFlow<HeadlessLogging.LogEntry>()
|
||||
override fun logEntry(exception: HeadlessLogging.LogEntry) {
|
||||
}
|
||||
|
||||
override fun loggingFlow(): SharedFlow<HeadlessLogging.LogEntry> {
|
||||
return emptyFlow
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.openapi.project.configuration
|
||||
|
||||
import com.intellij.openapi.diagnostic.thisLogger
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
|
||||
class HeadlessLoggingServiceImpl : HeadlessLogging.HeadlessLoggingService {
|
||||
|
||||
private val flow: MutableSharedFlow<HeadlessLogging.LogEntry> = MutableSharedFlow(replay = 0, extraBufferCapacity = 1024, onBufferOverflow = BufferOverflow.SUSPEND)
|
||||
|
||||
|
||||
override fun logEntry(logEntry: HeadlessLogging.LogEntry) {
|
||||
emitLogEntry(logEntry)
|
||||
}
|
||||
|
||||
private fun emitLogEntry(entry: HeadlessLogging.LogEntry) {
|
||||
var internalLoggingPerformed = false
|
||||
while (!flow.tryEmit(entry)) {
|
||||
// we have some slow collectors
|
||||
// there is nothing the platform can do, other than report this incident
|
||||
if (!internalLoggingPerformed) {
|
||||
thisLogger().warn("Cannot log message: ${entry}. \n" +
|
||||
"Headless logger has exhausted the buffer of messages. Please speed up the listeners of the Headless logger.")
|
||||
internalLoggingPerformed = true
|
||||
}
|
||||
// Nevertheless, it is important to deliver complete information to the user.
|
||||
Thread.sleep(100)
|
||||
}
|
||||
}
|
||||
|
||||
override fun loggingFlow(): SharedFlow<HeadlessLogging.LogEntry> {
|
||||
return flow
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.openapi.project.configuration
|
||||
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.progress.ProgressManagerListener
|
||||
import com.intellij.openapi.progress.Task
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorBase
|
||||
import com.intellij.openapi.util.text.Formats
|
||||
import com.intellij.openapi.wm.ex.ProgressIndicatorEx
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class HeadlessProgressListener : ProgressManagerListener {
|
||||
|
||||
private val taskDurationMap = ConcurrentHashMap<Int, Long>()
|
||||
|
||||
override fun beforeTaskStart(task: Task, indicator: ProgressIndicator) {
|
||||
if (indicator !is ProgressIndicatorEx) {
|
||||
return
|
||||
}
|
||||
HeadlessLogging.logMessage("[IDE]: Task '${task.title}' started")
|
||||
taskDurationMap[System.identityHashCode(task)] = System.currentTimeMillis()
|
||||
indicator.addStateDelegate(ChannelingProgressIndicator("IDE"))
|
||||
super.beforeTaskStart(task, indicator)
|
||||
}
|
||||
|
||||
override fun afterTaskFinished(task: Task) {
|
||||
val currentTime = System.currentTimeMillis()
|
||||
val startTime = taskDurationMap.remove(System.identityHashCode(task))
|
||||
val elapsedTimeSuffix = if (startTime == null) "" else " in ${Formats.formatDuration(currentTime - startTime)}"
|
||||
HeadlessLogging.logMessage("[IDE]: Task '${task.title}' ended" + elapsedTimeSuffix)
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
@file:JvmName("ProjectConfigurationUtil")
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.util
|
||||
@file:JvmName("ProjectConfigurationUtil")
|
||||
|
||||
package com.intellij.openapi.project.configuration
|
||||
|
||||
import com.intellij.configurationStore.StoreUtil.saveSettings
|
||||
import com.intellij.configurationStore.saveProjectsAndApp
|
||||
import com.intellij.configurationStore.saveSettings
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.platform.backend.observation.Observation
|
||||
@@ -511,7 +511,6 @@
|
||||
<extensionPoint name="beforeRunStartupTasks" interface="com.intellij.execution.startup.BeforeRunStartupTasks" area="IDEA_PROJECT"/>
|
||||
|
||||
<extensionPoint name="warmupConfigurator" interface="com.intellij.ide.warmup.WarmupConfigurator" dynamic="true" />
|
||||
<extensionPoint name="warmupLogger" interface="com.intellij.ide.warmup.WarmupLogger" dynamic="true" />
|
||||
|
||||
<extensionPoint name="activityTracker" interface="com.intellij.platform.backend.observation.ActivityTracker"
|
||||
dynamic="true"/>
|
||||
|
||||
@@ -109,6 +109,10 @@
|
||||
|
||||
<ideEventQueueDispatcher implementation="com.intellij.openapi.keymap.impl.ModifierKeyDoubleClickHandler$MyEventDispatcher"/>
|
||||
|
||||
<applicationService serviceInterface="com.intellij.openapi.project.configuration.HeadlessLogging$HeadlessLoggingService"
|
||||
serviceImplementation="com.intellij.openapi.project.configuration.EmptyLoggingService"
|
||||
headlessImplementation="com.intellij.openapi.project.configuration.HeadlessLoggingServiceImpl"/>
|
||||
|
||||
<applicationService serviceInterface="com.intellij.openapi.client.ClientSessionsManager"
|
||||
serviceImplementation="com.intellij.openapi.client.ClientAppSessionsManager"/>
|
||||
<projectService serviceInterface="com.intellij.openapi.client.ClientSessionsManager"
|
||||
@@ -200,6 +204,10 @@
|
||||
<listener class="com.intellij.ide.ui.html.GlobalStyleSheetUpdateListener"
|
||||
topic="com.intellij.openapi.editor.colors.EditorColorsListener" activeInHeadlessMode="false"/>
|
||||
|
||||
<listener class="com.intellij.openapi.project.configuration.HeadlessProgressListener"
|
||||
topic="com.intellij.openapi.progress.ProgressManagerListener"
|
||||
activeInHeadlessMode="true"/>
|
||||
|
||||
<listener class="com.intellij.openapi.editor.actions.ResetFontSizeEditorActionHandler"
|
||||
topic="com.intellij.openapi.editor.colors.EditorColorsListener"/>
|
||||
|
||||
|
||||
@@ -25,12 +25,6 @@ f:com.intellij.warmup.util.ConsoleLog
|
||||
- bs:error$default(com.intellij.warmup.util.ConsoleLog,java.lang.String,java.lang.Throwable,I,java.lang.Object):V
|
||||
- f:info(java.lang.String):V
|
||||
- f:warn(java.lang.String):V
|
||||
f:com.intellij.warmup.util.DefaultWarmupLogger
|
||||
- com.intellij.ide.warmup.WarmupLogger
|
||||
- <init>():V
|
||||
- logError(java.lang.String,java.lang.Throwable):V
|
||||
- logFatalError(java.lang.String,java.lang.Throwable):V
|
||||
- logInfo(java.lang.String):V
|
||||
com.intellij.warmup.util.HeadlessConfigurableArgs
|
||||
- a:getPathToConfigurationFile():java.nio.file.Path
|
||||
c:com.intellij.warmup.util.HeadlessConfigurableArgsImpl
|
||||
@@ -74,10 +68,6 @@ f:com.intellij.warmup.util.WarmupLogger
|
||||
- f:logError(java.lang.String,java.lang.Throwable):V
|
||||
- bs:logError$default(com.intellij.warmup.util.WarmupLogger,java.lang.String,java.lang.Throwable,I,java.lang.Object):V
|
||||
- f:logInfo(java.lang.String):V
|
||||
f:com.intellij.warmup.util.WarmupProgressListener
|
||||
- <init>():V
|
||||
- afterTaskFinished(com.intellij.openapi.progress.Task):V
|
||||
- beforeTaskStart(com.intellij.openapi.progress.Task,com.intellij.openapi.progress.ProgressIndicator):V
|
||||
com.intellij.warmup.util.WarmupProjectArgs
|
||||
- com.intellij.warmup.util.OpenProjectArgs
|
||||
- a:getBuild():Z
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<appStarter id="warmup" implementation="com.intellij.warmup.ProjectCachesWarmup"/>
|
||||
<projectBuildWarmupSupport implementation="com.intellij.warmup.PlatformBuildWarmupSupport"/>
|
||||
<warmupLogger implementation="com.intellij.warmup.util.DefaultWarmupLogger"/>
|
||||
</extensions>
|
||||
|
||||
</idea-plugin>
|
||||
@@ -58,7 +58,7 @@ internal class ProjectCachesWarmup : ModernApplicationStarter() {
|
||||
configureVcsIndexing(commandArgs)
|
||||
|
||||
runWarmupActivity {
|
||||
initLogger(args)
|
||||
val loggingJob = initLogger(args)
|
||||
waitIndexInitialization()
|
||||
val project = try {
|
||||
importOrOpenProjectAsync(commandArgs)
|
||||
@@ -79,6 +79,7 @@ internal class ProjectCachesWarmup : ModernApplicationStarter() {
|
||||
waitForRefreshQueue()
|
||||
}
|
||||
ProjectManagerEx.getInstanceEx().forceCloseProjectAsync(project, save = true)
|
||||
loggingJob.cancel()
|
||||
}
|
||||
|
||||
exitApplication()
|
||||
@@ -225,7 +226,7 @@ private suspend fun buildProject(project: Project, commandArgs: WarmupProjectArg
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun runWarmupActivity(action: suspend () -> Unit) {
|
||||
private suspend fun runWarmupActivity(action: suspend CoroutineScope.() -> Unit) {
|
||||
val indexedFiles = installStatisticsCollector()
|
||||
WarmupStatus.statusChanged(WarmupStatus.InProgress)
|
||||
try {
|
||||
|
||||
@@ -4,14 +4,12 @@ package com.intellij.warmup.util
|
||||
import com.intellij.ide.impl.OpenProjectTask
|
||||
import com.intellij.ide.impl.ProjectUtil
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.util.awaitCompleteProjectConfiguration
|
||||
import com.intellij.openapi.project.configuration.HeadlessLogging
|
||||
import com.intellij.openapi.project.configuration.awaitCompleteProjectConfiguration
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.CoroutineStart
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.job
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.selects.select
|
||||
|
||||
suspend fun configureProjectByActivities(args: OpenProjectArgs) : Project {
|
||||
@@ -39,24 +37,15 @@ suspend fun configureProjectByActivities(args: OpenProjectArgs) : Project {
|
||||
return project
|
||||
}
|
||||
|
||||
|
||||
internal val abortFlow : MutableStateFlow<String?> = MutableStateFlow(null)
|
||||
|
||||
private fun CoroutineScope.getFailureDeferred() : Deferred<String> {
|
||||
return async {
|
||||
while (coroutineContext.job.isActive) {
|
||||
val message = abortFlow.value
|
||||
if (message != null) {
|
||||
return@async message
|
||||
}
|
||||
delay(500)
|
||||
}
|
||||
error("unreachable")
|
||||
val firstFatal = HeadlessLogging.loggingFlow().first { (level, _) -> level == HeadlessLogging.SeverityKind.Fatal }
|
||||
firstFatal.message.representation()
|
||||
}
|
||||
}
|
||||
|
||||
private fun CoroutineScope.getConfigurationDeferred(project : Project) : Deferred<Unit> {
|
||||
return async(start = CoroutineStart.UNDISPATCHED) {
|
||||
return async {
|
||||
withLoggingProgressReporter {
|
||||
project.awaitCompleteProjectConfiguration(WarmupLogger::logInfo)
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.warmup.util
|
||||
|
||||
import com.intellij.ide.warmup.WarmupLogger
|
||||
|
||||
class DefaultWarmupLogger : WarmupLogger {
|
||||
override fun logInfo(message: String) {
|
||||
com.intellij.warmup.util.WarmupLogger.logInfo(message)
|
||||
}
|
||||
|
||||
override fun logError(message: String, throwable: Throwable?) {
|
||||
com.intellij.warmup.util.WarmupLogger.logError(message, throwable)
|
||||
}
|
||||
|
||||
override fun logFatalError(message: String, throwable: Throwable?) {
|
||||
logError(message, throwable)
|
||||
abortFlow.tryEmit(message)
|
||||
}
|
||||
}
|
||||
@@ -2,26 +2,19 @@
|
||||
package com.intellij.warmup.util
|
||||
|
||||
import com.intellij.diagnostic.ThreadDumper
|
||||
import com.intellij.ide.warmup.WarmupStatus
|
||||
import com.intellij.openapi.application.ApplicationInfo
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.ApplicationNamesInfo
|
||||
import com.intellij.openapi.application.PathManager
|
||||
import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.diagnostic.JulLogger
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.diagnostic.RollingFileHandler
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.progress.ProgressManagerListener
|
||||
import com.intellij.openapi.progress.Task
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorBase
|
||||
import com.intellij.openapi.project.configuration.ChannelingProgressIndicator
|
||||
import com.intellij.openapi.project.configuration.HeadlessLogging
|
||||
import com.intellij.openapi.util.io.findOrCreateFile
|
||||
import com.intellij.openapi.util.text.Formats
|
||||
import com.intellij.openapi.wm.ex.ProgressIndicatorEx
|
||||
import com.intellij.platform.ide.bootstrap.logEssentialInfoAboutIde
|
||||
import com.intellij.platform.util.progress.createProgressPipe
|
||||
import com.intellij.util.application
|
||||
import com.intellij.util.lazyPub
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
@@ -42,28 +35,33 @@ import kotlin.time.Duration.Companion.milliseconds
|
||||
object WarmupLogger {
|
||||
fun logInfo(message: String) {
|
||||
ConsoleLog.info(message)
|
||||
warmupLogger?.info(message)
|
||||
}
|
||||
|
||||
fun logError(message: String, t: Throwable? = null) {
|
||||
ConsoleLog.error(message, t)
|
||||
warmupLogger?.error(message, t)
|
||||
}
|
||||
|
||||
internal fun logStructured(message: StructuredMessage) {
|
||||
ConsoleLog.info(message.fullMessage)
|
||||
warmupLogger?.info(message.contractedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun initLogger(args: List<String>) {
|
||||
val logger = warmupLogger ?: return
|
||||
internal fun CoroutineScope.initLogger(args: List<String>): Job {
|
||||
val logger = warmupLogger ?: return Job()
|
||||
val info = ApplicationInfo.getInstance()
|
||||
val buildDate = SimpleDateFormat("dd MMM yyyy HH:mm", Locale.US).format(info.buildDate.time)
|
||||
logEssentialInfoAboutIde(log = logger, appInfo = info, args = args)
|
||||
val connection = ApplicationManager.getApplication().messageBus.connect()
|
||||
connection.subscribe(ProgressManagerListener.TOPIC, WarmupProgressListener())
|
||||
logger.info("IDE: ${ApplicationNamesInfo.getInstance().fullProductName} (build #${info.build.asString()}, ${buildDate})")
|
||||
return launch {
|
||||
HeadlessLogging.loggingFlow().collect { (level, message) ->
|
||||
val messageRepresentation = message.representation()
|
||||
when (level) {
|
||||
HeadlessLogging.SeverityKind.Info -> ConsoleLog.info(messageRepresentation)
|
||||
HeadlessLogging.SeverityKind.Warning -> ConsoleLog.warn(messageRepresentation)
|
||||
HeadlessLogging.SeverityKind.Fatal -> ConsoleLog.error(messageRepresentation)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -99,42 +97,7 @@ internal fun progressStateText(fraction: Double?, text: String?, details: String
|
||||
return StructuredMessage(verboseReport, shortReport)
|
||||
}
|
||||
|
||||
private class ChannelingProgressIndicator(private val prefix: String) : ProgressIndicatorBase() {
|
||||
override fun setIndeterminate(indeterminate: Boolean) {
|
||||
super.setIndeterminate(indeterminate)
|
||||
offerState()
|
||||
}
|
||||
|
||||
override fun setFraction(fraction: Double) {
|
||||
super.setFraction(fraction)
|
||||
offerState()
|
||||
}
|
||||
|
||||
override fun setText(text: String?) {
|
||||
super.setText(text)
|
||||
super.setText2("")
|
||||
offerState()
|
||||
}
|
||||
|
||||
override fun setText2(text: String?) {
|
||||
super.setText2(text)
|
||||
offerState()
|
||||
}
|
||||
|
||||
private fun offerState() {
|
||||
val messages = ApplicationManager.getApplication().service<WarmupLoggingService>().messages
|
||||
val progressState = progressStateText(
|
||||
fraction = if (isIndeterminate) null else fraction,
|
||||
text = text,
|
||||
details = text2,
|
||||
) ?: return
|
||||
val actualPrefix = if (prefix.isEmpty()) "" else "[$prefix]: "
|
||||
messages.tryEmit(progressState.copy(
|
||||
contractedMessage = actualPrefix + progressState.contractedMessage,
|
||||
fullMessage = actualPrefix + progressState.fullMessage,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs a progress reporter that sends the information about progress to the stdout instead of UI.
|
||||
@@ -191,13 +154,8 @@ private val loggerFactory: WarmupLoggerFactory? by lazyPub {
|
||||
}
|
||||
|
||||
private val warmupLogger: Logger? by lazyPub {
|
||||
if (WarmupStatus.currentStatus() != WarmupStatus.InProgress) {
|
||||
null
|
||||
}
|
||||
else {
|
||||
val instance = loggerFactory?.getLoggerInstance("Warmup") ?: return@lazyPub null
|
||||
instance
|
||||
}
|
||||
val instance = loggerFactory?.getLoggerInstance("Warmup") ?: return@lazyPub null
|
||||
instance
|
||||
}
|
||||
|
||||
internal data class StructuredMessage(
|
||||
@@ -222,28 +180,6 @@ private class WarmupLoggingService(scope: CoroutineScope) {
|
||||
}
|
||||
}
|
||||
|
||||
class WarmupProgressListener : ProgressManagerListener {
|
||||
|
||||
private val taskDurationMap = ConcurrentHashMap<Int, Long>()
|
||||
|
||||
|
||||
override fun beforeTaskStart(task: Task, indicator: ProgressIndicator) {
|
||||
if (indicator !is ProgressIndicatorEx) {
|
||||
return
|
||||
}
|
||||
WarmupLogger.logInfo("[IDE]: Task '${task.title}' started")
|
||||
taskDurationMap[System.identityHashCode(task)] = System.currentTimeMillis()
|
||||
indicator.addStateDelegate(ChannelingProgressIndicator("IDE"))
|
||||
super.beforeTaskStart(task, indicator)
|
||||
}
|
||||
|
||||
override fun afterTaskFinished(task: Task) {
|
||||
val currentTime = System.currentTimeMillis()
|
||||
val startTime = taskDurationMap.remove(System.identityHashCode(task))
|
||||
val elapsedTimeSuffix = if (startTime == null) "" else " in ${Formats.formatDuration(currentTime - startTime)}"
|
||||
WarmupLogger.logInfo("[IDE]: Task '${task.title}' ended" + elapsedTimeSuffix)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun dumpThreadsAfterConfiguration() {
|
||||
val dump = ThreadDumper.getThreadDumpInfo(ThreadDumper.getThreadInfos(), false)
|
||||
|
||||
@@ -6,26 +6,23 @@ import com.intellij.ide.CommandLineProgressReporterElement
|
||||
import com.intellij.ide.environment.EnvironmentService
|
||||
import com.intellij.ide.impl.ProjectOpenKeyProvider
|
||||
import com.intellij.ide.warmup.WarmupConfigurator
|
||||
import com.intellij.ide.warmup.WarmupLogger
|
||||
import com.intellij.ide.warmup.WarmupStatus
|
||||
import com.intellij.openapi.application.PathManager
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.externalSystem.autoimport.AutoImportProjectTracker
|
||||
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId
|
||||
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener
|
||||
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType
|
||||
import com.intellij.openapi.externalSystem.service.notification.ExternalSystemProgressNotificationManager
|
||||
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataImportListener
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||
import com.intellij.openapi.progress.blockingContextScope
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.util.io.createParentDirectories
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.jetbrains.plugins.gradle.service.notification.ExternalAnnotationsProgressNotificationListener
|
||||
import org.jetbrains.plugins.gradle.service.notification.ExternalAnnotationsProgressNotificationManager
|
||||
import org.jetbrains.plugins.gradle.service.notification.ExternalAnnotationsTaskId
|
||||
import org.jetbrains.plugins.gradle.service.project.GradleHeadlessLoggingProjectActivity.LoggingNotificationListener
|
||||
import org.jetbrains.plugins.gradle.service.project.GradleHeadlessLoggingProjectActivity.StateExternalAnnotationNotificationListener
|
||||
import org.jetbrains.plugins.gradle.service.project.GradleHeadlessLoggingProjectActivity.StateNotificationListener
|
||||
import org.jetbrains.plugins.gradle.service.project.isGradleProjectResolveTask
|
||||
import org.jetbrains.plugins.gradle.service.project.open.createLinkSettings
|
||||
import org.jetbrains.plugins.gradle.settings.GradleImportHintService
|
||||
import org.jetbrains.plugins.gradle.settings.GradleSettings
|
||||
@@ -37,14 +34,10 @@ import java.nio.file.Paths
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import kotlin.coroutines.coroutineContext
|
||||
import kotlin.io.path.appendText
|
||||
import kotlin.io.path.createFile
|
||||
import kotlin.io.path.div
|
||||
|
||||
|
||||
private val LOG = logger<GradleCommandLineProjectConfigurator>()
|
||||
|
||||
private val gradleLogWriterPath = Path.of(PathManager.getLogPath()) / "gradle-import.log"
|
||||
|
||||
private const val DISABLE_GRADLE_AUTO_IMPORT = "external.system.auto.import.disabled"
|
||||
private const val DISABLE_GRADLE_JDK_FIX = "gradle.auto.auto.jdk.fix.disabled"
|
||||
@@ -156,66 +149,9 @@ class GradleWarmupConfigurator : WarmupConfigurator {
|
||||
return false
|
||||
}
|
||||
|
||||
class StateExternalAnnotationNotificationListener : ExternalAnnotationsProgressNotificationListener {
|
||||
|
||||
override fun onStartResolve(id: ExternalAnnotationsTaskId) {
|
||||
LOG.info("Gradle resolving external annotations started ${id.projectId}")
|
||||
}
|
||||
|
||||
override fun onFinishResolve(id: ExternalAnnotationsTaskId) {
|
||||
LOG.info("Gradle resolving external annotations completed ${id.projectId}")
|
||||
}
|
||||
}
|
||||
|
||||
class StateNotificationListener(
|
||||
private val project: Project, private val scope: CoroutineScope
|
||||
) : ExternalSystemTaskNotificationListener {
|
||||
|
||||
override fun onSuccess(id: ExternalSystemTaskId) {
|
||||
if (!id.isGradleProjectResolveTask()) return
|
||||
LOG.info("Gradle resolve stage finished with success: ${id.ideProjectId}")
|
||||
|
||||
project.messageBus.connect(scope)
|
||||
.subscribe(ProjectDataImportListener.TOPIC, object : ProjectDataImportListener {
|
||||
override fun onImportStarted(projectPath: String?) {
|
||||
LOG.info("Gradle data import stage started: ${id.ideProjectId}")
|
||||
}
|
||||
|
||||
override fun onImportFinished(projectPath: String?) {
|
||||
LOG.info("Gradle data import stage finished with success: ${id.ideProjectId}")
|
||||
}
|
||||
|
||||
override fun onFinalTasksFinished(projectPath: String?) {
|
||||
LOG.info("Gradle data import(final tasks) stage finished: ${id.ideProjectId}")
|
||||
}
|
||||
|
||||
override fun onFinalTasksStarted(projectPath: String?) {
|
||||
LOG.info("Gradle data import(final tasks) stage started: ${id.ideProjectId}")
|
||||
}
|
||||
|
||||
override fun onImportFailed(projectPath: String?, t: Throwable) {
|
||||
WarmupLogger.fatalError(t.message ?: "Gradle import finished with error", t)
|
||||
LOG.info("Gradle data import stage finished with failure: ${id.ideProjectId}")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onFailure(id: ExternalSystemTaskId, e: Exception) {
|
||||
if (!id.isGradleProjectResolveTask()) return
|
||||
WarmupLogger.fatalError(e.message ?: "Gradle import finished with error", e)
|
||||
LOG.error("Gradle resolve stage finished with failure ${id.ideProjectId}", e)
|
||||
}
|
||||
|
||||
override fun onCancel(id: ExternalSystemTaskId) {
|
||||
if (!id.isGradleProjectResolveTask()) return
|
||||
LOG.error("Gradle resolve stage canceled ${id.ideProjectId}")
|
||||
}
|
||||
|
||||
override fun onStart(id: ExternalSystemTaskId, workingDir: String) {
|
||||
if (!id.isGradleProjectResolveTask()) return
|
||||
LOG.info("Gradle resolve stage started ${id.ideProjectId}, working dir: $workingDir")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ImportErrorListener(
|
||||
@@ -246,39 +182,6 @@ class GradleWarmupConfigurator : WarmupConfigurator {
|
||||
}
|
||||
}
|
||||
|
||||
class LoggingNotificationListener(val logger: CommandLineInspectionProgressReporter?) : ExternalSystemTaskNotificationListener {
|
||||
|
||||
private val logPath = try {
|
||||
gradleLogWriterPath.createParentDirectories().createFile()
|
||||
}
|
||||
catch (e: java.nio.file.FileAlreadyExistsException) {
|
||||
gradleLogWriterPath
|
||||
}
|
||||
|
||||
override fun onTaskOutput(id: ExternalSystemTaskId, text: String, stdOut: Boolean) {
|
||||
val gradleText = (if (stdOut) "" else "STDERR: ") + text
|
||||
logPath.appendText(gradleText)
|
||||
val croppedMessage = processMessage(gradleText)
|
||||
if (croppedMessage != null) {
|
||||
logger?.reportMessage(1, croppedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
private fun processMessage(gradleText: String): String? {
|
||||
if (WarmupStatus.currentStatus() != WarmupStatus.InProgress) {
|
||||
return gradleText
|
||||
}
|
||||
val cropped = gradleText.trimStart('\r').trimEnd('\n')
|
||||
if (cropped.startsWith("Download")) {
|
||||
// we don't want to be flooded by a ton of download messages, so we'll print only final message
|
||||
if (cropped.contains(" took ")) {
|
||||
return cropped
|
||||
}
|
||||
return null
|
||||
}
|
||||
return cropped
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun prepareGradleConfiguratorEnvironment(logger: CommandLineInspectionProgressReporter?) {
|
||||
@@ -288,11 +191,9 @@ internal fun prepareGradleConfiguratorEnvironment(logger: CommandLineInspectionP
|
||||
System.setProperty(DISABLE_UPDATE_ANDROID_SDK_LOCAL_PROPERTIES, true.toString())
|
||||
val progressManager = ExternalSystemProgressNotificationManager.getInstance()
|
||||
if (logger != null) {
|
||||
progressManager.addNotificationListener(GradleWarmupConfigurator.LoggingNotificationListener(logger))
|
||||
progressManager.addNotificationListener(LoggingNotificationListener())
|
||||
}
|
||||
Unit
|
||||
}
|
||||
|
||||
|
||||
private fun ExternalSystemTaskId.isGradleProjectResolveTask() = this.projectSystemId == GradleConstants.SYSTEM_ID &&
|
||||
this.type == ExternalSystemTaskType.RESOLVE_PROJECT
|
||||
@@ -1,22 +1,32 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.plugins.gradle.service.project
|
||||
|
||||
import com.intellij.ide.CommandLineInspectionProgressReporter
|
||||
import com.intellij.ide.warmup.WarmupLogger
|
||||
import com.intellij.ide.warmup.WarmupStatus
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.PathManager
|
||||
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId
|
||||
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener
|
||||
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType
|
||||
import com.intellij.openapi.externalSystem.service.notification.ExternalSystemProgressNotificationManager
|
||||
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataImportListener
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.configuration.HeadlessLogging
|
||||
import com.intellij.openapi.startup.ProjectActivity
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.util.application
|
||||
import com.intellij.util.awaitCancellationAndInvoke
|
||||
import com.intellij.util.io.createParentDirectories
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.jetbrains.plugins.gradle.GradleWarmupConfigurator
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.plugins.gradle.service.notification.ExternalAnnotationsProgressNotificationListener
|
||||
import org.jetbrains.plugins.gradle.service.notification.ExternalAnnotationsProgressNotificationManager
|
||||
import org.jetbrains.plugins.gradle.service.notification.ExternalAnnotationsTaskId
|
||||
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.appendText
|
||||
import kotlin.io.path.createFile
|
||||
import kotlin.io.path.div
|
||||
|
||||
class GradleHeadlessLoggingProjectActivity(val scope: CoroutineScope) : ProjectActivity {
|
||||
override suspend fun execute(project: Project) {
|
||||
if (WarmupStatus.currentStatus() != WarmupStatus.InProgress || !Registry.`is`("ide.warmup.use.predicates")) {
|
||||
if (!application.isHeadlessEnvironment || application.isUnitTestMode) {
|
||||
return
|
||||
}
|
||||
val progressManager = ExternalSystemProgressNotificationManager.getInstance()
|
||||
@@ -26,42 +36,132 @@ class GradleHeadlessLoggingProjectActivity(val scope: CoroutineScope) : ProjectA
|
||||
}
|
||||
|
||||
private fun addTaskNotificationListener(progressManager: ExternalSystemProgressNotificationManager) {
|
||||
val listener = GradleWarmupConfigurator.LoggingNotificationListener(object : CommandLineInspectionProgressReporter {
|
||||
override fun reportError(message: String?) {
|
||||
if (message == null) {
|
||||
return
|
||||
}
|
||||
WarmupLogger.fatalError(message, null)
|
||||
}
|
||||
|
||||
override fun reportMessage(minVerboseLevel: Int, message: String?) {
|
||||
if (message == null) {
|
||||
return
|
||||
}
|
||||
WarmupLogger.message(message)
|
||||
}
|
||||
})
|
||||
val listener = LoggingNotificationListener()
|
||||
progressManager.addNotificationListener(listener)
|
||||
scope.awaitCancellationAndInvoke {
|
||||
progressManager.removeNotificationListener(listener)
|
||||
scope.launch {
|
||||
awaitCancellationAndInvoke {
|
||||
progressManager.removeNotificationListener(listener)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addStateNotificationListener(project: Project, progressManager: ExternalSystemProgressNotificationManager) {
|
||||
val notificationListener = GradleWarmupConfigurator.StateNotificationListener(project, scope)
|
||||
val notificationListener = StateNotificationListener(project, scope)
|
||||
progressManager.addNotificationListener(notificationListener)
|
||||
scope.awaitCancellationAndInvoke {
|
||||
progressManager.removeNotificationListener(notificationListener)
|
||||
scope.launch {
|
||||
awaitCancellationAndInvoke {
|
||||
progressManager.removeNotificationListener(notificationListener)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addAnnotationListener() {
|
||||
val externalAnnotationsNotificationManager = ExternalAnnotationsProgressNotificationManager.getInstance()
|
||||
val externalAnnotationsProgressListener = GradleWarmupConfigurator.StateExternalAnnotationNotificationListener()
|
||||
val externalAnnotationsProgressListener = StateExternalAnnotationNotificationListener()
|
||||
|
||||
externalAnnotationsNotificationManager.addNotificationListener(externalAnnotationsProgressListener)
|
||||
scope.awaitCancellationAndInvoke {
|
||||
externalAnnotationsNotificationManager.removeNotificationListener(externalAnnotationsProgressListener)
|
||||
scope.launch {
|
||||
awaitCancellationAndInvoke {
|
||||
externalAnnotationsNotificationManager.removeNotificationListener(externalAnnotationsProgressListener)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class StateExternalAnnotationNotificationListener : ExternalAnnotationsProgressNotificationListener {
|
||||
|
||||
override fun onStartResolve(id: ExternalAnnotationsTaskId) {
|
||||
HeadlessLogging.logMessage(gradlePrefix + "Gradle resolving external annotations started ${id.projectId}")
|
||||
}
|
||||
|
||||
override fun onFinishResolve(id: ExternalAnnotationsTaskId) {
|
||||
HeadlessLogging.logMessage(gradlePrefix + "Gradle resolving external annotations finished ${id.projectId}")
|
||||
}
|
||||
}
|
||||
|
||||
class StateNotificationListener(
|
||||
private val project: Project, private val scope: CoroutineScope
|
||||
) : ExternalSystemTaskNotificationListener {
|
||||
|
||||
override fun onSuccess(id: ExternalSystemTaskId) {
|
||||
if (!id.isGradleProjectResolveTask()) return
|
||||
HeadlessLogging.logMessage(gradlePrefix + "Gradle resolve stage finished with success: ${id.ideProjectId}")
|
||||
|
||||
project.messageBus.connect(scope)
|
||||
.subscribe(ProjectDataImportListener.TOPIC, object : ProjectDataImportListener {
|
||||
override fun onImportStarted(projectPath: String?) {
|
||||
HeadlessLogging.logMessage(gradlePrefix + "Gradle data import stage started: ${id.ideProjectId}")
|
||||
}
|
||||
|
||||
override fun onImportFinished(projectPath: String?) {
|
||||
HeadlessLogging.logMessage(gradlePrefix + "Gradle data import stage finished with success: ${id.ideProjectId}")
|
||||
}
|
||||
|
||||
override fun onFinalTasksFinished(projectPath: String?) {
|
||||
HeadlessLogging.logMessage(gradlePrefix + "Gradle data import(final tasks) stage finished: ${id.ideProjectId}")
|
||||
}
|
||||
|
||||
override fun onFinalTasksStarted(projectPath: String?) {
|
||||
HeadlessLogging.logMessage(gradlePrefix + "Gradle data import(final tasks) stage started: ${id.ideProjectId}")
|
||||
}
|
||||
|
||||
override fun onImportFailed(projectPath: String?, t: Throwable) {
|
||||
HeadlessLogging.logFatalError(t)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onFailure(id: ExternalSystemTaskId, e: Exception) {
|
||||
if (!id.isGradleProjectResolveTask()) return
|
||||
HeadlessLogging.logFatalError(e)
|
||||
}
|
||||
|
||||
override fun onCancel(id: ExternalSystemTaskId) {
|
||||
if (!id.isGradleProjectResolveTask()) return
|
||||
HeadlessLogging.logWarning(gradlePrefix + "Gradle resolve stage canceled ${id.ideProjectId}")
|
||||
}
|
||||
|
||||
override fun onStart(id: ExternalSystemTaskId, workingDir: String) {
|
||||
if (!id.isGradleProjectResolveTask()) return
|
||||
HeadlessLogging.logMessage(gradlePrefix + "Gradle resolve stage started ${id.ideProjectId}, working dir: $workingDir")
|
||||
}
|
||||
}
|
||||
|
||||
class LoggingNotificationListener : ExternalSystemTaskNotificationListener {
|
||||
|
||||
private val logPath = try {
|
||||
gradleLogWriterPath.createParentDirectories().createFile()
|
||||
}
|
||||
catch (e: java.nio.file.FileAlreadyExistsException) {
|
||||
gradleLogWriterPath
|
||||
}
|
||||
|
||||
override fun onTaskOutput(id: ExternalSystemTaskId, text: String, stdOut: Boolean) {
|
||||
val gradleText = (if (stdOut) "" else "STDERR: ") + text
|
||||
logPath.appendText(gradleText)
|
||||
val croppedMessage = processMessage(gradleText)
|
||||
if (croppedMessage != null) {
|
||||
HeadlessLogging.logMessage(gradlePrefix + croppedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
private fun processMessage(gradleText: String): String? {
|
||||
val cropped = gradleText.trimStart('\r').trimEnd('\n')
|
||||
if (cropped.startsWith("Download")) {
|
||||
// we don't want to be flooded by a ton of download messages, so we'll print only final message
|
||||
if (cropped.contains(" took ")) {
|
||||
return cropped
|
||||
}
|
||||
return null
|
||||
}
|
||||
return cropped
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal fun ExternalSystemTaskId.isGradleProjectResolveTask() = this.projectSystemId == GradleConstants.SYSTEM_ID &&
|
||||
this.type == ExternalSystemTaskType.RESOLVE_PROJECT
|
||||
|
||||
private val gradleLogWriterPath = Path.of(PathManager.getLogPath()) / "gradle-import.log"
|
||||
|
||||
private val gradlePrefix = "[Gradle]: "
|
||||
@@ -2,8 +2,8 @@ package com.jetbrains.performancePlugin.commands
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.project.configuration.awaitCompleteProjectConfiguration
|
||||
import com.intellij.openapi.ui.playback.PlaybackContext
|
||||
import com.intellij.util.awaitCompleteProjectConfiguration
|
||||
|
||||
|
||||
private val LOG: Logger
|
||||
|
||||
Reference in New Issue
Block a user