I know that in Play! using Scala that there is no Http.context available since the idea is to leverage implicits to pass any data around your stack. However, this seems like kind of a lot of boiler plate to pass through when you need a piece of information available for the entire context.
More specifically what I'm interested in is tracking a UUID that is passed from the request header and making it available to any logger so that each request gets its own unique identifier. I'd like this to be seamless from anyone who calls into a logger (or log wrapper)
Coming from a .NET background the http context flows with async calls, and this is also possible with the call context in WCF. At that point you can register a function with the logger to return the current uuid for the request based on a logging pattern of something like "%requestID%".
Building a larger distributed system you need to be able to correlate requests across multiple stacks.
But, being new to scala and play I'm not even sure where to look for a way to do this?
What you are looking for in Java is called the Mapped Diagnostic Context or MDC (at least by SLF4J) - here's an article I found that details how to set this up for Play. In the interest of preserving the details for future visitors here is the code used for an MDC-propagating Akka dispatcher:
package monitoring
import java.util.concurrent.TimeUnit
import akka.dispatch._
import com.typesafe.config.Config
import org.slf4j.MDC
import scala.concurrent.ExecutionContext
import scala.concurrent.duration.{Duration, FiniteDuration}
/**
* Configurator for a MDC propagating dispatcher.
* Authored by Yann Simon
* See: http://yanns.github.io/blog/2014/05/04/slf4j-mapped-diagnostic-context-mdc-with-play-framework/
*
* To use it, configure play like this:
* {{{
* play {
* akka {
* actor {
* default-dispatcher = {
* type = "monitoring.MDCPropagatingDispatcherConfigurator"
* }
* }
* }
* }
* }}}
*
* Credits to James Roper for the [[https://github.com/jroper/thread-local-context-propagation/ initial implementation]]
*/
class MDCPropagatingDispatcherConfigurator(config: Config, prerequisites: DispatcherPrerequisites)
extends MessageDispatcherConfigurator(config, prerequisites) {
private val instance = new MDCPropagatingDispatcher(
this,
config.getString("id"),
config.getInt("throughput"),
FiniteDuration(config.getDuration("throughput-deadline-time", TimeUnit.NANOSECONDS), TimeUnit.NANOSECONDS),
configureExecutor(),
FiniteDuration(config.getDuration("shutdown-timeout", TimeUnit.MILLISECONDS), TimeUnit.MILLISECONDS))
override def dispatcher(): MessageDispatcher = instance
}
/**
* A MDC propagating dispatcher.
*
* This dispatcher propagates the MDC current request context if it's set when it's executed.
*/
class MDCPropagatingDispatcher(_configurator: MessageDispatcherConfigurator,
id: String,
throughput: Int,
throughputDeadlineTime: Duration,
executorServiceFactoryProvider: ExecutorServiceFactoryProvider,
shutdownTimeout: FiniteDuration)
extends Dispatcher(_configurator, id, throughput, throughputDeadlineTime, executorServiceFactoryProvider, shutdownTimeout ) {
self =>
override def prepare(): ExecutionContext = new ExecutionContext {
// capture the MDC
val mdcContext = MDC.getCopyOfContextMap
def execute(r: Runnable) = self.execute(new Runnable {
def run() = {
// backup the callee MDC context
val oldMDCContext = MDC.getCopyOfContextMap
// Run the runnable with the captured context
setContextMap(mdcContext)
try {
r.run()
} finally {
// restore the callee MDC context
setContextMap(oldMDCContext)
}
}
})
def reportFailure(t: Throwable) = self.reportFailure(t)
}
private[this] def setContextMap(context: java.util.Map[String, String]) {
if (context == null) {
MDC.clear()
} else {
MDC.setContextMap(context)
}
}
}
You can then set values in the MDC using MDC.put and remove it using MDC.remove (alternatively, take a look at putCloseable if you need to add and remove some context from a set of synchronous calls):
import org.slf4j.MDC
// Somewhere in a handler
MDC.put("X-UserId", currentUser.id)
// Later, when the user is no longer available
MDC.remove("X-UserId")
and add them to your logging output using %mdc{field-name:default-value}:
<!-- an example from the blog -->
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %coloredLevel %logger{35} %mdc{X-UserId:--} - %msg%n%rootException</pattern>
</encoder>
</appender>
There are more details in the linked blog post about tweaking the ExecutionContext that Play uses to propagate the MDC context correctly (as an alternative approach).
Related
I recently encountered a situation, where it was possible to trigger a database update via a REST endpoint, but not via a #Scheduled method:
#Service
class DbTestService(
private val repo: TestRepository,
private val tx: TransactionTemplate,
private val em: EntityManager,
) {
fun updateAllEntities() {
val entities = repo.findAll() // intentionally outside transaction
tx.execute {
for (entity in entities) {
// if called from SchedulingService, this prints false
// if called from TestController, this prints true
println(" entity named '${entity.name}' is managed: ${em.contains(entity)}")
entity.lastChanged = LocalDateTime.now()
}
}
}
}
#Service
class SchedulingService(
private val dbService: DbTestService,
) {
#Scheduled(cron = "0/20 * * * * *")
fun scheduledUpdate() {
dbService.updateAllEntities() // DOES NOT persist the update
}
}
#RestController
class TestController(
private val dbService: DbTestService,
) {
#GetMapping("/updateAll")
fun updateAll() {
dbService.updateAllEntities() // DOES persist the update
}
}
While I know how to fix this, (just move the repo.findAll() inside the transaction) I find it rather curious that this is the actual behaviour of the system. Scheduled methods seem to run in a different persistence context, but I currently lack the detailed knowledge to fully understand the situation.
Can someone please explain, why this is happening exactly?
I also created a minimal working example project to demonstrate the situation.
In my Scalatra routes, I often use halt() to fail fast:
val user: User = userRepository.getUserById(params("userId"))
.getOrElse {
logger.warn(s"Unknown user: $userId")
halt(404, s"Unknown user: $userId")
}
As shown in the example, I also want to log a warning in those cases. But I'd like to avoid the code duplication between the halt() and the logger. It would be a lot cleaner to simply do:
val user: User = userRepository.getUserById(params("userId"))
.getOrElse(halt(404, s"Unknown user: $userId"))
What would be the best way of logging all "HaltExceptions" in a cross-cutting manner ?
I've considered:
1) Overriding the halt() method in my route:
override def halt[T](status: Integer, body: T, headers: Map[String, String])(implicit evidence$1: Manifest[T]): Nothing = {
logger.warn(s"Halting with status $status and message: $body")
super.halt(status, body, headers)
}
Aside from the weird method signature, I don't really like this approach, because I could be calling the real halt() by mistake instead of the overridden method, for example if I'm halting outside the route. In this case, no warning would be logged.
2) Use trap() to log all error responses:
trap(400 to 600) {
logger.warn(s"Error returned with status $status and body ${extractBodyInSomeWay()}")
}
But I'm not sure it's the best approach, especially since it adds 201 routes to the _statusRoutes Map (one mapping for each integer in the range...). I also don't know how to extract the body here ?
3) Enable some kind of response logging in Jetty for specific status codes ?
What would be the best approach to do this? Am I even approaching this correctly?
The easiest solution is doing it in a servlet filter like below:
package org.scalatra.example
import javax.servlet._
import javax.servlet.http.HttpServletResponse
class LoggingFilter extends Filter {
override def init(filterConfig: FilterConfig): Unit = ()
override def destroy(): Unit = ()
override def doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain): Unit = {
chain.doFilter(request, response)
val status = response.asInstanceOf[HttpServletResponse].getStatus
if (status >= 400 && status <= 600) {
// Do logging here!
}
}
}
Register this filter in your Bootstrap class (or it's possible even in web.xml):
package org.scalatra.example
import org.scalatra._
import javax.servlet.ServletContext
class ScalatraBootstrap extends LifeCycle {
override def init(context: ServletContext): Unit = {
context.addFilter("loggingFilter", new LoggingFilter())
context.getFilterRegistration("loggingFilter")
.addMappingForUrlPatterns(EnumSet.allOf(classOf[DispatcherType]), true, "/*")
// mount your servlets or filters
...
}
}
In my opinion, Scalatra should provide a way to trap halting easier essentially. In fact, there is a method named renderHaltException in ScalatraBase, it looks to be possible to add logging by overriding this method at a glance:
https://github.com/scalatra/scalatra/blob/cec3f75e3484f2233274b1af900f078eb15c35b1/core/src/main/scala/org/scalatra/ScalatraBase.scala#L512
However we can't do it actually because HaltException is package private and it can be accessed inside of org.scalatra package only. I wonder HaltException should be public.
I would like to design a client that would talk to a REST API. I have implemented the bit that actually does call the HTTP methods on the server. I call this Layer, the API layer. Each operation the server exposes is encapsulated as one method in this layer. This method takes as input a ClientContext which contains all the needed information to make the HTTP method call on the server.
I'm now trying to set up the interface to this layer, let's call it ClientLayer. This interface will be the one any users of my client library should use to consume the services. When calling the interface, the user should create the ClientContext, set up the request parameters depending on the operation that he is willing to invoke. With the traditional Java approach, I would have a state on my ClientLayer object which represents the ClientContext:
For example:
public class ClientLayer {
private static final ClientContext;
...
}
I would then have some constructors that would set up my ClientContext. A sample call would look like below:
ClientLayer client = ClientLayer.getDefaultClient();
client.executeMyMethod(client.getClientContext, new MyMethodParameters(...))
Coming to Scala, any suggestions on how to have the same level of simplicity with respect to the ClientContext instantiation while avoiding having it as a state on the ClientLayer?
I would use factory pattern here:
object RestClient {
class ClientContext
class MyMethodParameters
trait Client {
def operation1(params: MyMethodParameters)
}
class MyClient(val context: ClientContext) extends Client {
def operation1(params: MyMethodParameters) = {
// do something here based on the context
}
}
object ClientFactory {
val defaultContext: ClientContext = // set it up here;
def build(context: ClientContext): Client = {
// builder logic here
// object caching can be used to avoid instantiation of duplicate objects
context match {
case _ => new MyClient(context)
}
}
def getDefaultClient = build(defaultContext)
}
def main(args: Array[String]) {
val client = ClientFactory.getDefaultClient
client.operation1(new MyMethodParameters())
}
}
I've been following the Scala testing examples using Specs2 from the official Play documentation. I notice that they use WithApplication to start up a fake application to test against, with clode like the following:
"something" should {
"do X" in new WithApplication { /* ... */ }
"do Y" in new WithApplication { /* ... */ }
"do Z" in new WithApplication { /* ... */ }
}
This is fine and all, but the problem that I'm having is that I incur the cost of my application starting up each time this happens. This isn't necessarily "fast" or at least not fast enough once your test-suite grows to a reasonable size. I've tried doing things like:
val app = FakeApplication()
"something" should {
"do X" in new WithApplication(app) { /* ... */ }
"do Y" in new WithApplication(app) { /* ... */ }
"do Z" in new WithApplication(app) { /* ... */ }
}
and
"something" should {
val app = FakeApplication()
Helpers.running(app) {
"do X" in { /* ... */ }
"do Y" in { /* ... */ }
"do Z" in { /* ... */ }
}
}
The first seems to work for the first test and then complains about db connection issues on the later tests. I'm guessing something is getting shutdown here or something (not sure what).
The second doesn't work at all because it complains about there being no running application, which I'm not sure about either.
Any help is greatly appreciated. Thanks!
Well, it depends on what you want to test. If you're just unit testing code that has no external dependencies or dependencies that you can mock or stub out (and it would be a good idea to structure your code in such a way that allows this), then you don't need to use WithApplication. This is probably the best approach.
The first solution you provided doesn't work because applications can only be used once. It's WithApplication that starts and stops your application, so even if that did work, you wouldn't get any performance benefit.
The second solution you provided doesn't work because when the Helpers.running(app) { } code block runs, this is only declaring the specs. Specs puts all these in a list, and then you exit the running block and it shuts down the app. Then at some point later, specs runs the tests, and there's no application of course then.
So, if you can't test your code in isolation of the rest of your app, then you need to have a running app, there's nothing you can do about that, it's the reality of integration testing. And you probably want it started and shutdown between each test, otherwise your tests aren't running in isolation of each other.
It's outdated, but I'll give my answer. Since I faced same problem, and had similar idea. There is AfterAll & BeforeAll traits in spec2, maybe it was not there at the time of post, so my solution is basically:
package com.equipx.spec.util
import org.specs2.specification.{AfterAll, BeforeAll}
import play.Application
import play.api.Play
import play.test.{Helpers, FakeApplication}
/**
* #author Anton Oparin (antono#clemble.com)
*/
trait WithGlobalApplication extends BeforeAll with AfterAll {
protected var app: Application = null
/**
* Override this method to setup the application to use.
*
* By default this will call the old {#link #provideFakeApplication() provideFakeApplication} method.
*
* #return The application to use
*/
protected def provideApplication: Application = {
return provideFakeApplication
}
/**
* Old method - use the new {#link #provideApplication() provideApplication} method instead.
*
* Override this method to setup the fake application to use.
*
* #return The fake application to use
*/
protected def provideFakeApplication: FakeApplication = {
return Helpers.fakeApplication
}
override def beforeAll {
app = provideApplication
Helpers.start(app)
Play.current
}
override def afterAll {
if (app != null) {
Helpers.stop(app)
app = null
}
}
}
Basically I took WithApplication implementation, and made it global.
My target is building a highly concurrent backend for my widgets. I'm currently exposing the backend as a web service, which receives requests to run a specific widget (using Scalatra), fetches widget's code from DB and runs it in an actor (using Akka) which then replies with the results. So imagine I'm doing something like:
get("/run:id") {
...
val actor = Actor.actorOf("...").start
val result = actor !! (("Run",id), 10000)
...
}
Now I believe this is not the best concurrent solution and I should somehow combine listening for requests and running widgets in one actor implementation. How would you design this for maximum concurrency? Thanks.
You can start your actors in an akka boot file or in your own ServletContextListener so that they are started without being tied to a servlet.
Then you can look for them with the akka registry.
Actor.registry.actorFor[MyActor] foreach { _ !! (("Run",id), 10000) }
Apart from that there is no real integration for akka with scalatra at this moment.
So until now the best you can do is by using blocking requests to a bunch of actors.
I'm not sure but I wouldn't necessary spawn an actor for each request but rather have a pool of widget actors which you can send those requests. If you use a supervisor hierarchy then the you can use a supervisor to resize the pool if it is too big or too small.
class MyContextListener extends ServletContextListener {
def contextInitialized(sce: ServletContextEvent) {
val factory = SupervisorFactory(
SupervisorConfig(
OneForOneStrategy(List(classOf[Exception]), 3, 1000),
Supervise(actorOf[WidgetPoolSupervisor], Permanent)
}
def contextDestroyed(sce: ServletContextEvent) {
Actor.registry.shutdownAll()
}
}
class WidgetPoolSupervisor extends Actor {
self.faultHandler = OneForOneStrategy(List(classOf[Exception]), 3, 1000)
override def preStart() {
(1 to 5) foreach { _ =>
self.spawnLink[MyWidgetProcessor]
}
Scheduler.schedule(self, 'checkPoolSize, 5, 5, TimeUnit.MINUTES)
}
protected def receive = {
case 'checkPoolSize => {
//implement logic that checks how quick the actors respond and if
//it takes to long add some actors to the pool.
//as a bonus you can keep downsizing the actor pool until it reaches 1
//or until the message starts returning too late.
}
}
}
class ScalatraApp extends ScalatraServlet {
get("/run/:id") {
// the !! construct should not appear anywhere else in your code except
// in the scalatra action. You don't want to block anywhere else, but in a
// scalatra action it's ok as the web request itself is synchronous too and needs to
// to wait for the full response to have come back anyway.
Actor.registry.actorFor[MyWidgetProcessor] foreach {
_ !! ((Run, id), 10000)
} getOrElse {
throw new HeyIExpectedAResultException()
}
}
}
Please do regard the code above as pseudo code that happens to look like scala, I just wanted to illustrate the concept.