|
|
/*
* =========================================================================================
* Copyright © 2013-2014 the kamon project <http://kamon.io/>
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions
* and limitations under the License.
* =========================================================================================
*/
package kamon.system.sigar
import java.io._
import java.util
import java.util.logging.Logger
import java.util.{ Date, ArrayList, List }
import org.hyperic.sigar.{ OperatingSystem, CpuPerc, Sigar, SigarProxy }
import scala.annotation.tailrec
import scala.collection.JavaConversions._
import scala.io.Source
object SigarLoader {
val Version = "1.6.4"
val JavaLibraryPath = "java.library.path"
val TmpDir = "java.io.tmpdir"
val IndexFile = "/kamon/system/sigar/index"
val UsrPathField = "usr_paths"
private val log = Logger.getLogger("SigarLoader")
def sigarProxy = init(new File(System.getProperty(TmpDir)))
private[sigar] def init(baseTmp: File): SigarProxy = {
val tmpDir = createTmpDir(baseTmp)
for (lib ← loadIndex) copy(lib, tmpDir)
attachToLibraryPath(tmpDir)
try {
val sigar = new Sigar()
printBanner(sigar)
sigar
} catch {
case t: Throwable ⇒ {
log.severe("Failed to load sigar")
throw new RuntimeException(t)
}
}
}
private[sigar] val usrPathField = {
val usrPathField = classOf[ClassLoader].getDeclaredField(UsrPathField)
usrPathField.setAccessible(true)
usrPathField
}
private[sigar] def attachToLibraryPath(dir: File): Unit = {
val dirAbsolute = dir.getAbsolutePath
System.setProperty(JavaLibraryPath, newLibraryPath(dirAbsolute))
var paths = usrPathField.get(null).asInstanceOf[Array[String]]
if (paths == null) paths = new Array[String](0)
for (path ← paths) if (path == dirAbsolute) return
val newPaths = util.Arrays.copyOf(paths, paths.length + 1)
newPaths(newPaths.length - 1) = dirAbsolute
usrPathField.set(null, newPaths)
}
private[sigar] def newLibraryPath(dirAbsolutePath: String): String = {
Option(System.getProperty(JavaLibraryPath)).fold(dirAbsolutePath)(oldValue ⇒ s"$dirAbsolutePath${File.pathSeparator}$oldValue")
}
private[sigar] def copy(lib: String, tmpDir: File) {
val target = new File(tmpDir, lib)
if (target.exists()) return
write(classOf[Loader].getResourceAsStream(lib), target)
}
private[sigar] def createTmpDir(baseTmp: File): File = {
val tmpDir = new File(baseTmp, s"sigar-$Version")
if (!tmpDir.exists()) {
if (!tmpDir.mkdirs()) throw new RuntimeException(s"Could not create temp sigar directory: ${tmpDir.getAbsolutePath}")
}
if (!tmpDir.isDirectory) throw new RuntimeException(s"sigar temp directory path is not a directory: ${tmpDir.getAbsolutePath}")
if (!tmpDir.canWrite()) throw new RuntimeException(s"sigar temp directory not writeable: ${tmpDir.getAbsolutePath}")
tmpDir
}
private[sigar] def loadIndex(): List[String] = {
val libs = new ArrayList[String]()
val is = classOf[Loader].getResourceAsStream(IndexFile)
for (line ← Source.fromInputStream(is).getLines()) {
val currentLine = line.trim()
libs add currentLine
}
libs
}
private[sigar] def write(input: InputStream, to: File) {
val out = new FileOutputStream(to)
try {
transfer(input, out)
} finally {
out.close()
}
}
private[sigar] def transfer(input: InputStream, out: OutputStream) {
val buffer = new Array[Byte](8192)
@tailrec def transfer() {
val read = input.read(buffer)
if (read >= 0) {
out.write(buffer, 0, read)
transfer()
}
}
transfer()
}
private[sigar] def printBanner(sigar: Sigar) = {
def loadAverage(sigar: Sigar) = {
val average = sigar.getLoadAverage
(average(0), average(1), average(2))
}
def uptime(sigar: Sigar) = {
val uptime = sigar.getUptime
val now = System.currentTimeMillis()
new Date(now - (uptime.getUptime() * 1000).toLong)
}
def osInfo() = {
val NewLine = "\n"
val os = OperatingSystem.getInstance
val osInfo = new StringBuilder("------ OS Information ------").append(NewLine)
osInfo.append("Description: ").append(os.getDescription).append(NewLine)
.append("Name: ").append(os.getName).append(NewLine)
.append("Version: ").append(os.getVersion).append(NewLine)
.append("Arch: ").append(os.getArch).append(NewLine)
.toString()
}
val message = """
|
| _____ _ __ __ _ _ _ _ _
| / ____| | | | \/ | | | (_) | | | | | |
|| (___ _ _ ___| |_ ___ _ __ ___ | \ / | ___| |_ _ __ _ ___ ___| | ___ __ _ __| | ___ __| |
| \___ \| | | / __| __/ _ \ '_ ` _ \| |\/| |/ _ \ __| '__| |/ __/ __| | / _ \ / _` |/ _` |/ _ \/ _` |
| ____) | |_| \__ \ || __/ | | | | | | | | __/ |_| | | | (__\__ \ |___| (_) | (_| | (_| | __/ (_| |
||_____/ \__, |___/\__\___|_| |_| |_|_| |_|\___|\__|_| |_|\___|___/______\___/ \__,_|\__,_|\___|\__,_|
| __/ |
| |___/
""".stripMargin + s"\nBoot Time: ${uptime(sigar)} \nLoad Average: ${loadAverage(sigar)} \n${osInfo()}"
log.info(message)
}
class Loader private[sigar]
}
|