Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
HealthMonitorDashboard.java
Go to the documentation of this file.
1/*
2 * Autopsy Forensic Browser
3 *
4 * Copyright 2018-2021 Basis Technology Corp.
5 * Contact: carrier <at> sleuthkit <dot> org
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19package org.sleuthkit.autopsy.healthmonitor;
20
21import java.awt.Container;
22import java.awt.Cursor;
23import java.awt.Dimension;
24import java.util.Set;
25import java.util.HashSet;
26import java.util.HashMap;
27import java.util.Map;
28import java.util.Arrays;
29import java.util.ArrayList;
30import java.util.List;
31import java.awt.event.ActionEvent;
32import java.awt.event.ActionListener;
33import java.io.BufferedWriter;
34import java.io.File;
35import java.io.FileOutputStream;
36import java.io.IOException;
37import java.io.OutputStreamWriter;
38import javax.swing.Box;
39import javax.swing.JButton;
40import javax.swing.JDialog;
41import javax.swing.JComboBox;
42import javax.swing.JSeparator;
43import javax.swing.JCheckBox;
44import javax.swing.JLabel;
45import javax.swing.JPanel;
46import javax.swing.JScrollPane;
47import javax.swing.BorderFactory;
48import javax.swing.BoxLayout;
49import java.awt.GridLayout;
50import java.nio.charset.StandardCharsets;
51import java.nio.file.Paths;
52import java.text.DateFormat;
53import java.text.SimpleDateFormat;
54import java.util.Date;
55import java.util.Collections;
56import java.util.logging.Level;
57import java.util.stream.Collectors;
58import javax.swing.JFileChooser;
59import org.openide.util.NbBundle;
60import org.sleuthkit.autopsy.core.UserPreferences;
61import org.sleuthkit.autopsy.coreutils.Logger;
62import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
63import org.sleuthkit.autopsy.coreutils.PlatformUtil;
64import org.sleuthkit.autopsy.guiutils.JFileChooserFactory;
65
70
71 private final static Logger logger = Logger.getLogger(HealthMonitorDashboard.class.getName());
72
73 private final static String ADMIN_ACCESS_FILE_NAME = "admin"; // NON-NLS
74 private final static String ADMIN_ACCESS_FILE_PATH = Paths.get(PlatformUtil.getUserConfigDirectory(), ADMIN_ACCESS_FILE_NAME).toString();
75
76 Map<String, List<HealthMonitor.DatabaseTimingResult>> timingData;
77 List<HealthMonitor.UserData> userData;
78
79 private JComboBox<String> timingDateComboBox = null;
80 private JComboBox<String> timingHostComboBox = null;
81 private JCheckBox timingHostCheckBox = null;
82 private JCheckBox timingShowTrendLineCheckBox = null;
83 private JCheckBox timingSkipOutliersCheckBox = null;
84 private JPanel timingGraphPanel = null;
85 private JComboBox<String> userDateComboBox = null;
86 private JPanel userGraphPanel = null;
87 private JDialog dialog = null;
88 private final Container parentWindow;
89
91
97 public HealthMonitorDashboard(Container parent) {
98 timingData = new HashMap<>();
99 userData = new ArrayList<>();
100 parentWindow = parent;
102 }
103
107 @NbBundle.Messages({"HealthMonitorDashboard.display.errorCreatingDashboard=Error creating health monitor dashboard",
108 "HealthMonitorDashboard.display.dashboardTitle=Health Monitor"})
109 public void display() {
110
111 // Update the enabled status and get the timing data, then create all
112 // the sub panels.
113 JPanel timingPanel;
114 JPanel userPanel;
115 JPanel adminPanel;
116 try {
117 updateData();
118 timingPanel = createTimingPanel();
119 userPanel = createUserPanel();
120 adminPanel = createAdminPanel();
121 } catch (HealthMonitorException ex) {
122 logger.log(Level.SEVERE, "Error creating panels for health monitor dashboard", ex);
123 MessageNotifyUtil.Message.error(Bundle.HealthMonitorDashboard_display_errorCreatingDashboard());
124 return;
125 }
126
127 // Create the main panel for the dialog
128 JPanel mainPanel = new JPanel();
129 mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
130
131 // Add the timing panel
132 mainPanel.add(timingPanel);
133
134 // Add the user panel
135 mainPanel.add(userPanel);
136
137 // Add the admin panel if the admin file is present
138 File adminFile = new File(ADMIN_ACCESS_FILE_PATH);
139 if(adminFile.exists()) {
140 mainPanel.add(adminPanel);
141 }
142
143 // Create and show the dialog
144 dialog = new JDialog();
145 dialog.setTitle(Bundle.HealthMonitorDashboard_display_dashboardTitle());
146 dialog.add(mainPanel);
147 dialog.pack();
148 dialog.setLocationRelativeTo(parentWindow);
149 dialog.setVisible(true);
150 }
151
156 private void redisplay() {
157 if (dialog != null) {
158 dialog.setVisible(false);
159 dialog.dispose();
160 }
161 display();
162 }
163
168 private void updateData() throws HealthMonitorException {
169
170 // Update the monitor status
171 HealthMonitor.getInstance().updateFromGlobalEnabledStatus();
172
173 if(HealthMonitor.monitorIsEnabled()) {
174 // Get a copy of the timing data from the database
175 timingData = HealthMonitor.getInstance().getTimingMetricsFromDatabase(DateRange.getMaximumTimestampRange());
176
177 // Get a copy of the user data from the database
178 userData = HealthMonitor.getInstance().getUserMetricsFromDatabase(DateRange.getMaximumTimestampRange());
179 }
180 }
181
187 @NbBundle.Messages({"HealthMonitorDashboard.createTimingPanel.noData=No data to display - monitor is not enabled",
188 "HealthMonitorDashboard.createTimingPanel.timingMetricsTitle=Timing Metrics"})
189 private JPanel createTimingPanel() throws HealthMonitorException {
190
191 // If the monitor isn't enabled, just add a message
192 if(! HealthMonitor.monitorIsEnabled()) {
193 //timingMetricPanel.setPreferredSize(new Dimension(400,100));
194 JPanel emptyTimingMetricPanel = new JPanel();
195 emptyTimingMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createTimingPanel_timingMetricsTitle()));
196 emptyTimingMetricPanel.add(new JLabel(" "));
197 emptyTimingMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createTimingPanel_noData()));
198
199 return emptyTimingMetricPanel;
200 }
201
202 JPanel timingMetricPanel = new JPanel();
203 timingMetricPanel.setLayout(new BoxLayout(timingMetricPanel, BoxLayout.PAGE_AXIS));
204 timingMetricPanel.setBorder(BorderFactory.createEtchedBorder());
205
206 // Add title
207 JLabel timingMetricTitle = new JLabel(Bundle.HealthMonitorDashboard_createTimingPanel_timingMetricsTitle());
208 timingMetricPanel.add(timingMetricTitle);
209 timingMetricPanel.add(new JSeparator());
210
211 // Add the controls
212 timingMetricPanel.add(createTimingControlPanel());
213 timingMetricPanel.add(new JSeparator());
214
215 // Create panel to hold graphs
216 timingGraphPanel = new JPanel();
217 timingGraphPanel.setLayout(new GridLayout(0,2));
218
219 // Update the graph panel, put it in a scroll pane, and add to the timing metric panel
221 JScrollPane scrollPane = new JScrollPane(timingGraphPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
222 timingMetricPanel.add(scrollPane);
223 timingMetricPanel.revalidate();
224 timingMetricPanel.repaint();
225
226 return timingMetricPanel;
227 }
228
233 @NbBundle.Messages({"HealthMonitorDashboard.createTimingControlPanel.filterByHost=Filter by host",
234 "HealthMonitorDashboard.createTimingControlPanel.maxDays=Max days to display",
235 "HealthMonitorDashboard.createTimingControlPanel.skipOutliers=Do not plot outliers",
236 "HealthMonitorDashboard.createTimingControlPanel.showTrendLine=Show trend line"})
237 private JPanel createTimingControlPanel() {
238 JPanel timingControlPanel = new JPanel();
239
240 // If the monitor is not enabled, don't add any components
241 if(! HealthMonitor.monitorIsEnabled()) {
242 return timingControlPanel;
243 }
244
245 // Create the combo box for selecting how much data to display
246 String[] dateOptionStrings = Arrays.stream(DateRange.values()).map(e -> e.getLabel()).toArray(String[]::new);
247 timingDateComboBox = new JComboBox<>(dateOptionStrings);
248 timingDateComboBox.setSelectedItem(DateRange.ONE_DAY.getLabel());
249
250 // Set up the listener on the date combo box
251 timingDateComboBox.addActionListener(new ActionListener() {
252 @Override
253 public void actionPerformed(ActionEvent arg0) {
254 try {
256 } catch (HealthMonitorException ex) {
257 logger.log(Level.SEVERE, "Error updating timing metric panel", ex);
258 }
259 }
260 });
261
262 // Create an array of host names
263 Set<String> hostNameSet = new HashSet<>();
264 for(String metricType:timingData.keySet()) {
265 for(HealthMonitor.DatabaseTimingResult result: timingData.get(metricType)) {
266 hostNameSet.add(result.getHostName());
267 }
268 }
269
270 // Load the host names into the combo box
271 timingHostComboBox = new JComboBox<>(hostNameSet.toArray(new String[hostNameSet.size()]));
272
273 // Set up the listener on the combo box
274 timingHostComboBox.addActionListener(new ActionListener() {
275 @Override
276 public void actionPerformed(ActionEvent arg0) {
277 try {
278 if((timingHostCheckBox != null) && timingHostCheckBox.isSelected()) {
280 }
281 } catch (HealthMonitorException ex) {
282 logger.log(Level.SEVERE, "Error populating timing metric panel", ex);
283 }
284 }
285 });
286
287 // Create the host checkbox
288 timingHostCheckBox = new JCheckBox(Bundle.HealthMonitorDashboard_createTimingControlPanel_filterByHost());
289 timingHostCheckBox.setSelected(false);
290 timingHostComboBox.setEnabled(false);
291
292 // Set up the listener on the checkbox
293 timingHostCheckBox.addActionListener(new ActionListener() {
294 @Override
295 public void actionPerformed(ActionEvent arg0) {
296 try {
297 timingHostComboBox.setEnabled(timingHostCheckBox.isSelected());
299 } catch (HealthMonitorException ex) {
300 logger.log(Level.SEVERE, "Error populating timing metric panel", ex);
301 }
302 }
303 });
304
305 // Create the checkbox for showing the trend line
306 timingShowTrendLineCheckBox = new JCheckBox(Bundle.HealthMonitorDashboard_createTimingControlPanel_showTrendLine());
307 timingShowTrendLineCheckBox.setSelected(true);
308
309 // Set up the listener on the checkbox
310 timingShowTrendLineCheckBox.addActionListener(new ActionListener() {
311 @Override
312 public void actionPerformed(ActionEvent arg0) {
313 try {
315 } catch (HealthMonitorException ex) {
316 logger.log(Level.SEVERE, "Error populating timing metric panel", ex);
317 }
318 }
319 });
320
321 // Create the checkbox for omitting outliers
322 timingSkipOutliersCheckBox = new JCheckBox(Bundle.HealthMonitorDashboard_createTimingControlPanel_skipOutliers());
323 timingSkipOutliersCheckBox.setSelected(false);
324
325 // Set up the listener on the checkbox
326 timingSkipOutliersCheckBox.addActionListener(new ActionListener() {
327 @Override
328 public void actionPerformed(ActionEvent arg0) {
329 try {
331 } catch (HealthMonitorException ex) {
332 logger.log(Level.SEVERE, "Error populating timing metric panel", ex);
333 }
334 }
335 });
336
337 // Add the date range combo box and label to the panel
338 timingControlPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createTimingControlPanel_maxDays()));
339 timingControlPanel.add(timingDateComboBox);
340
341 // Put some space between the elements
342 timingControlPanel.add(Box.createHorizontalStrut(100));
343
344 // Add the host combo box and checkbox to the panel
345 timingControlPanel.add(timingHostCheckBox);
346 timingControlPanel.add(timingHostComboBox);
347
348 // Put some space between the elements
349 timingControlPanel.add(Box.createHorizontalStrut(100));
350
351 // Add the skip outliers checkbox
352 timingControlPanel.add(this.timingShowTrendLineCheckBox);
353
354 // Put some space between the elements
355 timingControlPanel.add(Box.createHorizontalStrut(100));
356
357 // Add the skip outliers checkbox
358 timingControlPanel.add(this.timingSkipOutliersCheckBox);
359
360 return timingControlPanel;
361 }
362
367 @NbBundle.Messages({"HealthMonitorDashboard.updateTimingMetricGraphs.noData=No data to display"})
368 private void updateTimingMetricGraphs() throws HealthMonitorException {
369
370 // Clear out any old graphs
371 timingGraphPanel.removeAll();
372
373 if(timingData.keySet().isEmpty()) {
374 // There are no timing metrics in the database
375 timingGraphPanel.add(new JLabel(Bundle.HealthMonitorDashboard_updateTimingMetricGraphs_noData()));
376 return;
377 }
378
379 for(String metricName:timingData.keySet()) {
380
381 // If necessary, trim down the list of results to fit the selected time range
382 List<HealthMonitor.DatabaseTimingResult> intermediateTimingDataForDisplay;
383 if(timingDateComboBox.getSelectedItem() != null) {
384 DateRange selectedDateRange = DateRange.fromLabel(timingDateComboBox.getSelectedItem().toString());
385 long threshold = System.currentTimeMillis() - selectedDateRange.getTimestampRange();
386 intermediateTimingDataForDisplay = timingData.get(metricName).stream()
387 .filter(t -> t.getTimestamp() > threshold)
388 .collect(Collectors.toList());
389 } else {
390 intermediateTimingDataForDisplay = timingData.get(metricName);
391 }
392
393 // Get the name of the selected host, if there is one.
394 // The graph always uses the data from all hosts to generate the x and y scales
395 // so we don't filter anything out here.
396 String hostToDisplay = null;
397 if(timingHostCheckBox.isSelected() && (timingHostComboBox.getSelectedItem() != null)) {
398 hostToDisplay = timingHostComboBox.getSelectedItem().toString();
399 }
400
401 // Generate the graph
402 TimingMetricGraphPanel singleTimingGraphPanel = new TimingMetricGraphPanel(intermediateTimingDataForDisplay,
403 hostToDisplay, true, metricName, timingSkipOutliersCheckBox.isSelected(), timingShowTrendLineCheckBox.isSelected());
404 singleTimingGraphPanel.setPreferredSize(new Dimension(700,200));
405
406 timingGraphPanel.add(singleTimingGraphPanel);
407 }
408 timingGraphPanel.revalidate();
409 timingGraphPanel.repaint();
410 }
411
417 @NbBundle.Messages({"HealthMonitorDashboard.createUserPanel.noData=No data to display - monitor is not enabled",
418 "HealthMonitorDashboard.createUserPanel.userMetricsTitle=User Metrics"})
419 private JPanel createUserPanel() throws HealthMonitorException {
420 // If the monitor isn't enabled, just add a message
421 if(! HealthMonitor.monitorIsEnabled()) {
422 JPanel emptyUserMetricPanel = new JPanel();
423 emptyUserMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createUserPanel_userMetricsTitle()));
424 emptyUserMetricPanel.add(new JLabel(" "));
425 emptyUserMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createUserPanel_noData()));
426
427 return emptyUserMetricPanel;
428 }
429
430 JPanel userMetricPanel = new JPanel();
431 userMetricPanel.setLayout(new BoxLayout(userMetricPanel, BoxLayout.PAGE_AXIS));
432 userMetricPanel.setBorder(BorderFactory.createEtchedBorder());
433
434 // Add title
435 JLabel userMetricTitle = new JLabel(Bundle.HealthMonitorDashboard_createUserPanel_userMetricsTitle());
436 userMetricPanel.add(userMetricTitle);
437 userMetricPanel.add(new JSeparator());
438
439 // Add the controls
440 userMetricPanel.add(createUserControlPanel());
441 userMetricPanel.add(new JSeparator());
442
443 // Create panel to hold graphs
444 userGraphPanel = new JPanel();
445 userGraphPanel.setLayout(new GridLayout(0,2));
446
447 // Update the graph panel, put it in a scroll pane, and add to the timing metric panel
449 JScrollPane scrollPane = new JScrollPane(userGraphPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
450 userMetricPanel.add(scrollPane);
451 userMetricPanel.revalidate();
452 userMetricPanel.repaint();
453
454 return userMetricPanel;
455 }
456
461 @NbBundle.Messages({"HealthMonitorDashboard.createUserControlPanel.maxDays=Max days to display",
462 "HealthMonitorDashboard.createUserControlPanel.userReportButton=Generate Report",
463 "HealthMonitorDashboard.createUserControlPanel.reportError=Error generating report",
464 "# {0} - Report file name",
465 "HealthMonitorDashboard.createUserControlPanel.reportDone=Report saved to: {0}"})
466 private JPanel createUserControlPanel() {
467 JPanel userControlPanel = new JPanel();
468
469 // If the monitor is not enabled, don't add any components
470 if(! HealthMonitor.monitorIsEnabled()) {
471 return userControlPanel;
472 }
473
474 // Create the combo box for selecting how much data to display
475 String[] dateOptionStrings = Arrays.stream(DateRange.values()).map(e -> e.getLabel()).toArray(String[]::new);
476 userDateComboBox = new JComboBox<>(dateOptionStrings);
477 userDateComboBox.setSelectedItem(DateRange.ONE_DAY.getLabel());
478
479 // Set up the listener on the date combo box
480 userDateComboBox.addActionListener(new ActionListener() {
481 @Override
482 public void actionPerformed(ActionEvent arg0) {
483 try {
485 } catch (HealthMonitorException ex) {
486 logger.log(Level.SEVERE, "Error updating user metric panel", ex);
487 }
488 }
489 });
490
491 // Add the date range combo box and label to the panel
492 userControlPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createUserControlPanel_maxDays()));
493 userControlPanel.add(userDateComboBox);
494
495 // Create a button to create a user report
496 JButton reportButton = new JButton(Bundle.HealthMonitorDashboard_createUserControlPanel_userReportButton());
497
498 // Set up a listener on the report button
499 reportButton.addActionListener(new ActionListener() {
500 @Override
501 public void actionPerformed(ActionEvent arg0) {
502 JFileChooser reportFileChooser = chooserHelper.getChooser();
503 reportFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
504 reportFileChooser.setCurrentDirectory(new File(UserPreferences.getHealthMonitorReportPath()));
505 final DateFormat csvTimestampFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
506 String fileName = "UserReport_" + csvTimestampFormat.format(new Date())+ ".csv";
507 reportFileChooser.setSelectedFile(new File(fileName));
508
509 int returnVal = reportFileChooser.showSaveDialog(userControlPanel);
510 if (returnVal == JFileChooser.APPROVE_OPTION) {
511
512 File selectedFile = reportFileChooser.getSelectedFile();
513 UserPreferences.setHealthMonitorReportPath(selectedFile.getParent());
514 try {
515 dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
516 generateCSVUserReport(selectedFile);
517 MessageNotifyUtil.Message.info(Bundle.HealthMonitorDashboard_createUserControlPanel_reportDone(selectedFile.getAbsoluteFile()));
518 } catch (HealthMonitorException ex) {
519 logger.log(Level.SEVERE, "Error generating report", ex);
520 MessageNotifyUtil.Message.error(Bundle.HealthMonitorDashboard_createUserControlPanel_reportError());
521 } finally {
522 dialog.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
523 }
524 }
525 }
526 });
527 userControlPanel.add(reportButton);
528
529 return userControlPanel;
530 }
531
539 private void generateCSVUserReport(File reportFile) throws HealthMonitorException {
540 final DateFormat timestampFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
541
542 try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(reportFile), StandardCharsets.UTF_8))) {
543 // Write header
544 writer.write("Case open,Case close,Duration,Host,User,Case name");
545 writer.newLine();
546
547 // Get the list of user data sorted by timestamp
548 List<HealthMonitor.UserData> dataForReport = HealthMonitor.getInstance().getUserMetricsFromDatabase(DateRange.ONE_WEEK.getTimestampRange());
549 Collections.sort(dataForReport);
550
551 // Go through the list of events in order of timestamp. For each case open event, look for the next case closed
552 // event for that host/user/case name.
553 for (int caseOpenIndex = 0; caseOpenIndex < dataForReport.size() - 1; caseOpenIndex++) {
554 if (! dataForReport.get(caseOpenIndex).getEventType().equals(HealthMonitor.UserEvent.CASE_OPEN)) {
555 continue;
556 }
557
558 // Try to find the next event logged for this user/host. We do not check that
559 // it is a case closed event.
560 HealthMonitor.UserData caseOpenEvent = dataForReport.get(caseOpenIndex);
561 HealthMonitor.UserData nextEventAfterCaseOpen = null;
562 for (int nextEventIndex = caseOpenIndex + 1; nextEventIndex < dataForReport.size(); nextEventIndex++) {
563 HealthMonitor.UserData nextEvent = dataForReport.get(nextEventIndex);
564 // If the user and host name do not match, ignore this event
565 if ( nextEvent.getHostname().equals(caseOpenEvent.getHostname())
566 && nextEvent.getUserName().equals(caseOpenEvent.getUserName())) {
567 nextEventAfterCaseOpen = nextEvent;
568 break;
569 }
570 }
571
572 // Prepare the columns
573 String caseOpenTime = timestampFormat.format(caseOpenEvent.getTimestamp());
574
575 // If everything is recorded properly then the next event for a given user after
576 // a case open will be a case close. In this case we record the close time and
577 // how long the case was open. If the next event was not a case close event
578 // or if there is no next event (which could happen if Autopsy crashed or if
579 // there were network issues, or if the user simply still has the case open),
580 // leave the close time and duration blank.
581 String caseCloseTime = "";
582 String duration = "";
583 if (nextEventAfterCaseOpen != null
584 && nextEventAfterCaseOpen.getEventType().equals(HealthMonitor.UserEvent.CASE_CLOSE)
585 && nextEventAfterCaseOpen.getCaseName().equals(caseOpenEvent.getCaseName())) {
586 caseCloseTime = timestampFormat.format(nextEventAfterCaseOpen.getTimestamp());
587 duration = getDuration(caseOpenEvent.getTimestamp(), nextEventAfterCaseOpen.getTimestamp());
588 }
589
590 String host = caseOpenEvent.getHostname();
591 String user = caseOpenEvent.getUserName();
592 String caseName = caseOpenEvent.getCaseName();
593
594 String csvEntry = caseOpenTime + "," + caseCloseTime + "," + duration + "," + host + "," + user + ",\"" + caseName + "\"";
595 writer.write(csvEntry);
596 writer.newLine();
597 }
598 } catch (IOException ex) {
599 throw new HealthMonitorException("Error writing to output file " + reportFile.getAbsolutePath(), ex);
600 }
601 }
602
612 private String getDuration(long start, long end) {
613 long durationInSeconds = (end - start) / 1000;
614 long second = durationInSeconds % 60;
615 long minute = (durationInSeconds / 60) % 60;
616 long hours = durationInSeconds / (60 * 60);
617
618 return String.format("%d:%02d:%02d", hours, minute, second);
619 }
620
625 @NbBundle.Messages({"HealthMonitorDashboard.updateUserMetricGraphs.noData=No data to display"})
626 private void updateUserMetricGraphs() throws HealthMonitorException {
627
628 // Clear out any old graphs
629 userGraphPanel.removeAll();
630
631 if(userData.isEmpty()) {
632 // There are no user metrics in the database
633 userGraphPanel.add(new JLabel(Bundle.HealthMonitorDashboard_updateUserMetricGraphs_noData()));
634 return;
635 }
636
637 // Calculate the minimum timestamp for the graph.
638 // Unlike the timing graphs, we do not filter the list of user metrics here.
639 // This is because even if we're only displaying one day, the
640 // last metric for a host may be that it logged on two days ago, so we would want
641 // to show that node as logged on.
642 long timestampThreshold;
643 if(userDateComboBox.getSelectedItem() != null) {
644 DateRange selectedDateRange = DateRange.fromLabel(userDateComboBox.getSelectedItem().toString());
645 timestampThreshold = System.currentTimeMillis() - selectedDateRange.getTimestampRange();
646
647 } else {
648 timestampThreshold = System.currentTimeMillis() - DateRange.getMaximumTimestampRange();
649 }
650
651 // Generate the graphs
652 UserMetricGraphPanel caseGraphPanel = new UserMetricGraphPanel(userData, timestampThreshold, true);
653 caseGraphPanel.setPreferredSize(new Dimension(700,200));
654
655 UserMetricGraphPanel logonGraphPanel = new UserMetricGraphPanel(userData, timestampThreshold, false);
656 logonGraphPanel.setPreferredSize(new Dimension(700,200));
657
658 userGraphPanel.add(caseGraphPanel);
659 userGraphPanel.add(logonGraphPanel);
660 userGraphPanel.revalidate();
661 userGraphPanel.repaint();
662 }
663
669 @NbBundle.Messages({"HealthMonitorDashboard.createAdminPanel.enableButton=Enable monitor",
670 "HealthMonitorDashboard.createAdminPanel.disableButton=Disable monitor"})
671 private JPanel createAdminPanel() {
672
673 JPanel adminPanel = new JPanel();
674 adminPanel.setBorder(BorderFactory.createEtchedBorder());
675
676 // Create the buttons for enabling/disabling the monitor
677 JButton enableButton = new JButton(Bundle.HealthMonitorDashboard_createAdminPanel_enableButton());
678 JButton disableButton = new JButton(Bundle.HealthMonitorDashboard_createAdminPanel_disableButton());
679
680 boolean isEnabled = HealthMonitor.monitorIsEnabled();
681 enableButton.setEnabled(! isEnabled);
682 disableButton.setEnabled(isEnabled);
683
684 // Set up a listener on the enable button
685 enableButton.addActionListener(new ActionListener() {
686 @Override
687 public void actionPerformed(ActionEvent arg0) {
688 try {
689 dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
690 HealthMonitor.setEnabled(true);
691 redisplay();
692 } catch (HealthMonitorException ex) {
693 logger.log(Level.SEVERE, "Error enabling monitoring", ex);
694 } finally {
695 dialog.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
696 }
697 }
698 });
699
700 // Set up a listener on the disable button
701 disableButton.addActionListener(new ActionListener() {
702 @Override
703 public void actionPerformed(ActionEvent arg0) {
704 try {
705 dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
706 HealthMonitor.setEnabled(false);
707 redisplay();
708 } catch (HealthMonitorException ex) {
709 logger.log(Level.SEVERE, "Error disabling monitoring", ex);
710 } finally {
711 dialog.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
712 }
713 }
714 });
715
716 // Add the buttons
717 adminPanel.add(enableButton);
718 adminPanel.add(Box.createHorizontalStrut(25));
719 adminPanel.add(disableButton);
720
721 return adminPanel;
722 }
723
727 @NbBundle.Messages({"HealthMonitorDashboard.DateRange.oneMonth=One month",
728 "HealthMonitorDashboard.DateRange.twoWeeks=Two weeks",
729 "HealthMonitorDashboard.DateRange.oneWeek=One week",
730 "HealthMonitorDashboard.DateRange.oneDay=One day"})
731 private enum DateRange {
732 ONE_DAY(Bundle.HealthMonitorDashboard_DateRange_oneDay(), 1),
733 ONE_WEEK(Bundle.HealthMonitorDashboard_DateRange_oneWeek(), 7),
734 TWO_WEEKS(Bundle.HealthMonitorDashboard_DateRange_twoWeeks(), 14),
735 ONE_MONTH(Bundle.HealthMonitorDashboard_DateRange_oneMonth(), 31);
736
737 private final String label;
738 private final long numberOfDays;
739 private static final long MILLISECONDS_PER_DAY = 1000 * 60 * 60 * 24;
740
742 this.label = label;
743 this.numberOfDays = numberOfDays;
744 }
745
750 String getLabel() {
751 return label;
752 }
753
761 if (numberOfDays > 0) {
763 } else {
764 return Long.MAX_VALUE;
765 }
766 }
767
774 long maxRange = Long.MIN_VALUE;
775 for (DateRange dateRange : DateRange.values()) {
776 if (dateRange.getTimestampRange() > maxRange) {
777 maxRange = dateRange.getTimestampRange();
778 }
779 }
780 return maxRange;
781 }
782
783 static DateRange fromLabel(String text) {
784 for (DateRange dateRange : DateRange.values()) {
785 if (dateRange.label.equalsIgnoreCase(text)) {
786 return dateRange;
787 }
788 }
789 return ONE_DAY; // If the comparison failed, return a default
790 }
791 }
792
793}
static void setHealthMonitorReportPath(String reportPath)
synchronized static Logger getLogger(String name)
Definition Logger.java:124

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.