Menu

#83 Better STDOUT/STDERR support

closed
nobody
None
5
2006-08-23
2006-07-12
No

At this moment STDOUT and STDERR are used to get
messages into the JmolConsole, making it rather
difficult to catch and redirect these somewhere other
than this JmolConsole. For example, Bioclipse has it's
own console, but some Jmol messages are debug or error
messages, while others are really informative messages
for the user. Moreover, I can't just route STDOUT to
the BioclipseConsole anyway, as any Bioclipse plugin
could potentially spit things to STDOUT...

Discussion

  • Bob Hanson

    Bob Hanson - 2006-07-13

    Logged In: YES
    user_id=1082841

    There isn't an actual request here, but I did some testing,
    and I have this to report:

    There are 412 instances of "System.out.println" in the
    Viewer package. Some of these might be commented out; it's
    not a perfect count.

    I changed these to "viewer.systemOutPrintln" calls, and then
    added a flag that turns these off. "set systemOutEnabled
    false" and back on "set systemOutEnabled true".

    Interestingly enough, there was also an unused nonpublic
    "logError()" function that did exactly this, but was never
    implemented. So basically I have replaced
    "viewer.logError()" with "viewer.systemOutPrintln()".

    I realize that that is only the first step - the second
    would be to go through these and decide which should go to
    the equivalent of STDOUT and which to the equivalent of
    STDERR -- and which should just be abandoned. But the point
    is, it's pretty easy to do this sort of wholesale change.

    Should I commit these changes? Are we OK with that? It
    obviously doesn't affect any functionality (well, it COULD,
    but I think we've been careful not to load any actual
    functionality into any System.out.println() call. So I think
    the chances are very good that it is not a problem.

    The changes are all minor, but they are all over the place
    (about 70 files, I think).

    And the changes I put in really make it SILENT when you flip
    that toggle. We could have something like verbose levels if
    we wanted.

    You decide. What's the actual feature request?

    Bob

     
  • Nobody/Anonymous

    Logged In: NO

    Ok, the systemOutPrintln() is probably a first good step;
    splitting them up according to some verbosity level would
    be good too. Except for the verbosity level, I would like
    to request the option to be able to set the PrintStream to
    where the "sysout"s go.

     
  • Nicolas

    Nicolas - 2006-07-13

    Logged In: YES
    user_id=1096197

    My 2 cts:
    - create an Interface (LoggerInterface) with methods:
    debug(), info(), warn(), error(), fatal() (the usual levels
    for example in Log4j)
    - create a Class (DefaultLogger) implementing the above
    interface which would simply output messages to stdout or
    stderr depending on the level
    - create a Class (Logger ?) with static methods debug(), ...
    to do the output by calling the above class, and also static
    methods to change the class really used for the output.
    - replace all the print() calls by Logger.debug(),
    Logger.info(), ...

    Note: Put all the classes / interfaces above in a separate
    package

    This would be very adaptable:
    - for example, Bioclipse could code it's own class
    implementing LoggerInterface and use it instead of Jmol
    default one.
    - if Jmol is integrated in an other project, they could for
    example use Log4J

     
  • Nobody/Anonymous

    Logged In: NO

    Nico, sounds reasonable.

     
  • Bob Hanson

    Bob Hanson - 2006-07-13

    Logged In: YES
    user_id=1082841

    OK, how about this. util is a handy class with not too much
    in it. Logger seems to me to be basically a utility method.
    Could it fit there?

    package org.jmol.util;

    public class Logger {
    static Boolean systemOutEnabled = Boolean.TRUE;

    public static void setEnabled(boolean TF) {
    systemOutEnabled = (TF ? Boolean.TRUE : Boolean.FALSE);
    out.println("systemOutEnabled = " + TF);
    }

    public static class out {
    public static void println(String msg) {
    if (systemOutEnabled.booleanValue())
    System.out.println(msg);
    }
    }
    }

    so one can use

    Logger.out.println()

    instead of System.out.println()

    and

    Logger.setEnabled(true|false);

    and, of course, we could add others.

    OK, you all know better than I how to do this correctly.

     
  • Nobody/Anonymous

    Logged In: NO

    It would be nice if one could set the PrintStream too, for
    example:

    package org.jmol.util;

    public class Logger {

    static boolean systemOutEnabled = true;
    private static PrintStream out = System.out; // the
    default

    public static void setPrintStream(PrintStream out) {
    this.out = out;
    }

    public static void setEnabled(boolean TF) {
    systemOutEnabled = (TF ? Boolean.TRUE :
    Boolean.FALSE);
    out.println("systemOutEnabled = " + TF);
    }

    public static error(String msg) {
    print("ERROR ");
    println(msg);
    }

    private static void println(String msg) {
    if (systemOutEnabled.booleanValue())
    System.out.println(msg);
    }
    }
    }

     
  • Bob Hanson

    Bob Hanson - 2006-07-13

    Logged In: YES
    user_id=1082841

    Ah, I see. That's interesting -- right -- this is the level
    of Java I'm not familiar with. I'd like to keep this static
    so it can also be used from any static method the way
    System.out.println can. How would we do it without using
    "this" ?

     
  • Nobody/Anonymous

    Logged In: NO

    You are correct: I should not have stated this.out here,
    but the local out *is* static, so it should have stated:

    public static void setPrintStream(PrintStream out) {
    Logger.out = out;
    }

     
  • Nicolas

    Nicolas - 2006-07-13

    Logged In: YES
    user_id=1096197

    This is really not what I had in mind: I was thinking of
    something more flexible.

    See below for coding example (only debug and error levels
    done, info, warn and fatal could be added)

    -------------------

    public Interface LoggerInterface {
    public void debug(String txt);
    public void error(String txt);
    }

    -------------------

    public Class DefaultLogger implements LoggerInterface {
    public DefaultLogger() {
    }
    public void debug(String txt) {
    System.out.println(txt);
    }
    public void error(String txt) {
    System.err.println(txt);
    }
    }

    -------------------

    public class Logger {
    private static LoggerInterface _logger = new DefaultLogger();

    public static void setLogger(LoggerInterface logger) {
    _logger = logger;
    }

    public static void debug(String txt) {
    _logger.debug(txt);
    }
    public static void error(String txt) {
    _logger.error(txt);
    }
    }

    -------------------

    Eventually, DefaultLogger can be modified to authorize some
    customisation.

     
  • Nobody/Anonymous

    Logged In: NO

    And the DefaultLogger can this have the 'enabled' field.
    This is more general and flexible indeed.

    BTW, who said we needed a mailing list ?? :)

     
  • Bob Hanson

    Bob Hanson - 2006-07-13

    Logged In: YES
    user_id=1082841

    Nico,

    OK, that's slick. Can you synthesize these two ideas, adding
    in the set enabled/disabled business? I think there is a
    middle level of "note" or "warn" between "debug" and "err"
    that could be useful. -- Messages that are standard or
    informational but could be avoided. Maybe "inform"

     
  • Nicolas

    Nicolas - 2006-07-13

    Logged In: YES
    user_id=1096197

    Let's keep the usual levels in order of importance (Log4j) :
    - debug
    - info
    - warn
    - error
    - fatal

     
  • Bob Hanson

    Bob Hanson - 2006-07-13

    Logged In: YES
    user_id=1082841

    This is an easy addition, at least at the "back end" -- the
    class itself and the interface. Nico, do you want to make
    the addition? I can go through the Viewer methods after that
    and make a call on what's which level. Let's then have a
    verbose level that corresponds to these. I can add that to
    eval afterwards.

    Please add it to bob200603 anytime if you want to.

     
  • Nicolas

    Nicolas - 2006-07-13

    Logged In: YES
    user_id=1096197

    I have just done the first version of the Logger, but SVN
    commit isn't currently working. I will try to commit it
    tomorrow.

    I have created 5 levels, and I suggest to use them this way:
    - fatal: fatal errors in Jmol (error + tells that Jmol may
    not work correctly afterwards)
    - error: errors in Jmol (unexpected error: indicates a
    coding problem)
    - warn: user error (wrong script, ...) or problem that is
    dealt with by Jmol (incorrect file format, ...)
    - info: information only
    - debug (deactivated by default): for developers

    For other applications integrating Jmol (Bioclipse for
    example), the default logger can be replaced by a custom logger.

    Each level can be activated/deactivated through a system
    property "jmol.logger.<level>" or by calling
    Logger.setActiveLevel(). It works even if a custom logger is
    used.

    Logging is done simply by calling Logger.debug("Text"),
    Logger.info("Text"), ...

     
  • Bob Hanson

    Bob Hanson - 2006-08-23
    • status: open --> closed
     
  • Bob Hanson

    Bob Hanson - 2006-08-23

    Logged In: YES
    user_id=1082841

    Logger done

     

Log in to post a comment.