jLogMan Documentation

__TOC__

Embedding in an Application

packaging

using zip from website. After unpacking the zip you can do "java -jar jLogMan.jar" to for jLogMan test. The lib directory contains a few jars that are used by jLogMan.

Extracting and unpacking jars from nbm, include outline-jar.

example source code for embedding

There are a few bits of code here. A two liner that calls the init method and then brings up the logTree dialog; this is followed by the methods used in the two lines.

A method for initialized jLogMan and an action class to bring up a non-modal dialog with the log tree table. Note that the SwingLogTree that is returned from the initLogMan(); method is used for the dialog as shown in the two line fragment.

    // initialize jLogMan and save the logTree model for the action
    LogManAction.setModel(initLogMan("com/mypath/to/prefs"));
    // bring up the dialog
    LogManAction.get().actionPerformed(null);
    /**
     * Initialize jLogMan for this JVM's logging. Set up Preferences.
     *
     * @return logTree model which references modified loggers.
     */
    private static SwingLogTree initLogMan(String prefsPath) {
        // create logging interface to this JVM's logger
        LogCom logCom = new LocalLogCom();
        // LogCom logCom = new RestrictedLogCom(LogManager.getLoggingMXBean());
        SwingLogTree logTree = new SwingLogTree(logCom);
        // Initialize jLogMan.
        // The Current Configuration is applied if Preference so indicates
        StringBuilder emsg = LogUtil.init(logTree,
                            Preferences.userRoot().node(prefsPath));

        if(emsg != null && emsg.length() != 0) {
            // put up a dialog with the error, could log it
            displayInitError(emsg.toString());
        }

        // Even with an error during startup initialization,
        // the model is OK; no exception was thrown.
        return logTree;
    }
    /**
     * Factory for Action that brings up jLogMan outline/tree-table.
     * If the dialog containing the logTree table is still open,
     * possibly minimized or hidden, then this action fronts it.
     *
     * TODO: This should have icons and such.
     */
    final class LogManAction extends AbstractAction {
        // The lock shouldn't be needed since everything is on EventQueue, but...
        private static final Object LOCK = new Object();
        private static JDialog INSTANCE;
        private static SwingLogTree logTree;

        static void setModel(SwingLogTree logTree) {
            if(LogManAction.logTree != null)
                throw new IllegalStateException("logTree already set");
            LogManAction.logTree = logTree;
        }

        static LogManAction get() {
            if(LogManAction.logTree == null)
                throw new IllegalStateException("logTree not set");
            return new LogManAction();
        }

        private LogManAction() {
            super("jLogMan");
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            synchronized(LOCK) {
                if(INSTANCE == null) {
                    JDialog dialog;

                    logTree.refresh();
                    dialog = LogUI.createOutlineDialog(logTree, (JFrame)null);
                    dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
                    dialog.addWindowListener(new WindowAdapter() {
                        @Override public void windowClosed(WindowEvent e) {
                            synchronized(LOCK) { INSTANCE = null; }
                        }});
                    INSTANCE = dialog;
                    dialog.setVisible(true);
                } else {
                    INSTANCE.setVisible(true);
                    INSTANCE.toFront();
                }
            }
        }
    }

Gotchas and Programming Considerations

Things work best if the application does not modify the logging configuration or if any setup or modifications occur before jLogMan init. The reason for this is simply that programmatic changes could override changes made by jLogMan.

If the application uses standard practice for logging configuration jLogMan does not have any problems.

Two of common patterns for using Loggers are

   Logger.getLogger(clazz.class.getName()).log(Level.SEVERE, null, ex);

and

   private static final Logger LOG = Logger.getLogger(LogTree.class.getName());
   LOG.log(Level.SEVERE, null, ex);

And customization, for example of logging levels, is done either through the LogManager properties or by JVM startup properties. See the LogManager documentation for details.

Garbage Collection

Notice that in the first usage pattern in the previous section, the program does not keep a reference to the logger. In this situation, setting a logger level like

   Logger.getLogger(clazz.class.getName()).setLevel(Level.FINER);

only last as long as the logger is not garbage collected, since the LogManager only keeps a weak reference.

The jLogMan logTree model keeps a reference to any logger that it modifies. Thus it is important to use a single logTree model and keep a reference to it.

other issues

There is no notification mechanism for changes in the logging configuration. The refresh action is used to update the known state.

Loggers are created on demand, Handlers are not. An implication is that changing the level on a handler may fail, if the application hasn't yet created it. This isn't an issue if the handler is created through LogManager properties.