Initial commit.
This commit is contained in:
commit
61274350d5
42
.gitignore
vendored
Normal file
42
.gitignore
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
.kotlin
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea/modules.xml
|
||||||
|
.idea/jarRepositories.xml
|
||||||
|
.idea/compiler.xml
|
||||||
|
.idea/libraries/
|
||||||
|
.idea/*.xml
|
||||||
|
.idea/*
|
||||||
|
.idea/
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### Eclipse ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
### Mac OS ###
|
||||||
|
.DS_Store
|
||||||
9
Dockerfile
Normal file
9
Dockerfile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
FROM amazoncorretto:17.0.14-alpine3.21
|
||||||
|
LABEL authors="fey"
|
||||||
|
WORKDIR /app
|
||||||
|
COPY . /app/
|
||||||
|
RUN apk add maven
|
||||||
|
RUN mvn dependency:resolve-plugins dependency:go-offline -B
|
||||||
|
RUN mvn compile package
|
||||||
|
EXPOSE 9400
|
||||||
|
ENTRYPOINT mvn -o exec:java
|
||||||
13
README.md
Normal file
13
README.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Octonet Exporter
|
||||||
|
|
||||||
|
This is a Java application that exports metrics from a Digital Devices OctopusNET to Prometheus.
|
||||||
|
|
||||||
|
## How to run?
|
||||||
|
|
||||||
|
* Option 1: Set the OCTONET_IP environment variable to the IP address of your OctopusNET device and run the application using `mvn exec:java`.
|
||||||
|
* Option 2: There's are pre-built binary supplied in the download archive. You can use this by setting the OCTONET_IP environment variable to the IP address of your OctopusNET device and then run the application using `java -jar octonet-exporter-1.0-SNAPSHOT-jar-with-dependencies.jar`.
|
||||||
|
* Option 3 (recommended): Use the provided Dockerfile to build a container and run this application in Docker or Podman. Don't forget to supply an `-e OCTONET_IP=<your_octonet_ip>` to the container.
|
||||||
|
|
||||||
|
## How to compile a binary?
|
||||||
|
|
||||||
|
To compile a binary, run `mvn clean compile assembly:single` in the project directory. This will create a JAR file in the `target` directory that you can run using `java -jar octonet-exporter-1.0-SNAPSHOT-jar-with-dependencies.jar`.
|
||||||
75
pom.xml
Normal file
75
pom.xml
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>moe.yo3explorer</groupId>
|
||||||
|
<artifactId>octonet-exporter</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-core</artifactId>
|
||||||
|
<version>2.25.4</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.okhttp3</groupId>
|
||||||
|
<artifactId>okhttp</artifactId>
|
||||||
|
<version>5.0.0-alpha.12</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.prometheus</groupId>
|
||||||
|
<artifactId>prometheus-metrics-core</artifactId>
|
||||||
|
<version>1.3.6</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.prometheus</groupId>
|
||||||
|
<artifactId>prometheus-metrics-exporter-httpserver</artifactId>
|
||||||
|
<version>1.3.6</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
<version>2.17.0</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>moe.yo3explorer.octonet_exporter.Main</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
<descriptorRefs>
|
||||||
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
|
</descriptorRefs>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>exec-maven-plugin</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
<configuration>
|
||||||
|
<mainClass>moe.yo3explorer.octonet_exporter.Main</mainClass>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
121
src/main/java/moe/yo3explorer/octonet_exporter/Main.java
Normal file
121
src/main/java/moe/yo3explorer/octonet_exporter/Main.java
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
package moe.yo3explorer.octonet_exporter;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import io.prometheus.metrics.core.metrics.Gauge;
|
||||||
|
import io.prometheus.metrics.exporter.httpserver.HTTPServer;
|
||||||
|
import moe.yo3explorer.octonet_exporter.entities.FanspeedResponse;
|
||||||
|
import moe.yo3explorer.octonet_exporter.entities.Tuner;
|
||||||
|
import moe.yo3explorer.octonet_exporter.entities.TunerResponse;
|
||||||
|
import okhttp3.Call;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
private static final Logger log = LogManager.getLogger(Main.class);
|
||||||
|
|
||||||
|
private static boolean safeSleep()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
return true;
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException {
|
||||||
|
Logger logger = LogManager.getLogger(Main.class);
|
||||||
|
logger.info("Hello! This is octonet_exporter!");
|
||||||
|
Map<String, String> getenv = System.getenv();
|
||||||
|
if (!getenv.containsKey("OCTONET_IP"))
|
||||||
|
{
|
||||||
|
logger.error("OCTONET_IP environment variable is not set");
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
String octonetIp = getenv.get("OCTONET_IP");
|
||||||
|
logger.info("Octonet IP: " + octonetIp);
|
||||||
|
|
||||||
|
HTTPServer server = HTTPServer.builder()
|
||||||
|
.hostname("0.0.0.0")
|
||||||
|
.port(9401)
|
||||||
|
.buildAndStart();
|
||||||
|
logger.info("Server started on port 9401");
|
||||||
|
|
||||||
|
String fanspeedUrl = "http:/%s/system/fanspeed?_=%d";
|
||||||
|
String temperaturUrl = "http://%s/log/Temperatur.log?_=%d";
|
||||||
|
String tunerstatusUrl = "http://%s/octoserve/tunerstatus.json";
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
Gauge fanspeed = Gauge.builder().name("octonetExporter_fanspeed").help("Fan speed").register();
|
||||||
|
Gauge temperature = Gauge.builder().name("octonetExporter_temperature").help("Temperature").register();
|
||||||
|
Gauge locked = Gauge.builder().name("octonetExporter_locked").help("Is the tuner locked?").labelNames("input").register();
|
||||||
|
Gauge strength = Gauge.builder().name("octonetExporter_strength").help("Signal strength").labelNames("input").register();
|
||||||
|
Gauge snr = Gauge.builder().name("octonetExporter_snr").help("Signal to noise ratio").labelNames("input").register();
|
||||||
|
Gauge quality = Gauge.builder().name("octonetExporter_quality").help("Signal quality").labelNames("input").register();
|
||||||
|
Gauge level = Gauge.builder().name("octonetExporter_level").help("Signal level").labelNames("input").register();
|
||||||
|
|
||||||
|
OkHttpClient client = new OkHttpClient.Builder().build();
|
||||||
|
int state = 1;
|
||||||
|
while (state != Integer.MAX_VALUE)
|
||||||
|
{
|
||||||
|
if (state == 1)
|
||||||
|
{
|
||||||
|
logger.info("Starting scraping loop...");
|
||||||
|
state++;
|
||||||
|
}
|
||||||
|
Request request = new Request.Builder().url(String.format(fanspeedUrl,octonetIp,System.currentTimeMillis())).build();
|
||||||
|
Call call = client.newCall(request);
|
||||||
|
Response execute = call.execute();
|
||||||
|
String string = execute.body().string();
|
||||||
|
FanspeedResponse fanspeedResponse = objectMapper.readValue(string, FanspeedResponse.class);
|
||||||
|
fanspeed.set(fanspeedResponse.speed);
|
||||||
|
if (!safeSleep())
|
||||||
|
break;
|
||||||
|
|
||||||
|
request = new Request.Builder().url(String.format(temperaturUrl,octonetIp,System.currentTimeMillis())).build();
|
||||||
|
call = client.newCall(request);
|
||||||
|
execute = call.execute();
|
||||||
|
string = execute.body().string();
|
||||||
|
StringReader stringReader = new StringReader(string);
|
||||||
|
BufferedReader bufferedReader = new BufferedReader(stringReader);
|
||||||
|
String headLine = bufferedReader.readLine();
|
||||||
|
String temperatureString = bufferedReader.readLine();
|
||||||
|
bufferedReader.close();
|
||||||
|
stringReader.close();
|
||||||
|
temperature.set(Double.parseDouble(temperatureString));
|
||||||
|
if (!safeSleep())
|
||||||
|
break;
|
||||||
|
|
||||||
|
request = new Request.Builder().url(String.format(tunerstatusUrl,octonetIp)).build();
|
||||||
|
call = client.newCall(request);
|
||||||
|
execute = call.execute();
|
||||||
|
string = execute.body().string();
|
||||||
|
TunerResponse tunerResponse = objectMapper.readValue(string, TunerResponse.class);
|
||||||
|
for (Tuner tuner : tunerResponse.getTunerList())
|
||||||
|
{
|
||||||
|
locked.labelValues(tuner.getInput()).set(tuner.isLock() ? 1 : 0);
|
||||||
|
strength.labelValues(tuner.getInput()).set(tuner.isLock() ? ((double)(tuner.getStrength() + 108750) / 1000.0) : 0.0);
|
||||||
|
snr.labelValues(tuner.getInput()).set((double)tuner.getSnr() / 1000.0);
|
||||||
|
quality.labelValues(tuner.getInput()).set(tuner.getQuality());
|
||||||
|
level.labelValues(tuner.getInput()).set(tuner.getLevel());
|
||||||
|
}
|
||||||
|
if (!safeSleep())
|
||||||
|
break;
|
||||||
|
if (state == 2)
|
||||||
|
{
|
||||||
|
logger.info("Scraping loop successfully started.");
|
||||||
|
state++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.warn("Scraping loop stopped.");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package moe.yo3explorer.octonet_exporter.entities;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
public class FanspeedResponse
|
||||||
|
{
|
||||||
|
@JsonProperty("speed")
|
||||||
|
public int speed;
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package moe.yo3explorer.octonet_exporter.entities;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
public class Tuner {
|
||||||
|
@JsonProperty("Input")
|
||||||
|
private String input;
|
||||||
|
|
||||||
|
@JsonProperty("Status")
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
@JsonProperty("Lock")
|
||||||
|
private boolean lock;
|
||||||
|
|
||||||
|
@JsonProperty("Strength")
|
||||||
|
private long strength;
|
||||||
|
|
||||||
|
@JsonProperty("SNR")
|
||||||
|
private int snr;
|
||||||
|
|
||||||
|
@JsonProperty("Quality")
|
||||||
|
private int quality;
|
||||||
|
|
||||||
|
@JsonProperty("Level")
|
||||||
|
private int level;
|
||||||
|
|
||||||
|
// Getters and Setters
|
||||||
|
public String getInput() { return input; }
|
||||||
|
public String getStatus() { return status; }
|
||||||
|
public boolean isLock() { return lock; }
|
||||||
|
public long getStrength() { return strength; }
|
||||||
|
public int getSnr() { return snr; }
|
||||||
|
public int getQuality() { return quality; }
|
||||||
|
public int getLevel() { return level; }
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
package moe.yo3explorer.octonet_exporter.entities;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TunerResponse {
|
||||||
|
@JsonProperty("TunerList")
|
||||||
|
private List<Tuner> tunerList;
|
||||||
|
|
||||||
|
public List<Tuner> getTunerList() {
|
||||||
|
return tunerList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTunerList(List<Tuner> tunerList) {
|
||||||
|
this.tunerList = tunerList;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/main/resources/log4j2.xml
Normal file
17
src/main/resources/log4j2.xml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Configuration xmlns="https://logging.apache.org/xml/ns"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="
|
||||||
|
https://logging.apache.org/xml/ns
|
||||||
|
https://logging.apache.org/xml/ns/log4j-config-2.xsd">
|
||||||
|
<Appenders>
|
||||||
|
<Console name="CONSOLE">
|
||||||
|
<PatternLayout pattern="%p - %m%n"/>
|
||||||
|
</Console>
|
||||||
|
</Appenders>
|
||||||
|
<Loggers>
|
||||||
|
<Root level="INFO">
|
||||||
|
<AppenderRef ref="CONSOLE" level="DEBUG"/>
|
||||||
|
</Root>
|
||||||
|
</Loggers>
|
||||||
|
</Configuration>
|
||||||
Loading…
x
Reference in New Issue
Block a user