From 53ee6967a873a90ce17eb404b5e31031ed2149b3 Mon Sep 17 00:00:00 2001 From: Max Medvedev Date: Thu, 13 Aug 2026 09:44:30 +0200 Subject: [PATCH] IJPL-252788 keep user text out of default-level split completion logs The completion prefix was interpolated into INFO messages, and INFO is on by default, so idea.log kept whatever the user was typing. In the integrated terminal an editor line is a shell command, which put secrets on disk verbatim ("prefix='export DATASTORE_PASSWORD=$...'") with no debug flag enabled. For fcLogger, bcLogger and ccLogger, user-derived text no longer appears at INFO or above: the default-level line keeps the correlation ids, and the text moves to a paired debug { } line carrying the same id. This extends the split already used by logRpcCompletionResponseEvent (full toString at TRACE, debugToString at DEBUG). Besides the prefix, this covers the details argument of errorWithWarnDetails -- logged at WARN -- where a LookupElement's toString is its lookupString; those sites now pass the new text-free LookupElement.logId(). The user file path in ModCommandDeserializer's not-found warning moves to debug for the same reason. The log-overview tool matched on prefix='...', so leaving it untouched would have degraded those events to OTHER rather than merely losing the prefix. Its matchers no longer require the prefix, and a new REQUEST_PREFIX kind picks it up from the debug line, so the report's Prefix(es) row still works on a DEBUG/TRACE capture -- which is the state every investigation already runs in. The docs and the investigate-split-completion skill record the convention and the consequence that an INFO-only capture has no prefixes to report. (cherry picked from commit 7c0b5c6563b8fa3e523a82d70112c1623d204401) GitOrigin-RevId: 9c7c5ff8b393566e4710c2b08aa44c563bc2d96d --- .../completion/common/src/LookupElementLogging.kt | 15 +++++++++++++++ .../protocol/modCommand/ModCommandDeserializer.kt | 4 +++- 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 platform/completion/common/src/LookupElementLogging.kt diff --git a/platform/completion/common/src/LookupElementLogging.kt b/platform/completion/common/src/LookupElementLogging.kt new file mode 100644 index 000000000000..1b71991f6459 --- /dev/null +++ b/platform/completion/common/src/LookupElementLogging.kt @@ -0,0 +1,15 @@ +// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.platform.completion.common + +import com.intellij.codeInsight.lookup.LookupElement + +/** + * Identifies a [LookupElement] in a log message **without** disclosing its text. + * + * `LookupElement.toString()` is the element's `lookupString`, which is user-derived — in a terminal or a scratch buffer + * it can be a secret the user just typed (IJPL-252788). Levels that are enabled by default (`INFO`, `WARN`, `ERROR`, + * including the `details` of [com.intellij.openapi.diagnostic.errorWithWarnDetails], which are logged at `WARN`) must + * use this instead. The full element still belongs in a paired `debug { }` line, which is off unless someone is + * investigating. + */ +fun LookupElement.logId(): String = "${javaClass.name}@${Integer.toHexString(System.identityHashCode(this))}" diff --git a/platform/completion/common/src/protocol/modCommand/ModCommandDeserializer.kt b/platform/completion/common/src/protocol/modCommand/ModCommandDeserializer.kt index 87fa2b980587..baf9e703e045 100644 --- a/platform/completion/common/src/protocol/modCommand/ModCommandDeserializer.kt +++ b/platform/completion/common/src/protocol/modCommand/ModCommandDeserializer.kt @@ -16,6 +16,7 @@ import com.intellij.modcommand.ModRegisterTabOut import com.intellij.modcommand.ModStartRename import com.intellij.modcommand.ModUpdateFileText import com.intellij.modcommand.ModUpdateReferences +import com.intellij.openapi.diagnostic.debug import com.intellij.openapi.editor.colors.TextAttributesKey import com.intellij.openapi.util.TextRange import com.intellij.openapi.vfs.VirtualFile @@ -147,6 +148,7 @@ private fun findFile(path: String): VirtualFile? = private fun RpcTextRange.toTextRange(): TextRange = TextRange(startOffset, endOffset) private fun logFileNotFound(commandType: String, path: String): Nothing? { - ccLogger.warn("ModCommandDeserializer: file not found for $commandType: $path") + ccLogger.debug { "ModCommandDeserializer: file not found for $commandType: $path" } + ccLogger.warn("ModCommandDeserializer: file not found for $commandType") return null }