aboutsummaryrefslogtreecommitdiff
path: root/kamon-system/src/main/scala/kamon/system/native/SigarLoader.scala
blob: 511a8ffcfd6547dea2a0dc60b89e0caca73a4ede (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package kamon.system.native

import org.hyperic.sigar.Sigar
import org.hyperic.sigar.SigarProxy
import java.io._
import scalax.io.JavaConverters._
import scalax.io._

import Resource._

import scalax.file.Path
import java.util
import scala.collection.JavaConversions._

object SigarLoader {
  val Version = "1.6.4"
  val JavaLibraryPath = "java.library.path"
  val TmpDir = "java.io.tmpdir"
  val IndexFile = "/kamon/system/native/index"
  val UsrPathField = "usr_paths"

  def init: SigarProxy = init(new File(System.getProperty(TmpDir)))

  private def init(baseTmp: File): SigarProxy = {
    val tmpDir = createTmpDir(baseTmp)
    for (lib  loadIndex) copy(lib, tmpDir)

    attachToLibraryPath(tmpDir)

    try {
      val sigar = new Sigar
      sigar.getPid
      sigar
    } catch {
      case t: Throwable 
        throw new RuntimeException("Failed to load sigar", t)
    }
  }

  private val usrPathField = {
    val usrPathField = classOf[ClassLoader].getDeclaredField(UsrPathField)
    usrPathField.setAccessible(true)
    usrPathField
  }

  private 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 def newLibraryPath(dirAbsolutePath: String): String = {
    Option(System.getProperty(JavaLibraryPath)).fold(dirAbsolutePath)(oldValue  s"$dirAbsolutePath${File.pathSeparator}$oldValue")
  }

  private def copy(lib: String, tmpDir: File) {
    val dest: Path = Path(new File(tmpDir, lib))
    if (dest.exists) return
    val currentFile = Resource.fromInputStream(classOf[Loader].getResourceAsStream("" + lib))
    currentFile.acquireFor(current  dest.doCopyFrom(current.asInput))
  }

  private def createTmpDir(baseTmp: File): File = {
    val path = Path(new File(baseTmp, s"sigar-$Version"))
    path.createDirectory(failIfExists = false)
    path.jfile
  }

  private def loadIndex: util.List[String] = {
    val libs = new util.ArrayList[String]
    val input = fromInputStream(classOf[Loader].getResourceAsStream(IndexFile))
    input.lines().foreach(libs.add)
    libs
  }
}

class Loader