From 44048365d7efb5e640c22d6c427a4d3013b84c97 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Thu, 7 May 2020 11:00:33 -0400 Subject: [PATCH 1/2] [JENKINS-62181] Deadlock during log formatting --- core/src/main/java/hudson/slaves/SlaveComputer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/slaves/SlaveComputer.java b/core/src/main/java/hudson/slaves/SlaveComputer.java index cc1f5cdaa9..4acb106bf0 100644 --- a/core/src/main/java/hudson/slaves/SlaveComputer.java +++ b/core/src/main/java/hudson/slaves/SlaveComputer.java @@ -1022,7 +1022,7 @@ public class SlaveComputer extends Computer { SLAVE_LOG_HANDLER = new RingBufferLogHandler(ringBufferSize) { Formatter dummy = new SimpleFormatter(); @Override - public synchronized void publish(LogRecord record) { + public /* not synchronized */ void publish(LogRecord record) { // see LogRecord.writeObject for dangers of serializing non-String/null parameters if (record.getMessage() != null && record.getParameters() != null && Stream.of(record.getParameters()).anyMatch(p -> p != null && !(p instanceof String))) { record.setMessage(dummy.formatMessage(record)); From a01810e7d5096eadeeb061a94107f8f219296d69 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Fri, 15 May 2020 11:44:15 -0400 Subject: [PATCH 2/2] Keep a ThreadLocal for the SimpleFormatter --- core/src/main/java/hudson/slaves/SlaveComputer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/hudson/slaves/SlaveComputer.java b/core/src/main/java/hudson/slaves/SlaveComputer.java index 4acb106bf0..c6d1c56019 100644 --- a/core/src/main/java/hudson/slaves/SlaveComputer.java +++ b/core/src/main/java/hudson/slaves/SlaveComputer.java @@ -1020,12 +1020,12 @@ public class SlaveComputer extends Computer { public Void call() { SLAVE_LOG_HANDLER = new RingBufferLogHandler(ringBufferSize) { - Formatter dummy = new SimpleFormatter(); + ThreadLocal dummy = ThreadLocal.withInitial(() -> new SimpleFormatter()); @Override public /* not synchronized */ void publish(LogRecord record) { // see LogRecord.writeObject for dangers of serializing non-String/null parameters if (record.getMessage() != null && record.getParameters() != null && Stream.of(record.getParameters()).anyMatch(p -> p != null && !(p instanceof String))) { - record.setMessage(dummy.formatMessage(record)); + record.setMessage(dummy.get().formatMessage(record)); record.setParameters(null); } super.publish(record);