Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. 
                        
                        Project price only 1 $ 
                        
                            You can buy this project and download/modify it how often you want.
                        
                        
                        
                     
                 
             
         
            xitrum.metrics.MetricsAction.scala Maven / Gradle / Ivy 
    
package xitrum.metrics
import akka.actor.{Actor, ActorRef, Terminated}
import akka.cluster.metrics.{ClusterMetricsChanged, ClusterMetricsExtension, NodeMetrics}
import akka.cluster.metrics.StandardMetrics.{Cpu, HeapMemory}
import io.netty.handler.codec.http.HttpResponseStatus
import xitrum.{FutureAction, Config, SockJsAction, SockJsText}
import xitrum.annotation.{GET, Last, SOCKJS}
import xitrum.util.SeriDeseri
import xitrum.view.DocType
/** JMX metrics collector for single node application. */
class MetricsCollector(localPublisher: ActorRef) extends Actor {
  def receive: Receive = {
    case Collect => localPublisher ! MetricsManager.jmx.sample()
    case _ =>
  }
}
/** JMX metrics collector for clustered node application. */
class ClusterMetricsCollector(localPublisher: ActorRef) extends Actor {
  private val extension = ClusterMetricsExtension(context.system)
  override def preStart(): Unit = {
    extension.subscribe(self)
  }
  override def postStop(): Unit = {
    extension.unsubscribe(self)
  }
  def receive: Receive = {
    case m: ClusterMetricsChanged =>
      localPublisher ! m
    case UnSubscribe =>
      extension.unsubscribe(self)
    case _ =>
  }
}
/**
 * Example: XitrumMetricsChannel
 */
class MetricsPublisher extends Actor {
  private var clients                                = Seq[ActorRef]()
  private var lastPublished                          = System.currentTimeMillis()
  private var cachedNodeMetrics:    NodeMetrics      = _
  private var cachedClusterMetrics: Set[NodeMetrics] = _
  private var cachedRegistryAsJson: String           = _
  def receive: Receive = {
    case ClusterMetricsChanged(clusterMetrics) =>
      cachedClusterMetrics = clusterMetrics
    case nodeMetrics: NodeMetrics =>
      cachedNodeMetrics = nodeMetrics
    case Publish(registryAsJson) =>
      cachedRegistryAsJson = registryAsJson
      clients.foreach { client =>
        client ! Publish(registryAsJson)
        if (cachedNodeMetrics != null) client ! cachedNodeMetrics
        // Ignore if clusterd metricsManager sent duplicated requests
        if (System.currentTimeMillis - lastPublished > Config.xitrum.metrics.get.collectActorInterval.toMillis) {
          if (cachedClusterMetrics != null) client ! cachedClusterMetrics.toList
          lastPublished = System.currentTimeMillis
        }
      }
    case Pull =>
      sender() ! Publish(MetricsManager.registryAsJson)
      if (cachedNodeMetrics != null)    sender() ! cachedNodeMetrics
      if (cachedClusterMetrics != null) sender() ! cachedClusterMetrics.toList
    case Subscribe =>
      clients = clients :+ sender()
      context.watch(sender())
    case UnSubscribe =>
      clients =  clients.filterNot(_ == sender())
      context.unwatch(sender())
    case Terminated(client) =>
      clients = clients.filterNot(_ == client)
    case _ =>
  }
}
/** Javascript fragment for establish metrics JSON sockJS channel. */
trait MetricsViewer extends FutureAction {
  def jsAddMetricsNameSpace(namespace: String = null): Unit = {
    jsAddToView(s"""
(function (namespace) {
  var ns  = namespace || window;
  var url = '${sockJsUrl[XitrumMetricsChannel]}';
  var pullTimer;
  var initMetricsChannel = function(onMessageFunc) {
    var socket;
    socket = new SockJS(url);
    socket.onopen = function(event) {
      socket.send('${MetricsManager.metrics.apiKey}');
      pullTimer = setInterval(function() { socket.send('pull') }, 2000);
    };
    socket.onclose = function(e) {
      clearInterval(pullTimer);
      // Reconnect
      setTimeout(function() { initMetricsChannel(onMessageFunc) }, 2000);
    };
    socket.onmessage = function(e) { onMessageFunc(e.data); }
  };
  ns.initMetricsChannel = initMetricsChannel;
})($namespace);
"""
    )
  }
}
/**
 * Default metrics viewer page.
 * This page could be overwritten in user application with any style.
 */
