package net.iponweb.disthene.reader; import net.iponweb.disthene.reader.config.DistheneReaderConfiguration; import net.iponweb.disthene.reader.config.ThrottlingConfiguration; import net.iponweb.disthene.reader.handler.*; import net.iponweb.disthene.reader.server.ReaderServer; import net.iponweb.disthene.reader.service.index.IndexService; import net.iponweb.disthene.reader.service.metric.MetricService; import net.iponweb.disthene.reader.service.stats.StatsService; import net.iponweb.disthene.reader.service.store.CassandraService; import net.iponweb.disthene.reader.service.throttling.ThrottlingService; import org.apache.commons.cli.*; import org.apache.log4j.Logger; import org.yaml.snakeyaml.Yaml; import sun.misc.Signal; import sun.misc.SignalHandler; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Paths; /** * @author Andrei Ivanov */ public class DistheneReader { private static final String DEFAULT_CONFIG_LOCATION = "/etc/disthene-reader/disthene-reader.yaml"; private static final String DEFAULT_LOG_CONFIG_LOCATION = "/etc/disthene-reader/disthene-reader-log4j.xml"; private static final String DEFAULT_THROTTLING_CONFIG_LOCATION = "/etc/disthene-reader/throttling.yaml"; private static final String METRICS_PATH = "^/metrics\\/?$"; private static final String PATHS_PATH = "^/paths\\/?$"; private static final String PING_PATH = "^/ping\\/?$"; private static final String RENDER_PATH = "^/render\\/?$"; private static final String SEARCH_PATH = "^/search\\/?$"; private static Logger logger; private String configLocation; private String throttlingConfigLocation; private ReaderServer readerServer; private IndexService indexService; private CassandraService cassandraService; private MetricService metricService; private StatsService statsService; private ThrottlingService throttlingService; private DistheneReader(String configLocation, String throttlingConfigLocation) { this.configLocation = configLocation; this.throttlingConfigLocation = throttlingConfigLocation; } private void run() { try { Yaml yaml = new Yaml(); InputStream in = Files.newInputStream(Paths.get(configLocation)); DistheneReaderConfiguration distheneReaderConfiguration = yaml.loadAs(in, DistheneReaderConfiguration.class); in.close(); logger.info("Running with the following config: " + distheneReaderConfiguration.toString()); ThrottlingConfiguration throttlingConfiguration; File file = new File(throttlingConfigLocation); if(file.exists() && !file.isDirectory()) { logger.info("Loading throttling rules"); in = Files.newInputStream(Paths.get(throttlingConfigLocation)); throttlingConfiguration = yaml.loadAs(in, ThrottlingConfiguration.class); in.close(); } else { throttlingConfiguration = new ThrottlingConfiguration(); } logger.debug("Running with the following throttling configuration: " + throttlingConfiguration.toString()); logger.info("Creating throttling"); throttlingService = new ThrottlingService(throttlingConfiguration); logger.info("Creating stats"); statsService = new StatsService(distheneReaderConfiguration.getStats()); logger.info("Creating reader"); readerServer = new ReaderServer(distheneReaderConfiguration.getReader()); logger.info("Creating index service"); indexService = new IndexService(distheneReaderConfiguration.getIndex()); logger.info("Creating C* service"); cassandraService = new CassandraService(distheneReaderConfiguration.getStore()); logger.info("Creating metric service"); metricService = new MetricService(indexService, cassandraService, statsService, distheneReaderConfiguration); logger.info("Creating paths handler"); PathsHandler pathsHandler = new PathsHandler(indexService, statsService); readerServer.registerHandler(PATHS_PATH, pathsHandler); logger.info("Creating metrics handler"); MetricsHandler metricsHandler = new MetricsHandler(metricService); readerServer.registerHandler(METRICS_PATH, metricsHandler); logger.info("Creating ping handler"); PingHandler pingHandler = new PingHandler(); readerServer.registerHandler(PING_PATH, pingHandler); logger.info("Creating render handler"); RenderHandler renderHandler = new RenderHandler(metricService, statsService, throttlingService, distheneReaderConfiguration.getReader()); readerServer.registerHandler(RENDER_PATH, renderHandler); logger.info("Creating search handler"); SearchHandler searchHandler = new SearchHandler(indexService, statsService); readerServer.registerHandler(SEARCH_PATH, searchHandler); logger.info("Starting reader"); readerServer.run(); Signal.handle(new Signal("TERM"), new SigtermSignalHandler()); Signal.handle(new Signal("HUP"), new SighupSignalHandler()); } catch (IOException e) { logger.error(e); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { Options options = new Options(); options.addOption("c", "config", true, "config location"); options.addOption("l", "log-config", true, "log config location"); options.addOption("t", "throttling-config", true, "throttling config location"); CommandLineParser parser = new GnuParser(); try { CommandLine commandLine = parser.parse(options, args); System.getProperties().setProperty("log4j.configuration", "file:" + commandLine.getOptionValue("l", DEFAULT_LOG_CONFIG_LOCATION)); logger = Logger.getLogger(DistheneReader.class); new DistheneReader(commandLine.getOptionValue("c", DEFAULT_CONFIG_LOCATION), commandLine.getOptionValue("t", DEFAULT_THROTTLING_CONFIG_LOCATION)).run(); } catch (ParseException e) { HelpFormatter formatter = new HelpFormatter(); formatter.printHelp("Disthene", options); } catch (Exception e) { System.out.println("Start failed"); e.printStackTrace(); } } private class SigtermSignalHandler implements SignalHandler { @Override public void handle(Signal signal) { logger.info("Shutting down carbon server"); readerServer.shutdown(); logger.info("Shutting down index service"); indexService.shutdown(); logger.info("Shutting down C* service"); cassandraService.shutdown(); logger.info("Shutting down stats service"); statsService.shutdown(); logger.info("Shutdown complete"); System.exit(0); } } private class SighupSignalHandler implements SignalHandler { @Override public void handle(Signal signal) { logger.info("Received sighup"); logger.info("Reloading throttling configuration"); try { ThrottlingConfiguration throttlingConfiguration; File file = new File(throttlingConfigLocation); if(file.exists() && !file.isDirectory()) { Yaml yaml = new Yaml(); logger.info("Loading throttling configuration"); InputStream in = Files.newInputStream(Paths.get(throttlingConfigLocation)); throttlingConfiguration = yaml.loadAs(in, ThrottlingConfiguration.class); in.close(); } else { throttlingConfiguration = new ThrottlingConfiguration(); } throttlingService.reload(throttlingConfiguration); logger.debug("Running with the following throttling configuration: " + throttlingConfiguration.toString()); } catch (Exception e) { logger.error("Reloading throttling configuration failed"); logger.error(e); } } } }