package org.testcontainers.utility; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.github.dockerjava.api.command.DockerCmd; import lombok.experimental.UtilityClass; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.Nullable; import org.slf4j.MDC; import java.util.List; /** * Logger for tracking potentially destructive actions, intended for usage in a shared Docker environment where * traceability is needed. This class uses SLF4J, logging at TRACE level and capturing common fields as MDC fields. * <p> * Users should configure their test logging to apply appropriate filters/storage so that these logs are * captured appropriately. */ @Slf4j @UtilityClass public class AuditLogger { private static final ObjectMapper objectMapper = new ObjectMapper(); public static final String MDC_PREFIX = AuditLogger.class.getCanonicalName(); public static void doLog(String action, String image, String containerId, DockerCmd<?> cmd) { doLog(action, image, containerId, cmd, null); } public static void doLog(String action, String image, String containerId, DockerCmd<?> cmd, @Nullable Exception e) { MDC.put(MDC_PREFIX + ".Action", action); MDC.put(MDC_PREFIX + ".Image", image); MDC.put(MDC_PREFIX + ".ContainerId", containerId); try { MDC.put(MDC_PREFIX + ".Command", objectMapper.writeValueAsString(cmd)); } catch (JsonProcessingException ignored) { } if (e != null) { MDC.put(MDC_PREFIX + ".Exception", e.getLocalizedMessage()); log.trace("{} action with image: {}, containerId: {}", action, image, containerId, e); } else { log.trace("{} action with image: {}, containerId: {}", action, image, containerId); } MDC.remove(MDC_PREFIX + ".Action"); MDC.remove(MDC_PREFIX + ".Image"); MDC.remove(MDC_PREFIX + ".ContainerId"); MDC.remove(MDC_PREFIX + ".Command"); MDC.remove(MDC_PREFIX + ".Exception"); } public static void doComposeLog(String[] commandParts, List<String> env) { MDC.put(MDC_PREFIX + ".Action", "COMPOSE"); final String command = StringUtils.join(commandParts, ' '); MDC.put(MDC_PREFIX + ".Compose.Command", command); MDC.put(MDC_PREFIX + ".Compose.Env", env.toString()); log.trace("COMPOSE action with command: {}, env: {}", command, env); MDC.remove(MDC_PREFIX + ".Action"); MDC.remove(MDC_PREFIX + ".Compose.Command"); MDC.remove(MDC_PREFIX + ".Compose.Env"); } }