package codeine.statistics;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import org.apache.log4j.Logger;
import codeine.api.CommandExecutionStatusInfo;
import codeine.api.NodeGetter;
import codeine.api.NodeWithMonitorsInfo;
import codeine.configuration.ConfigurationReadManagerServer;
import codeine.configuration.IConfigurationManager;
import codeine.configuration.PathHelper;
import codeine.jsons.project.ProjectJson;
import codeine.utils.FilesUtils;
import codeine.utils.LimitedQueue;
import codeine.utils.SerializationUtils;
import codeine.utils.StringUtils;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
public class MonitorsStatistics implements IMonitorStatistics{
private static final Logger log = Logger.getLogger(MonitorsStatistics.class);
private static final int SAMPLE_TIME_MINUTES = 5;
private static final int MAX_SIZE =(int) (TimeUnit.DAYS.toMinutes(60) / SAMPLE_TIME_MINUTES);
@Inject private IConfigurationManager configurationManager;
@Inject private NodeGetter nodesGetter;
@Inject private PathHelper pathHelper;
private Map<String, LimitedQueue<MonitorStatusItem>> data = Maps.newConcurrentMap();
private Multimap<String, CommandExecutionStatusInfo> commands = Multimaps.synchronizedSetMultimap(HashMultimap.<String,CommandExecutionStatusInfo>create());
public static final long SLEEP_TIME = TimeUnit.MINUTES.toMillis(SAMPLE_TIME_MINUTES);
public MonitorsStatistics() {
super();
}
public void restore() {
try {
String statisticsFile = pathHelper.getStatisticsFile();
if (FilesUtils.exists(statisticsFile)) {
log.info("reading statistics from " + statisticsFile);
data = SerializationUtils.fromFile(statisticsFile);
} else {
//make sure directory exists
FilesUtils.mkdirs(pathHelper.getPersistentDir());
}
} catch (Exception e) {
log.warn("failed to read statistics, will reset", e);
}
}
/* (non-Javadoc)
* @see codeine.statistics.IMonitorStatistics#getDataJson(java.lang.String)
*/
@Override
public List<MonitorStatusItem> getData(String projectName) {
LimitedQueue<MonitorStatusItem> d = data.get(projectName);
if (null == d){
return Lists.newArrayList();
}
ArrayList<MonitorStatusItem> l;
synchronized (d) {
l = Lists.newArrayList(d.subList(0, Math.min(d.size(), 1000)));
}
Collections.reverse(l);
return l;
}
@Override
public void run() {
collectData();
}
private void collectData() {
long currentTime = System.currentTimeMillis();
List<ProjectJson> projects = configurationManager.getConfiguredProjects();
projects.add(ConfigurationReadManagerServer.NODES_INTERNAL_PROJECT);
for (ProjectJson projectJson : projects) {
try {
collectForProject(currentTime, projectJson);
} catch (Exception e) {
log.warn("error collecting for project " + projectJson.name(), e);
}
}
log.info("saving statistics data to file");
SerializationUtils.toFile(pathHelper.getStatisticsFile(), data);
}
private void collectForProject(long currentTime, ProjectJson projectJson) {
{
int fail = 0, success = 0;
List<NodeWithMonitorsInfo> nodes = nodesGetter.getNodes(projectJson.name());
for (NodeWithMonitorsInfo nodeWithMonitorsInfo : nodes) {
if (nodeWithMonitorsInfo.status()) {
success++;
} else {
fail++;
}
}
LimitedQueue<MonitorStatusItem> projectData = data.get(projectJson.name());
if (projectData == null) {
projectData = new LimitedQueue<>(MAX_SIZE);
data.put(projectJson.name(), projectData);
}
if (success + fail == 0 && projectData.isEmpty()){
log.info("ignoring empty statistics on project " + projectJson.name());
return;
}
int total_nodes = 0;
String commands_name = StringUtils.EMPTY;
Collection<CommandExecutionStatusInfo> projectCommands = commands.get(projectJson.name());
boolean firstCommand = true;
synchronized (projectCommands) {
for (Iterator<CommandExecutionStatusInfo> iterator = projectCommands.iterator(); iterator.hasNext();) {
CommandExecutionStatusInfo command = (CommandExecutionStatusInfo) iterator.next();
total_nodes += command.nodes_list().size();
if (!firstCommand) {
commands_name += ",";
firstCommand = false;
}
commands_name += command.command();
iterator.remove();
}
}
MonitorStatusItem item = new MonitorStatusItem(StringUtils.formatDate(currentTime),currentTime, success, fail, total_nodes, commands_name);
synchronized (projectData) {
projectData.addFirst(item);
}
log.info("Project: " + projectJson.name() + " , Total Success: " + success + " , Total Fail: " + fail);
}
}
@Override
public void updateCommand(CommandExecutionStatusInfo command) {
commands.put(command.project_name(), command);
}
}