From 19b3e47972ddc6558dc9010edf9dce761d96f98e Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Thu, 13 Jul 2017 20:20:49 -0400 Subject: [PATCH] Fix casting error during initialization While running scripted, you see ``` ERROR StatusLogger Unable to create custom ContextSelector. Falling back to default. java.lang.ClassCastException: Cannot cast org.apache.logging.log4j.core.async.AsyncLoggerContextSelector to org.apache.logging.log4j.core.selector.ContextSelector at java.lang.Class.cast(Class.java:3369) at org.apache.logging.log4j.util.LoaderUtil.newCheckedInstanceOf(LoaderUtil.java:201) at org.apache.logging.log4j.util.LoaderUtil.newCheckedInstanceOfProperty(LoaderUtil.java:226) at org.apache.logging.log4j.core.impl.Log4jContextFactory.createContextSelector(Log4jContextFactory.java:97) at org.apache.logging.log4j.core.impl.Log4jContextFactory.(Log4jContextFactory.java:58) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at java.lang.Class.newInstance(Class.java:442) at org.apache.logging.log4j.LogManager.(LogManager.java:94) at org.apache.logging.log4j.spi.ThreadContextMapFactory.createThreadContextMap(ThreadContextMapFactory.java:73) at org.apache.logging.log4j.ThreadContext.init(ThreadContext.java:223) at org.apache.logging.log4j.ThreadContext.(ThreadContext.java:202) at org.apache.logging.log4j.core.impl.ContextDataInjectorFactory.createDefaultInjector(ContextDataInjectorFactory.java:83) at org.apache.logging.log4j.core.impl.ContextDataInjectorFactory.createInjector(ContextDataInjectorFactory.java:67) at org.apache.logging.log4j.core.lookup.ContextMapLookup.(ContextMapLookup.java:34) at org.apache.logging.log4j.core.lookup.Interpolator.(Interpolator.java:117) at org.apache.logging.log4j.core.config.AbstractConfiguration.(AbstractConfiguration.java:125) at org.apache.logging.log4j.core.config.DefaultConfiguration.(DefaultConfiguration.java:46) at org.apache.logging.log4j.core.layout.PatternLayout$Builder.build(PatternLayout.java:650) at org.apache.logging.log4j.core.layout.PatternLayout.createDefaultLayout(PatternLayout.java:487) at sbt.internal.util.ConsoleAppender.(ConsoleAppender.scala:245) ``` This aims to workaround the casting error during PatternLayout.createDefaultLayout() that was originally used for ConsoleAppender. The stacktrace shows it's having issue initializing default DefaultConfiguration. Since we currently do not use Layout inside ConsoleAppender, the actual pattern is not relevant. --- .../sbt/internal/util/ConsoleAppender.scala | 3 +-- .../src/main/scala/sbt/util/LogExchange.scala | 20 ++++++++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/ConsoleAppender.scala b/internal/util-logging/src/main/scala/sbt/internal/util/ConsoleAppender.scala index e85f70fa8..75ca7146e 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/ConsoleAppender.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/ConsoleAppender.scala @@ -8,7 +8,6 @@ import org.apache.logging.log4j.{ Level => XLevel } import org.apache.logging.log4j.message.{ Message, ObjectMessage, ReusableObjectMessage } import org.apache.logging.log4j.core.{ LogEvent => XLogEvent } import org.apache.logging.log4j.core.appender.AbstractAppender -import org.apache.logging.log4j.core.layout.PatternLayout import ConsoleAppender._ @@ -242,7 +241,7 @@ class ConsoleAppender private[ConsoleAppender] ( val ansiCodesSupported: Boolean, val useColor: Boolean, val suppressedMessage: SuppressedTraceContext => Option[String] -) extends AbstractAppender(name, null, PatternLayout.createDefaultLayout(), true) { +) extends AbstractAppender(name, null, LogExchange.dummyLayout, true) { import scala.Console.{ BLUE, GREEN, RED, RESET, YELLOW } def append(event: XLogEvent): Unit = diff --git a/internal/util-logging/src/main/scala/sbt/util/LogExchange.scala b/internal/util-logging/src/main/scala/sbt/util/LogExchange.scala index 1dc17804d..150814bc5 100644 --- a/internal/util-logging/src/main/scala/sbt/util/LogExchange.scala +++ b/internal/util-logging/src/main/scala/sbt/util/LogExchange.scala @@ -5,6 +5,7 @@ import org.apache.logging.log4j.{ LogManager => XLogManager, Level => XLevel } import org.apache.logging.log4j.core._ import org.apache.logging.log4j.core.appender.AsyncAppender import org.apache.logging.log4j.core.config.{ AppenderRef, LoggerConfig } +import org.apache.logging.log4j.core.layout.PatternLayout import scala.collection.JavaConverters._ import scala.collection.concurrent import sjsonnew.JsonFormat @@ -47,6 +48,22 @@ sealed abstract class LogExchange { val config = ctx.getConfiguration config.getLoggerConfig(loggerName) } + + // This is a dummy layout to avoid casting error during PatternLayout.createDefaultLayout() + // that was originally used for ConsoleAppender. + // The stacktrace shows it's having issue initializing default DefaultConfiguration. + // Since we currently do not use Layout inside ConsoleAppender, the actual pattern is not relevant. + private[sbt] lazy val dummyLayout: PatternLayout = { + val _ = context + val ctx = XLogManager.getContext(false) match { case x: LoggerContext => x } + val config = ctx.getConfiguration + val lo = PatternLayout.newBuilder + .withConfiguration(config) + .withPattern(PatternLayout.SIMPLE_CONVERSION_PATTERN) + .build + lo + } + def jsonCodec[A](tag: String): Option[JsonFormat[A]] = jsonCodecs.get(tag) map { _.asInstanceOf[JsonFormat[A]] } def hasJsonCodec(tag: String): Boolean = @@ -63,9 +80,6 @@ sealed abstract class LogExchange { private[sbt] def buildAsyncStdout: AsyncAppender = { val ctx = XLogManager.getContext(false) match { case x: LoggerContext => x } val config = ctx.getConfiguration - // val layout = PatternLayout.newBuilder - // .withPattern(PatternLayout.SIMPLE_CONVERSION_PATTERN) - // .build val appender = ConsoleAppender("Stdout") // CustomConsoleAppenderImpl.createAppender("Stdout", layout, null, null) appender.start