0

I am learning Java (SE 8) using the Eclipse IDE (Oxygen) on Windows. I have done some "hobby" programming before but this is my first formal class in the subject. I want to be able to print the output that the assignment requires in the normal console (System.out.println) and print informational what's happening text into a different console at the same time.

In pseudocode what I want is something like:

printToConsole1("Normal program outputs."); printToConsole2("Behind the scenes information.");

Can I do anything like this in Java?

  • Stuff like this is possible but not really easy for a first time student. Why do you want to do this? Also: would using Swing (a GUI) and two or more windows on screen work? – markspace Mar 26 '18 at 22:47
  • Why not prepend the *behind-the-scenes information* with `[DEBUG]`? – Jacob G. Mar 26 '18 at 22:48
  • Also, you can print to standard err (`System.err.println()`) and my IDE (which is not Eclipse) will format those lines differently -- they show up in red, making them easy spot. – markspace Mar 26 '18 at 22:55
  • @markspace - FYI, I tried your suggestion and Eclipse (Oyxgen) does format the **err.println()** in red text. This is helpful if I cannot find a better way but I would like to have a technique that does not disrupt the appearance of the actual program output. You should post that as an answer, I may end up selecting it. – Ambrose2018 Mar 28 '18 at 20:50
  • @markspace - I am not sure if my instructor will allow me to use Swing, I will ask him. In the meantime are you by any chance thinking about [**swing-console**](https://github.com/mikera/swing-console) ... that caught my eye last night and I am going to explore it as soon as I have some free time. *Hopefully it (still) works as it has not been updated since 2013.* I will keep you posted. – Ambrose2018 Mar 28 '18 at 20:55

3 Answers3

1

Using a logging framework like Logback or Log4j2, you can write messages at specific logging levels or from different loggers to two separate files. In this vein, you can accomplish what you're looking for; you would write out the "normal" output to either the console or one file, and the behind-the-scenes information to a separate file.

How to configure these in your application is well outside the scope of Stack Overflow, but I strongly encourage you to peruse them.

Hey, there's no one saying you can't have two terminal windows open, y'know?

Makoto
  • 104,088
  • 27
  • 192
  • 230
  • Are you aware of any way to watch the log file data being updated in real time? If it is plain text I would guess something like Notepad++ (which alerts when a file is changed) could be used by manually reloading the file. Not quite what I am looking for but thank you. – Ambrose2018 Mar 28 '18 at 20:58
  • @Ambrose2018: `tail -100f /path/to/log/file.txt` would do it "in real time". Monitoring logs is a fickle business, and you definitely *don't* want to open a text editor to watch a live stream. – Makoto Mar 28 '18 at 21:01
  • Isn't *tail* a linux command? I have never seen it in Windows (though I am sure someone probably has created something like it). ... UPDATE: I found this: https://stackify.com/13-ways-to-tail-a-log-file-on-windows-unix/ (I should have looked before I posted.) – Ambrose2018 Mar 28 '18 at 21:03
  • It is. I don't know the same command for Windows machines. That I leave as an exercise for the reader. – Makoto Mar 28 '18 at 21:04
  • Here is a StackExchange Q/A that addresses ways to do *tail* on Windows. https://stackoverflow.com/questions/187587/a-windows-equivalent-of-the-unix-tail-command – Ambrose2018 Mar 28 '18 at 21:16
0

You can print to standard err (System.err.println()) and my IDE (which is not Eclipse) will format those lines differently -- they show up in red, making them easy spot.

Regarding swing-console, no I was thinking of something different. Namely just using the logging framework as Makoto suggested, and then just using a log handler that will display log lines to a window. The following is a short example I created.

/**
 * A log handler which creates a visible window for logging output.
 * 
 * <p>A WindowHandler is a standard log handler which may be utilized
 * in just the same was as any other log handler.</p>
 *
 * <p>In addition, a convenience static method is provided, WindowHandler.show(),
 * which will programmatically install a root handler and display a window,
 * allowing debugging output to be easily captured and viewed on screen.</p>
 * 
 * @author Brenden
 */
public class WindowHandler extends java.util.logging.Handler {

   // These static globals must be accessed on the EDT only!
   private static WindowHandler globalHandler;
   private static final ArrayList<WeakReference<WindowHandler>> windowList =
           new ArrayList<>();

   private JTextArea text;
   private JFrame logWindow;

   /**
    * Returns the window component (usually a JFrame) associated with this
    * WindowHandler.
    * 
    * @return The top-level window for this handler.
    */
   public Component getWindow() {
      return logWindow;
   }

   /**
    * Returns the JTextArea associated with the logging output captured by
    * this handler.
    * 
    * @return A JTextArea where logging is displayed. 
    */
   public JTextArea getTextArea() {
      return text;
   }

   /**
    * A list of ALL WindowHandler created so far in the system.
    * 
    * <p>This list is useful for getting a list of windows on screen, for
    * example, and then performing some operation on these windows.  For
    * example, hiding all windows, or closing them, or tiling them on screen
    * for easier viewing.</p>
    * 
    * @return An array list of all current window handlers. 
    */
   public static ArrayList<WindowHandler> getHandlers() {
      ArrayList<WindowHandler> retVal = new ArrayList<>();
      for( WeakReference<WindowHandler> wr : windowList ) {
         WindowHandler h = wr.get();
         if( h != null ) retVal.add( h );
      }
      return retVal;
   }

   /**
    * A convenience method for starting an instance of a WindowHandler.
    * 
    * <p>Call this method at the beginning of your program.  After calling
    * this method, all debugging output will be captured by the 
    * WindowHandler.  Note that individual loggers still have their respective
    * log levels.  WindowHandler is set to Level.ALL by default, but won't
    * receive output from loggers that have their own levels set too high
    * to capture output.</p>
    */
   public static synchronized void show() {
      utilEDTWait( () -> {
         if( globalHandler == null ) {
            Logger root = Logger.getLogger( "" );
            root.addHandler( globalHandler = new WindowHandler() );
         } else {
            globalHandler.getWindow().setVisible( true );
         }
      } );
   }

   /**
    * Creates a new WindowHandler.
    * 
    * <p>This method creates a new handler, sets its level to ALL, and creates
    * the necessary Swing components on the EDT, and displays those components
    * as well.  After creation, this handler may still be configured as normal
    * for any other logging handler.</p>
    */
   public WindowHandler() {
      utilEDTWait( () -> {
         setLevel( Level.ALL );
         JFrame frame = new JFrame( "DEBUG" );
         text = new JTextArea();
         text.setEditable( false );
         text.setPreferredSize( new Dimension( 300, 300 ) );
         JScrollPane scroll = new JScrollPane( text );
         frame.add( scroll );
         frame.setDefaultCloseOperation( JFrame.HIDE_ON_CLOSE );
         frame.pack();
         frame.setLocation( windowList.size()*20, windowList.size()*20 );
         frame.setVisible( true );
         logWindow = frame;
         windowList.add( new WeakReference<>( this ) );
      } );
   }

   @Override
   public void publish( LogRecord record ) {
      SwingUtilities.invokeLater( () -> {
         StringBuilder log = new StringBuilder( text.getText() );
         log.append( record.getMessage() );
         log.append( " -- " );
         log.append( record.getLoggerName() );
         log.append( " : " );
         log.append( record.getLevel() );
         log.append( "  //  " );
         log.append( new Date( record.getMillis() ) );
         log.append( "\n" );
         text.setText( log.toString() );
      } );
   }

   @Override
   public void flush() {
   }

   @Override
   public void close() throws SecurityException {
   }

   private static void utilEDTWait( Runnable r ) {
      if( SwingUtilities.isEventDispatchThread() ) {
         r.run();
      } else {
         try {
            SwingUtilities.invokeAndWait( r );
         } catch( InterruptedException ex ) {
            Thread.currentThread().interrupt();
            throw new RuntimeException( ex );
         } catch( InvocationTargetException ex ) {
            Logger.getLogger( WindowHandler.class.getName() ).log( Level.SEVERE, null, ex );
         }
      }
   }

}
markspace
  • 10,621
  • 3
  • 25
  • 39
  • This is great **markspace**. Both suggestions (*err.print* and *logHandler*) are practical and fairly easy to implement. I had run across the following *jTextArea* article and was thinking about ways to implement it for my purposes when you provided the answer above. Much appreciation to both you and **Makato**. https://docs.oracle.com/javase/tutorial/uiswing/components/textarea.html – Ambrose2018 Mar 29 '18 at 22:32
-1

No. Your Java Application has the same limitations as any process: a standard input (System.in), a standard output (System.out), and standard error output (System.err), and both the regular and error output are displayed in the same Console. They are, however, displayed using different colors. Typically you would either wrap invocations of one using a master boolean value as an on/off switch, or use a logging library of some kind that would make the two kinds of output easier to differentiate.

Separating the two into consoles of their own would make for an interesting feature request.

nitind
  • 19,089
  • 4
  • 34
  • 43