@Last
@GET("xitrum/metrics/viewer")
class XitrumMetricsViewer extends FutureAction with MetricsViewer {
  beforeFilter {
    val apiKey  = param("api_key")
    if (apiKey != MetricsManager.metrics.apiKey) {
      response.setStatus(HttpResponseStatus.UNAUTHORIZED)
      respondHtml(Unauthorized
)
    }
  }
  lazy val html: String = DocType.html5(
    
      
        {xitrumCss}
        {jsDefaults}
        
        
        Xitrum Default Metrics Viewer 
      
      
        Xitrum Default Metrics Viewer 
        
        Xitrum Default Metrics Viewer 
      
      
        
        {jsForView}
      
    
  )
  def execute(): Unit = {
    jsAddMetricsNameSpace("window")
    paramo("focusAction") match {
      case Some(key) =>
        jsAddToView("initMetricsChannel(channelOnMessageWithKey('"+ key +"'));")
        respondHtml(focusHtml)
      case None =>
        jsAddToView("initMetricsChannel(channelOnMessage);")
        respondHtml(html)
    }
  }
}
/** SockJS channel for metrics JSON. */
@SOCKJS("xitrum/metrics/channel")
class XitrumMetricsChannel extends SockJsAction with PublisherLookUp {
  def execute(): Unit = {
    checkAPIKey()
  }
  private def checkAPIKey(): Unit = {
    context.become {
      case SockJsText(text) if text == MetricsManager.metrics.apiKey =>
        lookUpPublisher()
      case SockJsText(key) =>
        respondSockJsText("Wrong apikey")
        respondSockJsClose()
      case ignore =>
        log.warn("Unexpected message: " + ignore)
    }
  }
  override def doWithPublisher(publisher: ActorRef): Unit = {
    publisher ! Subscribe
    context.watch(publisher)
    context.become {
      case msg: Seq[_] =>
        msg.asInstanceOf[Seq[NodeMetrics]].foreach { nodeMetrics =>
          sendHeapMemory(nodeMetrics)
          sendCpu(nodeMetrics)
        }
      case nodeMetrics: NodeMetrics =>
        sendHeapMemory(nodeMetrics)
        sendCpu(nodeMetrics)
      case Publish(registryAsJson) =>
        respondSockJsText(registryAsJson)
      case SockJsText(text) =>
        if (text == "pull" ) publisher ! Pull
      case Terminated(`publisher`) =>
        lookUpPublisher()
      case _ =>
    }
  }
  private def sendHeapMemory(nodeMetrics: NodeMetrics): Unit = {
    nodeMetrics match {
      case HeapMemory(address, timestamp, used, committed, max) =>
        respondSockJsText(SeriDeseri.toJson(Map(
          "TYPE"      -> "heapMemory",
          "SYSTEM"    -> address.system,
          "HOST"      -> address.host,
          "PORT"      -> address.port,
          "HASH"      -> address.hashCode,
          "TIMESTAMP" -> timestamp,
          "USED"      -> used,
          "COMMITTED" -> committed,
          "MAX"       -> max
        )))
      case _ =>
    }
  }
  private def sendCpu(nodeMetrics: NodeMetrics):Unit = {
    nodeMetrics match {
      case Cpu(address, timestamp, Some(systemLoadAverage), cpuCombined, cpuStolen, processors) =>
        respondSockJsText(SeriDeseri.toJson(Map(
          "TYPE"              -> "cpu",
          "SYSTEM"            -> address.system,
          "HOST"              -> address.host,
          "PORT"              -> address.port,
          "HASH"              -> address.hashCode,
          "TIMESTAMP"         -> timestamp,
          "SYSTEMLOADAVERAGE" -> systemLoadAverage,
          "CPUCOMBINED"       -> cpuCombined,
          "PROCESSORS"        -> processors
        )))
      case _ =>
    }
  }
}