19 package org.sleuthkit.autopsy.healthmonitor;
21 import com.google.common.util.concurrent.ThreadFactoryBuilder;
22 import java.beans.PropertyChangeEvent;
23 import java.beans.PropertyChangeListener;
24 import java.sql.Connection;
25 import java.sql.DriverManager;
26 import java.sql.PreparedStatement;
27 import java.sql.ResultSet;
28 import java.sql.SQLException;
29 import java.sql.Statement;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.ArrayList;
34 import java.util.Calendar;
35 import java.util.GregorianCalendar;
36 import java.util.UUID;
37 import java.util.concurrent.ScheduledThreadPoolExecutor;
38 import java.util.concurrent.TimeUnit;
39 import java.util.concurrent.atomic.AtomicBoolean;
40 import java.util.logging.Level;
41 import java.util.Random;
42 import org.apache.commons.dbcp2.BasicDataSource;
51 import org.
sleuthkit.datamodel.CaseDbSchemaVersionNumber;
70 =
new CaseDbSchemaVersionNumber(1, 1);
72 private static final AtomicBoolean
isEnabled =
new AtomicBoolean(
false);
87 timingInfoMap =
new HashMap<>();
91 userInfoList =
new ArrayList<>();
95 hostName = java.net.InetAddress.getLocalHost().getHostName();
96 }
catch (java.net.UnknownHostException ex) {
98 hostName = UUID.randomUUID().toString();
99 logger.log(Level.SEVERE,
"Unable to look up host name - falling back to UUID " + hostName, ex);
103 updateFromGlobalEnabledStatus();
115 if (instance == null) {
130 logger.log(Level.INFO,
"Activating Servies Health Monitor");
136 throw new HealthMonitorException(
"Multi user mode is not enabled - can not activate health monitor");
142 throw new HealthMonitorException(
"Error getting database lock");
161 throw new HealthMonitorException(
"Error releasing database lock", ex);
165 timingInfoMap.clear();
166 userInfoList.clear();
174 logger.log(Level.INFO,
"Upgrading Health Monitor database");
175 CaseDbSchemaVersionNumber currentSchema =
getVersion();
179 throw new HealthMonitorException(
"Error getting database connection");
182 try (Statement statement = conn.createStatement()) {
183 conn.setAutoCommit(
false);
187 if(currentSchema.compareTo(
new CaseDbSchemaVersionNumber(1,1)) < 0) {
190 statement.execute(
"CREATE TABLE IF NOT EXISTS user_data ("+
191 "id SERIAL PRIMARY KEY," +
192 "host text NOT NULL," +
193 "timestamp bigint NOT NULL," +
194 "event_type int NOT NULL," +
195 "is_examiner boolean NOT NULL," +
196 "case_name text NOT NULL" +
201 statement.execute(
"UPDATE db_info SET value='" +
CURRENT_DB_SCHEMA_VERSION.getMajor() +
"' WHERE name='SCHEMA_VERSION'");
202 statement.execute(
"UPDATE db_info SET value='" +
CURRENT_DB_SCHEMA_VERSION.getMinor() +
"' WHERE name='SCHEMA_MINOR_VERSION'");
206 }
catch (SQLException ex) {
209 }
catch (SQLException ex2) {
210 logger.log(Level.SEVERE,
"Rollback error");
212 throw new HealthMonitorException(
"Error upgrading database", ex);
216 }
catch (SQLException ex) {
217 logger.log(Level.SEVERE,
"Error closing connection.", ex);
231 logger.log(Level.INFO,
"Deactivating Servies Health Monitor");
234 timingInfoMap.clear();
247 healthMonitorOutputTimer =
new ScheduledThreadPoolExecutor(1,
new ThreadFactoryBuilder().setNameFormat(
"health_monitor_timer").build());
248 healthMonitorOutputTimer.scheduleWithFixedDelay(
new PeriodicHealthMonitorTask(), DATABASE_WRITE_INTERVAL, DATABASE_WRITE_INTERVAL, TimeUnit.MINUTES);
255 if(healthMonitorOutputTimer != null) {
264 static synchronized void startUpIfEnabled() throws HealthMonitorException {
273 static synchronized void shutdown() throws HealthMonitorException {
283 static synchronized void setEnabled(
boolean enabled)
throws HealthMonitorException {
284 if(enabled == isEnabled.get()) {
296 if(isEnabled.get()) {
300 isEnabled.set(
false);
316 if(isEnabled.get()) {
330 if(isEnabled.get() && (metric != null)) {
334 }
catch (HealthMonitorException ex) {
336 logger.log(Level.SEVERE,
"Error adding timing metric", ex);
351 if(isEnabled.get() && (metric != null)) {
354 metric.normalize(normalization);
356 }
catch (HealthMonitorException ex) {
358 logger.log(Level.SEVERE,
"Error adding timing metric", ex);
378 if(timingInfoMap.containsKey(metric.getName())) {
379 timingInfoMap.get(metric.getName()).addMetric(metric);
381 timingInfoMap.put(metric.getName(),
new TimingInfo(metric));
391 UserData userInfo =
new UserData(eventType);
393 userInfoList.add(userInfo);
410 List<Image> images = skCase.getImages();
414 long normalization = images.size();
415 if (images.isEmpty()) {
417 }
else if (images.size() == 1){
419 }
else if (images.size() < 10) {
428 }
catch (TskCoreException ex) {
429 throw new HealthMonitorException(
"Error running getImages()", ex);
447 Map<String, TimingInfo> timingMapCopy;
448 List<UserData> userDataCopy;
453 if(! isEnabled.get()) {
460 timingInfoMap.clear();
463 userInfoList.clear();
467 if(timingMapCopy.keySet().isEmpty() && userDataCopy.isEmpty()) {
471 logger.log(Level.INFO,
"Writing health monitor metrics to database");
476 throw new HealthMonitorException(
"Error getting database lock");
481 throw new HealthMonitorException(
"Error getting database connection");
485 String addTimingInfoSql =
"INSERT INTO timing_data (name, host, timestamp, count, average, max, min) VALUES (?, ?, ?, ?, ?, ?, ?)";
486 String addUserInfoSql =
"INSERT INTO user_data (host, timestamp, event_type, is_examiner, case_name) VALUES (?, ?, ?, ?, ?)";
487 try (PreparedStatement timingStatement = conn.prepareStatement(addTimingInfoSql);
488 PreparedStatement userStatement = conn.prepareStatement(addUserInfoSql)) {
490 for(String name:timingMapCopy.keySet()) {
493 timingStatement.setString(1, name);
494 timingStatement.setString(2, hostName);
495 timingStatement.setLong(3, System.currentTimeMillis());
496 timingStatement.setLong(4, info.getCount());
497 timingStatement.setDouble(5, info.getAverage());
498 timingStatement.setDouble(6, info.getMax());
499 timingStatement.setDouble(7, info.getMin());
501 timingStatement.execute();
504 for(UserData userInfo:userDataCopy) {
505 userStatement.setString(1, hostName);
506 userStatement.setLong(2, userInfo.getTimestamp());
507 userStatement.setInt(3, userInfo.getEventType().getEventValue());
508 userStatement.setBoolean(4, userInfo.isExaminerNode());
509 userStatement.setString(5, userInfo.getCaseName());
510 userStatement.execute();
513 }
catch (SQLException ex) {
514 throw new HealthMonitorException(
"Error saving metric data to database", ex);
518 }
catch (SQLException ex) {
519 logger.log(Level.SEVERE,
"Error closing Connection.", ex);
523 throw new HealthMonitorException(
"Error releasing database lock", ex);
537 Class.forName(
"org.postgresql.Driver");
539 try (Connection connection = DriverManager.getConnection(
"jdbc:postgresql://" + db.getHost() +
":" + db.getPort() +
"/postgres", db.getUserName(), db.getPassword());
540 Statement statement = connection.createStatement();) {
541 String createCommand =
"SELECT 1 AS result FROM pg_database WHERE datname='" + DATABASE_NAME +
"'";
542 rs = statement.executeQuery(createCommand);
552 throw new HealthMonitorException(
"Failed check for health monitor database", ex);
565 Class.forName(
"org.postgresql.Driver");
566 try (Connection connection = DriverManager.getConnection(
"jdbc:postgresql://" + db.getHost() +
":" + db.getPort() +
"/postgres", db.getUserName(), db.getPassword());
567 Statement statement = connection.createStatement();) {
568 String createCommand =
"CREATE DATABASE \"" + DATABASE_NAME +
"\" OWNER \"" + db.getUserName() +
"\"";
569 statement.execute(createCommand);
571 logger.log(Level.INFO,
"Created new health monitor database " + DATABASE_NAME);
573 throw new HealthMonitorException(
"Failed to delete health monitor database", ex);
584 connectionSettingsInUse = db;
586 connectionPool =
new BasicDataSource();
587 connectionPool.setDriverClassName(
"org.postgresql.Driver");
589 StringBuilder connectionURL =
new StringBuilder();
590 connectionURL.append(
"jdbc:postgresql://");
591 connectionURL.append(db.getHost());
592 connectionURL.append(
":");
593 connectionURL.append(db.getPort());
594 connectionURL.append(
"/");
595 connectionURL.append(DATABASE_NAME);
597 connectionPool.setUrl(connectionURL.toString());
598 connectionPool.setUsername(db.getUserName());
599 connectionPool.setPassword(db.getPassword());
602 connectionPool.setInitialSize(3);
603 connectionPool.setMaxIdle(CONN_POOL_SIZE);
604 connectionPool.setValidationQuery(
"SELECT version()");
606 throw new HealthMonitorException(
"Error loading database configuration", ex);
617 if(connectionPool != null){
618 connectionPool.close();
619 connectionPool = null;
622 }
catch (SQLException ex) {
623 throw new HealthMonitorException(
"Failed to close existing database connections.", ex);
633 private Connection
connect() throws HealthMonitorException {
634 synchronized (
this) {
635 if (connectionPool == null) {
641 return connectionPool.getConnection();
642 }
catch (SQLException ex) {
643 throw new HealthMonitorException(
"Error getting connection from connection pool.", ex);
656 throw new HealthMonitorException(
"Error getting database connection");
658 ResultSet resultSet = null;
660 try (Statement statement = conn.createStatement()) {
661 resultSet = statement.executeQuery(
"SELECT value FROM db_info WHERE name='SCHEMA_VERSION'");
662 return resultSet.next();
663 }
catch (SQLException ex) {
667 if(resultSet != null) {
670 }
catch (SQLException ex) {
671 logger.log(Level.SEVERE,
"Error closing result set", ex);
676 }
catch (SQLException ex) {
677 logger.log(Level.SEVERE,
"Error closing Connection.", ex);
687 static boolean monitorIsEnabled() {
688 return isEnabled.get();
696 synchronized void updateFromGlobalEnabledStatus() throws HealthMonitorException {
698 boolean previouslyEnabled = monitorIsEnabled();
701 if (!UserPreferences.getIsMultiUserModeEnabled()) {
702 isEnabled.set(
false);
704 if(previouslyEnabled) {
713 isEnabled.set(
false);
715 if(previouslyEnabled) {
723 if(previouslyEnabled && (connectionSettingsInUse != null)) {
725 CaseDbConnectionInfo currentSettings = UserPreferences.getDatabaseConnectionInfo();
726 if(! (connectionSettingsInUse.getUserName().equals(currentSettings.getUserName())
727 && connectionSettingsInUse.getPassword().equals(currentSettings.getPassword())
728 && connectionSettingsInUse.getPort().equals(currentSettings.getPort())
729 && connectionSettingsInUse.getHost().equals(currentSettings.getHost()) )) {
732 }
catch (UserPreferencesException ex) {
733 throw new HealthMonitorException(
"Error reading database connection info", ex);
738 if( currentlyEnabled != previouslyEnabled) {
739 if( ! currentlyEnabled ) {
740 isEnabled.set(
false);
757 try (Connection conn =
connect();
758 Statement statement = conn.createStatement();
759 ResultSet resultSet = statement.executeQuery(
"SELECT value FROM db_info WHERE name='MONITOR_ENABLED'")) {
761 if (resultSet.next()) {
762 return(resultSet.getBoolean(
"value"));
764 throw new HealthMonitorException(
"No enabled status found in database");
765 }
catch (SQLException ex) {
766 throw new HealthMonitorException(
"Error initializing database", ex);
776 try (Connection conn =
connect();
777 Statement statement = conn.createStatement();) {
778 statement.execute(
"UPDATE db_info SET value='" + status +
"' WHERE name='MONITOR_ENABLED'");
779 }
catch (SQLException ex) {
780 throw new HealthMonitorException(
"Error setting enabled status", ex);
789 private CaseDbSchemaVersionNumber
getVersion() throws HealthMonitorException {
792 throw new HealthMonitorException(
"Error getting database connection");
794 ResultSet resultSet = null;
796 try (Statement statement = conn.createStatement()) {
797 int minorVersion = 0;
798 int majorVersion = 0;
799 resultSet = statement.executeQuery(
"SELECT value FROM db_info WHERE name='SCHEMA_MINOR_VERSION'");
800 if (resultSet.next()) {
801 String minorVersionStr = resultSet.getString(
"value");
803 minorVersion = Integer.parseInt(minorVersionStr);
804 }
catch (NumberFormatException ex) {
805 throw new HealthMonitorException(
"Bad value for schema minor version (" + minorVersionStr +
") - database is corrupt");
809 resultSet = statement.executeQuery(
"SELECT value FROM db_info WHERE name='SCHEMA_VERSION'");
810 if (resultSet.next()) {
811 String majorVersionStr = resultSet.getString(
"value");
813 majorVersion = Integer.parseInt(majorVersionStr);
814 }
catch (NumberFormatException ex) {
815 throw new HealthMonitorException(
"Bad value for schema version (" + majorVersionStr +
") - database is corrupt");
819 return new CaseDbSchemaVersionNumber(majorVersion, minorVersion);
820 }
catch (SQLException ex) {
821 throw new HealthMonitorException(
"Error initializing database", ex);
823 if(resultSet != null) {
826 }
catch (SQLException ex) {
827 logger.log(Level.SEVERE,
"Error closing result set", ex);
832 }
catch (SQLException ex) {
833 logger.log(Level.SEVERE,
"Error closing Connection.", ex);
845 throw new HealthMonitorException(
"Error getting database connection");
848 try (Statement statement = conn.createStatement()) {
849 conn.setAutoCommit(
false);
851 statement.execute(
"CREATE TABLE IF NOT EXISTS timing_data (" +
852 "id SERIAL PRIMARY KEY," +
853 "name text NOT NULL," +
854 "host text NOT NULL," +
855 "timestamp bigint NOT NULL," +
856 "count bigint NOT NULL," +
857 "average double precision NOT NULL," +
858 "max double precision NOT NULL," +
859 "min double precision NOT NULL" +
862 statement.execute(
"CREATE TABLE IF NOT EXISTS db_info (" +
863 "id SERIAL PRIMARY KEY NOT NULL," +
864 "name text NOT NULL," +
865 "value text NOT NULL" +
868 statement.execute(
"CREATE TABLE IF NOT EXISTS user_data ("+
869 "id SERIAL PRIMARY KEY," +
870 "host text NOT NULL," +
871 "timestamp bigint NOT NULL," +
872 "event_type int NOT NULL," +
873 "is_examiner BOOLEAN NOT NULL," +
874 "case_name text NOT NULL" +
878 statement.execute(
"INSERT INTO db_info (name, value) VALUES ('SCHEMA_VERSION', '" +
CURRENT_DB_SCHEMA_VERSION.getMajor() +
"')");
879 statement.execute(
"INSERT INTO db_info (name, value) VALUES ('SCHEMA_MINOR_VERSION', '" +
CURRENT_DB_SCHEMA_VERSION.getMinor() +
"')");
880 statement.execute(
"INSERT INTO db_info (name, value) VALUES ('MONITOR_ENABLED', 'true')");
883 }
catch (SQLException ex) {
886 }
catch (SQLException ex2) {
887 logger.log(Level.SEVERE,
"Rollback error");
889 throw new HealthMonitorException(
"Error initializing database", ex);
893 }
catch (SQLException ex) {
894 logger.log(Level.SEVERE,
"Error closing connection.", ex);
903 static final class PeriodicHealthMonitorTask
implements Runnable {
920 getInstance().updateFromGlobalEnabledStatus();
921 if(monitorIsEnabled()) {
925 }
catch (HealthMonitorException ex) {
926 logger.log(Level.SEVERE,
"Error performing periodic task", ex);
933 switch (
Case.
Events.valueOf(evt.getPropertyName())) {
936 if ((null == evt.getNewValue()) && (evt.getOldValue() instanceof
Case)) {
940 }
else if((null == evt.getOldValue()) && (evt.getNewValue() instanceof
Case)) {
953 void populateDatabaseWithSampleData(
int nDays,
int nNodes,
boolean createVerificationData)
throws HealthMonitorException {
955 if(! isEnabled.get()) {
956 throw new HealthMonitorException(
"Can't populate database - monitor not enabled");
962 throw new HealthMonitorException(
"Error getting database lock");
965 String[] metricNames = {
"Disk Reads: Hash calculation",
"Database: getImages query",
"Solr: Index chunk",
"Solr: Connectivity check",
966 "Correlation Engine: Notable artifact query",
"Correlation Engine: Bulk insert"};
968 Random rand =
new Random();
970 long maxTimestamp = System.currentTimeMillis();
971 long millisPerHour = 1000 * 60 * 60;
972 long minTimestamp = maxTimestamp - (nDays * (millisPerHour * 24));
974 Connection conn = null;
978 throw new HealthMonitorException(
"Error getting database connection");
981 try (Statement statement = conn.createStatement()) {
983 statement.execute(
"DELETE FROM timing_data");
984 }
catch (SQLException ex) {
985 logger.log(Level.SEVERE,
"Error clearing timing data", ex);
992 String addTimingInfoSql =
"INSERT INTO timing_data (name, host, timestamp, count, average, max, min) VALUES (?, ?, ?, ?, ?, ?, ?)";
993 try (PreparedStatement statement = conn.prepareStatement(addTimingInfoSql)) {
995 for(String metricName:metricNames) {
997 long baseIndex = rand.nextInt(900) + 100;
998 int multiplier = rand.nextInt(5);
999 long minIndexTimeNanos;
1000 switch(multiplier) {
1002 minIndexTimeNanos = baseIndex;
1005 minIndexTimeNanos = baseIndex * 1000;
1008 minIndexTimeNanos = baseIndex * 1000 * 1000;
1012 long maxIndexTimeOverMin = minIndexTimeNanos * 3;
1014 for(
int node = 0;node < nNodes; node++) {
1016 String host =
"testHost" + node;
1019 double maxCount = nDays * 24 + 1;
1022 for(
long timestamp = minTimestamp + rand.nextInt(1000 * 60 * 55);timestamp < maxTimestamp;timestamp += millisPerHour) {
1029 double slowNodeMultiplier = 1.0;
1030 if((maxCount - count) <= 3 * 24) {
1031 slowNodeMultiplier += (3 - (maxCount - count) / 24) * 0.33;
1034 if( ! createVerificationData ) {
1037 int outlierVal = rand.nextInt(30);
1038 long randVal = rand.nextLong();
1043 aveTime = minIndexTimeNanos + maxIndexTimeOverMin + randVal % maxIndexTimeOverMin;
1044 }
else if(outlierVal == 2){
1045 aveTime = (minIndexTimeNanos / 2) + randVal % (minIndexTimeNanos / 2);
1046 }
else if(outlierVal < 17) {
1047 aveTime = minIndexTimeNanos + randVal % (maxIndexTimeOverMin / 2);
1049 aveTime = minIndexTimeNanos + randVal % maxIndexTimeOverMin;
1053 aveTime = aveTime * slowNodeMultiplier;
1059 Calendar thisDate =
new GregorianCalendar();
1060 thisDate.setTimeInMillis(timestamp);
1061 int day = thisDate.get(Calendar.DAY_OF_MONTH);
1062 aveTime = day * 1000000;
1066 statement.setString(1, metricName);
1067 statement.setString(2, host);
1068 statement.setLong(3, timestamp);
1069 statement.setLong(4, 0);
1070 statement.setDouble(5, aveTime / 1000000);
1071 statement.setDouble(6, 0);
1072 statement.setDouble(7, 0);
1074 statement.execute();
1078 }
catch (SQLException ex) {
1079 throw new HealthMonitorException(
"Error saving metric data to database", ex);
1086 }
catch (SQLException ex) {
1087 logger.log(Level.SEVERE,
"Error closing Connection.", ex);
1091 }
catch (CoordinationService.CoordinationServiceException ex) {
1092 throw new HealthMonitorException(
"Error releasing database lock", ex);
1103 Map<String, List<DatabaseTimingResult>> getTimingMetricsFromDatabase(
long timeRange)
throws HealthMonitorException {
1108 if(! isEnabled.get()) {
1109 throw new HealthMonitorException(
"Health Monitor is not enabled");
1113 long minimumTimestamp = System.currentTimeMillis() - timeRange;
1117 throw new HealthMonitorException(
"Error getting database lock");
1122 throw new HealthMonitorException(
"Error getting database connection");
1125 Map<String, List<DatabaseTimingResult>> resultMap =
new HashMap<>();
1127 try (Statement statement = conn.createStatement();
1128 ResultSet resultSet = statement.executeQuery(
"SELECT * FROM timing_data WHERE timestamp > " + minimumTimestamp)) {
1130 while (resultSet.next()) {
1131 String name = resultSet.getString(
"name");
1132 DatabaseTimingResult timingResult =
new DatabaseTimingResult(resultSet);
1134 if(resultMap.containsKey(name)) {
1135 resultMap.get(name).add(timingResult);
1137 List<DatabaseTimingResult> resultList =
new ArrayList<>();
1138 resultList.add(timingResult);
1139 resultMap.put(name, resultList);
1143 }
catch (SQLException ex) {
1144 throw new HealthMonitorException(
"Error reading timing metrics from database", ex);
1148 }
catch (SQLException ex) {
1149 logger.log(Level.SEVERE,
"Error closing Connection.", ex);
1152 }
catch (CoordinationService.CoordinationServiceException ex) {
1153 throw new HealthMonitorException(
"Error getting database lock", ex);
1163 List<UserData> getUserMetricsFromDatabase(
long timeRange)
throws HealthMonitorException {
1168 if(! isEnabled.get()) {
1169 throw new HealthMonitorException(
"Health Monitor is not enabled");
1173 long minimumTimestamp = System.currentTimeMillis() - timeRange;
1177 throw new HealthMonitorException(
"Error getting database lock");
1180 List<UserData> resultList =
new ArrayList<>();
1182 try (Connection conn =
connect();
1183 Statement statement = conn.createStatement();
1184 ResultSet resultSet = statement.executeQuery(
"SELECT * FROM user_data WHERE timestamp > " + minimumTimestamp)) {
1186 while (resultSet.next()) {
1187 resultList.add(
new UserData(resultSet));
1190 }
catch (SQLException ex) {
1191 throw new HealthMonitorException(
"Error reading user metrics from database", ex);
1193 }
catch (CoordinationService.CoordinationServiceException ex) {
1194 throw new HealthMonitorException(
"Error getting database lock", ex);
1211 throw new HealthMonitorException(
"Error acquiring database lock");
1213 throw new HealthMonitorException(
"Error acquiring database lock", ex);
1231 throw new HealthMonitorException(
"Error acquiring database lock");
1233 throw new HealthMonitorException(
"Error acquiring database lock");
1248 UserEvent(
int value) {
1256 int getEventValue() {
1266 static UserEvent valueOf(
int value)
throws HealthMonitorException {
1267 for (UserEvent v : UserEvent.values()) {
1268 if (v.value == value) {
1272 throw new HealthMonitorException(
"Can not create UserEvent from unknown value " + value);
1280 boolean caseIsOpen() {
1281 return(this.equals(CASE_OPEN));
1289 boolean userIsLoggedIn() {
1292 return( ! this.equals(LOG_OFF));
1301 static class UserData {
1302 private final UserEvent eventType;
1303 private long timestamp;
1304 private final boolean isExaminer;
1305 private final String hostname;
1306 private String caseName;
1313 private UserData(UserEvent eventType) {
1314 this.eventType = eventType;
1315 this.timestamp = System.currentTimeMillis();
1316 this.isExaminer = (UserPreferences.SelectedMode.STANDALONE == UserPreferences.getMode());
1321 this.caseName = Case.getCurrentCaseThrows().getDisplayName();
1322 }
catch (NoCurrentCaseException ex) {
1334 UserData(ResultSet resultSet)
throws SQLException, HealthMonitorException {
1335 this.timestamp = resultSet.getLong(
"timestamp");
1336 this.hostname = resultSet.getString(
"host");
1337 this.eventType = UserEvent.valueOf(resultSet.getInt(
"event_type"));
1338 this.isExaminer = resultSet.getBoolean(
"is_examiner");
1339 this.caseName = resultSet.getString(
"case_name");
1348 static UserData createDummyUserData(
long timestamp) {
1349 UserData userData =
new UserData(UserEvent.CASE_CLOSE);
1350 userData.timestamp = timestamp;
1358 long getTimestamp() {
1366 String getHostname() {
1374 UserEvent getEventType() {
1382 boolean isExaminerNode() {
1390 String getCaseName() {
1411 sum = metric.getDuration();
1412 max = metric.getDuration();
1413 min = metric.getDuration();
1423 void addMetric(
TimingMetric metric)
throws HealthMonitorException {
1427 sum += metric.getDuration();
1430 if(max < metric.getDuration()) {
1431 max = metric.getDuration();
1435 if(min > metric.getDuration()) {
1436 min = metric.getDuration();
1444 double getAverage() {
1477 static class DatabaseTimingResult {
1478 private final long timestamp;
1479 private final String hostname;
1480 private final long count;
1481 private final double average;
1482 private final double max;
1483 private final double min;
1485 DatabaseTimingResult(ResultSet resultSet)
throws SQLException {
1486 this.timestamp = resultSet.getLong(
"timestamp");
1487 this.hostname = resultSet.getString(
"host");
1488 this.count = resultSet.getLong(
"count");
1489 this.average = resultSet.getDouble(
"average");
1490 this.max = resultSet.getDouble(
"max");
1491 this.min = resultSet.getDouble(
"min");
1498 long getTimestamp() {
1506 double getAverage() {
1538 String getHostName() {
final List< UserData > userInfoList
BasicDataSource connectionPool
synchronized void deactivateMonitorLocally()
static void submitTimingMetric(TimingMetric metric)
CoordinationService.Lock getExclusiveDbLock()
void performDatabaseQuery()
void addUserEvent(UserEvent eventType)
synchronized void stopTimer()
EnterpriseHealthMonitor()
static boolean getIsMultiUserModeEnabled()
void setGlobalEnabledStatusInDB(boolean status)
static CaseDbConnectionInfo getDatabaseConnectionInfo()
void addTimingMetric(TimingMetric metric)
void initializeDatabaseSchema()
static void shutDownTaskExecutor(ExecutorService executor)
final Map< String, TimingInfo > timingInfoMap
void propertyChange(PropertyChangeEvent evt)
static void submitNormalizedTimingMetric(TimingMetric metric, long normalization)
void writeCurrentStateToDatabase()
static final String DATABASE_NAME
CoordinationService.Lock getSharedDbLock()
static TimingMetric getTimingMetric(String name)
CaseDbSchemaVersionNumber getVersion()
static final Logger logger
Lock tryGetExclusiveLock(CategoryNode category, String nodePath, int timeOut, TimeUnit timeUnit)
ScheduledThreadPoolExecutor healthMonitorOutputTimer
SleuthkitCase getSleuthkitCase()
static final AtomicBoolean isEnabled
static void addPropertyChangeListener(PropertyChangeListener listener)
static void recordMetrics()
static final int CONN_POOL_SIZE
void shutdownConnections()
static final long DATABASE_WRITE_INTERVAL
synchronized void startTimer()
void upgradeDatabaseSchema()
synchronized void activateMonitorLocally()
static EnterpriseHealthMonitor instance
synchronized static Logger getLogger(String name)
void gatherTimerBasedMetrics()
static Case getCurrentCaseThrows()
Lock tryGetSharedLock(CategoryNode category, String nodePath, int timeOut, TimeUnit timeUnit)
static synchronized CoordinationService getInstance()
boolean getGlobalEnabledStatusFromDB()
boolean databaseIsInitialized()
static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION
void setupConnectionPool()
CaseDbConnectionInfo connectionSettingsInUse