diff options
Diffstat (limited to 'src/main/java/com/gitblit/instance/GitblitInstance.java')
-rw-r--r-- | src/main/java/com/gitblit/instance/GitblitInstance.java | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/src/main/java/com/gitblit/instance/GitblitInstance.java b/src/main/java/com/gitblit/instance/GitblitInstance.java new file mode 100644 index 00000000..ca1fda38 --- /dev/null +++ b/src/main/java/com/gitblit/instance/GitblitInstance.java @@ -0,0 +1,212 @@ +package com.gitblit.instance; + +import com.gitblit.IStoredSettings; +import com.gitblit.manager.IRuntimeManager; +import com.gitblit.utils.JsonUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import static com.gitblit.utils.JsonUtils.sendJsonString; + +public class GitblitInstance +{ + private final static String STATS_URL = "https://instats.gitblit.dev/hiitsme/"; + private final static Logger LOG = LoggerFactory.getLogger(GitblitInstance.class); + + private IRuntimeManager runtimeManager; + + private String instanceId; + + private GitblitInstanceReport report; + + private ScheduledExecutorService executor; + + + /** + * Initialize the Gitblit instance reporting system. + * + * This will gather the static and dynamic statistics about the running + * instance, so that they can be reported. + * + * @param runtimeManager + * The runtime manager is used to determine the type of instance + * as well as for some other settings and data. + */ + public void init(IRuntimeManager runtimeManager) { + this.runtimeManager = runtimeManager; + + // Initialize ID + GitblitInstanceId instanceId = new GitblitInstanceId(runtimeManager.getBaseFolder()); + this.instanceId = instanceId.getId().toString(); + LOG.info(this.instanceId); + + GitblitInstanceStat instanceStat; + + if (runtimeManager.getSettings().hasSettings("container.dockerfileVersion")) { + instanceStat = new GitblitInstanceStat(GitblitInstanceStat.GitblitInstanceType.DOCKER); + } + else if (runtimeManager.getStatus().isGO){ + instanceStat = new GitblitInstanceStat(GitblitInstanceStat.GitblitInstanceType.GO); + } + else { + instanceStat = new GitblitInstanceStat(GitblitInstanceStat.GitblitInstanceType.WAR); + } + + instanceStat.init(runtimeManager.getStatus()); + + this.report = new GitblitInstanceReport(this.instanceId, instanceStat); + } + + + public void start() + { + if (shouldRunReports()) { + startReports(); + } + } + + public void stop() + { + if (this.executor != null && !this.executor.isShutdown() && !this.executor.isTerminated()) { + this.executor.shutdownNow(); + System.out.println("Gitblit instance reporting task stopped."); + } + } + + + + /** + * Determine if the reporting task should run. + * + * We do not want to report anything, i.e. the reporting task to run, + * if we are running unit tests or integration tests. + * Instance reports should only be sent for production instances or released versions. + * Therefore we also check if the Gitblit version is a SNAPSHOT version, + * or if the docker image is not a release version, when running from a docker image. + * A docker image running under GOSS should also not report anything. + */ + boolean shouldRunReports() + { + // We can only run reports when we have been initialized + if (this.report == null || this.runtimeManager == null) { + return false; + } + + // Check if we are running in a test environment + IStoredSettings settings = this.runtimeManager.getSettings(); + if (! settings.getString("gitblit.testReportingUrl", "").isEmpty()) { + // Force reporting to run overriding any test settings + LOG.debug("Enabled reporting to test server URL: {}", settings.getString("gitblit.testReportingUrl", "")); + return true; + } + if (settings.getBoolean("gitblit.testRun", false)) { + return false; + } + + // Check if we are running a SNAPSHOT version + if (this.runtimeManager.getStatus().version.endsWith("SNAPSHOT")) { + return false; + } + + if (this.report.instanceStat.instanceType == GitblitInstanceStat.GitblitInstanceType.DOCKER) { + // Check if we are running a docker image that is not a release version + if (! settings.getString("container.imageType", "").equals("release")) { + return false; + } + + // Check if we are running a docker image under GOSS + if (System.getenv("GITBLIT_GOSS_TEST") != null) { + return false; + } + } + + return true; + } + + + /** + * Start the reporting task. + * + * This will start a thread that runs once a day and sends the instance + * report to the popularity report server. + */ + private void startReports() + { + this.executor = Executors.newSingleThreadScheduledExecutor(); + + String statsUrl = STATS_URL; + int delay = 24; + int period = 24 * 60; // 24 hours in minutes + TimeUnit unit = TimeUnit.MINUTES; + long retryInterval = 60 * 60 * 1000; // 1 hour in milliseconds + final long retryTimeout = 20 * 60 * 60 * 1000; // 20 hours in milliseconds + + // If we are running in a test environment, we will send the reports more frequently + String testUrl = this.runtimeManager.getSettings().getString("gitblit.testReportingUrl", ""); + if (! testUrl.isEmpty()) { + statsUrl = testUrl; + delay = 10; + period = 24; + unit = TimeUnit.SECONDS; + retryInterval = 10 * 1000; // 10 seconds in milliseconds + } + + final String baseUrl = statsUrl; + final long retryIntervalFinal = retryInterval; + this.executor.scheduleAtFixedRate(new Runnable() + { + @Override + public void run() + { + sendMyStats(baseUrl + instanceId, retryIntervalFinal, retryTimeout); + } + }, delay, period, unit); + } + + /** + * Send the instance report to the popularity report server. + * + * This will send a JSON object to the server with the instance report. + * + * @param reportUrl + * The URL to send the report to. + * @param retryInterval + * The interval in milliseconds to wait before retrying to send the report if it failed. + * @param retryTimeout + * The timeout in milliseconds to give up sending the report if it fails repeatedly. + */ + private void sendMyStats(String reportUrl, long retryInterval, long retryTimeout) + { + // Create a HTTP POST request payload + String report = JsonUtils.toJsonString(this.report.fromNow()); + + int status = 0; + long timeToGiveup = System.currentTimeMillis() + retryTimeout; + while (status != 200 && System.currentTimeMillis() < timeToGiveup) { + try { + status = sendJsonString(reportUrl, report, "gitblitta", "countmein".toCharArray()); + if (status != 200) { + LOG.debug("Error sending stats to " + reportUrl + ": " + status); + } + } + catch (IOException e) { + LOG.debug("Exception sending stats to " + reportUrl + ": " + e.getMessage()); + } + + if (status != 200) { + try { + Thread.sleep(retryInterval); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return; // exit if interrupted + } + } + } + } + +} |