Skip to content
This repository was archived by the owner on Mar 11, 2019. It is now read-only.

Commit a33899f

Browse files
committed
feature(reporter): add an InfluxDB display
This feature adds an InfluxDB display, using the standard java API.
1 parent dd1a093 commit a33899f

File tree

17 files changed

+183
-30
lines changed

17 files changed

+183
-30
lines changed

.travis.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ script:
1616
- sbt 'set concurrentRestrictions in Global += Tags.limit(Tags.Test, 1)' "project powerapi-core" coverage test
1717
- find $HOME/.sbt -name "*.lock" | xargs rm
1818

19+
before_install:
20+
- wget -O influxdb.deb https://s3.amazonaws.com/influxdb/influxdb_0.10.2-1_amd64.deb
21+
- sudo dpkg -i influxdb.deb
22+
- sudo service influxdb start
23+
- sleep 5; /usr/bin/influx --execute "CREATE USER powerapi WITH PASSWORD 'powerapi' WITH ALL PRIVILEGES"
24+
25+
1926
after_success:
2027
- sbt "project powerapi-core" coverageReport
2128
- sbt "project powerapi-core" codacyCoverage

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ We all stand on the shoulders of giants and get by with a little help from our f
5858
* [Sigar](https://support.hyperic.com/display/SIGAR/Home) (version 1.6.5 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for providing a portable interface for gathering system information.
5959
* [spray-json](http://spray.io/) (version 1.3.2 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for (de)serializing JSON.
6060
* [docker-java](https://github.com/docker-java/docker-java) (version 2.1.4 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for using the JAVA Docker API.
61+
* [influxdb-java](https://github.com/influxdata/influxdb-java) (version 2.1 under [MIT license](https://github.com/influxdata/influxdb-java/blob/master/LICENSE)), for using the JAVA InfluxDB API.
6162

6263
# License
6364
This software is licensed under the *GNU Affero General Public License*, quoted below.

powerapi-cli/build.sbt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,8 @@ mappings in Universal ++= {
2121

2222
scriptClasspath ++= Seq("../conf", "../scripts")
2323

24-
NativePackagerKeys.executableScriptName := "powerapi"
24+
packageName in Universal := name.value
25+
26+
topLevelDirectory := Some(name.value)
27+
28+
executableScriptName := "powerapi"

powerapi-cli/src/main/scala/org/powerapi/app/PowerAPI.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import org.powerapi.module.extpowermeter.g5komegawatt.G5kOmegaWattModule
3737
import org.powerapi.module.extpowermeter.powerspy.PowerSpyModule
3838
import org.powerapi.module.extpowermeter.rapl.RAPLModule
3939
import org.powerapi.module.libpfm.{LibpfmCoreModule, LibpfmCoreProcessModule, LibpfmHelper, LibpfmModule, LibpfmProcessModule}
40-
import org.powerapi.reporter.{ConsoleDisplay, FileDisplay, JFreeChartDisplay}
40+
import org.powerapi.reporter.{InfluxDisplay, ConsoleDisplay, FileDisplay, JFreeChartDisplay}
4141
import org.powerapi.{PowerDisplay, PowerMeter, PowerMonitoring}
4242

4343
/**
@@ -58,6 +58,7 @@ object PowerAPI extends App {
5858
@volatile var monitors = Seq[PowerMonitoring]()
5959

6060
val shutdownHookThread = scala.sys.ShutdownHookThread {
61+
println("PowerAPI is shutting down ...")
6162
monitors.foreach(monitor => monitor.cancel())
6263
monitors = Seq()
6364
powerMeters.foreach(powerMeter => powerMeter.shutdown())
@@ -97,7 +98,7 @@ object PowerAPI extends App {
9798
| --frequency $MILLISECONDS
9899
| --self (0, 1) --pids [pid, ...] (0, *) --apps [app, ...] (0, *) --containers [id, ...] (0, *) | all (0, 1)
99100
| --agg max|min|geomean|logsum|mean|median|stdev|sum|variance
100-
| --console (0, 1) --file $FILEPATH (0, *) --chart (0, 1)
101+
| --console (0, 1) --file $FILEPATH (0, *) --chart (0, 1) --influx $HOST $USER $PWD $DB $MEASUREMENT (0, *)
101102
| duration [s]
102103
|
103104
|example: ./powerapi modules procfs-cpu-simple monitor --frequency 1000 --apps firefox,chrome --agg max --console \
@@ -155,6 +156,8 @@ object PowerAPI extends App {
155156
cliMonitorsSubcommand(options, currentMonitor + ('displays -> (currentMonitor.getOrElse('displays, Set[Any]()).asInstanceOf[Set[Any]] + new FileDisplay(value))), tail)
156157
case "--chart" :: tail =>
157158
cliMonitorsSubcommand(options, currentMonitor + ('displays -> (currentMonitor.getOrElse('displays, Set[Any]()).asInstanceOf[Set[Any]] + new JFreeChartDisplay)), tail)
159+
case "--influx" :: host :: user :: pwd :: db :: measurement :: tail =>
160+
cliMonitorsSubcommand(options, currentMonitor + ('displays -> (currentMonitor.getOrElse('displays, Set[Any]()).asInstanceOf[Set[Any]] + new InfluxDisplay(host, user, pwd, db, measurement))), tail)
158161
case option :: tail =>
159162
println(s"unknown monitor option $option")
160163
sys.exit(1)

powerapi-core/build.sbt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ libraryDependencies ++= Seq(
2020
"org.hyperic" % "sigar" % "1.6.5.132",
2121
"net.java.dev.jna" % "jna" % "4.2.1",
2222
"io.spray" %% "spray-json" % "1.3.2",
23-
"com.github.docker-java" % "docker-java" % "2.1.4"
23+
"com.github.docker-java" % "docker-java" % "2.1.4",
24+
"org.influxdb" % "influxdb-java" % "2.1"
2425
)
2526

2627
// Tests

powerapi-core/src/main/scala/org/powerapi/PowerMeter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ object PowerMeter {
182182
}
183183

184184
/**
185-
* A PowerModule groups a sets of tightly coupled API components that need to be deployed together.
185+
* A PowerModule groups a set of tightly coupled API components that need to be deployed together.
186186
*
187187
* @author <a href="mailto:romain.rouvoy@univ-lille1.fr">Romain Rouvoy</a>
188188
*/

powerapi-core/src/main/scala/org/powerapi/core/ClockActors.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ class ClockChild(eventBus: MessageBus, frequency: FiniteDuration) extends ActorC
9090
}
9191

9292
/**
93-
* This clock listens the bus on a given topic and reacts on the received message.
93+
* This clock listens to the bus on a given topic and reacts on the received message.
9494
* It is responsible to handle a pool of clocks for the monitored frequencies.
9595
*
9696
* @author <a href="mailto:maxime.colmant@gmail.com">Maxime Colmant</a>
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* This software is licensed under the GNU Affero General Public License, quoted below.
3+
*
4+
* This file is a part of PowerAPI.
5+
*
6+
* Copyright (C) 2011-2016 Inria, University of Lille 1.
7+
*
8+
* PowerAPI is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Affero General Public License as
10+
* published by the Free Software Foundation, either version 3 of
11+
* the License, or (at your option) any later version.
12+
*
13+
* PowerAPI is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* GNU Affero General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Affero General Public License
19+
* along with PowerAPI.
20+
*
21+
* If not, please consult http://www.gnu.org/licenses/agpl-3.0.html.
22+
*/
23+
package org.powerapi.reporter
24+
25+
import java.util.UUID
26+
import java.util.concurrent.TimeUnit
27+
28+
import collection.JavaConversions._
29+
30+
31+
import org.influxdb.InfluxDBFactory
32+
import org.influxdb.dto.Point
33+
import org.powerapi.PowerDisplay
34+
import org.powerapi.core.power.Power
35+
import org.powerapi.core.target.Target
36+
37+
/**
38+
* Write power information inside an InfluxDB database.
39+
*/
40+
class InfluxDisplay(host: String, user: String, pwd: String, dbName: String, measurement: String) extends PowerDisplay {
41+
42+
val influxdb = InfluxDBFactory.connect(host, user, pwd)
43+
44+
def display(muid: UUID, timestamp: Long, targets: Set[Target], devices: Set[String], power: Power) {
45+
val point = Point.measurement(measurement)
46+
.time(timestamp, TimeUnit.MILLISECONDS)
47+
.field("power", s"${power.toMilliWatts}")
48+
.tag(Map("muid" -> s"$muid", "targets" -> s"${targets.mkString(",")}", "devices" -> s"${devices.mkString(",")}"))
49+
.build()
50+
51+
influxdb.write(dbName, "default", point)
52+
}
53+
}

powerapi-core/src/test/scala/org/powerapi/UnitTest.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ package org.powerapi
2525
import akka.actor.ActorSystem
2626
import akka.testkit.{ImplicitSender, TestKit}
2727

28+
import org.scalatest.concurrent.ScalaFutures
2829
import org.scalatest.{BeforeAndAfterAll, FlatSpecLike, Matchers, OneInstancePerTest}
2930

3031
abstract class UnitTest extends TestKit(ActorSystem("system"))
@@ -33,3 +34,4 @@ abstract class UnitTest extends TestKit(ActorSystem("system"))
3334
with Matchers
3435
with BeforeAndAfterAll
3536
with OneInstancePerTest
37+
with ScalaFutures
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* This software is licensed under the GNU Affero General Public License, quoted below.
3+
*
4+
* This file is a part of PowerAPI.
5+
*
6+
* Copyright (C) 2011-2016 Inria, University of Lille 1.
7+
*
8+
* PowerAPI is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Affero General Public License as
10+
* published by the Free Software Foundation, either version 3 of
11+
* the License, or (at your option) any later version.
12+
*
13+
* PowerAPI is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* GNU Affero General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Affero General Public License
19+
* along with PowerAPI.
20+
*
21+
* If not, please consult http://www.gnu.org/licenses/agpl-3.0.html.
22+
*/
23+
package org.powerapi.reporter
24+
25+
import java.util.UUID
26+
27+
import scala.concurrent.duration.DurationInt
28+
import collection.JavaConversions._
29+
30+
import akka.util.Timeout
31+
32+
import org.influxdb.dto.Query
33+
import org.joda.time.{DateTimeZone, DateTime}
34+
import org.powerapi.UnitTest
35+
import org.powerapi.core.power._
36+
import org.powerapi.core.target.{Application, Process, Target}
37+
38+
class InfluxDisplaySuite extends UnitTest {
39+
40+
val timeout = Timeout(10.seconds)
41+
42+
override def afterAll() = {
43+
system.shutdown()
44+
}
45+
46+
"An InfluxDisplay" should "write an AggPowerReport message in a database" in {
47+
val muid = UUID.randomUUID()
48+
val timestamp = System.currentTimeMillis()
49+
val targets = Set[Target](Application("firefox"), Process(1), Process(2))
50+
val devices = Set[String]("cpu", "gpu", "ssd")
51+
val power = 10.W
52+
53+
val influxDisplay = new InfluxDisplay("http://localhost:8086", "powerapi", "powerapi", "test", "event.powerapi")
54+
influxDisplay.influxdb.createDatabase("test")
55+
influxDisplay.display(muid, timestamp, targets, devices, power)
56+
val query = new Query("SELECT * FROM \"event.powerapi\"", "test")
57+
val result = influxDisplay.influxdb.query(query)
58+
result.getResults.head.getSeries.head.getValues.head should contain theSameElementsAs Seq(s"${new DateTime(timestamp, DateTimeZone.UTC)}", s"$muid", devices.mkString(","), targets.mkString(","), s"${power.toMilliWatts}")
59+
influxDisplay.influxdb.deleteDatabase("test")
60+
}
61+
}
62+

0 commit comments

Comments
 (0)