I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
LogWriter.java 6.99 KiB
Newer Older
zzz's avatar
zzz committed
package net.i2p.util;

/*
 * public domain
 *
 */

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
zzz's avatar
zzz committed
import java.util.Queue;
zzz's avatar
zzz committed

/**
 * bridge to android logging
 *
 * @author zzz
 */
class LogWriter implements Runnable {
    /** every 10 seconds? why? Just have the gui force a reread after a change?? */
zzz's avatar
zzz committed
    private final static long CONFIG_READ_ITERVAL = 10 * 1000;
    final static long FLUSH_INTERVAL = 29 * 1000;
    private final static long MIN_FLUSH_INTERVAL = 2*1000;
    private final static long MAX_FLUSH_INTERVAL = 5*60*1000;
zzz's avatar
zzz committed
    private long _lastReadConfig = 0;
    private long _numBytesInCurrentFile = 0;
    private OutputStream _currentOut; // = System.out
    private int _rotationNum = -1;
    private String _logFilenamePattern;
    private File _currentFile;
    private LogManager _manager;

    private boolean _write;
    // ms
    private volatile long _flushInterval = FLUSH_INTERVAL;
zzz's avatar
zzz committed
    private LogWriter() { // nop
    }

    public LogWriter(LogManager manager) {
        _manager = manager;
    }

    public void stopWriting() {
        _write = false;
    }
    /**
     *  @param interval in ms
     *  @since 0.9.18
     */
    public void setFlushInterval(long interval) {
        _flushInterval = Math.min(MAX_FLUSH_INTERVAL, Math.max(MIN_FLUSH_INTERVAL, interval));
    }

zzz's avatar
zzz committed
    public void run() {
        _write = true;
        try {
            while (_write) {
                flushRecords();
zzz's avatar
zzz committed
                if (_write)
                    rereadConfig();
zzz's avatar
zzz committed
            }
        } catch (Exception e) {
            System.err.println("Error writing the logs: " + e.getMessage());
            e.printStackTrace(System.err);
zzz's avatar
zzz committed
        }
    }

    public void flushRecords() { flushRecords(true); }
    public void flushRecords(boolean shouldWait) {
        try {
zzz's avatar
zzz committed
            // zero copy, drain the manager queue directly
            Queue<LogRecord> records = _manager.getQueue();
zzz's avatar
zzz committed
            if (records == null) return;
zzz's avatar
zzz committed
            if (!records.isEmpty()) {
                LogRecord rec;
                while ((rec = records.poll()) != null) {
                    writeRecord(rec);
                }
                try {
                    if (_currentOut != null)
                        _currentOut.flush();
                } catch (IOException ioe) {
                    //if (++_diskFullMessageCount < MAX_DISKFULL_MESSAGES)
                        System.err.println("Error writing the router log - disk full? " + ioe);
                }
zzz's avatar
zzz committed
            }
        } catch (Throwable t) {
            t.printStackTrace(System.err);
zzz's avatar
zzz committed
        } finally {
            if (shouldWait) {
zzz's avatar
zzz committed
                    synchronized (this) {
                        this.wait(_flushInterval);
zzz's avatar
zzz committed
                    }
                } catch (InterruptedException ie) { // nop
                }
            }
        }
    }
zzz's avatar
zzz committed

    public String currentFile() {
        return _currentFile != null ? _currentFile.getAbsolutePath() : "uninitialized";
    }
zzz's avatar
zzz committed
    private void rereadConfig() {
        long now = Clock.getInstance().now();
        if (now - _lastReadConfig > CONFIG_READ_ITERVAL) {
            _manager.rereadConfig();
            _lastReadConfig = now;
        }
    }

    private void writeRecord(LogRecord rec) {
        if (rec.getThrowable() == null)
            log(rec.getPriority(), rec.getSource(), rec.getSourceName(), rec.getThreadName(), rec.getMessage());
zzz's avatar
zzz committed
        else
            log(rec.getPriority(), rec.getSource(), rec.getSourceName(), rec.getThreadName(), rec.getMessage(), rec.getThrowable());
zzz's avatar
zzz committed

zzz's avatar
zzz committed
        // to be viewed on android screen
        String val = LogRecordFormatter.formatRecord(_manager, rec, true);
        _manager.getBuffer().add(val);
        if (rec.getPriority() >= Log.ERROR)
            _manager.getBuffer().addCritical(val);

zzz's avatar
zzz committed
        // we always add to the console buffer, but only sometimes write to stdout
        if (_manager.getDisplayOnScreenLevel() <= rec.getPriority()) {
            if (_manager.displayOnScreen()) {
                // android log already does time stamps, so reformat without the date
                System.out.print(LogRecordFormatter.formatRecord(_manager, rec, false));
            }
        }
zzz's avatar
zzz committed
    }

zzz's avatar
zzz committed
    private static final String ANDROID_LOG_TAG = "I2P";

    public void log(int priority, Class<?> src, String name, String threadName, String msg) {
            if (src != null) {
                String tag = src.getName();
                int dot = tag.lastIndexOf(".");
                if (dot >= 0)
                    tag = tag.substring(dot + 1);
zzz's avatar
zzz committed
                android.util.Log.println(toAndroidLevel(priority),
zzz's avatar
zzz committed
                                         ANDROID_LOG_TAG,
                                         tag +
                                         " [" + threadName + "] " + msg);
            } else if (name != null)
zzz's avatar
zzz committed
                android.util.Log.println(toAndroidLevel(priority),
zzz's avatar
zzz committed
                                         ANDROID_LOG_TAG,
                                         name +
                                         " ["  + threadName + "] " + msg);
zzz's avatar
zzz committed
            else
                android.util.Log.println(toAndroidLevel(priority),
zzz's avatar
zzz committed
                                         ANDROID_LOG_TAG,
                                         '[' + threadName + "] " + msg);
zzz's avatar
zzz committed
    }

    public void log(int priority, Class<?> src, String name, String threadName, String msg, Throwable t) {
            if (src != null) {
                String tag = src.getName();
                int dot = tag.lastIndexOf(".");
                if (dot >= 0)
                    tag = tag.substring(dot + 1);
zzz's avatar
zzz committed
                android.util.Log.println(toAndroidLevel(priority),
zzz's avatar
zzz committed
                                         ANDROID_LOG_TAG,
                                         tag +
                                         " [" + threadName + "] " + msg +
                                         ' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
            } else if (name != null)
zzz's avatar
zzz committed
                android.util.Log.println(toAndroidLevel(priority),
zzz's avatar
zzz committed
                                         ANDROID_LOG_TAG,
                                         name +
                                         " [" + threadName + "] " + msg +
                                         ' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
zzz's avatar
zzz committed
            else
                android.util.Log.println(toAndroidLevel(priority),
zzz's avatar
zzz committed
                                         ANDROID_LOG_TAG,
                                         '[' + threadName + "] " +
zzz's avatar
zzz committed
                                         msg + ' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
    }

    private static int toAndroidLevel(int level) {
        switch (level) {
        case Log.DEBUG:
            return android.util.Log.DEBUG;
        case Log.INFO:
            return android.util.Log.INFO;
        case Log.WARN:
            return android.util.Log.WARN;
        case Log.ERROR:
        case Log.CRIT:
        default:
            return android.util.Log.ERROR;
        }
    }
}