
com.github.endoscope.storage.jdbc.JdbcStorage Maven / Gradle / Ivy
package com.github.endoscope.storage.jdbc;
import com.github.endoscope.core.Stat;
import com.github.endoscope.core.Stats;
import com.github.endoscope.storage.Filters;
import com.github.endoscope.storage.StatDetails;
import com.github.endoscope.storage.Storage;
import com.github.endoscope.storage.jdbc.dto.GroupEntity;
import com.github.endoscope.storage.jdbc.dto.StatEntity;
import com.github.endoscope.storage.jdbc.handler.GroupEntityHandler;
import com.github.endoscope.storage.jdbc.handler.StatEntityHandler;
import com.github.endoscope.storage.jdbc.handler.StringHandler;
import com.github.endoscope.util.DateUtil;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import static com.github.endoscope.storage.jdbc.ListUtil.emptyIfNull;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.time.DateUtils.setMilliseconds;
import static org.slf4j.LoggerFactory.getLogger;
public class JdbcStorage implements Storage {
private static final Logger log = getLogger(JdbcStorage.class);
private QueryRunnerExt run;
private GroupEntityHandler groupHandler = new GroupEntityHandler();
private StatEntityHandler statHandler = new StatEntityHandler();
private StringHandler stringHandler = new StringHandler();
private String tablePrefix = "";
public JdbcStorage setTablePrefix(String tablePrefix){
this.tablePrefix = tablePrefix;
return this;
}
/**
* Accepts following input parameters:
* - class name of your com.github.endoscope.storage.jdbc.DataSourceProvider implementation
* - JDBC connection string for com.github.endoscope.basic.ds.BasicDataSourceProvider
* (if included on class path)
* - JNDI name of DataSource object
* @param initParam
*/
@Override
public void setup(String initParam) {
DataSource ds = DataSourceHelper.findDatasource(initParam);
if( ds == null ){
throw new IllegalStateException("Cannot setup storage without DataSource");
}
run = new QueryRunnerExt(ds);
}
public QueryRunnerExt getRun() {
return run;
}
public void setRun(QueryRunnerExt run) {
this.run = run;
}
@Override
public String save(Stats stats, String instance, String type) {
return replace(null, stats, instance, type);
}
@Override
public void cleanup(int daysToKeep, String type) {
if( daysToKeep <= 0 ){
log.debug("cleanup disabled - skipping");
return;
}
List groupsToDelete = null;
Date date = DateUtils.addDays(new Date(), -1 * daysToKeep);
Timestamp ts = new Timestamp(date.getTime());
try{
log.debug("searching for groups to delete. Table prefix:{}, days to keep: {}", tablePrefix, daysToKeep);
groupsToDelete = run.queryExt(10,
" SELECT id " +
" FROM "+tablePrefix+"endoscopeGroup " +
" WHERE 1=1" +
" AND enddate < ?" +
" AND appType = ?" +
" LIMIT 10",
stringHandler, ts, type);
if( groupsToDelete.isEmpty() ){
log.debug("nothing to cleanup");
return;
}
log.debug("Found groups to clean: {}", groupsToDelete);
log.debug("cleaning stats");
run.update("DELETE FROM "+tablePrefix+"endoscopeStat WHERE groupId in(" + listOfArgs(groupsToDelete.size()) + ")",
groupsToDelete.toArray());
log.debug("cleaning groups");
run.update("DELETE FROM "+tablePrefix+"endoscopeGroup WHERE id in(" + listOfArgs(groupsToDelete.size()) + ")",
groupsToDelete.toArray());
log.debug("completed cleanup");
} catch (SQLException e) {
throw new RuntimeException("Failed to cleanup groups: " + groupsToDelete, e);
}
}
@Override
public String replace(String statsId, Stats stats, String instance, String type) {
try{
try(Connection conn = run.getDataSource().getConnection()){
conn.setAutoCommit(false);
try{
if( isNotBlank(statsId) ){
List groups = run.query(conn, "SELECT id FROM "+tablePrefix+"endoscopeGroup WHERE id = ? FOR UPDATE", stringHandler, statsId);
if( groups.size() != 1 ){
throw new RuntimeException("Failed to lock group with ID: " + statsId + " - ABORTING");
}
run.update(conn, "DELETE FROM "+tablePrefix+"endoscopeGroup WHERE id = ? ", statsId);
run.update(conn, "DELETE FROM "+tablePrefix+"endoscopeStat WHERE groupId = ? ", statsId);
}
String groupId = UUID.randomUUID().toString();
insertGroup(stats, conn, groupId, instance, type);
insertStats(stats, conn, groupId);
conn.commit();
return groupId;
}catch(Exception e){
conn.rollback();
throw new RuntimeException(e);
}
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
private void insertGroup(Stats stats, Connection conn, String groupId, String instance, String type) throws SQLException {
int u = run.update(conn,
"INSERT INTO "+tablePrefix+"endoscopeGroup(id, startDate, endDate, statsLeft, lost, fatalError, appGroup, appType) " +
" values( ?, ?, ?, ?, ?, ?, ?, ?)",
groupId,
new Timestamp(setMilliseconds(stats.getStartDate(), 0).getTime()),
new Timestamp(setMilliseconds(stats.getEndDate(), 0).getTime()),
stats.getStatsLeft(),
stats.getLost(),
stats.getFatalError(),
instance,
type
);
if( u != 1 ){
throw new RuntimeException("Failed to insert stats group. Expected 1 result but got: " + u);
}
}
protected void insertStats( Stats stats, Connection conn, String groupId) throws SQLException {
Object[][] data = prepareStatsData(groupId, stats);
int[] result = run.batch(conn,
//endoscopeStat OR endoscopeDailyStat
"INSERT INTO "+tablePrefix+"endoscopeStat(id, groupId, parentId, rootId, name, hits, max, min, avg, ah10, hasChildren) " +
" values( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
data);
long errors = Arrays.stream(result)
.filter( i -> i < 0 && i != Statement.SUCCESS_NO_INFO )
.count();
if( errors > 0 ){
throw new RuntimeException("Failed to insert stats. Got " + errors + " errors");
}
}
private Object[][] prepareStatsData(String groupId, Stats stats) {
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy