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 private final static AtomicBoolean
isEnabled =
new AtomicBoolean(
false);
85 timingInfoMap =
new HashMap<>();
89 userInfoList =
new ArrayList<>();
93 hostName = java.net.InetAddress.getLocalHost().getHostName();
94 }
catch (java.net.UnknownHostException ex) {
96 hostName = UUID.randomUUID().toString();
97 logger.log(Level.SEVERE,
"Unable to look up host name - falling back to UUID " + hostName, ex);
101 updateFromGlobalEnabledStatus();
114 synchronized static HealthMonitor getInstance() throws HealthMonitorException {
115 if (instance == null) {
131 logger.log(Level.INFO,
"Activating Servies Health Monitor");
137 throw new HealthMonitorException(
"Multi user mode is not enabled - can not activate health monitor");
143 throw new HealthMonitorException(
"Error getting database lock");
157 if (!CURRENT_DB_SCHEMA_VERSION.equals(
getVersion())) {
162 throw new HealthMonitorException(
"Error releasing database lock", ex);
166 timingInfoMap.clear();
167 userInfoList.clear();
175 logger.log(Level.INFO,
"Upgrading Health Monitor database");
176 CaseDbSchemaVersionNumber currentSchema =
getVersion();
180 throw new HealthMonitorException(
"Error getting database connection");
183 try (Statement statement = conn.createStatement()) {
184 conn.setAutoCommit(
false);
188 if (currentSchema.compareTo(
new CaseDbSchemaVersionNumber(1, 1)) < 0) {
191 statement.execute(
"CREATE TABLE IF NOT EXISTS user_data ("
192 +
"id SERIAL PRIMARY KEY,"
193 +
"host text NOT NULL,"
194 +
"timestamp bigint NOT NULL,"
195 +
"event_type int NOT NULL,"
196 +
"is_examiner boolean NOT NULL,"
197 +
"case_name text NOT NULL"
202 statement.execute(
"UPDATE db_info SET value='" + CURRENT_DB_SCHEMA_VERSION.getMajor() +
"' WHERE name='SCHEMA_VERSION'");
203 statement.execute(
"UPDATE db_info SET value='" + CURRENT_DB_SCHEMA_VERSION.getMinor() +
"' WHERE name='SCHEMA_MINOR_VERSION'");
206 logger.log(Level.INFO,
"Health Monitor database upgraded to version {0}", CURRENT_DB_SCHEMA_VERSION.toString());
207 }
catch (SQLException ex) {
210 }
catch (SQLException ex2) {
211 logger.log(Level.SEVERE,
"Rollback error");
213 throw new HealthMonitorException(
"Error upgrading database", ex);
217 }
catch (SQLException ex) {
218 logger.log(Level.SEVERE,
"Error closing connection.", ex);
233 logger.log(Level.INFO,
"Deactivating Servies Health Monitor");
236 timingInfoMap.clear();
250 healthMonitorOutputTimer =
new ScheduledThreadPoolExecutor(1,
new ThreadFactoryBuilder().setNameFormat(
"health_monitor_timer").build());
251 healthMonitorOutputTimer.scheduleWithFixedDelay(
new PeriodicHealthMonitorTask(), DATABASE_WRITE_INTERVAL, DATABASE_WRITE_INTERVAL, TimeUnit.MINUTES);
258 if (healthMonitorOutputTimer != null) {
269 static synchronized void startUpIfEnabled() throws HealthMonitorException {
279 static synchronized void shutdown() throws HealthMonitorException {
291 static synchronized void setEnabled(
boolean enabled)
throws HealthMonitorException {
292 if (enabled == isEnabled.get()) {
304 if (isEnabled.get()) {
308 isEnabled.set(
false);
325 if (isEnabled.get()) {
339 if (isEnabled.get() && (metric != null)) {
343 }
catch (HealthMonitorException ex) {
345 logger.log(Level.SEVERE,
"Error adding timing metric", ex);
362 if (isEnabled.get() && (metric != null)) {
365 metric.normalize(normalization);
367 }
catch (HealthMonitorException ex) {
369 logger.log(Level.SEVERE,
"Error adding timing metric", ex);
384 synchronized (
this) {
391 if (timingInfoMap.containsKey(metric.getName())) {
392 timingInfoMap.get(metric.getName()).addMetric(metric);
394 timingInfoMap.put(metric.getName(),
new TimingInfo(metric));
405 UserData userInfo =
new UserData(eventType);
406 synchronized (
this) {
407 userInfoList.add(userInfo);
424 List<Image> images = skCase.getImages();
428 long normalization = images.size();
429 if (images.isEmpty()) {
431 }
else if (images.size() == 1) {
433 }
else if (images.size() < 10) {
442 }
catch (TskCoreException ex) {
443 throw new HealthMonitorException(
"Error running getImages()", ex);
463 Map<String, TimingInfo> timingMapCopy;
464 List<UserData> userDataCopy;
468 synchronized (
this) {
469 if (!isEnabled.get()) {
476 timingInfoMap.clear();
479 userInfoList.clear();
483 if (timingMapCopy.keySet().isEmpty() && userDataCopy.isEmpty()) {
487 logger.log(Level.INFO,
"Writing health monitor metrics to database");
492 throw new HealthMonitorException(
"Error getting database lock");
497 throw new HealthMonitorException(
"Error getting database connection");
501 String addTimingInfoSql =
"INSERT INTO timing_data (name, host, timestamp, count, average, max, min) VALUES (?, ?, ?, ?, ?, ?, ?)";
502 String addUserInfoSql =
"INSERT INTO user_data (host, timestamp, event_type, is_examiner, case_name) VALUES (?, ?, ?, ?, ?)";
503 try (PreparedStatement timingStatement = conn.prepareStatement(addTimingInfoSql);
504 PreparedStatement userStatement = conn.prepareStatement(addUserInfoSql)) {
506 for (String name : timingMapCopy.keySet()) {
509 timingStatement.setString(1, name);
510 timingStatement.setString(2, hostName);
511 timingStatement.setLong(3, System.currentTimeMillis());
512 timingStatement.setLong(4, info.getCount());
513 timingStatement.setDouble(5, info.getAverage());
514 timingStatement.setDouble(6, info.getMax());
515 timingStatement.setDouble(7, info.getMin());
517 timingStatement.execute();
520 for (UserData userInfo : userDataCopy) {
521 userStatement.setString(1, hostName);
522 userStatement.setLong(2, userInfo.getTimestamp());
523 userStatement.setInt(3, userInfo.getEventType().getEventValue());
524 userStatement.setBoolean(4, userInfo.isExaminerNode());
525 userStatement.setString(5, userInfo.getCaseName());
526 userStatement.execute();
529 }
catch (SQLException ex) {
530 throw new HealthMonitorException(
"Error saving metric data to database", ex);
534 }
catch (SQLException ex) {
535 logger.log(Level.SEVERE,
"Error closing Connection.", ex);
539 throw new HealthMonitorException(
"Error releasing database lock", ex);
555 Class.forName(
"org.postgresql.Driver");
557 try (Connection connection = DriverManager.getConnection(
"jdbc:postgresql://" + db.getHost() +
":" + db.getPort() +
"/postgres", db.getUserName(), db.getPassword());
558 Statement statement = connection.createStatement();) {
559 String createCommand =
"SELECT 1 AS result FROM pg_database WHERE datname='" + DATABASE_NAME +
"'";
560 rs = statement.executeQuery(createCommand);
570 throw new HealthMonitorException(
"Failed check for health monitor database", ex);
584 Class.forName(
"org.postgresql.Driver");
585 try (Connection connection = DriverManager.getConnection(
"jdbc:postgresql://" + db.getHost() +
":" + db.getPort() +
"/postgres", db.getUserName(), db.getPassword());
586 Statement statement = connection.createStatement();) {
587 String createCommand =
"CREATE DATABASE \"" + DATABASE_NAME +
"\" OWNER \"" + db.getUserName() +
"\"";
588 statement.execute(createCommand);
590 logger.log(Level.INFO,
"Created new health monitor database " + DATABASE_NAME);
592 throw new HealthMonitorException(
"Failed to delete health monitor database", ex);
604 connectionSettingsInUse = db;
606 connectionPool =
new BasicDataSource();
607 connectionPool.setDriverClassName(
"org.postgresql.Driver");
609 StringBuilder connectionURL =
new StringBuilder();
610 connectionURL.append(
"jdbc:postgresql://");
611 connectionURL.append(db.getHost());
612 connectionURL.append(
":");
613 connectionURL.append(db.getPort());
614 connectionURL.append(
"/");
615 connectionURL.append(DATABASE_NAME);
617 connectionPool.setUrl(connectionURL.toString());
618 connectionPool.setUsername(db.getUserName());
619 connectionPool.setPassword(db.getPassword());
622 connectionPool.setInitialSize(3);
623 connectionPool.setMaxIdle(CONN_POOL_SIZE);
624 connectionPool.setValidationQuery(
"SELECT version()");
626 throw new HealthMonitorException(
"Error loading database configuration", ex);
637 synchronized (
this) {
638 if (connectionPool != null) {
639 connectionPool.close();
640 connectionPool = null;
643 }
catch (SQLException ex) {
644 throw new HealthMonitorException(
"Failed to close existing database connections.", ex);
655 private Connection
connect() throws HealthMonitorException {
656 synchronized (
this) {
657 if (connectionPool == null) {
663 return connectionPool.getConnection();
664 }
catch (SQLException ex) {
665 throw new HealthMonitorException(
"Error getting connection from connection pool.", ex);
680 throw new HealthMonitorException(
"Error getting database connection");
682 ResultSet resultSet = null;
684 try (Statement statement = conn.createStatement()) {
685 resultSet = statement.executeQuery(
"SELECT value FROM db_info WHERE name='SCHEMA_VERSION'");
686 return resultSet.next();
687 }
catch (SQLException ex) {
691 if (resultSet != null) {
694 }
catch (SQLException ex) {
695 logger.log(Level.SEVERE,
"Error closing result set", ex);
700 }
catch (SQLException ex) {
701 logger.log(Level.SEVERE,
"Error closing Connection.", ex);
712 static boolean monitorIsEnabled() {
713 return isEnabled.get();
722 synchronized void updateFromGlobalEnabledStatus() throws HealthMonitorException {
724 boolean previouslyEnabled = monitorIsEnabled();
727 if (!UserPreferences.getIsMultiUserModeEnabled()) {
728 isEnabled.set(
false);
730 if (previouslyEnabled) {
739 isEnabled.set(
false);
741 if (previouslyEnabled) {
749 if (previouslyEnabled && (connectionSettingsInUse != null)) {
751 CaseDbConnectionInfo currentSettings = UserPreferences.getDatabaseConnectionInfo();
752 if (!(connectionSettingsInUse.getUserName().equals(currentSettings.getUserName())
753 && connectionSettingsInUse.getPassword().equals(currentSettings.getPassword())
754 && connectionSettingsInUse.getPort().equals(currentSettings.getPort())
755 && connectionSettingsInUse.getHost().equals(currentSettings.getHost()))) {
758 }
catch (UserPreferencesException ex) {
759 throw new HealthMonitorException(
"Error reading database connection info", ex);
764 if (currentlyEnabled != previouslyEnabled) {
765 if (!currentlyEnabled) {
766 isEnabled.set(
false);
785 try (Connection conn =
connect();
786 Statement statement = conn.createStatement();
787 ResultSet resultSet = statement.executeQuery(
"SELECT value FROM db_info WHERE name='MONITOR_ENABLED'")) {
789 if (resultSet.next()) {
790 return (resultSet.getBoolean(
"value"));
792 throw new HealthMonitorException(
"No enabled status found in database");
793 }
catch (SQLException ex) {
794 throw new HealthMonitorException(
"Error initializing database", ex);
805 try (Connection conn =
connect();
806 Statement statement = conn.createStatement();) {
807 statement.execute(
"UPDATE db_info SET value='" + status +
"' WHERE name='MONITOR_ENABLED'");
808 }
catch (SQLException ex) {
809 throw new HealthMonitorException(
"Error setting enabled status", ex);
820 private CaseDbSchemaVersionNumber
getVersion() throws HealthMonitorException {
823 throw new HealthMonitorException(
"Error getting database connection");
825 ResultSet resultSet = null;
827 try (Statement statement = conn.createStatement()) {
828 int minorVersion = 0;
829 int majorVersion = 0;
830 resultSet = statement.executeQuery(
"SELECT value FROM db_info WHERE name='SCHEMA_MINOR_VERSION'");
831 if (resultSet.next()) {
832 String minorVersionStr = resultSet.getString(
"value");
834 minorVersion = Integer.parseInt(minorVersionStr);
835 }
catch (NumberFormatException ex) {
836 throw new HealthMonitorException(
"Bad value for schema minor version (" + minorVersionStr +
") - database is corrupt");
840 resultSet = statement.executeQuery(
"SELECT value FROM db_info WHERE name='SCHEMA_VERSION'");
841 if (resultSet.next()) {
842 String majorVersionStr = resultSet.getString(
"value");
844 majorVersion = Integer.parseInt(majorVersionStr);
845 }
catch (NumberFormatException ex) {
846 throw new HealthMonitorException(
"Bad value for schema version (" + majorVersionStr +
") - database is corrupt");
850 return new CaseDbSchemaVersionNumber(majorVersion, minorVersion);
851 }
catch (SQLException ex) {
852 throw new HealthMonitorException(
"Error initializing database", ex);
854 if (resultSet != null) {
857 }
catch (SQLException ex) {
858 logger.log(Level.SEVERE,
"Error closing result set", ex);
863 }
catch (SQLException ex) {
864 logger.log(Level.SEVERE,
"Error closing Connection.", ex);
877 throw new HealthMonitorException(
"Error getting database connection");
880 try (Statement statement = conn.createStatement()) {
881 conn.setAutoCommit(
false);
883 statement.execute(
"CREATE TABLE IF NOT EXISTS timing_data ("
884 +
"id SERIAL PRIMARY KEY,"
885 +
"name text NOT NULL,"
886 +
"host text NOT NULL,"
887 +
"timestamp bigint NOT NULL,"
888 +
"count bigint NOT NULL,"
889 +
"average double precision NOT NULL,"
890 +
"max double precision NOT NULL,"
891 +
"min double precision NOT NULL"
894 statement.execute(
"CREATE TABLE IF NOT EXISTS db_info ("
895 +
"id SERIAL PRIMARY KEY NOT NULL,"
896 +
"name text NOT NULL,"
897 +
"value text NOT NULL"
900 statement.execute(
"CREATE TABLE IF NOT EXISTS user_data ("
901 +
"id SERIAL PRIMARY KEY,"
902 +
"host text NOT NULL,"
903 +
"timestamp bigint NOT NULL,"
904 +
"event_type int NOT NULL,"
905 +
"is_examiner BOOLEAN NOT NULL,"
906 +
"case_name text NOT NULL"
909 statement.execute(
"INSERT INTO db_info (name, value) VALUES ('SCHEMA_VERSION', '" + CURRENT_DB_SCHEMA_VERSION.getMajor() +
"')");
910 statement.execute(
"INSERT INTO db_info (name, value) VALUES ('SCHEMA_MINOR_VERSION', '" + CURRENT_DB_SCHEMA_VERSION.getMinor() +
"')");
911 statement.execute(
"INSERT INTO db_info (name, value) VALUES ('MONITOR_ENABLED', 'true')");
914 }
catch (SQLException ex) {
917 }
catch (SQLException ex2) {
918 logger.log(Level.SEVERE,
"Rollback error");
920 throw new HealthMonitorException(
"Error initializing database", ex);
924 }
catch (SQLException ex) {
925 logger.log(Level.SEVERE,
"Error closing connection.", ex);
934 static final class PeriodicHealthMonitorTask
implements Runnable {
950 getInstance().updateFromGlobalEnabledStatus();
951 if (monitorIsEnabled()) {
955 }
catch (HealthMonitorException ex) {
956 logger.log(Level.SEVERE,
"Error performing periodic task", ex);
963 switch (
Case.
Events.valueOf(evt.getPropertyName())) {
966 if ((null == evt.getNewValue()) && (evt.getOldValue() instanceof
Case)) {
970 }
else if ((null == evt.getOldValue()) && (evt.getNewValue() instanceof
Case)) {
983 void populateDatabaseWithSampleData(
int nDays,
int nNodes,
boolean createVerificationData)
throws HealthMonitorException {
985 if (!isEnabled.get()) {
986 throw new HealthMonitorException(
"Can't populate database - monitor not enabled");
992 throw new HealthMonitorException(
"Error getting database lock");
995 String[] metricNames = {
"Disk Reads: Hash calculation",
"Database: getImages query",
"Solr: Index chunk",
"Solr: Connectivity check",
996 "Correlation Engine: Notable artifact query",
"Correlation Engine: Bulk insert"};
998 Random rand =
new Random();
1000 long maxTimestamp = System.currentTimeMillis();
1001 long millisPerHour = 1000 * 60 * 60;
1002 long minTimestamp = maxTimestamp - (nDays * (millisPerHour * 24));
1004 Connection conn = null;
1008 throw new HealthMonitorException(
"Error getting database connection");
1011 try (Statement statement = conn.createStatement()) {
1013 statement.execute(
"DELETE FROM timing_data");
1014 }
catch (SQLException ex) {
1015 logger.log(Level.SEVERE,
"Error clearing timing data", ex);
1020 String addTimingInfoSql =
"INSERT INTO timing_data (name, host, timestamp, count, average, max, min) VALUES (?, ?, ?, ?, ?, ?, ?)";
1021 try (PreparedStatement statement = conn.prepareStatement(addTimingInfoSql)) {
1023 for (String metricName : metricNames) {
1025 long baseIndex = rand.nextInt(900) + 100;
1026 int multiplier = rand.nextInt(5);
1027 long minIndexTimeNanos;
1028 switch (multiplier) {
1030 minIndexTimeNanos = baseIndex;
1033 minIndexTimeNanos = baseIndex * 1000;
1036 minIndexTimeNanos = baseIndex * 1000 * 1000;
1040 long maxIndexTimeOverMin = minIndexTimeNanos * 3;
1042 for (
int node = 0; node < nNodes; node++) {
1044 String host =
"testHost" + node;
1047 double maxCount = nDays * 24 + 1;
1050 for (
long timestamp = minTimestamp + rand.nextInt(1000 * 60 * 55); timestamp < maxTimestamp; timestamp += millisPerHour) {
1057 double slowNodeMultiplier = 1.0;
1058 if ((maxCount - count) <= 3 * 24) {
1059 slowNodeMultiplier += (3 - (maxCount - count) / 24) * 0.33;
1062 if (!createVerificationData) {
1065 int outlierVal = rand.nextInt(30);
1066 long randVal = rand.nextLong();
1070 if (outlierVal < 2) {
1071 aveTime = minIndexTimeNanos + maxIndexTimeOverMin + randVal % maxIndexTimeOverMin;
1072 }
else if (outlierVal == 2) {
1073 aveTime = (minIndexTimeNanos / 2) + randVal % (minIndexTimeNanos / 2);
1074 }
else if (outlierVal < 17) {
1075 aveTime = minIndexTimeNanos + randVal % (maxIndexTimeOverMin / 2);
1077 aveTime = minIndexTimeNanos + randVal % maxIndexTimeOverMin;
1081 aveTime = aveTime * slowNodeMultiplier;
1087 Calendar thisDate =
new GregorianCalendar();
1088 thisDate.setTimeInMillis(timestamp);
1089 int day = thisDate.get(Calendar.DAY_OF_MONTH);
1090 aveTime = day * 1000000;
1093 statement.setString(1, metricName);
1094 statement.setString(2, host);
1095 statement.setLong(3, timestamp);
1096 statement.setLong(4, 0);
1097 statement.setDouble(5, aveTime / 1000000);
1098 statement.setDouble(6, 0);
1099 statement.setDouble(7, 0);
1101 statement.execute();
1105 }
catch (SQLException ex) {
1106 throw new HealthMonitorException(
"Error saving metric data to database", ex);
1113 }
catch (SQLException ex) {
1114 logger.log(Level.SEVERE,
"Error closing Connection.", ex);
1118 }
catch (CoordinationService.CoordinationServiceException ex) {
1119 throw new HealthMonitorException(
"Error releasing database lock", ex);
1133 Map<String, List<DatabaseTimingResult>> getTimingMetricsFromDatabase(
long timeRange)
throws HealthMonitorException {
1138 if (!isEnabled.get()) {
1139 throw new HealthMonitorException(
"Health Monitor is not enabled");
1143 long minimumTimestamp = System.currentTimeMillis() - timeRange;
1147 throw new HealthMonitorException(
"Error getting database lock");
1152 throw new HealthMonitorException(
"Error getting database connection");
1155 Map<String, List<DatabaseTimingResult>> resultMap =
new HashMap<>();
1157 try (Statement statement = conn.createStatement();
1158 ResultSet resultSet = statement.executeQuery(
"SELECT * FROM timing_data WHERE timestamp > " + minimumTimestamp)) {
1160 while (resultSet.next()) {
1161 String name = resultSet.getString(
"name");
1162 DatabaseTimingResult timingResult =
new DatabaseTimingResult(resultSet);
1164 if (resultMap.containsKey(name)) {
1165 resultMap.get(name).add(timingResult);
1167 List<DatabaseTimingResult> resultList =
new ArrayList<>();
1168 resultList.add(timingResult);
1169 resultMap.put(name, resultList);
1173 }
catch (SQLException ex) {
1174 throw new HealthMonitorException(
"Error reading timing metrics from database", ex);
1178 }
catch (SQLException ex) {
1179 logger.log(Level.SEVERE,
"Error closing Connection.", ex);
1182 }
catch (CoordinationService.CoordinationServiceException ex) {
1183 throw new HealthMonitorException(
"Error getting database lock", ex);
1196 List<UserData> getUserMetricsFromDatabase(
long timeRange)
throws HealthMonitorException {
1201 if (!isEnabled.get()) {
1202 throw new HealthMonitorException(
"Health Monitor is not enabled");
1206 long minimumTimestamp = System.currentTimeMillis() - timeRange;
1210 throw new HealthMonitorException(
"Error getting database lock");
1213 List<UserData> resultList =
new ArrayList<>();
1215 try (Connection conn =
connect();
1216 Statement statement = conn.createStatement();
1217 ResultSet resultSet = statement.executeQuery(
"SELECT * FROM user_data WHERE timestamp > " + minimumTimestamp)) {
1219 while (resultSet.next()) {
1220 resultList.add(
new UserData(resultSet));
1223 }
catch (SQLException ex) {
1224 throw new HealthMonitorException(
"Error reading user metrics from database", ex);
1226 }
catch (CoordinationService.CoordinationServiceException ex) {
1227 throw new HealthMonitorException(
"Error getting database lock", ex);
1246 throw new HealthMonitorException(
"Error acquiring database lock");
1248 throw new HealthMonitorException(
"Error acquiring database lock", ex);
1268 throw new HealthMonitorException(
"Error acquiring database lock");
1270 throw new HealthMonitorException(
"Error acquiring database lock");
1285 UserEvent(
int value) {
1294 int getEventValue() {
1307 static UserEvent valueOf(
int value)
throws HealthMonitorException {
1308 for (UserEvent v : UserEvent.values()) {
1309 if (v.value == value) {
1313 throw new HealthMonitorException(
"Can not create UserEvent from unknown value " + value);
1322 boolean caseIsOpen() {
1323 return (this.equals(CASE_OPEN));
1332 boolean userIsLoggedIn() {
1335 return (!this.equals(LOG_OFF));
1343 static class UserData {
1345 private final UserEvent eventType;
1346 private long timestamp;
1347 private final boolean isExaminer;
1348 private final String hostname;
1349 private String caseName;
1357 private UserData(UserEvent eventType) {
1358 this.eventType = eventType;
1359 this.timestamp = System.currentTimeMillis();
1360 this.isExaminer = (UserPreferences.SelectedMode.STANDALONE == UserPreferences.getMode());
1365 this.caseName = Case.getCurrentCaseThrows().getDisplayName();
1366 }
catch (NoCurrentCaseException ex) {
1380 UserData(ResultSet resultSet)
throws SQLException, HealthMonitorException {
1381 this.timestamp = resultSet.getLong(
"timestamp");
1382 this.hostname = resultSet.getString(
"host");
1383 this.eventType = UserEvent.valueOf(resultSet.getInt(
"event_type"));
1384 this.isExaminer = resultSet.getBoolean(
"is_examiner");
1385 this.caseName = resultSet.getString(
"case_name");
1396 static UserData createDummyUserData(
long timestamp) {
1397 UserData userData =
new UserData(UserEvent.CASE_CLOSE);
1398 userData.timestamp = timestamp;
1407 long getTimestamp() {
1416 String getHostname() {
1425 UserEvent getEventType() {
1434 boolean isExaminerNode() {
1443 String getCaseName() {
1464 sum = metric.getDuration();
1465 max = metric.getDuration();
1466 min = metric.getDuration();
1479 void addMetric(
TimingMetric metric)
throws HealthMonitorException {
1483 sum += metric.getDuration();
1486 if (max < metric.getDuration()) {
1487 max = metric.getDuration();
1491 if (min > metric.getDuration()) {
1492 min = metric.getDuration();
1501 double getAverage() {
1537 static class DatabaseTimingResult {
1539 private final long timestamp;
1540 private final String hostname;
1541 private final long count;
1542 private final double average;
1543 private final double max;
1544 private final double min;
1546 DatabaseTimingResult(ResultSet resultSet)
throws SQLException {
1547 this.timestamp = resultSet.getLong(
"timestamp");
1548 this.hostname = resultSet.getString(
"host");
1549 this.count = resultSet.getLong(
"count");
1550 this.average = resultSet.getDouble(
"average");
1551 this.max = resultSet.getDouble(
"max");
1552 this.min = resultSet.getDouble(
"min");
1560 long getTimestamp() {
1569 double getAverage() {
1605 String getHostName() {
void writeCurrentStateToDatabase()
BasicDataSource connectionPool
CoordinationService.Lock getSharedDbLock()
CaseDbSchemaVersionNumber getVersion()
static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION
static void recordMetrics()
synchronized void startTimer()
static final String DATABASE_NAME
synchronized void deactivateMonitorLocally()
void performDatabaseQuery()
static boolean getIsMultiUserModeEnabled()
static CaseDbConnectionInfo getDatabaseConnectionInfo()
final Map< String, TimingInfo > timingInfoMap
boolean databaseIsInitialized()
CaseDbConnectionInfo connectionSettingsInUse
static TimingMetric getTimingMetric(String name)
boolean getGlobalEnabledStatusFromDB()
static final Logger logger
static void shutDownTaskExecutor(ExecutorService executor)
void initializeDatabaseSchema()
synchronized void activateMonitorLocally()
ScheduledThreadPoolExecutor healthMonitorOutputTimer
void setGlobalEnabledStatusInDB(boolean status)
void addTimingMetric(TimingMetric metric)
Lock tryGetExclusiveLock(CategoryNode category, String nodePath, int timeOut, TimeUnit timeUnit)
static final int CONN_POOL_SIZE
SleuthkitCase getSleuthkitCase()
static void addPropertyChangeListener(PropertyChangeListener listener)
void setupConnectionPool()
static final long DATABASE_WRITE_INTERVAL
static final AtomicBoolean isEnabled
static void submitTimingMetric(TimingMetric metric)
static HealthMonitor instance
final List< UserData > userInfoList
void shutdownConnections()
synchronized static Logger getLogger(String name)
synchronized void stopTimer()
void upgradeDatabaseSchema()
CoordinationService.Lock getExclusiveDbLock()
static Case getCurrentCaseThrows()
Lock tryGetSharedLock(CategoryNode category, String nodePath, int timeOut, TimeUnit timeUnit)
static synchronized CoordinationService getInstance()
static void submitNormalizedTimingMetric(TimingMetric metric, long normalization)
void gatherTimerBasedMetrics()
void propertyChange(PropertyChangeEvent evt)
void addUserEvent(UserEvent eventType)