From 03e188b57ad44dce48de4242d29e1a1b6705d7e1 Mon Sep 17 00:00:00 2001
From: str4d <str4d@mail.i2p>
Date: Sat, 28 May 2016 22:51:44 +0000
Subject: [PATCH] Rename LogWriter -> FileLogWriter, LogWriterBase -> LogWriter

---
 core/java/src/net/i2p/util/FileLogWriter.java | 218 +++++++++++++
 core/java/src/net/i2p/util/LogManager.java    |   2 +-
 core/java/src/net/i2p/util/LogWriter.java     | 306 ++++++++----------
 core/java/src/net/i2p/util/LogWriterBase.java | 190 -----------
 4 files changed, 358 insertions(+), 358 deletions(-)
 create mode 100644 core/java/src/net/i2p/util/FileLogWriter.java
 delete mode 100644 core/java/src/net/i2p/util/LogWriterBase.java

diff --git a/core/java/src/net/i2p/util/FileLogWriter.java b/core/java/src/net/i2p/util/FileLogWriter.java
new file mode 100644
index 0000000000..92babcf862
--- /dev/null
+++ b/core/java/src/net/i2p/util/FileLogWriter.java
@@ -0,0 +1,218 @@
+package net.i2p.util;
+
+/*
+ * free (adj.): unencumbered; not under the control of others
+ * Written by jrandom in 2003 and released into the public domain 
+ * with no warranty of any kind, either expressed or implied.  
+ * It probably won't make your computer catch on fire, or eat 
+ * your children, but it might.  Use at your own risk.
+ *
+ */
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
+/**
+ * File-based log writer thread that pulls log records from the LogManager,
+ * writes them to the current logfile, and rotates the logs as necessary.
+ *
+ */
+class FileLogWriter extends LogWriter {
+    // volatile as it changes on log file rotation
+    private volatile Writer _currentOut;
+    private int _rotationNum = -1;
+    private File _currentFile;
+    private long _numBytesInCurrentFile;
+
+    private static final int MAX_DISKFULL_MESSAGES = 8;
+    private int _diskFullMessageCount;
+
+    public FileLogWriter(LogManager manager) {
+        super(manager);
+    }
+
+    /**
+     *  File may not exist or have old logs in it if not opened yet
+     */
+    public synchronized String currentFile() {
+        if (_currentFile != null)
+            return _currentFile.getAbsolutePath();
+        String rv = getNextFile().getAbsolutePath();
+        // so it doesn't increment every time we call this
+        _rotationNum = -1;
+        return rv;
+    }
+
+    protected void writeRecord(LogRecord rec, String formatted) {
+    	writeRecord(rec.getPriority(), formatted);
+    }
+
+    protected synchronized void writeRecord(int priority, String val) {
+        if (val == null) return;
+        if (_currentOut == null) {
+            rotateFile();
+            if (_currentOut == null)
+                return; // hosed
+        }
+
+        try {
+            _currentOut.write(val);
+            // may be a little off if a lot of multi-byte chars, but unlikely
+            _numBytesInCurrentFile += val.length();
+        } catch (Throwable t) {
+            if (!_write)
+                return;
+            if (++_diskFullMessageCount < MAX_DISKFULL_MESSAGES)
+                System.err.println("Error writing log, disk full? " + t);
+            //t.printStackTrace();
+        }
+        if (_numBytesInCurrentFile >= _manager.getFileSize()) {
+            rotateFile();
+        }
+    }
+
+    /**
+     *  @since 0.9.19
+     */
+    protected void flushWriter() {
+        try {
+            if (_currentOut != null)
+                _currentOut.flush();
+        } catch (IOException ioe) {
+            if (_write && ++_diskFullMessageCount < MAX_DISKFULL_MESSAGES)
+                System.err.println("Error writing the router log - disk full? " + ioe);
+        }
+    }
+
+    /**
+     *  @since 0.9.19 renamed from closeFile()
+     */
+    protected void closeWriter() {
+        Writer out = _currentOut;
+        if (out != null) {
+            try {
+                out.close();
+            } catch (IOException ioe) {}
+        }
+    }
+
+    /**
+     * Rotate to the next file (or the first file if this is the first call)
+     *
+     * Caller must synch
+     */
+    private void rotateFile() {
+        File f = getNextFile();
+        _currentFile = f;
+        _numBytesInCurrentFile = 0;
+        File parent = f.getParentFile();
+        if (parent != null) {
+            if (!parent.exists()) {
+                File sd = new SecureDirectory(parent.getAbsolutePath());
+                boolean ok = sd.mkdirs();
+                if (!ok) {
+                    System.err.println("Unable to create the parent directory: " + parent.getAbsolutePath());
+                    //System.exit(0);
+                }
+            }
+            if (!parent.isDirectory()) {
+                System.err.println("Cannot put the logs in a subdirectory of a plain file: " + f.getAbsolutePath());
+                //System.exit(0);
+            }
+        }
+        closeWriter();
+        try {
+            _currentOut = new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(f), "UTF-8"));
+        } catch (IOException ioe) {
+            if (++_diskFullMessageCount < MAX_DISKFULL_MESSAGES)
+                System.err.println("Error creating log file [" + f.getAbsolutePath() + "]" + ioe);
+        }
+    }
+
+    /**
+     * Get the next file in the rotation
+     *
+     * Caller must synch
+     */
+    private File getNextFile() {
+        String pattern = _manager.getBaseLogfilename();
+        File f = new File(pattern);
+        File base = null;
+        if (!f.isAbsolute())
+            base = _manager.getContext().getLogDir();
+
+        if ( (pattern.indexOf('#') < 0) && (pattern.indexOf('@') <= 0) ) {
+            if (base != null)
+                return new File(base, pattern);
+            else
+                return f;
+        }
+        
+        int max = _manager.getRotationLimit();
+        if (_rotationNum == -1) {
+            return getFirstFile(base, pattern, max);
+        }
+             
+        // we're in rotation, just go to the next  
+        _rotationNum++;
+        if (_rotationNum > max) _rotationNum = 0;
+
+        String newf = replace(pattern, _rotationNum);
+        if (base != null)
+            return new File(base, newf);
+        return new File(newf);
+    }
+
+    /**
+     * Retrieve the first file, updating the rotation number accordingly
+     *
+     * Caller must synch
+     */
+    private File getFirstFile(File base, String pattern, int max) {
+        for (int i = 0; i < max; i++) {
+            File f;
+            if (base != null)
+                f = new File(base, replace(pattern, i));
+            else
+                f = new File(replace(pattern, i));
+            if (!f.exists()) {
+                _rotationNum = i;
+                return f;
+            }
+        }
+
+        // all exist, pick the oldest to replace
+        File oldest = null;
+        for (int i = 0; i < max; i++) {
+            File f;
+            if (base != null)
+                f = new File(base, replace(pattern, i));
+            else
+                f = new File(replace(pattern, i));
+            if (oldest == null) {
+                oldest = f;
+            } else {
+                if (f.lastModified() < oldest.lastModified()) {
+                    _rotationNum = i;
+                    oldest = f;
+                }
+            }
+        }
+        return oldest;
+    }
+
+    private static final String replace(String pattern, int num) {
+        char c[] = pattern.toCharArray();
+        StringBuilder buf = new StringBuilder();
+        for (int i = 0; i < c.length; i++) {
+            if ( (c[i] != '#') && (c[i] != '@') )
+                buf.append(c[i]);
+            else
+                buf.append(num);
+        }
+        return buf.toString();
+    }
+}
diff --git a/core/java/src/net/i2p/util/LogManager.java b/core/java/src/net/i2p/util/LogManager.java
index 86012c0251..d608438065 100644
--- a/core/java/src/net/i2p/util/LogManager.java
+++ b/core/java/src/net/i2p/util/LogManager.java
@@ -163,7 +163,7 @@ public class LogManager implements Flushable {
         // yeah, this doesn't always work, _writer should be volatile
         if (_writer != null)
             return;
-        _writer = new LogWriter(this);
+        _writer = new FileLogWriter(this);
         _writer.setFlushInterval(_flushInterval * 1000);
         // if you enable logging in I2PThread again, you MUST change this back to Thread
         Thread t = new I2PThread(_writer, "LogWriter");
diff --git a/core/java/src/net/i2p/util/LogWriter.java b/core/java/src/net/i2p/util/LogWriter.java
index d44bcb1b05..12571288dd 100644
--- a/core/java/src/net/i2p/util/LogWriter.java
+++ b/core/java/src/net/i2p/util/LogWriter.java
@@ -9,210 +9,182 @@ package net.i2p.util;
  *
  */
 
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
+import java.util.Queue;
 
 /**
- * File-based log writer thread that pulls log records from the LogManager,
- * writes them to the current logfile, and rotates the logs as necessary.
+ * Log writer thread that pulls log records from the LogManager and writes them to
+ * the log.  This also periodically instructs the LogManager to reread its config
+ * file.
  *
+ * @since 0.9.19 pulled from FileLogWriter so Android may extend
  */
-class LogWriter extends LogWriterBase {
-    // volatile as it changes on log file rotation
-    private volatile Writer _currentOut;
-    private int _rotationNum = -1;
-    private File _currentFile;
-    private long _numBytesInCurrentFile;
-
-    private static final int MAX_DISKFULL_MESSAGES = 8;
-    private int _diskFullMessageCount;
+abstract class LogWriter implements Runnable {
+    /** every 10 seconds? why? Just have the gui force a reread after a change?? */
+    private final static long CONFIG_READ_INTERVAL = 50 * 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;
+    private long _lastReadConfig;
+    protected final LogManager _manager;
+
+    protected volatile boolean _write;
+    private LogRecord _last;
+    // ms
+    private volatile long _flushInterval = FLUSH_INTERVAL;
 
     public LogWriter(LogManager manager) {
-        super(manager);
+        _manager = manager;
+        _lastReadConfig = Clock.getInstance().now();
     }
 
+    public abstract String currentFile();
     /**
-     *  File may not exist or have old logs in it if not opened yet
+     * Write the provided LogRecord to the writer.
+     * @param rec the LogRecord to write.
+     * @param formatted a String pre-formatted from rec, may be ignored.
      */
-    public synchronized String currentFile() {
-        if (_currentFile != null)
-            return _currentFile.getAbsolutePath();
-        String rv = getNextFile().getAbsolutePath();
-        // so it doesn't increment every time we call this
-        _rotationNum = -1;
-        return rv;
-    }
+    protected abstract void writeRecord(LogRecord rec, String formatted);
+    /**
+     * Write a single String verbatim to the writer.
+     * @param priority the level to log the line at.
+     * @param line the String to write.
+     */
+    protected abstract void writeRecord(int priority, String line);
+    protected abstract void flushWriter();
+    protected abstract void closeWriter();
 
-    protected void writeRecord(LogRecord rec, String formatted) {
-    	writeRecord(rec.getPriority(), formatted);
+    public void stopWriting() {
+        _write = false;
     }
 
-    protected synchronized void writeRecord(int priority, String val) {
-        if (val == null) return;
-        if (_currentOut == null) {
-            rotateFile();
-            if (_currentOut == null)
-                return; // hosed
-        }
+    /**
+     *  @param interval ms
+     *  @since 0.9.18
+     */
+    public void setFlushInterval(long interval) {
+        _flushInterval = Math.min(MAX_FLUSH_INTERVAL, Math.max(MIN_FLUSH_INTERVAL, interval));
+    }
 
+    public void run() {
+        _write = true;
+        // don't bother on Android
+        final boolean shouldReadConfig = !SystemVersion.isAndroid();
         try {
-            _currentOut.write(val);
-            // may be a little off if a lot of multi-byte chars, but unlikely
-            _numBytesInCurrentFile += val.length();
-        } catch (Throwable t) {
-            if (!_write)
-                return;
-            if (++_diskFullMessageCount < MAX_DISKFULL_MESSAGES)
-                System.err.println("Error writing log, disk full? " + t);
-            //t.printStackTrace();
-        }
-        if (_numBytesInCurrentFile >= _manager.getFileSize()) {
-            rotateFile();
+            while (_write) {
+                flushRecords();
+                if (_write && shouldReadConfig)
+                    rereadConfig();
+            }
+        } catch (RuntimeException e) {
+            System.err.println("Error writing the log: " + e);
+            e.printStackTrace();
         }
+        closeWriter();
     }
 
-    /**
-     *  @since 0.9.19
-     */
-    protected void flushWriter() {
+    public void flushRecords() { flushRecords(true); }
+
+    public void flushRecords(boolean shouldWait) {
         try {
-            if (_currentOut != null)
-                _currentOut.flush();
-        } catch (IOException ioe) {
-            if (_write && ++_diskFullMessageCount < MAX_DISKFULL_MESSAGES)
-                System.err.println("Error writing the router log - disk full? " + ioe);
+            // zero copy, drain the manager queue directly
+            Queue<LogRecord> records = _manager.getQueue();
+            if (records == null) return;
+            if (!records.isEmpty()) {
+                if (_last != null && _last.getDate() < _manager.getContext().clock().now() - 30*60*1000)
+                    _last = null;
+                LogRecord rec;
+                int dupCount = 0;
+                while ((rec = records.poll()) != null) {
+                    if (_manager.shouldDropDuplicates() && rec.equals(_last)) {
+                        dupCount++;
+                    } else {
+                        if (dupCount > 0) {
+                            writeDupMessage(dupCount, _last);
+                            dupCount = 0;
+                        }
+                        writeRecord(rec);
+                    }
+                    _last = rec;
+                }
+                if (dupCount > 0) {
+                    writeDupMessage(dupCount, _last);
+                }
+                flushWriter();
+            }
+        } catch (Throwable t) {
+            t.printStackTrace();
+        } finally {
+            if (shouldWait) {
+                try { 
+                    synchronized (this) {
+                        this.wait(_flushInterval); 
+                    }
+                } catch (InterruptedException ie) { // nop
+                }
+            }
         }
     }
 
     /**
-     *  @since 0.9.19 renamed from closeFile()
+     *  Write a msg with the date stamp of the last duplicate
+     *  @since 0.9.21
      */
-    protected void closeWriter() {
-        Writer out = _currentOut;
-        if (out != null) {
-            try {
-                out.close();
-            } catch (IOException ioe) {}
-        }
+    private void writeDupMessage(int dupCount, LogRecord lastRecord) {
+        String dmsg = dupMessage(dupCount, lastRecord, false);
+        writeRecord(lastRecord.getPriority(), dmsg);
+        if (_manager.getDisplayOnScreenLevel() <= lastRecord.getPriority() && _manager.displayOnScreen())
+            System.out.print(dmsg);
+        dmsg = dupMessage(dupCount, lastRecord, true);
+        _manager.getBuffer().add(dmsg);
+        if (lastRecord.getPriority() >= Log.CRIT)
+            _manager.getBuffer().addCritical(dmsg);
     }
 
     /**
-     * Rotate to the next file (or the first file if this is the first call)
-     *
-     * Caller must synch
+     *  Return a msg with the date stamp of the last duplicate
+     *  @since 0.9.3
      */
-    private void rotateFile() {
-        File f = getNextFile();
-        _currentFile = f;
-        _numBytesInCurrentFile = 0;
-        File parent = f.getParentFile();
-        if (parent != null) {
-            if (!parent.exists()) {
-                File sd = new SecureDirectory(parent.getAbsolutePath());
-                boolean ok = sd.mkdirs();
-                if (!ok) {
-                    System.err.println("Unable to create the parent directory: " + parent.getAbsolutePath());
-                    //System.exit(0);
-                }
-            }
-            if (!parent.isDirectory()) {
-                System.err.println("Cannot put the logs in a subdirectory of a plain file: " + f.getAbsolutePath());
-                //System.exit(0);
-            }
-        }
-        closeWriter();
-        try {
-            _currentOut = new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(f), "UTF-8"));
-        } catch (IOException ioe) {
-            if (++_diskFullMessageCount < MAX_DISKFULL_MESSAGES)
-                System.err.println("Error creating log file [" + f.getAbsolutePath() + "]" + ioe);
-        }
+    private String dupMessage(int dupCount, LogRecord lastRecord, boolean reverse) {
+        String arrows = reverse ? (SystemVersion.isAndroid() ? "vvv" : "&darr;&darr;&darr;") : "^^^";
+        return LogRecordFormatter.getWhen(_manager, lastRecord) + ' ' + arrows + ' ' +
+               _t(dupCount, "1 similar message omitted", "{0} similar messages omitted") + ' ' + arrows +
+               LogRecordFormatter.NL;
     }
+    
+    private static final String BUNDLE_NAME = "net.i2p.router.web.messages";
 
     /**
-     * Get the next file in the rotation
-     *
-     * Caller must synch
+     *  gettext
+     *  @since 0.9.3
      */
-    private File getNextFile() {
-        String pattern = _manager.getBaseLogfilename();
-        File f = new File(pattern);
-        File base = null;
-        if (!f.isAbsolute())
-            base = _manager.getContext().getLogDir();
-
-        if ( (pattern.indexOf('#') < 0) && (pattern.indexOf('@') <= 0) ) {
-            if (base != null)
-                return new File(base, pattern);
-            else
-                return f;
-        }
-        
-        int max = _manager.getRotationLimit();
-        if (_rotationNum == -1) {
-            return getFirstFile(base, pattern, max);
-        }
-             
-        // we're in rotation, just go to the next  
-        _rotationNum++;
-        if (_rotationNum > max) _rotationNum = 0;
-
-        String newf = replace(pattern, _rotationNum);
-        if (base != null)
-            return new File(base, newf);
-        return new File(newf);
+    private String _t(int a, String b, String c) {
+        return Translate.getString(a, b, c, _manager.getContext(), BUNDLE_NAME);
     }
 
-    /**
-     * Retrieve the first file, updating the rotation number accordingly
-     *
-     * Caller must synch
-     */
-    private File getFirstFile(File base, String pattern, int max) {
-        for (int i = 0; i < max; i++) {
-            File f;
-            if (base != null)
-                f = new File(base, replace(pattern, i));
-            else
-                f = new File(replace(pattern, i));
-            if (!f.exists()) {
-                _rotationNum = i;
-                return f;
-            }
+    private void rereadConfig() {
+        long now = Clock.getInstance().now();
+        if (now - _lastReadConfig > CONFIG_READ_INTERVAL) {
+            _manager.rereadConfig();
+            _lastReadConfig = now;
         }
-
-        // all exist, pick the oldest to replace
-        File oldest = null;
-        for (int i = 0; i < max; i++) {
-            File f;
-            if (base != null)
-                f = new File(base, replace(pattern, i));
-            else
-                f = new File(replace(pattern, i));
-            if (oldest == null) {
-                oldest = f;
-            } else {
-                if (f.lastModified() < oldest.lastModified()) {
-                    _rotationNum = i;
-                    oldest = f;
-                }
-            }
-        }
-        return oldest;
     }
 
-    private static final String replace(String pattern, int num) {
-        char c[] = pattern.toCharArray();
-        StringBuilder buf = new StringBuilder();
-        for (int i = 0; i < c.length; i++) {
-            if ( (c[i] != '#') && (c[i] != '@') )
-                buf.append(c[i]);
-            else
-                buf.append(num);
+    private void writeRecord(LogRecord rec) {
+        String val = LogRecordFormatter.formatRecord(_manager, rec, true);
+        writeRecord(rec, val);
+
+        // we always add to the console buffer, but only sometimes write to stdout
+        _manager.getBuffer().add(val);
+        if (rec.getPriority() >= Log.CRIT)
+            _manager.getBuffer().addCritical(val);
+        if (_manager.getDisplayOnScreenLevel() <= rec.getPriority()) {
+            if (_manager.displayOnScreen()) {
+                // wrapper and android logs already do time stamps, so reformat without the date
+                if (_manager.getContext().hasWrapper() || SystemVersion.isAndroid())
+                    System.out.print(LogRecordFormatter.formatRecord(_manager, rec, false));
+                else
+                    System.out.print(val);
+            }
         }
-        return buf.toString();
     }
 }
diff --git a/core/java/src/net/i2p/util/LogWriterBase.java b/core/java/src/net/i2p/util/LogWriterBase.java
deleted file mode 100644
index 4eb6b89423..0000000000
--- a/core/java/src/net/i2p/util/LogWriterBase.java
+++ /dev/null
@@ -1,190 +0,0 @@
-package net.i2p.util;
-
-/*
- * free (adj.): unencumbered; not under the control of others
- * Written by jrandom in 2003 and released into the public domain 
- * with no warranty of any kind, either expressed or implied.  
- * It probably won't make your computer catch on fire, or eat 
- * your children, but it might.  Use at your own risk.
- *
- */
-
-import java.util.Queue;
-
-/**
- * Log writer thread that pulls log records from the LogManager and writes them to
- * the log.  This also periodically instructs the LogManager to reread its config
- * file.
- *
- * @since 0.9.19 pulled from LogWriter so Android may extend
- */
-abstract class LogWriterBase implements Runnable {
-    /** every 10 seconds? why? Just have the gui force a reread after a change?? */
-    private final static long CONFIG_READ_INTERVAL = 50 * 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;
-    private long _lastReadConfig;
-    protected final LogManager _manager;
-
-    protected volatile boolean _write;
-    private LogRecord _last;
-    // ms
-    private volatile long _flushInterval = FLUSH_INTERVAL;
-
-    public LogWriterBase(LogManager manager) {
-        _manager = manager;
-        _lastReadConfig = Clock.getInstance().now();
-    }
-
-    public abstract String currentFile();
-    /**
-     * Write the provided LogRecord to the writer.
-     * @param rec the LogRecord to write.
-     * @param formatted a String pre-formatted from rec, may be ignored.
-     */
-    protected abstract void writeRecord(LogRecord rec, String formatted);
-    /**
-     * Write a single String verbatim to the writer.
-     * @param priority the level to log the line at.
-     * @param line the String to write.
-     */
-    protected abstract void writeRecord(int priority, String line);
-    protected abstract void flushWriter();
-    protected abstract void closeWriter();
-
-    public void stopWriting() {
-        _write = false;
-    }
-
-    /**
-     *  @param interval ms
-     *  @since 0.9.18
-     */
-    public void setFlushInterval(long interval) {
-        _flushInterval = Math.min(MAX_FLUSH_INTERVAL, Math.max(MIN_FLUSH_INTERVAL, interval));
-    }
-
-    public void run() {
-        _write = true;
-        // don't bother on Android
-        final boolean shouldReadConfig = !SystemVersion.isAndroid();
-        try {
-            while (_write) {
-                flushRecords();
-                if (_write && shouldReadConfig)
-                    rereadConfig();
-            }
-        } catch (RuntimeException e) {
-            System.err.println("Error writing the log: " + e);
-            e.printStackTrace();
-        }
-        closeWriter();
-    }
-
-    public void flushRecords() { flushRecords(true); }
-
-    public void flushRecords(boolean shouldWait) {
-        try {
-            // zero copy, drain the manager queue directly
-            Queue<LogRecord> records = _manager.getQueue();
-            if (records == null) return;
-            if (!records.isEmpty()) {
-                if (_last != null && _last.getDate() < _manager.getContext().clock().now() - 30*60*1000)
-                    _last = null;
-                LogRecord rec;
-                int dupCount = 0;
-                while ((rec = records.poll()) != null) {
-                    if (_manager.shouldDropDuplicates() && rec.equals(_last)) {
-                        dupCount++;
-                    } else {
-                        if (dupCount > 0) {
-                            writeDupMessage(dupCount, _last);
-                            dupCount = 0;
-                        }
-                        writeRecord(rec);
-                    }
-                    _last = rec;
-                }
-                if (dupCount > 0) {
-                    writeDupMessage(dupCount, _last);
-                }
-                flushWriter();
-            }
-        } catch (Throwable t) {
-            t.printStackTrace();
-        } finally {
-            if (shouldWait) {
-                try { 
-                    synchronized (this) {
-                        this.wait(_flushInterval); 
-                    }
-                } catch (InterruptedException ie) { // nop
-                }
-            }
-        }
-    }
-
-    /**
-     *  Write a msg with the date stamp of the last duplicate
-     *  @since 0.9.21
-     */
-    private void writeDupMessage(int dupCount, LogRecord lastRecord) {
-        String dmsg = dupMessage(dupCount, lastRecord, false);
-        writeRecord(lastRecord.getPriority(), dmsg);
-        if (_manager.getDisplayOnScreenLevel() <= lastRecord.getPriority() && _manager.displayOnScreen())
-            System.out.print(dmsg);
-        dmsg = dupMessage(dupCount, lastRecord, true);
-        _manager.getBuffer().add(dmsg);
-        if (lastRecord.getPriority() >= Log.CRIT)
-            _manager.getBuffer().addCritical(dmsg);
-    }
-
-    /**
-     *  Return a msg with the date stamp of the last duplicate
-     *  @since 0.9.3
-     */
-    private String dupMessage(int dupCount, LogRecord lastRecord, boolean reverse) {
-        String arrows = reverse ? (SystemVersion.isAndroid() ? "vvv" : "&darr;&darr;&darr;") : "^^^";
-        return LogRecordFormatter.getWhen(_manager, lastRecord) + ' ' + arrows + ' ' +
-               _t(dupCount, "1 similar message omitted", "{0} similar messages omitted") + ' ' + arrows +
-               LogRecordFormatter.NL;
-    }
-    
-    private static final String BUNDLE_NAME = "net.i2p.router.web.messages";
-
-    /**
-     *  gettext
-     *  @since 0.9.3
-     */
-    private String _t(int a, String b, String c) {
-        return Translate.getString(a, b, c, _manager.getContext(), BUNDLE_NAME);
-    }
-
-    private void rereadConfig() {
-        long now = Clock.getInstance().now();
-        if (now - _lastReadConfig > CONFIG_READ_INTERVAL) {
-            _manager.rereadConfig();
-            _lastReadConfig = now;
-        }
-    }
-
-    private void writeRecord(LogRecord rec) {
-        String val = LogRecordFormatter.formatRecord(_manager, rec, true);
-        writeRecord(rec, val);
-
-        // we always add to the console buffer, but only sometimes write to stdout
-        _manager.getBuffer().add(val);
-        if (rec.getPriority() >= Log.CRIT)
-            _manager.getBuffer().addCritical(val);
-        if (_manager.getDisplayOnScreenLevel() <= rec.getPriority()) {
-            if (_manager.displayOnScreen()) {
-                // wrapper and android logs already do time stamps, so reformat without the date
-                if (_manager.getContext().hasWrapper() || SystemVersion.isAndroid())
-                    System.out.print(LogRecordFormatter.formatRecord(_manager, rec, false));
-                else
-                    System.out.print(val);
-            }
-        }
-    }
-}
-- 
GitLab