Created
February 27, 2018 21:31
-
-
Save richdougherty/91649b8efd6304376ed4187cc427a6d0 to your computer and use it in GitHub Desktop.
Example of capturing logging output in Play Framework
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (C) 2009-2017 Lightbend Inc. <https://www.lightbend.com> | |
*/ | |
package play.it.http | |
import ch.qos.logback.classic.Logger | |
import ch.qos.logback.classic.spi.ILoggingEvent | |
import ch.qos.logback.core.AppenderBase | |
import org.slf4j.LoggerFactory | |
import org.specs2.execute.AsResult | |
import play.api.inject.guice.GuiceApplicationBuilder | |
import play.api.mvc._ | |
import play.api.test._ | |
import play.api.{ Configuration, Mode } | |
import play.core.server.ServerConfig | |
import play.it._ | |
import scala.collection.mutable.ArrayBuffer | |
class NettyRequestHeadersSpec extends RequestHeadersSpec with NettyIntegrationSpecification | |
class AkkaHttpRequestHeadersSpec extends RequestHeadersSpec with AkkaHttpIntegrationSpecification | |
trait RequestHeadersSpec extends PlaySpecification with ServerIntegrationSpecification with HttpHeadersCommonSpec { | |
sequential | |
def withServerAndConfig[T](configuration: (String, Any)*)(action: (DefaultActionBuilder, PlayBodyParsers) => EssentialAction)(block: Port => T) = { | |
val port = testServerPort | |
val serverConfig: ServerConfig = { | |
val c = ServerConfig(port = Some(testServerPort), mode = Mode.Test) | |
c.copy(configuration = c.configuration ++ Configuration(configuration: _*)) | |
} | |
running(play.api.test.TestServer(serverConfig, GuiceApplicationBuilder().appRoutes { app => | |
val Action = app.injector.instanceOf[DefaultActionBuilder] | |
val parse = app.injector.instanceOf[PlayBodyParsers] | |
({ | |
case _ => action(Action, parse) | |
}) | |
}.build(), Some(integrationServerProvider))) { | |
block(port) | |
} | |
} | |
def withServer[T](action: (DefaultActionBuilder, PlayBodyParsers) => EssentialAction)(block: Port => T) = { | |
withServerAndConfig()(action)(block) | |
} | |
"Play request header handling" should { | |
"not complain about invalid User-Agent headers" in { | |
// This test modifies the global (!) logger to capture log messages. | |
// The test will not be reliable when run concurrently. However, since | |
// we're checking for the *absence* of log messages the worst thing | |
// that will happen is that the test will pass when it should fail. We | |
// should not get spurious failures which would cause our CI testing | |
// to fail. I think it's still worth including this test because it | |
// will still often report correct failures, even if it's not perfect. | |
import scala.collection.immutable | |
def recordLogEvents[T](block: => T): immutable.Seq[ILoggingEvent] = { | |
/** Collects all log events that occur */ | |
class RecordingAppender extends AppenderBase[ILoggingEvent] { | |
private val eventBuffer = ArrayBuffer[ILoggingEvent]() | |
override def append(e: ILoggingEvent): Unit = synchronized { | |
eventBuffer += e | |
} | |
def events: immutable.Seq[ILoggingEvent] = synchronized { | |
eventBuffer.to[immutable.Seq] | |
} | |
} | |
// Get the Logback root logger and attach a RecordingAppender | |
val rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME).asInstanceOf[Logger] | |
val appender = new RecordingAppender() | |
appender.setContext(rootLogger.getLoggerContext) | |
appender.start() | |
rootLogger.addAppender(appender) | |
block | |
rootLogger.detachAppender(appender) | |
appender.stop() | |
appender.events | |
} | |
withServerAndConfig()((Action, _) => Action { rh => | |
Results.Ok(rh.headers.get("User-Agent").toString) | |
}) { port => | |
def testAgent[R: AsResult](agent: String) = { | |
val logMessages = recordLogEvents { | |
val Seq(response) = BasicHttpClient.makeRequests(port)( | |
BasicRequest("GET", "/", "HTTP/1.1", Map( | |
"User-Agent" -> agent | |
), "") | |
) | |
response.body must beLeft(s"Some($agent)") | |
} | |
logMessages.map(_.getFormattedMessage) must contain(contain(agent)) | |
} | |
// These agent strings come from https://github.com/playframework/playframework/issues/7997 | |
testAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 11_0_3 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Mobile/15A432 [FBAN/FBIOS;FBAV/147.0.0.46.81;FBBV/76961488;FBDV/iPhone8,1;FBMD/iPhone;FBSN/iOS;FBSV/11.0.3;FBSS/2;FBCR/T-Mobile.pl;FBID/phone;FBLC/pl_PL;FBOP/5;FBRV/0]") | |
testAgent("Mozilla/5.0 (Linux; Android 7.0; TRT-LX1 Build/HUAWEITRT-LX1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.98 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/148.0.0.51.62;]") | |
testAgent("Mozilla/5.0 (Linux; Android 7.0; SM-G955F Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 [FB_IAB/Orca-Android;FBAV/142.0.0.18.63;]") | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment