diff --git a/play-scala-log4j2-example/.gitignore b/play-scala-log4j2-example/.gitignore
new file mode 100644
index 000000000..193873de8
--- /dev/null
+++ b/play-scala-log4j2-example/.gitignore
@@ -0,0 +1,10 @@
+build
+logs
+target
+/.idea
+/.idea_modules
+/.classpath
+/.gradle
+/.project
+/.settings
+/RUNNING_PID
diff --git a/play-scala-log4j2-example/.mergify.yml b/play-scala-log4j2-example/.mergify.yml
new file mode 100644
index 000000000..32f8689ae
--- /dev/null
+++ b/play-scala-log4j2-example/.mergify.yml
@@ -0,0 +1,27 @@
+pull_request_rules:
+ - name: automatic merge on CI success require review
+ conditions:
+ - status-success=Travis CI - Pull Request
+ - "#approved-reviews-by>=1"
+ - "#changes-requested-reviews-by=0"
+ - label!=block-merge
+ actions:
+ merge:
+ method: squash
+ strict: smart
+
+ - name: automatic merge on CI success for TemplateControl
+ conditions:
+ - status-success=Travis CI - Pull Request
+ - label=merge-when-green
+ - label!=block-merge
+ actions:
+ merge:
+ method: squash
+ strict: smart
+
+ - name: delete branch after merge
+ conditions:
+ - merged
+ actions:
+ delete_head_branch: {}
diff --git a/play-scala-log4j2-example/.travis.yml b/play-scala-log4j2-example/.travis.yml
new file mode 100644
index 000000000..1e8c0e7c4
--- /dev/null
+++ b/play-scala-log4j2-example/.travis.yml
@@ -0,0 +1,50 @@
+language: scala
+scala:
+ - 2.12.8
+
+before_install:
+ - curl -sL https://github.com/shyiko/jabba/raw/master/install.sh | bash && . ~/.jabba/jabba.sh
+
+env:
+ global:
+ - JABBA_HOME=$HOME/.jabba
+ matrix:
+ # There is no concise way to specify multi-dimensional build matrix:
+ # https://github.com/travis-ci/travis-ci/issues/1519
+ - SCRIPT=scripts/test-sbt TRAVIS_JDK=adopt@1.8.192-12
+ - SCRIPT=scripts/test-sbt TRAVIS_JDK=adopt@1.11.0-1
+ - SCRIPT=scripts/test-gradle TRAVIS_JDK=adopt@1.8.192-12
+ - SCRIPT=scripts/test-gradle TRAVIS_JDK=adopt@1.11.0-1
+
+# Exclude some combinations from build matrix. See:
+# https://docs.travis-ci.com/user/customizing-the-build/#Build-Matrix
+matrix:
+ fast_finish: true
+ allow_failures:
+ # Current release of Gradle still does not supports Play 2.7.x releases
+ # As soon as there is a release of Gradle that fixes that, we can then
+ # remove this allowed failure.
+ - env: SCRIPT=scripts/test-gradle TRAVIS_JDK=adopt@1.8.192-12
+ - env: SCRIPT=scripts/test-gradle TRAVIS_JDK=adopt@1.11.0-1
+ # Java 11 is still not fully supported. It is good that we are already
+ # testing our sample applications to better discover possible problems
+ # but we can allow failures here too.
+ - env: SCRIPT=scripts/test-sbt TRAVIS_JDK=adopt@1.11.0-1
+
+install:
+ - $JABBA_HOME/bin/jabba install $TRAVIS_JDK
+ - unset _JAVA_OPTIONS
+ - export JAVA_HOME="$JABBA_HOME/jdk/$TRAVIS_JDK" && export PATH="$JAVA_HOME/bin:$PATH" && java -Xmx32m -version
+
+script:
+ - $SCRIPT
+
+before_cache:
+ - find $HOME/.ivy2 -name "ivydata-*.properties" -delete
+ - find $HOME/.sbt -name "*.lock" -delete
+
+cache:
+ directories:
+ - "$HOME/.ivy2/cache"
+ - "$HOME/.gradle/caches"
+ - "$HOME/.jabba/jdk"
diff --git a/play-scala-log4j2-example/LICENSE b/play-scala-log4j2-example/LICENSE
new file mode 100644
index 000000000..670154e35
--- /dev/null
+++ b/play-scala-log4j2-example/LICENSE
@@ -0,0 +1,116 @@
+CC0 1.0 Universal
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific
+works ("Commons") that the public can reliably and without fear of later
+claims of infringement build upon, modify, incorporate in other works, reuse
+and redistribute as freely as possible in any form whatsoever and for any
+purposes, including without limitation commercial purposes. These owners may
+contribute to the Commons to promote the ideal of a free culture and the
+further production of creative, cultural and scientific works, or to gain
+reputation or greater distribution for their Work in part through the use and
+efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation
+of additional consideration or compensation, the person associating CC0 with a
+Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
+and publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not limited
+to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display, communicate,
+ and translate a Work;
+
+ ii. moral rights retained by the original author(s) and/or performer(s);
+
+ iii. publicity and privacy rights pertaining to a person's image or likeness
+ depicted in a Work;
+
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+
+ v. rights protecting the extraction, dissemination, use and reuse of data in
+ a Work;
+
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation thereof,
+ including any amended or successor version of such directive); and
+
+ vii. other similar, equivalent or corresponding rights throughout the world
+ based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of,
+applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
+unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
+and Related Rights and associated claims and causes of action, whether now
+known or unknown (including existing as well as future claims and causes of
+action), in the Work (i) in all territories worldwide, (ii) for the maximum
+duration provided by applicable law or treaty (including future time
+extensions), (iii) in any current or future medium and for any number of
+copies, and (iv) for any purpose whatsoever, including without limitation
+commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
+the Waiver for the benefit of each member of the public at large and to the
+detriment of Affirmer's heirs and successors, fully intending that such Waiver
+shall not be subject to revocation, rescission, cancellation, termination, or
+any other legal or equitable action to disrupt the quiet enjoyment of the Work
+by the public as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason be
+judged legally invalid or ineffective under applicable law, then the Waiver
+shall be preserved to the maximum extent permitted taking into account
+Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
+is so judged Affirmer hereby grants to each affected person a royalty-free,
+non transferable, non sublicensable, non exclusive, irrevocable and
+unconditional license to exercise Affirmer's Copyright and Related Rights in
+the Work (i) in all territories worldwide, (ii) for the maximum duration
+provided by applicable law or treaty (including future time extensions), (iii)
+in any current or future medium and for any number of copies, and (iv) for any
+purpose whatsoever, including without limitation commercial, advertising or
+promotional purposes (the "License"). The License shall be deemed effective as
+of the date CC0 was applied by Affirmer to the Work. Should any part of the
+License for any reason be judged legally invalid or ineffective under
+applicable law, such partial invalidity or ineffectiveness shall not
+invalidate the remainder of the License, and in such case Affirmer hereby
+affirms that he or she will not (i) exercise any of his or her remaining
+Copyright and Related Rights in the Work or (ii) assert any associated claims
+and causes of action with respect to the Work, in either case contrary to
+Affirmer's express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+
+ b. Affirmer offers the Work as-is and makes no representations or warranties
+ of any kind concerning the Work, express, implied, statutory or otherwise,
+ including without limitation warranties of title, merchantability, fitness
+ for a particular purpose, non infringement, or the absence of latent or
+ other defects, accuracy, or the present or absence of errors, whether or not
+ discoverable, all to the greatest extent permissible under applicable law.
+
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without limitation
+ any person's Copyright and Related Rights in the Work. Further, Affirmer
+ disclaims responsibility for obtaining any necessary consents, permissions
+ or other rights required for any use of the Work.
+
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to this
+ CC0 or use of the Work.
+
+For more information, please see
+
diff --git a/play-scala-log4j2-example/NOTICE b/play-scala-log4j2-example/NOTICE
new file mode 100644
index 000000000..6d6c034d3
--- /dev/null
+++ b/play-scala-log4j2-example/NOTICE
@@ -0,0 +1,8 @@
+Written by Lightbend
+
+To the extent possible under law, the author(s) have dedicated all copyright and
+related and neighboring rights to this software to the public domain worldwide.
+This software is distributed without any warranty.
+
+You should have received a copy of the CC0 Public Domain Dedication along with
+this software. If not, see .
diff --git a/play-scala-log4j2-example/README.md b/play-scala-log4j2-example/README.md
new file mode 100644
index 000000000..010c1c33c
--- /dev/null
+++ b/play-scala-log4j2-example/README.md
@@ -0,0 +1,59 @@
+# Play using Log4j 2
+
+[](https://travis-ci.org/playframework/play-scala-log4j2-example)
+
+This is an example project showing a sample Play application that use Log4J 2 instead of using Logback.
+
+Please see [Using a custom logging framework](https://www.playframework.com/documentation/2.6.x/SettingsLogger#Using-a-Custom-Logging-Framework) in the Play documentation for more details.
+
+## Running in Production
+
+This application will package everything correctly when you run `sbt dist` and run the packaged script.
+
+There is an outstanding bug where apparently this didn't work: please add comments to if this doesn't work for you.
+
+## Running in Development
+
+You must define the `log4j.configurationFile` explicitly when the JVM is loaded or `sbt`:
+
+```bash
+sbt -Dlog4j.configurationFile=conf/log4j2.xml
+```
+Or you can set as javaOptions in `build.sbt`:
+```bash
+javaOptions += "-Dlog4j.configurationFile=conf/log4j2.xml"
+```
+If you do not run with `log4j.configurationFile` loaded, you will see this error:
+
+```log
+ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console. Set system property 'log4j2.debug' to show Log4j2 internal initialization logging.
+```
+
+After you define the log4j system property, running the application should look like this:
+
+```log
+[info] Loading project definition from /Users/player/play-scala-log4j2-example/project
+[info] Set current project to play-2.6-log4j2 (in build file:/Users/player/play-scala-log4j2-example/)
+
+No play.logger.configurator found: logging must be configured entirely by the application.
+--- (Running the application, auto-reloading is enabled) ---
+
+[INFO ] 2017-12-20 09:41:12.268 [pool-7-thread-2] AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:9000
+
+(Server started, use Enter to stop and go back to the console...)
+
+[info] Compiling 1 Scala source to /Users/player/play-scala-log4j2-example/target/scala-2.12/classes ...
+[info] Done compiling.
+[INFO ] 2017-12-20 09:41:41.296 [play-dev-mode-akka.actor.default-dispatcher-4] application - ApplicationTimer demo: Starting application at 2017-12-20T11:41:41.295Z.
+[INFO ] 2017-12-20 09:41:41.477 [application-akka.actor.default-dispatcher-2] Slf4jLogger - Slf4jLogger started
+[WARN ] 2017-12-20 09:41:41.655 [play-dev-mode-akka.actor.default-dispatcher-4] application - Using the following cache for assets
+[INFO ] 2017-12-20 09:41:41.670 [play-dev-mode-akka.actor.default-dispatcher-4] Play - Application started (Dev)
+````
+
+Note that you will see
+
+```log
+No play.logger.configurator found: logging must be configured entirely by the application.
+```
+
+when you first start it -- this is a side effect of Play's immediate reload functionality, and will not affect the application itself. You won't see the `play.logger.configurator` warning if you run the Play application in production, because there isn't a different class loader for SBT vs for the Play application.
diff --git a/play-scala-log4j2-example/app/Filters.scala b/play-scala-log4j2-example/app/Filters.scala
new file mode 100644
index 000000000..a72db50dc
--- /dev/null
+++ b/play-scala-log4j2-example/app/Filters.scala
@@ -0,0 +1,33 @@
+import javax.inject._
+import play.api._
+import play.api.http.HttpFilters
+import play.api.mvc._
+
+import filters.ExampleFilter
+
+/**
+ * This class configures filters that run on every request. This
+ * class is queried by Play to get a list of filters.
+ *
+ * Play will automatically use filters from any class called
+ * `Filters` that is placed the root package. You can load filters
+ * from a different class by adding a `play.http.filters` setting to
+ * the `application.conf` configuration file.
+ *
+ * @param env Basic environment settings for the current application.
+ * @param exampleFilter A demonstration filter that adds a header to
+ * each response.
+ */
+@Singleton
+class Filters @Inject() (
+ env: Environment,
+ exampleFilter: ExampleFilter) extends HttpFilters {
+
+ override val filters = {
+ // Use the example filter if we're running development mode. If
+ // we're running in production or test mode then don't use any
+ // filters at all.
+ if (env.mode == Mode.Dev) Seq(exampleFilter) else Seq.empty
+ }
+
+}
diff --git a/play-scala-log4j2-example/app/Log4J2LoggerConfigurator.scala b/play-scala-log4j2-example/app/Log4J2LoggerConfigurator.scala
new file mode 100644
index 000000000..0b9a83441
--- /dev/null
+++ b/play-scala-log4j2-example/app/Log4J2LoggerConfigurator.scala
@@ -0,0 +1,45 @@
+import java.io.File
+import java.net.URL
+
+import org.apache.logging.log4j.LogManager
+import org.apache.logging.log4j.core.LoggerContext
+import org.apache.logging.log4j.core.config.Configurator
+import org.slf4j.ILoggerFactory
+import play.api.{Configuration, Environment, LoggerConfigurator, Mode}
+
+class Log4J2LoggerConfigurator extends LoggerConfigurator {
+
+ private lazy val factory: ILoggerFactory = org.slf4j.impl.StaticLoggerBinder.getSingleton.getLoggerFactory
+
+ override def init(rootPath: File, mode: Mode): Unit = {
+ val properties = Map("application.home" -> rootPath.getAbsolutePath)
+ val resourceName = "log4j2.xml"
+ val resourceUrl = Option(this.getClass.getClassLoader.getResource(resourceName))
+ configure(properties, resourceUrl)
+ }
+
+ override def shutdown(): Unit = {
+ val context = LogManager.getContext().asInstanceOf[LoggerContext]
+ Configurator.shutdown(context)
+ }
+
+ override def configure(env: Environment): Unit = {
+ val properties = LoggerConfigurator.generateProperties(env, Configuration.empty, Map.empty)
+ val resourceUrl = env.resource("log4j2.xml")
+ configure(properties, resourceUrl)
+ }
+
+ override def configure(env: Environment, configuration: Configuration, optionalProperties: Map[String, String]): Unit = {
+ // LoggerConfigurator.generateProperties enables play.logger.includeConfigProperties=true
+ val properties = LoggerConfigurator.generateProperties(env, configuration, optionalProperties)
+ val resourceUrl = env.resource("log4j2.xml")
+ configure(properties, resourceUrl)
+ }
+
+ override def configure(properties: Map[String, String], config: Option[URL]): Unit = {
+ val context = LogManager.getContext(false).asInstanceOf[LoggerContext]
+ context.setConfigLocation(config.get.toURI)
+ }
+
+ override def loggerFactory: ILoggerFactory = factory
+}
\ No newline at end of file
diff --git a/play-scala-log4j2-example/app/Module.scala b/play-scala-log4j2-example/app/Module.scala
new file mode 100644
index 000000000..27d5f4b20
--- /dev/null
+++ b/play-scala-log4j2-example/app/Module.scala
@@ -0,0 +1,28 @@
+import com.google.inject.AbstractModule
+import java.time.Clock
+
+import services.{ApplicationTimer, AtomicCounter, Counter}
+
+/**
+ * This class is a Guice module that tells Guice how to bind several
+ * different types. This Guice module is created when the Play
+ * application starts.
+
+ * Play will automatically use any class called `Module` that is in
+ * the root package. You can create modules in other locations by
+ * adding `play.modules.enabled` settings to the `application.conf`
+ * configuration file.
+ */
+class Module extends AbstractModule {
+
+ override def configure() = {
+ // Use the system clock as the default implementation of Clock
+ bind(classOf[Clock]).toInstance(Clock.systemDefaultZone)
+ // Ask Guice to create an instance of ApplicationTimer when the
+ // application starts.
+ bind(classOf[ApplicationTimer]).asEagerSingleton
+ // Set AtomicCounter as the implementation for Counter.
+ bind(classOf[Counter]).to(classOf[AtomicCounter])
+ }
+
+}
diff --git a/play-scala-log4j2-example/app/controllers/AsyncController.scala b/play-scala-log4j2-example/app/controllers/AsyncController.scala
new file mode 100644
index 000000000..112eca674
--- /dev/null
+++ b/play-scala-log4j2-example/app/controllers/AsyncController.scala
@@ -0,0 +1,41 @@
+package controllers
+
+import akka.actor.ActorSystem
+import javax.inject._
+import play.api._
+import play.api.mvc._
+import scala.concurrent.{ExecutionContext, Future, Promise}
+import scala.concurrent.duration._
+
+/**
+ * This controller creates an `Action` that demonstrates how to write
+ * simple asychronous code in a controller. It uses a timer to
+ * asynchronously delay sending a response for 1 second.
+ *
+ * @param actorSystem We need the `ActorSystem`'s `Scheduler` to
+ * run code after a delay.
+ * @param exec We need an `ExecutionContext` to execute our
+ * asynchronous code.
+ */
+@Singleton
+class AsyncController @Inject() (val controllerComponents: ControllerComponents, actorSystem: ActorSystem)(implicit exec: ExecutionContext) extends BaseController {
+
+ /**
+ * Create an Action that returns a plain text message after a delay
+ * of 1 second.
+ *
+ * The configuration in the `routes` file means that this method
+ * will be called when the application receives a `GET` request with
+ * a path of `/message`.
+ */
+ def message = Action.async {
+ getFutureMessage(1.second).map { msg => Ok(msg) }
+ }
+
+ private def getFutureMessage(delayTime: FiniteDuration): Future[String] = {
+ val promise: Promise[String] = Promise[String]()
+ actorSystem.scheduler.scheduleOnce(delayTime) { promise.success("Hi!") }
+ promise.future
+ }
+
+}
diff --git a/play-scala-log4j2-example/app/controllers/CountController.scala b/play-scala-log4j2-example/app/controllers/CountController.scala
new file mode 100644
index 000000000..29ede4f92
--- /dev/null
+++ b/play-scala-log4j2-example/app/controllers/CountController.scala
@@ -0,0 +1,25 @@
+package controllers
+
+import javax.inject._
+import play.api._
+import play.api.mvc._
+
+import services.Counter
+
+/**
+ * This controller demonstrates how to use dependency injection to
+ * bind a component into a controller class. The class creates an
+ * `Action` that shows an incrementing count to users. The [[Counter]]
+ * object is injected by the Guice dependency injection system.
+ */
+@Singleton
+class CountController @Inject() (val controllerComponents: ControllerComponents, counter: Counter) extends BaseController {
+
+ /**
+ * Create an action that responds with the [[Counter]]'s current
+ * count. The result is plain text. This `Action` is mapped to
+ * `GET /count` requests by an entry in the `routes` config file.
+ */
+ def count = Action { Ok(counter.nextCount().toString) }
+
+}
diff --git a/play-scala-log4j2-example/app/controllers/HomeController.scala b/play-scala-log4j2-example/app/controllers/HomeController.scala
new file mode 100644
index 000000000..3bf63461a
--- /dev/null
+++ b/play-scala-log4j2-example/app/controllers/HomeController.scala
@@ -0,0 +1,24 @@
+package controllers
+
+import javax.inject._
+import play.api._
+import play.api.mvc._
+
+/**
+ * This controller creates an `Action` to handle HTTP requests to the
+ * application's home page.
+ */
+@Singleton
+class HomeController @Inject() (val controllerComponents: ControllerComponents) extends BaseController {
+
+ /**
+ * Create an Action to render an HTML page with a welcome message.
+ * The configuration in the `routes` file means that this method
+ * will be called when the application receives a `GET` request with
+ * a path of `/`.
+ */
+ def index = Action {
+ Ok(views.html.index("Your new application is ready."))
+ }
+
+}
diff --git a/play-scala-log4j2-example/app/filters/ExampleFilter.scala b/play-scala-log4j2-example/app/filters/ExampleFilter.scala
new file mode 100644
index 000000000..e2f3c1eb3
--- /dev/null
+++ b/play-scala-log4j2-example/app/filters/ExampleFilter.scala
@@ -0,0 +1,33 @@
+package filters
+
+import akka.stream.Materializer
+import javax.inject._
+import play.api.mvc._
+import scala.concurrent.{ExecutionContext, Future}
+
+/**
+ * This is a simple filter that adds a header to all requests. It's
+ * added to the application's list of filters by the
+ * [[ExampleFilter]] class.
+ *
+ * @param mat This object is needed to handle streaming of requests
+ * and responses.
+ * @param exec This class is needed to execute code asynchronously.
+ * It is used below by the `map` method.
+ */
+@Singleton
+class ExampleFilter @Inject()(
+ implicit override val mat: Materializer,
+ exec: ExecutionContext) extends Filter {
+
+ override def apply(nextFilter: RequestHeader => Future[Result])
+ (requestHeader: RequestHeader): Future[Result] = {
+ // Run the next filter in the chain. This will call other filters
+ // and eventually call the action. Take the result and modify it
+ // by adding a new header.
+ nextFilter(requestHeader).map { result =>
+ result.withHeaders("X-ExampleFilter" -> "foo")
+ }
+ }
+
+}
diff --git a/play-scala-log4j2-example/app/services/ApplicationTimer.scala b/play-scala-log4j2-example/app/services/ApplicationTimer.scala
new file mode 100644
index 000000000..d893c7742
--- /dev/null
+++ b/play-scala-log4j2-example/app/services/ApplicationTimer.scala
@@ -0,0 +1,39 @@
+package services
+
+import java.time.{Clock, Instant}
+import javax.inject._
+import play.api.Logger
+import play.api.inject.ApplicationLifecycle
+import scala.concurrent.Future
+
+/**
+ * This class demonstrates how to run code when the
+ * application starts and stops. It starts a timer when the
+ * application starts. When the application stops it prints out how
+ * long the application was running for.
+ *
+ * This class is registered for Guice dependency injection in the
+ * [[Module]] class. We want the class to start when the application
+ * starts, so it is registered as an "eager singleton". See the code
+ * in the [[Module]] class to see how this happens.
+ *
+ * This class needs to run code when the server stops. It uses the
+ * application's [[ApplicationLifecycle]] to register a stop hook.
+ */
+@Singleton
+class ApplicationTimer @Inject() (clock: Clock, appLifecycle: ApplicationLifecycle) {
+
+ // This code is called when the application starts.
+ private val start: Instant = clock.instant
+ Logger.info(s"ApplicationTimer demo: Starting application at $start.")
+
+ // When the application starts, register a stop hook with the
+ // ApplicationLifecyle object. The code inside the stop hook wil
+ // be run when the application stops.
+ appLifecycle.addStopHook { () =>
+ val stop: Instant = clock.instant
+ val runningTime: Long = stop.getEpochSecond - start.getEpochSecond
+ Logger.info(s"ApplicationTimer demo: Stopping application at ${clock.instant} after ${runningTime}s.")
+ Future.successful(())
+ }
+}
diff --git a/play-scala-log4j2-example/app/services/Counter.scala b/play-scala-log4j2-example/app/services/Counter.scala
new file mode 100644
index 000000000..fe19334ee
--- /dev/null
+++ b/play-scala-log4j2-example/app/services/Counter.scala
@@ -0,0 +1,29 @@
+package services
+
+import java.util.concurrent.atomic.AtomicInteger
+import javax.inject._
+
+/**
+ * This trait demonstrates how to create a component that is injected
+ * into a controller. The trait represents a counter that returns a
+ * incremented number each time it is called.
+ */
+trait Counter {
+ def nextCount(): Int
+}
+
+/**
+ * This class is a concrete implementation of the [[Counter]] trait.
+ * It is configured for Guice dependency injection in the [[Module]]
+ * class.
+ *
+ * This class has a `Singleton` annotation because we need to make
+ * sure we only use one counter per application. Without this
+ * annotation we would get a new instance every time a [[Counter]] is
+ * injected.
+ */
+@Singleton
+class AtomicCounter extends Counter {
+ private val atomicCounter = new AtomicInteger()
+ override def nextCount(): Int = atomicCounter.getAndIncrement()
+}
diff --git a/play-scala-log4j2-example/app/views/index.scala.html b/play-scala-log4j2-example/app/views/index.scala.html
new file mode 100644
index 000000000..e5acbe68e
--- /dev/null
+++ b/play-scala-log4j2-example/app/views/index.scala.html
@@ -0,0 +1,15 @@
+@*
+ * This template takes a single argument, a String containing a
+ * message to display.
+ *@
+@(message: String)
+
+@*
+ * Call the the `main` template with two arguments. The first
+ * argument is a `String` with the title of the page, the second
+ * argument is an `Html` object containing the body of the page.
+ *@
+@main("Welcome to Play") {
+
Welcome to PlayFramework!
+
Your new application is ready.
+}
diff --git a/play-scala-log4j2-example/app/views/main.scala.html b/play-scala-log4j2-example/app/views/main.scala.html
new file mode 100644
index 000000000..9414f4be6
--- /dev/null
+++ b/play-scala-log4j2-example/app/views/main.scala.html
@@ -0,0 +1,23 @@
+@*
+ * This template is called from the `index` template. This template
+ * handles the rendering of the page header and body tags. It takes
+ * two arguments, a `String` for the title of the page and an `Html`
+ * object to insert into the body of the page.
+ *@
+@(title: String)(content: Html)
+
+
+
+
+ @* Here's where we render the page title `String`. *@
+ @title
+
+
+
+
+
+ @* And here's where we render the `Html` object containing
+ * the page content. *@
+ @content
+
+
diff --git a/play-scala-log4j2-example/build.gradle b/play-scala-log4j2-example/build.gradle
new file mode 100644
index 000000000..351f75e44
--- /dev/null
+++ b/play-scala-log4j2-example/build.gradle
@@ -0,0 +1,46 @@
+plugins {
+ id 'play'
+ id 'idea'
+}
+
+def playVersion = "2.6.21"
+def log4jVersion = '2.10.0'
+def scalaVersion = System.getProperty("scala.binary.version", /* default = */ "2.12")
+
+model {
+ components {
+ play {
+ platform play: playVersion, scala: scalaVersion, java: '1.8'
+ injectedRoutesGenerator = true
+
+ sources {
+ twirlTemplates {
+ defaultImports = TwirlImports.SCALA
+ }
+ }
+ }
+ }
+}
+
+dependencies {
+ play "com.typesafe.play:play-guice_$scalaVersion:$playVersion"
+
+ play "org.apache.logging.log4j:log4j-slf4j-impl:$log4jVersion"
+ play "org.apache.logging.log4j:log4j-api:$log4jVersion"
+ play "org.apache.logging.log4j:log4j-core:$log4jVersion"
+
+ playTest "org.scalatestplus.play:scalatestplus-play_$scalaVersion:3.1.2"
+}
+
+repositories {
+ jcenter()
+ maven {
+ name "lightbend-maven-releases"
+ url "https://repo.lightbend.com/lightbend/maven-release"
+ }
+ ivy {
+ name "lightbend-ivy-release"
+ url "https://repo.lightbend.com/lightbend/ivy-releases"
+ layout "ivy"
+ }
+}
diff --git a/play-scala-log4j2-example/build.sbt b/play-scala-log4j2-example/build.sbt
new file mode 100644
index 000000000..0911321ab
--- /dev/null
+++ b/play-scala-log4j2-example/build.sbt
@@ -0,0 +1,26 @@
+
+name := """play-2.6-log4j2"""
+
+version := "1.0-SNAPSHOT"
+
+val log4jVersion = "2.10.0"
+
+// Run with activator -Dlog4j.configurationFile=conf/log4j2.xml
+lazy val root = (project in file("."))
+ .enablePlugins(PlayScala)
+ .disablePlugins(PlayLogback).settings(
+ libraryDependencies ++= Seq(
+ guice,
+ "org.apache.logging.log4j" % "log4j-slf4j-impl" % log4jVersion,
+ "org.apache.logging.log4j" % "log4j-api" % log4jVersion,
+ "org.apache.logging.log4j" % "log4j-core" % log4jVersion
+ )
+)
+
+scalaVersion in ThisBuild := "2.12.4"
+
+crossScalaVersions := Seq("2.11.12", "2.12.4")
+
+libraryDependencies += "org.scalatestplus.play" %% "scalatestplus-play" % "3.1.2" % Test
+
+javaOptions += "-Dlog4j.configurationFile=conf/log4j2.xml"
diff --git a/play-scala-log4j2-example/conf/application.conf b/play-scala-log4j2-example/conf/application.conf
new file mode 100644
index 000000000..6355f43b3
--- /dev/null
+++ b/play-scala-log4j2-example/conf/application.conf
@@ -0,0 +1,345 @@
+# This is the main configuration file for the application.
+# https://www.playframework.com/documentation/latest/ConfigFile
+# ~~~~~
+# Play uses HOCON as its configuration file format. HOCON has a number
+# of advantages over other config formats, but there are two things that
+# can be used when modifying settings.
+#
+# You can include other configuration files in this main application.conf file:
+#include "extra-config.conf"
+#
+# You can declare variables and substitute for them:
+#mykey = ${some.value}
+#
+# And if an environment variable exists when there is no other subsitution, then
+# HOCON will fall back to substituting environment variable:
+#mykey = ${JAVA_HOME}
+
+## Akka
+# https://www.playframework.com/documentation/latest/ScalaAkka#Configuration
+# https://www.playframework.com/documentation/latest/JavaAkka#Configuration
+# ~~~~~
+# Play uses Akka internally and exposes Akka Streams and actors in Websockets and
+# other streaming HTTP responses.
+akka {
+ # "akka.log-config-on-start" is extraordinarly useful because it log the complete
+ # configuration at INFO level, including defaults and overrides, so it s worth
+ # putting at the very top.
+ #
+ # Put the following in your conf/logback.xml file:
+ #
+ #
+ #
+ # And then uncomment this line to debug the configuration.
+ #
+ #log-config-on-start = true
+}
+
+## Secret key
+# http://www.playframework.com/documentation/latest/ApplicationSecret
+# ~~~~~
+# The secret key is used to sign Play's session cookie.
+# This must be changed for production, but we don't recommend you change it in this file.
+play.http.secret.key = "changeme"
+
+## Modules
+# https://www.playframework.com/documentation/latest/Modules
+# ~~~~~
+# Control which modules are loaded when Play starts. Note that modules are
+# the replacement for "GlobalSettings", which are deprecated in 2.5.x.
+# Please see https://www.playframework.com/documentation/latest/GlobalSettings
+# for more information.
+#
+# You can also extend Play functionality by using one of the publically available
+# Play modules: https://playframework.com/documentation/latest/ModuleDirectory
+play.modules {
+ # By default, Play will load any class called Module that is defined
+ # in the root package (the "app" directory), or you can define them
+ # explicitly below.
+ # If there are any built-in modules that you want to disable, you can list them here.
+ #enabled += my.application.Module
+
+ # If there are any built-in modules that you want to disable, you can list them here.
+ #disabled += ""
+}
+
+## Internationalisation
+# https://www.playframework.com/documentation/latest/JavaI18N
+# https://www.playframework.com/documentation/latest/ScalaI18N
+# ~~~~~
+# Play comes with its own i18n settings, which allow the user's preferred language
+# to map through to internal messages, or allow the language to be stored in a cookie.
+play.i18n {
+ # The application languages
+ langs = [ "en" ]
+
+ # Whether the language cookie should be secure or not
+ #langCookieSecure = true
+
+ # Whether the HTTP only attribute of the cookie should be set to true
+ #langCookieHttpOnly = true
+}
+
+## Play HTTP settings
+# ~~~~~
+play.http {
+ ## Router
+ # https://www.playframework.com/documentation/latest/JavaRouting
+ # https://www.playframework.com/documentation/latest/ScalaRouting
+ # ~~~~~
+ # Define the Router object to use for this application.
+ # This router will be looked up first when the application is starting up,
+ # so make sure this is the entry point.
+ # Furthermore, it's assumed your route file is named properly.
+ # So for an application router like `my.application.Router`,
+ # you may need to define a router file `conf/my.application.routes`.
+ # Default to Routes in the root package (aka "apps" folder) (and conf/routes)
+ #router = my.application.Router
+
+ ## Action Creator
+ # https://www.playframework.com/documentation/latest/JavaActionCreator
+ # ~~~~~
+ #actionCreator = null
+
+ ## ErrorHandler
+ # https://www.playframework.com/documentation/latest/JavaRouting
+ # https://www.playframework.com/documentation/latest/ScalaRouting
+ # ~~~~~
+ # If null, will attempt to load a class called ErrorHandler in the root package,
+ #errorHandler = null
+
+ ## Filters
+ # https://www.playframework.com/documentation/latest/ScalaHttpFilters
+ # https://www.playframework.com/documentation/latest/JavaHttpFilters
+ # ~~~~~
+ # Filters run code on every request. They can be used to perform
+ # common logic for all your actions, e.g. adding common headers.
+ # Defaults to "Filters" in the root package (aka "apps" folder)
+ # Alternatively you can explicitly register a class here.
+ #filters += my.application.Filters
+
+ ## Session & Flash
+ # https://www.playframework.com/documentation/latest/JavaSessionFlash
+ # https://www.playframework.com/documentation/latest/ScalaSessionFlash
+ # ~~~~~
+ session {
+ # Sets the cookie to be sent only over HTTPS.
+ #secure = true
+
+ # Sets the cookie to be accessed only by the server.
+ #httpOnly = true
+
+ # Sets the max-age field of the cookie to 5 minutes.
+ # NOTE: this only sets when the browser will discard the cookie. Play will consider any
+ # cookie value with a valid signature to be a valid session forever. To implement a server side session timeout,
+ # you need to put a timestamp in the session and check it at regular intervals to possibly expire it.
+ #maxAge = 300
+
+ # Sets the domain on the session cookie.
+ #domain = "example.com"
+ }
+
+ flash {
+ # Sets the cookie to be sent only over HTTPS.
+ #secure = true
+
+ # Sets the cookie to be accessed only by the server.
+ #httpOnly = true
+ }
+}
+
+## Netty Provider
+# https://www.playframework.com/documentation/latest/SettingsNetty
+# ~~~~~
+play.server.netty {
+ # Whether the Netty wire should be logged
+ #log.wire = true
+
+ # If you run Play on Linux, you can use Netty's native socket transport
+ # for higher performance with less garbage.
+ #transport = "native"
+}
+
+## WS (HTTP Client)
+# https://www.playframework.com/documentation/latest/ScalaWS#Configuring-WS
+# ~~~~~
+# The HTTP client primarily used for REST APIs. The default client can be
+# configured directly, but you can also create different client instances
+# with customized settings. You must enable this by adding to build.sbt:
+#
+# libraryDependencies += ws // or javaWs if using java
+#
+play.ws {
+ # Sets HTTP requests not to follow 302 requests
+ #followRedirects = false
+
+ # Sets the maximum number of open HTTP connections for the client.
+ #ahc.maxConnectionsTotal = 50
+
+ ## WS SSL
+ # https://www.playframework.com/documentation/latest/WsSSL
+ # ~~~~~
+ ssl {
+ # Configuring HTTPS with Play WS does not require programming. You can
+ # set up both trustManager and keyManager for mutual authentication, and
+ # turn on JSSE debugging in development with a reload.
+ #debug.handshake = true
+ #trustManager = {
+ # stores = [
+ # { type = "JKS", path = "exampletrust.jks" }
+ # ]
+ #}
+ }
+}
+
+## Cache
+# https://www.playframework.com/documentation/latest/JavaCache
+# https://www.playframework.com/documentation/latest/ScalaCache
+# ~~~~~
+# Play comes with an integrated cache API that can reduce the operational
+# overhead of repeated requests. You must enable this by adding to build.sbt:
+#
+# libraryDependencies += cache
+#
+play.cache {
+ # If you want to bind several caches, you can bind the individually
+ #bindCaches = ["db-cache", "user-cache", "session-cache"]
+}
+
+## Filters
+# https://www.playframework.com/documentation/latest/Filters
+# ~~~~~
+# There are a number of built-in filters that can be enabled and configured
+# to give Play greater security. You must enable this by adding to build.sbt:
+#
+# libraryDependencies += filters
+#
+play.filters {
+ ## CORS filter configuration
+ # https://www.playframework.com/documentation/latest/CorsFilter
+ # ~~~~~
+ # CORS is a protocol that allows web applications to make requests from the browser
+ # across different domains.
+ # NOTE: You MUST apply the CORS configuration before the CSRF filter, as CSRF has
+ # dependencies on CORS settings.
+ cors {
+ # Filter paths by a whitelist of path prefixes
+ #pathPrefixes = ["/some/path", ...]
+
+ # The allowed origins. If null, all origins are allowed.
+ #allowedOrigins = ["http://www.example.com"]
+
+ # The allowed HTTP methods. If null, all methods are allowed
+ #allowedHttpMethods = ["GET", "POST"]
+ }
+
+ ## CSRF Filter
+ # https://www.playframework.com/documentation/latest/ScalaCsrf#Applying-a-global-CSRF-filter
+ # https://www.playframework.com/documentation/latest/JavaCsrf#Applying-a-global-CSRF-filter
+ # ~~~~~
+ # Play supports multiple methods for verifying that a request is not a CSRF request.
+ # The primary mechanism is a CSRF token. This token gets placed either in the query string
+ # or body of every form submitted, and also gets placed in the users session.
+ # Play then verifies that both tokens are present and match.
+ csrf {
+ # Sets the cookie to be sent only over HTTPS
+ #cookie.secure = true
+
+ # Defaults to CSRFErrorHandler in the root package.
+ #errorHandler = MyCSRFErrorHandler
+ }
+
+ ## Security headers filter configuration
+ # https://www.playframework.com/documentation/latest/SecurityHeaders
+ # ~~~~~
+ # Defines security headers that prevent XSS attacks.
+ # If enabled, then all options are set to the below configuration by default:
+ headers {
+ # The X-Frame-Options header. If null, the header is not set.
+ #frameOptions = "DENY"
+
+ # The X-XSS-Protection header. If null, the header is not set.
+ #xssProtection = "1; mode=block"
+
+ # The X-Content-Type-Options header. If null, the header is not set.
+ #contentTypeOptions = "nosniff"
+
+ # The X-Permitted-Cross-Domain-Policies header. If null, the header is not set.
+ #permittedCrossDomainPolicies = "master-only"
+
+ # The Content-Security-Policy header. If null, the header is not set.
+ #contentSecurityPolicy = "default-src 'self'"
+ }
+
+ ## Allowed hosts filter configuration
+ # https://www.playframework.com/documentation/latest/AllowedHostsFilter
+ # ~~~~~
+ # Play provides a filter that lets you configure which hosts can access your application.
+ # This is useful to prevent cache poisoning attacks.
+ hosts {
+ # Allow requests to example.com, its subdomains, and localhost:9000.
+ #allowed = [".example.com", "localhost:9000"]
+ }
+}
+
+## Evolutions
+# https://www.playframework.com/documentation/latest/Evolutions
+# ~~~~~
+# Evolutions allows database scripts to be automatically run on startup in dev mode
+# for database migrations. You must enable this by adding to build.sbt:
+#
+# libraryDependencies += evolutions
+#
+play.evolutions {
+ # You can disable evolutions for a specific datasource if necessary
+ #db.default.enabled = false
+}
+
+## Database Connection Pool
+# https://www.playframework.com/documentation/latest/SettingsJDBC
+# ~~~~~
+# Play doesn't require a JDBC database to run, but you can easily enable one.
+#
+# libraryDependencies += jdbc
+#
+play.db {
+ # The combination of these two settings results in "db.default" as the
+ # default JDBC pool:
+ #config = "db"
+ #default = "default"
+
+ # Play uses HikariCP as the default connection pool. You can override
+ # settings by changing the prototype:
+ prototype {
+ # Sets a fixed JDBC connection pool size of 50
+ #hikaricp.minimumIdle = 50
+ #hikaricp.maximumPoolSize = 50
+ }
+}
+
+## JDBC Datasource
+# https://www.playframework.com/documentation/latest/JavaDatabase
+# https://www.playframework.com/documentation/latest/ScalaDatabase
+# ~~~~~
+# Once JDBC datasource is set up, you can work with several different
+# database options:
+#
+# Slick (Scala preferred option): https://www.playframework.com/documentation/latest/PlaySlick
+# JPA (Java preferred option): https://playframework.com/documentation/latest/JavaJPA
+# EBean: https://playframework.com/documentation/latest/JavaEbean
+# Anorm: https://www.playframework.com/documentation/latest/ScalaAnorm
+#
+db {
+ # You can declare as many datasources as you want.
+ # By convention, the default datasource is named `default`
+
+ # https://www.playframework.com/documentation/latest/Developing-with-the-H2-Database
+ #default.driver = org.h2.Driver
+ #default.url = "jdbc:h2:mem:play"
+ #default.username = sa
+ #default.password = ""
+
+ # You can turn on SQL logging for any datasource
+ # https://www.playframework.com/documentation/latest/Highlights25#Logging-SQL-statements
+ #default.logSql=true
+}
diff --git a/play-scala-log4j2-example/conf/log4j2.xml b/play-scala-log4j2-example/conf/log4j2.xml
new file mode 100644
index 000000000..7b7abda05
--- /dev/null
+++ b/play-scala-log4j2-example/conf/log4j2.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/play-scala-log4j2-example/conf/logger-configurator.properties b/play-scala-log4j2-example/conf/logger-configurator.properties
new file mode 100644
index 000000000..b6645a4fc
--- /dev/null
+++ b/play-scala-log4j2-example/conf/logger-configurator.properties
@@ -0,0 +1 @@
+play.logger.configurator=Log4J2LoggerConfigurator
diff --git a/play-scala-log4j2-example/conf/routes b/play-scala-log4j2-example/conf/routes
new file mode 100644
index 000000000..cc707d49d
--- /dev/null
+++ b/play-scala-log4j2-example/conf/routes
@@ -0,0 +1,13 @@
+# Routes
+# This file defines all application routes (Higher priority routes first)
+# ~~~~
+
+# An example controller showing a sample home page
+GET / controllers.HomeController.index
+# An example controller showing how to use dependency injection
+GET /count controllers.CountController.count
+# An example controller showing how to write asynchronous code
+GET /message controllers.AsyncController.message
+
+# Map static resources from the /public folder to the /assets URL path
+GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
diff --git a/play-scala-log4j2-example/gradle/wrapper/gradle-wrapper.jar b/play-scala-log4j2-example/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..01b8bf6b1
Binary files /dev/null and b/play-scala-log4j2-example/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/play-scala-log4j2-example/gradle/wrapper/gradle-wrapper.properties b/play-scala-log4j2-example/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..89dba2d9d
--- /dev/null
+++ b/play-scala-log4j2-example/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
diff --git a/play-scala-log4j2-example/gradlew b/play-scala-log4j2-example/gradlew
new file mode 100755
index 000000000..cccdd3d51
--- /dev/null
+++ b/play-scala-log4j2-example/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/play-scala-log4j2-example/gradlew.bat b/play-scala-log4j2-example/gradlew.bat
new file mode 100644
index 000000000..e95643d6a
--- /dev/null
+++ b/play-scala-log4j2-example/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/play-scala-log4j2-example/project/build.properties b/play-scala-log4j2-example/project/build.properties
new file mode 100644
index 000000000..c0bab0494
--- /dev/null
+++ b/play-scala-log4j2-example/project/build.properties
@@ -0,0 +1 @@
+sbt.version=1.2.8
diff --git a/play-scala-log4j2-example/project/plugins.sbt b/play-scala-log4j2-example/project/plugins.sbt
new file mode 100644
index 000000000..372755e6f
--- /dev/null
+++ b/play-scala-log4j2-example/project/plugins.sbt
@@ -0,0 +1,2 @@
+// The Play plugin
+addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.21")
diff --git a/play-scala-log4j2-example/public/images/favicon.png b/play-scala-log4j2-example/public/images/favicon.png
new file mode 100644
index 000000000..c7d92d2ae
Binary files /dev/null and b/play-scala-log4j2-example/public/images/favicon.png differ
diff --git a/play-scala-log4j2-example/public/javascripts/hello.js b/play-scala-log4j2-example/public/javascripts/hello.js
new file mode 100644
index 000000000..02ee13c7c
--- /dev/null
+++ b/play-scala-log4j2-example/public/javascripts/hello.js
@@ -0,0 +1,3 @@
+if (window.console) {
+ console.log("Welcome to your Play application's JavaScript!");
+}
diff --git a/play-scala-log4j2-example/public/stylesheets/main.css b/play-scala-log4j2-example/public/stylesheets/main.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/play-scala-log4j2-example/scripts/script-helper b/play-scala-log4j2-example/scripts/script-helper
new file mode 100644
index 000000000..9a2faa643
--- /dev/null
+++ b/play-scala-log4j2-example/scripts/script-helper
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+java_version=$(java -version 2>&1 | java -version 2>&1 | awk -F '"' '/version/ {print $2}')
+
+if [[ $java_version = 1.8* ]] ; then
+ echo "The build is using Java 8 ($java_version). No addional JVM params needed."
+else
+ echo "The build is using Java 9+ ($java_version). We need additional JVM parameters"
+ export _JAVA_OPTIONS="$_JAVA_OPTIONS --add-modules=java.xml.bind"
+fi
diff --git a/play-scala-log4j2-example/scripts/test-gradle b/play-scala-log4j2-example/scripts/test-gradle
new file mode 100755
index 000000000..84a051a20
--- /dev/null
+++ b/play-scala-log4j2-example/scripts/test-gradle
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+. "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/script-helper"
+
+# Using cut because TRAVIS_SCALA_VERSION is the full Scala
+# version (for example 2.12.4), but Gradle expects just the
+# binary version (for example 2.12)
+scala_binary_version=$(echo $TRAVIS_SCALA_VERSION | cut -c1-4)
+
+echo "+------------------------------+"
+echo "| Executing tests using Gradle |"
+echo "+------------------------------+"
+./gradlew -Dscala.binary.version=$scala_binary_version check -i --stacktrace
diff --git a/play-scala-log4j2-example/scripts/test-sbt b/play-scala-log4j2-example/scripts/test-sbt
new file mode 100755
index 000000000..0425367b1
--- /dev/null
+++ b/play-scala-log4j2-example/scripts/test-sbt
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+. "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/script-helper"
+
+echo "+----------------------------+"
+echo "| Executing tests using sbt |"
+echo "+----------------------------+"
+sbt ++$TRAVIS_SCALA_VERSION test
diff --git a/play-scala-log4j2-example/test/ApplicationSpec.scala b/play-scala-log4j2-example/test/ApplicationSpec.scala
new file mode 100644
index 000000000..ee82bf4ef
--- /dev/null
+++ b/play-scala-log4j2-example/test/ApplicationSpec.scala
@@ -0,0 +1,43 @@
+import org.scalatestplus.play._
+import org.scalatestplus.play.guice.GuiceOneAppPerTest
+import play.api.test._
+import play.api.test.Helpers._
+
+/**
+ * Add your spec here.
+ * You can mock out a whole application including requests, plugins etc.
+ * For more information, consult the wiki.
+ */
+class ApplicationSpec extends PlaySpec with GuiceOneAppPerTest {
+
+ "Routes" should {
+
+ "send 404 on a bad request" in {
+ route(app, FakeRequest(GET, "/boum")).map(status) mustBe Some(NOT_FOUND)
+ }
+
+ }
+
+ "HomeController" should {
+
+ "render the index page" in {
+ val home = route(app, FakeRequest(GET, "/")).get
+
+ status(home) mustBe OK
+ contentType(home) mustBe Some("text/html")
+ contentAsString(home) must include ("Your new application is ready.")
+ }
+
+ }
+
+ "CountController" should {
+
+ "return an increasing count" in {
+ contentAsString(route(app, FakeRequest(GET, "/count")).get) mustBe "0"
+ contentAsString(route(app, FakeRequest(GET, "/count")).get) mustBe "1"
+ contentAsString(route(app, FakeRequest(GET, "/count")).get) mustBe "2"
+ }
+
+ }
+
+}
diff --git a/play-scala-log4j2-example/test/IntegrationSpec.scala b/play-scala-log4j2-example/test/IntegrationSpec.scala
new file mode 100644
index 000000000..40ebf7e12
--- /dev/null
+++ b/play-scala-log4j2-example/test/IntegrationSpec.scala
@@ -0,0 +1,19 @@
+import org.scalatestplus.play._
+import org.scalatestplus.play.guice.GuiceOneServerPerTest
+
+/**
+ * add your integration spec here.
+ * An integration test will fire up a whole play application in a real (or headless) browser
+ */
+class IntegrationSpec extends PlaySpec with GuiceOneServerPerTest with OneBrowserPerTest with HtmlUnitFactory {
+
+ "Application" should {
+
+ "work from within a browser" in {
+
+ go to ("http://localhost:" + port)
+
+ pageSource must include ("Your new application is ready.")
+ }
+ }
+}