M7 N2 Logging-Sensitivität produktiv verdrahtet und verifiziert
This commit is contained in:
@@ -5,6 +5,22 @@ package de.gecheckt.pdf.umbenenner.application.port.out;
|
||||
* <p>
|
||||
* The application delegates all logging to this port to remain decoupled from
|
||||
* specific logging frameworks. Concrete implementations are provided by adapters.
|
||||
* <p>
|
||||
* <h2>Sensitive AI content logging</h2>
|
||||
* <p>
|
||||
* The {@link #debugSensitiveAiContent(String, Object[])} method allows logging
|
||||
* of sensitive AI-generated content (complete raw response, complete reasoning)
|
||||
* subject to the {@link AiContentSensitivity} setting:
|
||||
* <ul>
|
||||
* <li>When {@link AiContentSensitivity#PROTECT_SENSITIVE_CONTENT} is active (default),
|
||||
* this method logs nothing.</li>
|
||||
* <li>When {@link AiContentSensitivity#LOG_SENSITIVE_CONTENT} is explicitly enabled,
|
||||
* this method logs the content to DEBUG level.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* The complete sensitive content is always persisted in SQLite for traceability,
|
||||
* regardless of this logging setting. The logging decision controls only whether
|
||||
* the content also appears in log files.
|
||||
*/
|
||||
public interface ProcessingLogger {
|
||||
|
||||
@@ -24,6 +40,29 @@ public interface ProcessingLogger {
|
||||
*/
|
||||
void debug(String message, Object... args);
|
||||
|
||||
/**
|
||||
* Logs a debug-level message containing sensitive AI-generated content,
|
||||
* subject to the configured {@link AiContentSensitivity}.
|
||||
* <p>
|
||||
* This method is called with message and arguments containing sensitive AI content
|
||||
* (e.g., complete raw response, complete reasoning). The implementation must:
|
||||
* <ul>
|
||||
* <li>Check the current {@link AiContentSensitivity} setting.</li>
|
||||
* <li>If set to {@link AiContentSensitivity#PROTECT_SENSITIVE_CONTENT} (default),
|
||||
* emit nothing to log.</li>
|
||||
* <li>If set to {@link AiContentSensitivity#LOG_SENSITIVE_CONTENT}, log the
|
||||
* message and arguments at DEBUG level normally.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* This is the only method where sensitive AI content may be logged based on
|
||||
* configuration. Other logging methods ({@link #info}, {@link #debug}, etc.)
|
||||
* must never log sensitive content.
|
||||
*
|
||||
* @param message the message template (may contain {} placeholders)
|
||||
* @param args optional message arguments that may include sensitive AI content
|
||||
*/
|
||||
void debugSensitiveAiContent(String message, Object... args);
|
||||
|
||||
/**
|
||||
* Logs a warning-level message.
|
||||
*
|
||||
|
||||
@@ -393,6 +393,16 @@ public class DocumentProcessingCoordinator {
|
||||
"Status is PROPOSAL_READY but no PROPOSAL_READY attempt exists in history");
|
||||
}
|
||||
|
||||
// Log sensitive AI content (raw response, reasoning) if configured
|
||||
if (proposalAttempt.aiRawResponse() != null) {
|
||||
logger.debugSensitiveAiContent("AI raw response for '{}' (fingerprint: {}): {}",
|
||||
candidate.uniqueIdentifier(), fingerprint.sha256Hex(), proposalAttempt.aiRawResponse());
|
||||
}
|
||||
if (proposalAttempt.aiReasoning() != null) {
|
||||
logger.debugSensitiveAiContent("AI reasoning for '{}' (fingerprint: {}): {}",
|
||||
candidate.uniqueIdentifier(), fingerprint.sha256Hex(), proposalAttempt.aiReasoning());
|
||||
}
|
||||
|
||||
// --- Step 2: Build base filename from the proposal ---
|
||||
TargetFilenameBuildingService.BaseFilenameResult filenameResult =
|
||||
TargetFilenameBuildingService.buildBaseFilename(proposalAttempt);
|
||||
|
||||
@@ -1280,6 +1280,11 @@ class DocumentProcessingCoordinatorTest {
|
||||
// No-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debugSensitiveAiContent(String message, Object... args) {
|
||||
// No-op: sensitivity is controlled by the Log4jProcessingLogger adapter
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String message, Object... args) {
|
||||
// No-op
|
||||
@@ -1367,6 +1372,7 @@ class DocumentProcessingCoordinatorTest {
|
||||
private static class CapturingProcessingLogger implements ProcessingLogger {
|
||||
int infoCallCount = 0;
|
||||
int debugCallCount = 0;
|
||||
int debugSensitiveAiContentCallCount = 0;
|
||||
int warnCallCount = 0;
|
||||
int errorCallCount = 0;
|
||||
|
||||
@@ -1380,6 +1386,11 @@ class DocumentProcessingCoordinatorTest {
|
||||
debugCallCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debugSensitiveAiContent(String message, Object... args) {
|
||||
debugSensitiveAiContentCallCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String message, Object... args) {
|
||||
warnCallCount++;
|
||||
|
||||
@@ -1157,6 +1157,11 @@ class BatchRunProcessingUseCaseTest {
|
||||
// No-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debugSensitiveAiContent(String message, Object... args) {
|
||||
// No-op: sensitivity is controlled by the Log4jProcessingLogger adapter
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String message, Object... args) {
|
||||
// No-op
|
||||
@@ -1175,6 +1180,7 @@ class BatchRunProcessingUseCaseTest {
|
||||
private static class MessageCapturingProcessingLogger implements ProcessingLogger {
|
||||
final List<String> infoMessages = new ArrayList<>();
|
||||
final List<String> debugMessages = new ArrayList<>();
|
||||
final List<String> debugSensitiveAiContentMessages = new ArrayList<>();
|
||||
final List<String> warnMessages = new ArrayList<>();
|
||||
final List<String> errorMessages = new ArrayList<>();
|
||||
|
||||
@@ -1204,6 +1210,11 @@ class BatchRunProcessingUseCaseTest {
|
||||
debugMessages.add(format(message, args));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debugSensitiveAiContent(String message, Object... args) {
|
||||
debugSensitiveAiContentMessages.add(format(message, args));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String message, Object... args) {
|
||||
warnMessages.add(format(message, args));
|
||||
@@ -1218,6 +1229,7 @@ class BatchRunProcessingUseCaseTest {
|
||||
List<String> all = new ArrayList<>();
|
||||
all.addAll(infoMessages);
|
||||
all.addAll(debugMessages);
|
||||
all.addAll(debugSensitiveAiContentMessages);
|
||||
all.addAll(warnMessages);
|
||||
all.addAll(errorMessages);
|
||||
return all;
|
||||
@@ -1228,6 +1240,7 @@ class BatchRunProcessingUseCaseTest {
|
||||
private static class CapturingProcessingLogger implements ProcessingLogger {
|
||||
int infoCallCount = 0;
|
||||
int debugCallCount = 0;
|
||||
int debugSensitiveAiContentCallCount = 0;
|
||||
int warnCallCount = 0;
|
||||
int errorCallCount = 0;
|
||||
|
||||
@@ -1241,6 +1254,11 @@ class BatchRunProcessingUseCaseTest {
|
||||
debugCallCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debugSensitiveAiContent(String message, Object... args) {
|
||||
debugSensitiveAiContentCallCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String message, Object... args) {
|
||||
warnCallCount++;
|
||||
|
||||
Reference in New Issue
Block a user