All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.twitter.server.handler.ServerInfoHandler.scala Maven / Gradle / Ivy

There is a newer version: 18.9.1
Show newest version
package com.twitter.server.handler

import com.twitter.finagle.Service
import com.twitter.finagle.stats.LoadedStatsReceiver
import com.twitter.finagle.http.{Request, Response}
import com.twitter.io.Buf
import com.twitter.server.util.HttpUtils.newResponse
import com.twitter.server.util.JsonConverter
import com.twitter.util.Future
import com.twitter.util.registry.GlobalRegistry
import java.lang.management.ManagementFactory
import java.util.{Date, Properties}
import scala.collection.JavaConverters._

/**
 * A simple http service for serving up information pulled from a build.properties
 * file. The ClassLoader for the given object is used to load the build.properties file,
 * which is first searched for relative to the given object's class's package
 * (class-package-name/build.properties), and if not found there, then it is searched for
 * with an absolute path ("/build.properties").
 */
class ServerInfoHandler(obj: AnyRef) extends Service[Request, Response] {
  private[this] val mxRuntime = ManagementFactory.getRuntimeMXBean

  private[this] val buildProperties = new Properties

  try {
    buildProperties.load(obj.getClass.getResource("build.properties").openStream)
  } catch {
    case _: Throwable =>
      try {
        buildProperties.load(obj.getClass.getResource("/build.properties").openStream)
      } catch {
        case _: Throwable =>
      }
  }

  private[this] val basicServerInfo = Map(
    "name" -> "unknown",
    "version" -> "0.0",
    "build" -> "unknown",
    "build_revision" -> "unknown",
    "build_branch_name" -> "unknown",
    "merge_base" -> "unknown",
    "merge_base_commit_date" -> "unknown",
    "scm_repository" -> "unknown"
  )

  private[this] val combinedInfo = basicServerInfo ++ buildProperties.asScala

  private[this] val registry = GlobalRegistry.get

  combinedInfo.foreach { case (key, value) =>
    registry.put(Seq("build.properties", key), value)
  }

  {
    // Note, don't use `scala.sys.props` until we are on 2.12:
    // https://github.com/scala/scala/pull/4372
    val props = System.getProperties
    for (key <- props.stringPropertyNames().asScala) {
      val value = props.getProperty(key)
      // we acquired a snapshot of keys above, but `key`
      // could have since been removed.
      if (value != null)
        registry.put(Seq("system", "properties", key), value)
    }
  }

  sys.env.foreach { case (key, value) =>
    registry.put(Seq("system", "env", key), value)
  }

  registry.put(Seq("system", "jvm_arguments"),
    ManagementFactory.getRuntimeMXBean.getInputArguments.toString)

  // Expose this build revision as a number. Useful to check cluster consistency.
  combinedInfo.get("build.git.revision.number") match {
    case Some(rev) => LoadedStatsReceiver.provideGauge("build.git.revision.number") { rev.toFloat }
    case None =>
  }

  private[this] val serverInfo = combinedInfo ++ Map(
    "build_last_few_commits" ->
      buildProperties.getProperty("build_last_few_commits", "unknown").split("\n"),
    "build" ->
      buildProperties.getProperty("build_name", "unknown"),
    "start_time" -> new Date(mxRuntime.getStartTime).toString
  ) - "build_name"

  def apply(req: Request): Future[Response] = {
    newResponse(
      contentType = "application/json;charset=UTF-8",
      content = Buf.Utf8(JsonConverter.writeToString(serverInfo + ("uptime" -> mxRuntime.getUptime)))
    )
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy