Introduction

SpaceIO is made for developers who want to monitor their plugin statistics with low effort. Also, the plugin statistic pages are generated automatically, so you don't need to configure them. Currently, SpaceIO only supports Spigot, including Bukkit.

Implementation

In order to use our service, your plugin needs to send data to our servers. To do so, we're providing a metrics java class file on GitHub . This class automatically collects system relevant information and sends this information to our server. Keep in mind that you need to call the class constructor upon the enabling process of your plugin.

Metrics.java class:
        
  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
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package de.Linus122.SpaceIOMetrics;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

import javax.net.ssl.HttpsURLConnection;

import org.bukkit.plugin.Plugin;

import com.google.gson.Gson;


/*
 * SpaceIOMetrics main class by Linus122
 * version: 0.07
 * 
 */

public class Metrics {
	private Plugin pl;
	private final Gson gson = new Gson();
	
	private String URL = "https://spaceio.xyz/update/%s";
	private final String VERSION = "0.07";
	private int REFRESH_INTERVAL = 600000;
	
	public Metrics(Plugin pl){
		this.pl = pl;
		
		// check if Metrics are disabled (checks if file "disablemetrics" is added to the plugins's folder
		try {
			Files.list(pl.getDataFolder().getParentFile().toPath()).filter(Files::isRegularFile).forEach(v -> {
				if(v.getFileName().toString().equalsIgnoreCase("disablemetrics")){
					return;
				}
			});
		} catch (IOException e1) {
			e1.printStackTrace();
		}

		URL = String.format(URL, pl.getName());
		
		// fetching refresh interval first
		pl.getServer().getScheduler().runTaskLaterAsynchronously(pl, () -> {
			String dataJson = collectData();
			try{
				REFRESH_INTERVAL = sendData(dataJson);
			}catch(Exception e){}
		}, 20L * 5);
		
		// executing repeating task, our main metrics updater
		pl.getServer().getScheduler().runTaskTimerAsynchronously(pl, () -> {
			String dataJson = collectData();
			try{
				sendData(dataJson);
			}catch(Exception e){}
			
		}, 20L * (REFRESH_INTERVAL / 1000), 20L * (REFRESH_INTERVAL / 1000));
	}
	private String collectData() {
		Data data = new Data();
		
		// collect plugin list
		for(Plugin plug : pl.getServer().getPluginManager().getPlugins()) data.plugs.put(plug.getName(), plug.getDescription().getVersion());
		
		// fetch online players
		data.onlinePlayers = pl.getServer().getOnlinePlayers().size();
		
		// server version
		data.serverVersion = getVersion();
		
		// plugin version
		data.pluginVersion = pl.getDescription().getVersion();
		
		// plugin author
		data.pluginAuthors = pl.getDescription().getAuthors();
		
		// core count
		data.coreCnt = Runtime.getRuntime().availableProcessors();
		
		// java version
		data.javaRuntime = System.getProperty("java.runtime.version");
		
		// online mode
		data.onlineMode = pl.getServer().getOnlineMode();

		// software information
		data.osName = System.getProperty("os.name");
		data.osArch = System.getProperty("os.arch");
		data.osVersion = System.getProperty("os.version");
		
		String executableName = new java.io.File(Metrics.class.getProtectionDomain()
				  .getCodeSource()
				  .getLocation()
				  .getPath())
				.getName();
		data.executableName = executableName;
		
		if(data.osName.equals("Linux")){
			data.linuxDistro = getDistro();
		}
		
		return gson.toJson(data);
	}
	private int sendData(String dataJson) throws Exception{
		java.net.URL obj = new java.net.URL(URL);
		HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();

		con.setRequestMethod("POST");
		con.setRequestProperty("User-Agent", "Java/Bukkit");
		con.setRequestProperty("Metrics-Version", this.VERSION);

		con.setDoOutput(true);
		DataOutputStream wr = new DataOutputStream(con.getOutputStream());
		wr.writeBytes(dataJson);
		wr.flush();
		wr.close();
		
		return Integer.parseInt(con.getHeaderField("interval-millis"));
	}
	private String getVersion(){
        String packageName = pl.getServer().getClass().getPackage().getName();
        return  packageName.substring(packageName.lastIndexOf('.') + 1);
	}
	// method source: http://www.jcgonzalez.com/linux-get-distro-from-java-examples
	private String getDistro(){
		
		// lists all the files ending with -release in the etc folder
        File dir = new File("/etc/");
        File fileList[] = new File[0];
        if(dir.exists()){
            fileList =  dir.listFiles(new FilenameFilter() {
                public boolean accept(File dir, String filename) {
                    return filename.endsWith("-release");
                }
            });
        }
        try {
	        // looks for the version file (not all linux distros)
	        File fileVersion = new File("/proc/version");
	        if(fileVersion.exists() && fileList.length > 0){
	            fileList = Arrays.copyOf(fileList,fileList.length+1);
	            fileList[fileList.length-1] = fileVersion;
	        }    
	        
	        // prints first version-related file
	        for (File f : fileList) {
	                BufferedReader br = new BufferedReader(new FileReader(f));
	                String strLine = null;
	                while ((strLine = br.readLine()) != null) {
	                    return strLine;
	                }
	                br.close();
	        }
        } catch (Exception e) {
        	// Exception is thrown when something went wrong while obtaining the distribution name.
        }
		return "unknown";    
	}
}
class Data {
	HashMap<String, String> plugs = new HashMap<String, String>();
	int onlinePlayers;
	String pluginVersion;
	public List<String> pluginAuthors;
	String serverVersion;
	
	int coreCnt;
	String javaRuntime;
	
	String executableName;
	boolean onlineMode;
	
	String osName;
	String osArch;
	String osVersion;
	String linuxDistro;
}
Minimal implementation example:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
package de.Linus122.SpaceIOMetrics;

import org.bukkit.plugin.java.JavaPlugin;


public class BukkitMain extends JavaPlugin{
	@Override
	public void onEnable(){
		// Initializing metrics
		new Metrics(this);
	}
}

After that, your plugin statistics should now be served on https://spaceio.xyz/plugin/<pluginname>

Building with Maven:

Integrating the metrics with Maven is also pretty simple, considering you already set up a Maven project. You can read on this page how to get Spigot working with Maven.
To integrate SpaceIO, you need to add our repository to your pom.xml:

1
2
3
4
<repository>
  <id>spaceio-snapshots</id>
  <url>https://hub.spaceio.de/repository/maven-snapshots/</url>
</repository>

After that, you have to add SpaceIO to your dependencies along with the maven-shade-plugin. The shade plugin is requiered in order to get the SpaceIO Metrics source files exported to the generated plugin jar.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<!--SpaceIO Metrics -->
<dependency>
  <groupId>de.spaceio</groupId>
  <artifactId>SpaceIOMetrics</artifactId>
  <version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- maven-shade-plugin -->
<dependency>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <version>3.1.0</version>
</dependency>

The shade plugin needs to be configured as follows:

 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
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <version>3.1.0</version>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <artifactSet>
          <includes>
            <include>de.spaceio:SpaceIOMetrics</include>
          </includes>
        </artifactSet>
        <filters>
          <filter>
            <artifact>de.spaceio:SpaceIOMetrics</artifact>
            <includes>
              <include>**</include>
            </includes>
          </filter>
        </filters>
      </configuration>
    </execution>
  </executions>
</plugin>

Thus you will get a pom.xml nearly similiar to this:

 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
83
84
85
86
87
<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>get-plugin</groupId>
  <artifactId>get-plugin</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <build>
    <sourceDirectory>src</sourceDirectory>
    <resources>
      <resource>
        <directory>src</directory>
        <excludes>
          <exclude>**/*.java</exclude>
        </excludes>
      </resource>
    </resources>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.5.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.1.0</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <artifactSet>
                <includes>
                  <include>de.spaceio:SpaceIOMetrics</include>
                </includes>
              </artifactSet>
              <filters>
                <filter>
                  <artifact>de.spaceio:SpaceIOMetrics</artifact>
                  <includes>
                    <include>**</include>
                  </includes>
                </filter>
              </filters>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  <repositories>
    <repository>
      <id>spigot-repo</id>
      <url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
    </repository>
    <repository>
      <id>spaceio-snapshots</id>
      <url>https://hub.spaceio.de/repository/maven-snapshots/</url>
    </repository>
  </repositories>
  <dependencies>
    <!--Spigot API  -->
    <dependency>
      <groupId>org.spigotmc</groupId>
      <artifactId>spigot-api</artifactId>
      <version>1.12.2-R0.1-SNAPSHOT</version>
      <scope>provided</scope>
    </dependency>
    <!--SpaceIO Metrics  -->
    <dependency>
      <groupId>de.spaceio</groupId>
      <artifactId>SpaceIOMetrics</artifactId>
      <version>0.0.1-SNAPSHOT</version>
    </dependency>
    <!--  maven-shade-plugin  -->
    <dependency>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-shade-plugin</artifactId>
      <version>3.1.0</version>
    </dependency>
  </dependencies>
</project>

Building with Gradle:

Gradle is used along with Jitpack to simplify the build process, and makes the code more easy to integrate:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
apply plugin: 'java'

repositories {
    jcenter()
    maven { url 'https://jitpack.io' }
}

dependencies {
    compile 'com.github.Mastercake10:SpaceIOMetrics:-SNAPSHOT'
}

Signature images

For each plugin, you have the ability to use a custom link for generating the line chart as an image. This feature is very usefull for forums. The link layout looks like this: https://spaceio.xyz/plugin/<pluginname>/toimg

Example statistics: