Print

Print


Author: [log in to unmask]
Date: Mon Mar  9 15:46:12 2015
New Revision: 2383

Log:
Add logging to terminal or file via a menu item.  HPSJAVA-462

Modified:
    java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/Commands.java
    java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/JobSettingsPanel.java
    java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java
    java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogPanel.java
    java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogTable.java
    java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/Main.java
    java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MenuBar.java
    java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplication.java
    java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java
    java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotPanel.java
    java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SettingsPanel.java
    java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/TriggerDiagnosticsPanel.java

Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/Commands.java
 =============================================================================
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/Commands.java	(original)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/Commands.java	Mon Mar  9 15:46:12 2015
@@ -38,10 +38,15 @@
     static final String SAVE_PLOTS = "savePlots";
     static final String CLEAR_PLOTS = "resetPlots";
     
+    // Exit the application.
     static final String EXIT = "exit";
+           
+    // Log to file or standard print stream.
+    static final String LOG_TO_FILE = "logToFile";
+    static final String LOG_TO_TERMINAL = "logToTerminal";
     
-    static final String LOG_LEVEL_FILTER_CHANGED = "logLevelFilterChanged";
-        
+    static final String LOG_LEVEL_FILTER_CHANGED = "logLevelFilterChanged";    
+    
     ////////////////////////////////////////////    
     static final String BLOCKING_CHANGED = "blockingChanged";
     static final String CHOOSE_COMPACT_FILE = "chooseCompactFile";
@@ -59,10 +64,7 @@
     static final String FREEZE_CONDITIONS_CHANGED = "freezeConditionsChanged";
     
     static final String LOG_LEVEL_CHANGED = "logLevelChanged";
-    static final String LOG_TO_FILE = "logToFile";
-    static final String LOG_TO_FILE_CHANGED = "logToFileChanged";
-    static final String LOG_TO_TERMINAL = "logToTerminal";
-
+    
     static final String PROCESSING_STAGE_CHANGED = "processingStageChanged";    
     static final String SAVE_LOG_TABLE = "saveLogTable";            
     static final String SELECT_LOG_FILE = "logToFile";

Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/JobSettingsPanel.java
 =============================================================================
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/JobSettingsPanel.java	(original)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/JobSettingsPanel.java	Mon Mar  9 15:46:12 2015
@@ -1,7 +1,29 @@
 package org.hps.monitoring.application;
 
-import static org.hps.monitoring.application.Commands.*;
-import static org.hps.monitoring.application.model.ConfigurationModel.*;
+import static org.hps.monitoring.application.Commands.DETECTOR_ALIAS_CHANGED;
+import static org.hps.monitoring.application.Commands.DETECTOR_NAME_CHANGED;
+import static org.hps.monitoring.application.Commands.DISCONNECT_ON_END_RUN_CHANGED;
+import static org.hps.monitoring.application.Commands.DISCONNECT_ON_ERROR_CHANGED;
+import static org.hps.monitoring.application.Commands.EVENT_BUILDER_CHANGED;
+import static org.hps.monitoring.application.Commands.FREEZE_CONDITIONS_CHANGED;
+import static org.hps.monitoring.application.Commands.LOG_LEVEL_CHANGED;
+import static org.hps.monitoring.application.Commands.STEERING_RESOURCE_CHANGED;
+import static org.hps.monitoring.application.Commands.STEERING_TYPE_CHANGED;
+import static org.hps.monitoring.application.Commands.USER_RUN_NUMBER_CHANGED;
+import static org.hps.monitoring.application.model.ConfigurationModel.DETECTOR_ALIAS_PROPERTY;
+import static org.hps.monitoring.application.model.ConfigurationModel.DETECTOR_NAME_PROPERTY;
+import static org.hps.monitoring.application.model.ConfigurationModel.DISCONNECT_ON_END_RUN_PROPERTY;
+import static org.hps.monitoring.application.model.ConfigurationModel.DISCONNECT_ON_ERROR_PROPERTY;
+import static org.hps.monitoring.application.model.ConfigurationModel.EVENT_BUILDER_PROPERTY;
+import static org.hps.monitoring.application.model.ConfigurationModel.FREEZE_CONDITIONS_PROPERTY;
+import static org.hps.monitoring.application.model.ConfigurationModel.LOG_FILE_NAME_PROPERTY;
+import static org.hps.monitoring.application.model.ConfigurationModel.LOG_LEVEL_PROPERTY;
+import static org.hps.monitoring.application.model.ConfigurationModel.LOG_TO_FILE_PROPERTY;
+import static org.hps.monitoring.application.model.ConfigurationModel.MAX_EVENTS_PROPERTY;
+import static org.hps.monitoring.application.model.ConfigurationModel.STEERING_FILE_PROPERTY;
+import static org.hps.monitoring.application.model.ConfigurationModel.STEERING_RESOURCE_PROPERTY;
+import static org.hps.monitoring.application.model.ConfigurationModel.STEERING_TYPE_PROPERTY;
+import static org.hps.monitoring.application.model.ConfigurationModel.USER_RUN_NUMBER_PROPERTY;
 
 import java.awt.GridBagLayout;
 import java.awt.Insets;
@@ -18,6 +40,7 @@
 import javax.swing.JComboBox;
 import javax.swing.JFileChooser;
 import javax.swing.JTextField;
+import javax.swing.border.EmptyBorder;
 import javax.swing.filechooser.FileFilter;
 
 import org.hps.monitoring.application.model.ConfigurationModel;
@@ -44,10 +67,10 @@
     private JCheckBox freezeConditionsCheckBox;    
     private JTextField maxEventsField;
     private JCheckBox disconnectOnErrorCheckBox;
-    private JCheckBox disconnectOnEndRunCheckBox;
-    private JTextField logFileNameField;
+    private JCheckBox disconnectOnEndRunCheckBox;    
     private JComboBox<?> logLevelComboBox;
     private JCheckBox logToFileCheckbox;
+    private JTextField logFileNameField;
            
     // The package where steering resources must be located.
     static final String STEERING_PACKAGE = "org/hps/steering/monitoring/";
@@ -68,9 +91,13 @@
     /**
      * Class constructor.
      */
-    JobSettingsPanel() {
-
-        super(new Insets(4, 2, 2, 4), true);
+    JobSettingsPanel(ConfigurationModel model) {
+
+        super(new Insets(5, 3, 3, 5), true);
+        
+        setBorder(new EmptyBorder(10, 10, 10, 10));
+        
+        model.addPropertyChangeListener(this);
         
         setLayout(new GridBagLayout());
 
@@ -136,11 +163,9 @@
                                             
         logToFileCheckbox = addCheckBox("Log to File", false, false);
         logToFileCheckbox.setEnabled(false);
-        logToFileCheckbox.setActionCommand(LOG_TO_FILE_CHANGED);
-        logToFileCheckbox.addActionListener(this);
-
-        logFileNameField = addField("Log File", "", "Full path to log file.", 30, false);
-        logFileNameField.addPropertyChangeListener("value", this);
+
+        logFileNameField = addField("Log File Name", "", "Full path to log file.", 50, false);
+        logFileNameField.setEditable(false);
     }
 
     @Override
@@ -152,8 +177,6 @@
      * Attaches the ActionListener from the main app to specific GUI components in this class.
      */
     public void addActionListener(ActionListener listener) {
-        logFileNameField.addActionListener(listener);
-        logToFileCheckbox.addActionListener(listener);
         steeringResourcesComboBox.addActionListener(listener);
         freezeConditionsCheckBox.addActionListener(listener);
     }
@@ -252,8 +275,6 @@
                 configurationModel.setSteeringType(SteeringType.valueOf((String) steeringTypeComboBox.getSelectedItem()));
             } else if (STEERING_RESOURCE_CHANGED.equals(event.getActionCommand())) {
                 configurationModel.setSteeringResource((String) steeringResourcesComboBox.getSelectedItem());
-            } else if (LOG_TO_FILE_CHANGED.equals(event.getActionCommand())) {
-                configurationModel.setLogToFile(logToFileCheckbox.isSelected());
             } else if (LOG_LEVEL_CHANGED.equals(event.getActionCommand())) {
                 configurationModel.setLogLevel(Level.parse((String) logLevelComboBox.getSelectedItem()));
             } else if (EVENT_BUILDER_CHANGED.equals(event.getActionCommand())) {
@@ -279,8 +300,8 @@
     }
 
     /**
-     * Updates the configuration with changes from the GUI component values. The changes from the
-     * GUI are distinguishable by their component object.
+     * Updates the configuration with changes from the GUI component values. 
+     * The changes from the GUI are distinguishable by their component object.
      */
     @Override
     public void propertyChange(PropertyChangeEvent evt) {                            
@@ -289,8 +310,6 @@
             Object source = evt.getSource();            
             if (source == steeringFileField) {
                 configurationModel.setSteeringFile(steeringFileField.getText());
-            } else if (source == logFileNameField) {
-                configurationModel.setLogFileName(logFileNameField.getText());
             } else if (source == userRunNumberField) {
                 // Is run number being reset to null or empty?
                 if (userRunNumberField.getText() == null || userRunNumberField.getText().isEmpty()) {
@@ -314,7 +333,21 @@
                 }
             } else if (source == maxEventsField) {
                 configurationModel.setMaxEvents(Long.parseLong(maxEventsField.getText()));
-                System.out.println("setMaxEvents - " + configurationModel.getMaxEvents());
+                //System.out.println("setMaxEvents - " + configurationModel.getMaxEvents());
+            } else if (evt.getPropertyName().equals(ConfigurationModel.LOG_TO_FILE_PROPERTY)) {
+                // This is getting the log to file prop change from the ConfigurationModel to update a read only component.
+                Boolean logToFile = (Boolean) evt.getNewValue();
+                if (logToFile != null) {
+                    logToFileCheckbox.setSelected(logToFile);
+                }
+            } else if (evt.getPropertyName().equals(ConfigurationModel.LOG_FILE_NAME_PROPERTY)) {
+                // This is getting the log file name prop change from the ConfigurationModel to update a read only component.
+                String logFileName = (String) evt.getNewValue();
+                if (logFileName != null && logFileName.length() > 0) {
+                    logFileNameField.setText(logFileName);
+                } else {
+                    logFileNameField.setText("");
+                }
             }
         } finally {
             configurationModel.addPropertyChangeListener(this);

Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java
 =============================================================================
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java	(original)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java	Mon Mar  9 15:46:12 2015
@@ -16,7 +16,7 @@
  * 
  * @author Jeremy McCormick <[log in to unmask]>
  */
-public class LogLevelFilterComboBox extends JComboBox<Level> implements ActionListener, PropertyChangeListener {
+class LogLevelFilterComboBox extends JComboBox<Level> implements ActionListener, PropertyChangeListener {
    
     ConfigurationModel configurationModel;
     

Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogPanel.java
 =============================================================================
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogPanel.java	(original)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogPanel.java	Mon Mar  9 15:46:12 2015
@@ -17,11 +17,16 @@
  * This is a simple GUI component for the log table and its controls.
  * @author Jeremy McCormick <[log in to unmask]>
  */
-public class LogPanel extends JPanel {
+class LogPanel extends JPanel{ 
 
     LogTable logTable;
+    LogLevelFilterComboBox logFilterComboBox;
+    
+    ConfigurationModel configurationModel;
         
     LogPanel(ConfigurationModel configurationModel, ActionListener listener) {
+        
+        this.configurationModel = configurationModel;
         
         setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
         
@@ -31,8 +36,8 @@
         controlsPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 5));
         
         JLabel label = new JLabel("Log Level Filter");
-        LogLevelFilterComboBox logFilterComboBox = new LogLevelFilterComboBox(configurationModel);
-        logFilterComboBox.setToolTipText("Messages below this level will be filtered out.");              
+        logFilterComboBox = new LogLevelFilterComboBox(configurationModel);
+        logFilterComboBox.setToolTipText("Messages below this level will be filtered out.");
         controlsPanel.add(label);        
         controlsPanel.add(logFilterComboBox);
         
@@ -51,5 +56,5 @@
                 
         add(controlsPanel, BorderLayout.PAGE_START);
         add(tablePane, BorderLayout.PAGE_END);
-    }    
+    }          
 }

Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogTable.java
 =============================================================================
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogTable.java	(original)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogTable.java	Mon Mar  9 15:46:12 2015
@@ -132,5 +132,5 @@
             filterLevel = (Level) event.getNewValue();
             model.fireTableDataChanged();
         }
