OSGi EventHandler dynamically listen to LogService

More information in logging

Conflicts:

	project/AkkaBuild.scala
This commit is contained in:
Christophe Pache 2013-01-28 16:03:42 +01:00
parent 49e73f2fb7
commit a88eb0d850
3 changed files with 109 additions and 54 deletions

View file

@ -5,9 +5,8 @@ package akka.osgi
import akka.actor.ActorSystem
import java.util.{ Dictionary, Properties }
import org.osgi.framework.{ ServiceRegistration, BundleContext, BundleActivator }
import org.osgi.framework._
import org.osgi.service.log.LogService
import org.osgi.util.tracker.ServiceTracker
/**
* Abstract bundle activator implementation to bootstrap and configure an actor system in an
@ -40,22 +39,40 @@ abstract class ActorSystemActivator extends BundleActivator {
*/
def start(context: BundleContext): Unit = {
system = Some(OsgiActorSystemFactory(context).createActorSystem(Option(getActorSystemName(context))))
findLogService(context) foreach (log system.foreach(sys sys.eventStream.publish(log)))
system foreach (addLogServiceListener(context, _))
system foreach (configure(context, _))
}
/**
* Finds a LogService in the BundleContext in any
* Adds a LogService Listener that will advertise the ActorSystem on LogService registration and unregistration
*
* @param context the BundleContext
* @return An option of the LogService in the BundleContext
* @param system the ActorSystem to be advertised
*/
def findLogService(context: BundleContext): Option[LogService] = {
val logServiceTracker = new ServiceTracker(context, classOf[LogService].getName, null)
logServiceTracker.open()
Option(logServiceTracker.getService.asInstanceOf[LogService])
def addLogServiceListener(context: BundleContext, system: ActorSystem) {
val logServiceListner = new ServiceListener {
def serviceChanged(event: ServiceEvent) {
event.getType match {
case ServiceEvent.REGISTERED system.eventStream.publish(serviceForReference[LogService](context, event.getServiceReference))
case ServiceEvent.UNREGISTERING system.eventStream.publish(UnregisteringLogService)
}
}
}
val filter = s"(objectclass=${classOf[LogService].getName})"
context.addServiceListener(logServiceListner, filter)
//Small trick to create an event if the service is registred before this start listing for
Option(context.getServiceReference(classOf[LogService].getName)).foreach(x {
logServiceListner.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, x))
})
}
/**
* Convenience method to find a service by its reference.
*/
def serviceForReference[T](context: BundleContext, reference: ServiceReference): T =
context.getService(reference).asInstanceOf[T]
/**
* Shuts down the ActorSystem when the bundle is stopped and, if necessary, unregisters a service registration.
*

View file

@ -0,0 +1,83 @@
/**
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.osgi
import akka.event.Logging
import org.osgi.service.log.LogService
import akka.event.Logging.{ DefaultLogger, LogEvent }
import akka.event.Logging.Error.NoCause
/**
* EventHandler for OSGi environment.
* Stands for an interface between akka and the OSGi LogService
* It uses the OSGi LogService to log the received LogEvents
*/
class DefaultOSGiLogger extends DefaultLogger {
val messageFormat = " %s | %s | %s | %s"
override def receive: Receive = uninitialisedReceive orElse super.receive
/**
* Behaviour of the EventHandler that waits for its LogService
* @return Receive: Store LogEvent or become initialised
*/
def uninitialisedReceive: Receive = {
var messagesToLog: Vector[LogEvent] = Vector()
//the Default Logger needs to be aware of the LogService which is published on the EventStream
context.system.eventStream.subscribe(self, classOf[LogService])
context.system.eventStream.unsubscribe(self, UnregisteringLogService.getClass)
/**
* Logs every already received LogEvent and set the EventHandler ready to log every incoming LogEvent.
*
* @param logService OSGi LogService that has been registered,
*/
def setLogService(logService: LogService) {
messagesToLog.foreach(x {
logMessage(logService, x)
})
context.become(initialisedReceive(logService))
}
{
case logService: LogService setLogService(logService)
case logEvent: LogEvent messagesToLog :+= logEvent
}
}
/**
* Behaviour of the Eventhanlder that is setup (has received a LogService)
* @param logService registrered OSGi LogService
* @return Receive : Logs LogEvent or go back to the uninitialised state
*/
def initialisedReceive(logService: LogService): Receive = {
context.system.eventStream.subscribe(self, UnregisteringLogService.getClass)
context.system.eventStream.unsubscribe(self, classOf[LogService])
{
case logEvent: LogEvent logMessage(logService, logEvent)
case UnregisteringLogService context.become(uninitialisedReceive)
}
}
/**
* Logs a message in an OSGi LogService
*
* @param logService OSGi LogService registered and used for logging
* @param event akka LogEvent that is log unsing the LogService
*/
def logMessage(logService: LogService, event: LogEvent) {
event match {
case error: Logging.Error if error.cause != NoCause logService.log(event.level.asInt, messageFormat.format(timestamp, event.thread.getName, event.logSource, event.message), error.cause)
case _ logService.log(event.level.asInt, messageFormat.format(timestamp, event.thread.getName, event.logSource, event.message))
}
}
}
/**
* Message sent when LogService is unregistred.
* Sent from the ActorSystemActivator to an EventHandler (as DefaultOsgiLogger).
*/
case object UnregisteringLogService

View file

@ -1,45 +0,0 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.osgi.impl
import akka.event.Logging.{ LogEvent, DefaultLogger }
import org.osgi.service.log.LogService
import akka.event.Logging
import collection.mutable.Buffer
/**
* EventHandler for OSGi environment.
* Stands for an interface between akka and the OSGi LogService
* It uses the OSGi LogService to log the received LogEvents
*/
class DefaultOSGiLogger extends DefaultLogger {
//the Default Logger needs to be aware of the LogService which is published on the EventStream
context.system.eventStream.subscribe(self, classOf[LogService])
val messageFormat = "[%s] %s"
var messagesToLog: Vector[LogEvent] = Vector()
override def receive: Receive = {
//register the log service to use
case logService: LogService setLogService(logService)
case logEvent: LogEvent messagesToLog = messagesToLog :+ logEvent
}
def setLogService(logService: LogService) {
messagesToLog.foreach(logMessage(logService, _))
context.become(receiveEvent(logService))
}
def receiveEvent(logService: LogService): Receive = { case logEvent: LogEvent logMessage(logService, logEvent) }
def logMessage(logService: LogService, event: LogEvent) {
event match {
case error: Logging.Error logService.log(event.level.asInt, Logging.stackTraceFor(error.cause))
case _ => logService.log(event.level.asInt, messageFormat.format(event.logSource, event.message))
}
}
}