Skip to content
Snippets Groups Projects
Logger.java 5.04 KiB
Newer Older
package cz.fidentis.analyst;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.logging.Level;

/**
 * A logging class that can be used from anywhere to display debugging or other
 * messages.
 * <p>
 * Messages are printed into the system standard output by default. But can be also
 * redirected to system error output or into the pipe.
 * If the messages are redirected into pipe, then <b>a consumer has to be running 
 * concurrently</b> and reading the data through the {@link #read()} method.
 * <b>Otherwise, the program can freeze due to the full buffer!</b>
 * FIDENTIS application automatically redirects logged messages to the output window 
 * via the {@code OutputWindowThread}. 
 * </p>
 * <p>
 * <b>Usage:</b>
 * <ul>
 *    <li>To print a message, use {@code Logger.print("message")}. A timestamp is added automatically.</li>
 *    <li>To print message together with duration, call {@code Logger log = Logger.measureTime();}, 
 *        then call the measured operations and finally call {@code log.printDuration("message")}. 
 *        a timestamp and measured duration are added to the log message automatically.</li>
 * </ul>
 * </p>
 * 
 * @author Radek Oslejsek
 */
public final class Logger {
    
    private static final int PIPE_SIZE = 10240; // default is 1024
    
    private static PrintStream out = System.out;
    private static BufferedReader in;
    
    private long lastTime = System.currentTimeMillis();
    
    private Logger() {
    }
    
    /**
     * Redirects messages into a pipe. 
     * <b>A consumer has to be running concurrently</b> and reading the messages
     * through the {@link #read()} method.
     * Otherwise, the program can freeze due to the full buffer!
     */
    public static synchronized void redirectToPipe() {
        if (in != null) {
            return;
        }
        
        PipedOutputStream pOut = new PipedOutputStream();
        out = new PrintStream(pOut);
        try {
            in = new BufferedReader(new InputStreamReader(new PipedInputStream(pOut, PIPE_SIZE)));
        } catch (IOException ex) {
            java.util.logging.Logger.getLogger(Logger.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    /**
     * Redirects messages into the system standard output.
     */
    public static synchronized void redirectToStdOut() {
        out = System.out;
        in = null;
    }
    
    /**
     * Redirects messages into the system error output.
     */
    public static synchronized void redirectToStdErr() {
        out = System.err;
        in = null;
    }
    
    /**
     * Returns an event message. If the logger is redirected to standard or error output,
     * then {@code null} is returned. Also, if the is no message, {@code null} is returned.
     * @return Event message or {@code null}
     * @throws IOException on error in reading the message buffer.
    public static String read() throws IOException {
        if (in == null/* || !in.ready()*/) {
            return null;
    }
    
    /**
     * Prints a message. The log time added automatically.
     * 
     * @param msg Message to be logged
     */
    public static void print(String msg) {
        String outMsg = 
                new SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())
                + " [duration unknown]: "
                + msg.trim();
        out.println(outMsg);
    }

    /**
     * Starts measuring of some operation. 
     * Call {@link #printDuration(java.lang.String)} on returned object
     * to print the measured duration.
     * 
     * @return An object used to print measured duration and message
     */
    public static Logger measureTime() {
        Logger ret = new Logger();
        ret.lastTime = System.currentTimeMillis();
        return ret;
    }
    
    /**
     * Prints the message about an operation and the duration of the operation. 
     * The duration is computed as the difference between current system time and 
     * the time of calling {@link #measureTime()}. The time difference is measured in 
     * milliseconds and printed as [+mm:ss.SSS] where mm=minutes, ss=seconds, 
     * and SSS=milliseconds.
     * 
     * @param msg Message to be printed
     */
    public void printDuration(String msg) {
        Duration duration = Duration.ofMillis(System.currentTimeMillis() - lastTime);
        String outMsg = 
                new SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())
                + " [duration "
                + String.format(
                        "%02d:%02d.%03d", 
                        duration.toMinutes(), 
                        duration.toSecondsPart(),
                        duration.toMillisPart())
                + "]: "
                + msg.trim();