-    }
+    }    
 }

Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/Main.java
 =============================================================================
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/Main.java	(original)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/Main.java	Mon Mar  9 15:46:12 2015
@@ -10,7 +10,6 @@
 import org.apache.commons.cli.ParseException;
 import org.apache.commons.cli.PosixParser;
 import org.hps.monitoring.application.model.Configuration;
-
 
 /**
  * This is the front-end for running the monitoring app via a {@link #main(String[])} method.

Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MenuBar.java
 =============================================================================
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MenuBar.java	(original)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MenuBar.java	Mon Mar  9 15:46:12 2015
@@ -39,16 +39,17 @@
     JMenuItem closeFileItem;
     JMenuItem openFileItem;    
     JMenu settingsMenu;
-    ConfigurationModel configurationModel;
+    JMenuItem logItem;
+    ConfigurationModel configurationModel;    
     
     MenuBar(ConfigurationModel configurationModel, ConnectionStatusModel connectionModel, ActionListener listener) {
-        
-        // Do not need to listen for changes on this model.
-        this.configurationModel = configurationModel;
+         
+        this.configurationModel = configurationModel;        
+        this.configurationModel.addPropertyChangeListener(this);
         
         // Need to listen for connection status changes.
-        connectionModel.addPropertyChangeListener(this);                
-
+        connectionModel.addPropertyChangeListener(this);  
+        
         JMenu fileMenu = new JMenu("File");
         fileMenu.setMnemonic(KeyEvent.VK_F);
         add(fileMenu);
@@ -138,6 +139,14 @@
         screenshotItem.setToolTipText("Save a screenshot to a graphics file");
         toolsMenu.add(screenshotItem);
         
+        logItem = new JMenuItem("Log to File ...");
+        logItem.setMnemonic(KeyEvent.VK_R);
+        logItem.setActionCommand(Commands.LOG_TO_FILE);
+        logItem.addActionListener(listener);
+        logItem.setEnabled(true);
+        logItem.setToolTipText("Redirect System.out to a file instead of terminal");
+        toolsMenu.add(logItem);
+        
         JMenu windowMenu = new JMenu("Window");
         windowMenu.setMnemonic(KeyEvent.VK_W);
         add(windowMenu);
@@ -164,64 +173,34 @@
         defaultsItem.addActionListener(listener);
         defaultsItem.setEnabled(true);
         defaultsItem.setToolTipText("Restore the window defaults");
-        windowMenu.add(defaultsItem);        
-        
-        /*                       
-
-        JMenu logMenu = new JMenu("Log");
-        logMenu.setMnemonic(KeyEvent.VK_L);
-        add(logMenu);
-
-        logItem = new JMenuItem("Redirect to File ...");
-        logItem.setMnemonic(KeyEvent.VK_F);
-        logItem.setActionCommand(CHOOSE_LOG_FILE);
-        //logItem.addActionListener(this);
-        logItem.setEnabled(true);
-        logItem.setToolTipText("Redirect std out and err to a file.");
-        logMenu.add(logItem);
-
-        terminalItem = new JMenuItem("Redirect to Terminal");
-        terminalItem.setMnemonic(KeyEvent.VK_T);
-        terminalItem.setActionCommand(LOG_TO_TERMINAL);
-        //terminalItem.addActionListener(this);
-        terminalItem.setEnabled(false);
-        terminalItem.setToolTipText("Redirect std out and err back to the terminal.");
-        logMenu.add(terminalItem);
-
-        JMenuItem saveLogItem = new JMenuItem("Save Log Table to File ...");
-        saveLogItem.setMnemonic(KeyEvent.VK_S);
-        saveLogItem.setActionCommand(SAVE_LOG_TABLE);
-        //saveLogItem.addActionListener(this);
-        saveLogItem.setToolTipText("Save the log records to a tab delimited text file.");
-        logMenu.add(saveLogItem);
-
-        JMenuItem clearLogItem = new JMenuItem("Clear Log Table");
-        //clearLogItem.addActionListener(this);
-        clearLogItem.setMnemonic(KeyEvent.VK_C);
-        clearLogItem.setActionCommand(CLEAR_LOG_TABLE);
-        clearLogItem.setToolTipText("Clear the log table of all messages.");
-        logMenu.add(clearLogItem);
-
-        JMenu utilMenu = new JMenu("Util");
-        plotsMenu.setMnemonic(KeyEvent.VK_U);
-        add(utilMenu);
-
-        JMenuItem screenshotItem = new JMenuItem("Take a Screenshot ...");
-        screenshotItem.setMnemonic(KeyEvent.VK_N);
-        screenshotItem.setActionCommand(SCREENSHOT);
-        //screenshotItem.addActionListener(this);
-        screenshotItem.setToolTipText("Save a screenshot to file");
-        utilMenu.add(screenshotItem);
-        */
+        windowMenu.add(defaultsItem);
     }
 
     @Override
     public void propertyChange(PropertyChangeEvent evt) {
-        if (evt.getPropertyName().equals(ConnectionStatusModel.CONNECTION_STATUS_PROPERTY)) {
-            ConnectionStatus status = (ConnectionStatus) evt.getNewValue();
-            boolean connected = status.equals(ConnectionStatus.CONNECTED);            
-            closeFileItem.setEnabled(!connected);
-            openFileItem.setEnabled(!connected);
+        configurationModel.removePropertyChangeListener(this);        
+        try {            
+            if (evt.getPropertyName().equals(ConnectionStatusModel.CONNECTION_STATUS_PROPERTY)) {
+                ConnectionStatus status = (ConnectionStatus) evt.getNewValue();
+                boolean connected = status.equals(ConnectionStatus.CONNECTED);
+                closeFileItem.setEnabled(!connected);
+                openFileItem.setEnabled(!connected);
+            } else if (evt.getPropertyName().equals(ConfigurationModel.LOG_TO_FILE_PROPERTY)) {
+                Boolean logToFile = (Boolean) evt.getNewValue();
+                if (logToFile == true) {
+                    // Toggle log item state to send to terminal.
+                    logItem.setText("Log to Terminal ...");
+                    logItem.setActionCommand(Commands.LOG_TO_TERMINAL);
+                    logItem.setToolTipText("Log messages to the terminal");
+                } else {
+                    // Toggle log item state to send to file.
+                    logItem.setText("Log to File ...");
+                    logItem.setActionCommand(Commands.LOG_TO_FILE);
+                    logItem.setToolTipText("Log messages to a file");
+                }
+            }
+        } finally {
+            configurationModel.addPropertyChangeListener(this);
         }
     }
 
@@ -234,6 +213,5 @@
                 closeFileItem.setEnabled(false);
             }
         }        
