sbt / sbt-assembly

Deploy über-JARs. Restart processes. (port of codahale/assembly-sbt)
MIT License
1.94k stars 223 forks source link

Document log4j2 plugins custom merge strategy #501

Closed conet closed 10 months ago

conet commented 11 months ago

It's really annoying that this does not work without custom code, the sbt-assembly-log4j2 plugin does not work with the new version of the sbt-assembly plugin so here's my contribution for everyone encountering this problem.

assembly / assemblyMergeStrategy := {
  case PathList(ps@_*) if ps.last equalsIgnoreCase "Log4j2Plugins.dat" =>
    import java.io.FileInputStream
    import java.io.FileOutputStream
    import org.apache.logging.log4j.core.config.plugins.processor.PluginCache

    import scala.collection.JavaConverters.asJavaEnumerationConverter

    import sbt.io.{ IO, Using }
    import sbtassembly.Assembly.Dependency

    CustomMergeStrategy("Log4j2Plugins") {
      conflicts =>
        val dependencyStreamResource = Using.resource((dependency: Dependency) => dependency.stream())
        val tempDir = "target/log4j2-plugin-cache"
        val urls = conflicts
          .map { conflict =>
            dependencyStreamResource(conflict) { is =>
              val file = new File(s"$tempDir/${conflict.module.get.jarName}-Log4j2Plugins.dat")
              IO.write(file, IO.readBytes(is))
              file.toURI.toURL
            }
          }
        val aggregator = new PluginCache()
        aggregator.loadCacheFiles(urls.toIterator.asJavaEnumeration)
        val pluginCache = new File(s"$tempDir/Log4j2Plugins.dat")
        val pluginCacheOutputStream = new FileOutputStream(pluginCache)
        aggregator.writeCache(pluginCacheOutputStream)
        pluginCacheOutputStream.close()
        Right(Vector(JarEntry(conflicts.head.target, () => new FileInputStream(pluginCache))))
    }
  case x =>
    val oldStrategy = (assembly / assemblyMergeStrategy).value
    oldStrategy(x)
}
conet commented 11 months ago

I know it's ugly but org.apache.logging.log4j.core.config.plugins.processor.PluginCache works only with files it does not work with in memory streams.

mpollmeier commented 10 months ago

I had the same needs, so I forked, upgraded and released it. For instructions see https://github.com/mpollmeier/sbt-assembly-log4j2

Special thanks to @fnqista for his PR.