M7 N2 Logging-Sensitivität produktiv verdrahtet und verifiziert
This commit is contained in:
@@ -205,7 +205,8 @@ public class BootstrapRunner {
|
||||
this.schemaInitPortFactory = SqliteSchemaInitializationAdapter::new;
|
||||
this.useCaseFactory = (startConfig, lock) -> {
|
||||
// Extract runtime configuration from startup configuration
|
||||
RuntimeConfiguration runtimeConfig = new RuntimeConfiguration(startConfig.maxPages(), startConfig.maxRetriesTransient(), resolveAiContentSensitivity(startConfig.logAiSensitive()));
|
||||
AiContentSensitivity aiContentSensitivity = resolveAiContentSensitivity(startConfig.logAiSensitive());
|
||||
RuntimeConfiguration runtimeConfig = new RuntimeConfiguration(startConfig.maxPages(), startConfig.maxRetriesTransient(), aiContentSensitivity);
|
||||
|
||||
String jdbcUrl = buildJdbcUrl(startConfig);
|
||||
FingerprintPort fingerprintPort = new Sha256FingerprintAdapter();
|
||||
@@ -215,7 +216,8 @@ public class BootstrapRunner {
|
||||
new SqliteProcessingAttemptRepositoryAdapter(jdbcUrl);
|
||||
UnitOfWorkPort unitOfWorkPort =
|
||||
new SqliteUnitOfWorkAdapter(jdbcUrl);
|
||||
ProcessingLogger coordinatorLogger = new Log4jProcessingLogger(DocumentProcessingCoordinator.class);
|
||||
// Wire coordinators logger with AI content sensitivity setting
|
||||
ProcessingLogger coordinatorLogger = new Log4jProcessingLogger(DocumentProcessingCoordinator.class, aiContentSensitivity);
|
||||
TargetFolderPort targetFolderPort = new FilesystemTargetFolderAdapter(startConfig.targetFolder());
|
||||
TargetFileCopyPort targetFileCopyPort = new FilesystemTargetFileCopyAdapter(startConfig.targetFolder());
|
||||
DocumentProcessingCoordinator documentProcessingCoordinator =
|
||||
@@ -235,7 +237,8 @@ public class BootstrapRunner {
|
||||
startConfig.apiModel(),
|
||||
startConfig.maxTextCharacters());
|
||||
|
||||
ProcessingLogger useCaseLogger = new Log4jProcessingLogger(DefaultBatchRunProcessingUseCase.class);
|
||||
// Wire use case logger with AI content sensitivity setting
|
||||
ProcessingLogger useCaseLogger = new Log4jProcessingLogger(DefaultBatchRunProcessingUseCase.class, aiContentSensitivity);
|
||||
return new DefaultBatchRunProcessingUseCase(
|
||||
runtimeConfig,
|
||||
lock,
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package de.gecheckt.pdf.umbenenner.bootstrap.adapter;
|
||||
|
||||
import de.gecheckt.pdf.umbenenner.application.port.out.AiContentSensitivity;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.out.ProcessingLogger;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Log4j-based adapter implementing the {@link ProcessingLogger} port.
|
||||
* <p>
|
||||
@@ -13,18 +16,45 @@ import org.apache.logging.log4j.Logger;
|
||||
* <p>
|
||||
* The error method intelligently detects if the last argument is a Throwable
|
||||
* and logs accordingly.
|
||||
* <p>
|
||||
* <h2>Sensitive AI content control</h2>
|
||||
* <p>
|
||||
* The adapter is initialized with an {@link AiContentSensitivity} setting that
|
||||
* controls whether sensitive AI-generated content (complete raw response, reasoning)
|
||||
* may be written to log files:
|
||||
* <ul>
|
||||
* <li>When set to {@link AiContentSensitivity#PROTECT_SENSITIVE_CONTENT} (default),
|
||||
* calls to {@link #debugSensitiveAiContent(String, Object[])} emit nothing.</li>
|
||||
* <li>When set to {@link AiContentSensitivity#LOG_SENSITIVE_CONTENT}, sensitive
|
||||
* content is logged at DEBUG level.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class Log4jProcessingLogger implements ProcessingLogger {
|
||||
|
||||
private final Logger log4jLogger;
|
||||
private final AiContentSensitivity aiContentSensitivity;
|
||||
|
||||
/**
|
||||
* Creates a logger instance for the given class.
|
||||
* Creates a logger instance for the given class with default sensitivity setting.
|
||||
* <p>
|
||||
* Uses {@link AiContentSensitivity#PROTECT_SENSITIVE_CONTENT} as the default.
|
||||
*
|
||||
* @param clazz the class to derive the logger name from; must not be null
|
||||
*/
|
||||
public Log4jProcessingLogger(Class<?> clazz) {
|
||||
this(clazz, AiContentSensitivity.PROTECT_SENSITIVE_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a logger instance for the given class with the specified sensitivity setting.
|
||||
*
|
||||
* @param clazz the class to derive the logger name from; must not be null
|
||||
* @param aiContentSensitivity the sensitivity setting for AI content logging; must not be null
|
||||
*/
|
||||
public Log4jProcessingLogger(Class<?> clazz, AiContentSensitivity aiContentSensitivity) {
|
||||
this.log4jLogger = LogManager.getLogger(clazz);
|
||||
this.aiContentSensitivity = Objects.requireNonNull(aiContentSensitivity,
|
||||
"aiContentSensitivity must not be null");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -37,6 +67,15 @@ public class Log4jProcessingLogger implements ProcessingLogger {
|
||||
log4jLogger.debug(message, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debugSensitiveAiContent(String message, Object... args) {
|
||||
// Only log sensitive content if explicitly enabled
|
||||
if (aiContentSensitivity == AiContentSensitivity.LOG_SENSITIVE_CONTENT) {
|
||||
log4jLogger.debug(message, args);
|
||||
}
|
||||
// Otherwise emit nothing (protect by default)
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String message, Object... args) {
|
||||
log4jLogger.warn(message, args);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package de.gecheckt.pdf.umbenenner.bootstrap.adapter;
|
||||
|
||||
import de.gecheckt.pdf.umbenenner.application.port.out.AiContentSensitivity;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.out.ProcessingLogger;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -188,4 +189,54 @@ class Log4jProcessingLoggerTest {
|
||||
() -> assertDoesNotThrow(() -> logger.error(testMessage, exception))
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void debugSensitiveAiContent_withDefaultSensitivity_acceptsMessage() {
|
||||
// Verify debugSensitiveAiContent method exists and executes with default PROTECT sensitivity
|
||||
Log4jProcessingLogger protectedLogger = new Log4jProcessingLogger(
|
||||
Log4jProcessingLoggerTest.class,
|
||||
AiContentSensitivity.PROTECT_SENSITIVE_CONTENT);
|
||||
|
||||
assertDoesNotThrow(() -> {
|
||||
protectedLogger.debugSensitiveAiContent("Sensitive content: {}", "raw AI response");
|
||||
}, "debugSensitiveAiContent() should execute without throwing with PROTECT_SENSITIVE_CONTENT");
|
||||
}
|
||||
|
||||
@Test
|
||||
void debugSensitiveAiContent_withLogSensitivity_acceptsMessage() {
|
||||
// Verify debugSensitiveAiContent method executes with LOG_SENSITIVE_CONTENT setting
|
||||
Log4jProcessingLogger logSensitiveLogger = new Log4jProcessingLogger(
|
||||
Log4jProcessingLoggerTest.class,
|
||||
AiContentSensitivity.LOG_SENSITIVE_CONTENT);
|
||||
|
||||
assertDoesNotThrow(() -> {
|
||||
logSensitiveLogger.debugSensitiveAiContent("AI reasoning: {}", "complete reasoning text");
|
||||
}, "debugSensitiveAiContent() should execute without throwing with LOG_SENSITIVE_CONTENT");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructorWithSensitivity_acceptsProtectSensitiveContent() {
|
||||
// Verify constructor accepts PROTECT_SENSITIVE_CONTENT
|
||||
Log4jProcessingLogger logger1 = new Log4jProcessingLogger(
|
||||
Log4jProcessingLoggerTest.class,
|
||||
AiContentSensitivity.PROTECT_SENSITIVE_CONTENT);
|
||||
assertNotNull(logger1, "Logger should be created with PROTECT_SENSITIVE_CONTENT");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructorWithSensitivity_acceptsLogSensitiveContent() {
|
||||
// Verify constructor accepts LOG_SENSITIVE_CONTENT
|
||||
Log4jProcessingLogger logger2 = new Log4jProcessingLogger(
|
||||
Log4jProcessingLoggerTest.class,
|
||||
AiContentSensitivity.LOG_SENSITIVE_CONTENT);
|
||||
assertNotNull(logger2, "Logger should be created with LOG_SENSITIVE_CONTENT");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructorWithSensitivity_rejectNullSensitivity() {
|
||||
// Verify constructor requires non-null AiContentSensitivity
|
||||
assertThrows(NullPointerException.class, () -> {
|
||||
new Log4jProcessingLogger(Log4jProcessingLoggerTest.class, null);
|
||||
}, "Constructor should reject null AiContentSensitivity");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user