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
This commit is contained in:
Max Medvedev
2026-08-14 11:28:27 +00:00
committed by intellij-monorepo-bot
parent 940e1f8fbf
commit 53ee6967a8
2 changed files with 18 additions and 1 deletions
@@ -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))}"
@@ -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
}