-    }
-    
+    }    
 }

Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplication.java
 =============================================================================
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplication.java	(original)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplication.java	Mon Mar  9 15:46:12 2015
@@ -14,7 +14,10 @@
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.io.PrintStream;
 import java.util.ArrayList;
 import java.util.List;
@@ -32,7 +35,6 @@
 import javax.swing.filechooser.FileFilter;
 import javax.swing.filechooser.FileNameExtensionFilter;
 
-import org.hps.conditions.database.DatabaseConditionsManager;
 import org.hps.monitoring.application.DataSourceComboBox.DataSourceItem;
 import org.hps.monitoring.application.LogTable.LogRecordModel;
 import org.hps.monitoring.application.model.Configuration;
@@ -73,7 +75,9 @@
     static final Level DEFAULT_LEVEL = Level.ALL;
 
     // Default log stream.
-    PrintStream logStream = System.out;
+    MonitoringApplicationStreamHandler streamHandler;
+    PrintStream sysOut = System.out;
+    PrintStream sysErr = System.err;
     
     // Application error handling.
     final ErrorHandler errorHandler;
@@ -124,6 +128,22 @@
     
     LogTable getLogTable() {
         return frame.logPanel.logTable;
+    }
+    
+    class MonitoringApplicationStreamHandler extends StreamHandler {
+        
+        MonitoringApplicationStreamHandler(PrintStream ps) {
+            super(ps, new DefaultLogFormatter());
+        }
+        
+        public void publish(LogRecord record) {
+            super.publish(record);
+            flush();
+        }
+        
+        public void setOutputStream(OutputStream out) {
+            super.setOutputStream(out);
+        }        
     }
              
     /**
@@ -160,6 +180,21 @@
         loadConfiguration(this.configuration);
                 
         logger.info("application initialized successfully");
+    }
+    
+    /**
+     * Setup the logger.
+     */
+    void setupLogger() {
+        logger.setUseParentHandlers(false);        
+        logger.addHandler(new LogHandler());
+        streamHandler = new MonitoringApplicationStreamHandler(System.out);
+        logger.addHandler(streamHandler);
+        for (Handler handler : logger.getHandlers()) {
+            handler.setLevel(DEFAULT_LEVEL);
+        }
+        logger.setLevel(DEFAULT_LEVEL);
+        logger.info("logging initialized");
     }
     
     /**
@@ -229,7 +264,11 @@
             saveLogTable();
         } else if (Commands.CLEAR_LOG_TABLE.equals(cmd)) {
             getLogRecordModel().clear();
-        }        
+        } else if (Commands.LOG_TO_FILE.equals(cmd)) {
+            chooseLogFile();
+        } else if (Commands.LOG_TO_TERMINAL.equals(cmd)) {
+            logToTerminal();
+        }
     }    
     
     /**
@@ -255,26 +294,7 @@
         // Perform global configuration of the JFreeChart back end.
         AnalysisFactory.configure();
     }
-    
-    /**
-     * Setup the logger.
-     */
-    void setupLogger() {
-        logger.setUseParentHandlers(false);
-        logger.addHandler(new LogHandler());
-        logger.addHandler(new StreamHandler(logStream, new DefaultLogFormatter()) {
-            public void publish(LogRecord record) {
-                super.publish(record);
-                flush();
-            }
-        });
-        for (Handler handler : logger.getHandlers()) {
-            handler.setLevel(DEFAULT_LEVEL);
-        }
-        logger.setLevel(DEFAULT_LEVEL);
-        logger.info("logging initialized");
-    }
-            
+                
     /**
      * This method sets the configuration on the model, which fires a change for every property.
      * @param configuration The new configuration.
@@ -644,4 +664,87 @@
     void saveLogTable() {
         saveTable(frame.logPanel.logTable);
     }
+        
+    /**
+     * Redirect <code>System.out</code> and <code>System.err</code> to file chosen
+     * by a file chooser.
+     */
+    void chooseLogFile() {
+        JFileChooser fc = new JFileChooser();
+        fc.setAcceptAllFileFilterUsed(false);
+        fc.setDialogTitle("Save Log Messages to File");       
+        fc.setCurrentDirectory(new File("."));
+        int r = fc.showSaveDialog(frame);
+        if (r == JFileChooser.APPROVE_OPTION) {            
+            String fileName = fc.getSelectedFile().getPath();
+            if (new File(fileName).exists()) {
+                DialogUtil.showErrorDialog(frame, "File Exists", "File already exists.");
+            } else {
+                logToFile(new File(fileName));
+            }
+        }        
+    }
+    
+    /**
+     * Redirect <code>System.out</code> and <code>System.err</code> to a file.
+     * @param file The output log file.
+     * @throws FileNotFoundException if the file does not exist.
+     */
+    void logToFile(File file) {
+        try {
+            
+            // Create the output file stream.
+            PrintStream fileStream = new PrintStream(new FileOutputStream(file.getPath()));
+            System.setOut(fileStream);
+            System.setErr(fileStream);
+            
+            // Flush the current handler, but do NOT close here or System.out gets clobbered!
+            streamHandler.flush();
+            
+            // Replace the current handler with one using the file stream.
+            logger.removeHandler(streamHandler);
+            streamHandler = new MonitoringApplicationStreamHandler(fileStream);
+            streamHandler.setLevel(logger.getLevel());
+            logger.addHandler(streamHandler);
+            
+            // Set the properties on the model.
+            configurationModel.setLogFileName(file.getPath());
+            configurationModel.setLogToFile(true);
+            
+            logger.info("Saving log messages to " + configurationModel.getLogFileName());
+            DialogUtil.showInfoDialog(frame, "Logging to File", 
+                    "Log messages redirected to file" + '\n' + configurationModel.getLogFileName());
+            
+        } catch (FileNotFoundException e) {
+            errorHandler.setError(e).log().showErrorDialog();
+        }
+    }      
+    
+    /**
+     * Send <code>System.out</code> and <code>System.err</code> back to the terminal, 
+     * e.g. if they were previously sent to a file.
+     */
+    void logToTerminal() {
+        
+        // Reset System.out and err back to original streams.
+        System.setOut(sysOut);
+        System.setErr(sysErr);
+        
+        // Flush and close the current handler, which is using a file stream.
+        streamHandler.flush();
+        streamHandler.close();
+        
+        // Replace the handler with the one printing to the terminal.
+        logger.removeHandler(streamHandler);               
+        streamHandler = new MonitoringApplicationStreamHandler(System.out);
+        streamHandler.setLevel(logger.getLevel());
+        logger.addHandler(streamHandler);
+        
+        logger.log(Level.INFO, "log messages redirected to terminal");
+        
+        // Update the model to indicate logging to file has been disabled.
+        configurationModel.setLogToFile(false);
+        
+        DialogUtil.showInfoDialog(frame, "Log to Terminal", "Log messages will be sent to the terminal.");
+    }    
 }

Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java
 =============================================================================
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java	(original)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java	Mon Mar  9 15:46:12 2015
@@ -38,9 +38,9 @@
 /**
  * <p>
  * This is a GUI component for showing the statistics and other information about an AIDA plot
- * when it is clicked on in the monitoring app.
+ * when it is clicked on in the monitoring application.
  * <p>
- * The information is updated dynamically via the <code>AIDAObserver</code> API on the AIDA object.
+ * The information in the table is updated dynamically via the <code>AIDAObserver</code> API on the AIDA object.
  */
 class PlotInfoPanel extends JPanel implements AIDAListener, ActionListener, FunctionListener {
 

Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotPanel.java
 =============================================================================
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotPanel.java	(original)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotPanel.java	Mon Mar  9 15:46:12 2015
@@ -6,7 +6,7 @@
 import javax.swing.JTabbedPane;
 
 /**
- * This is the panel containing the monitoring plots.
+ * This is the panel containing the tabs with the monitoring plots.
  * @author Jeremy McCormick <[log in to unmask]>
  */
 class PlotPanel extends JPanel {

Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SettingsPanel.java
 =============================================================================
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SettingsPanel.java	(original)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SettingsPanel.java	Mon Mar  9 15:46:12 2015
@@ -31,7 +31,7 @@
         this.parent = parent;
         
         connectionPanel = new ConnectionSettingsPanel();        
-        jobPanel = new JobSettingsPanel();
+        jobPanel = new JobSettingsPanel(configurationModel);
         
         // Push configuration to sub-components.
         connectionPanel.setConfigurationModel(configurationModel);
@@ -55,7 +55,6 @@
         add(Box.createRigidArea(new Dimension(1, 5)));
         JPanel buttonsPanel = new JPanel();
         buttonsPanel.add(okayButton);
-        //buttonsPanel.add(defaultsButton);
         buttonsPanel.setLayout(new FlowLayout());
         add(buttonsPanel);
         add(Box.createRigidArea(new Dimension(1, 5)));

Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/TriggerDiagnosticsPanel.java
 =============================================================================
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/TriggerDiagnosticsPanel.java	(original)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/TriggerDiagnosticsPanel.java	Mon Mar  9 15:46:12 2015
@@ -21,7 +21,7 @@
  * 
  * @author Jeremy McCormick <[log in to unmask]>
  */
-public class TriggerDiagnosticsPanel extends JPanel {
+class TriggerDiagnosticsPanel extends JPanel {
 
     JTabbedPane tabs = new JTabbedPane();
     ClusterTablePanel clusterPanel = new ClusterTablePanel();