mirror of
https://github.com/i2p/i2p.i2p.git
synced 2026-08-29 03:18:45 +00:00
Merge pull request 'Stats: Remove ancient stat log' (#503) from zzz/i2p.i2p:statlog into master
Reviewed-on: http://git.idk.i2p/I2P_Developers/i2p.i2p/pulls/503 Reviewed-by: idk <idki2p@mail.i2p>
This commit is contained in:
@@ -1,208 +0,0 @@
|
||||
package net.i2p.stat;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Note - if no filter is defined in stat.logFilters at startup, this class will not
|
||||
* be instantiated - see StatManager.
|
||||
*
|
||||
* Deprecated - unused - to be removed.
|
||||
* Not for external use - not a public API.
|
||||
*/
|
||||
public class BufferedStatLog implements StatLog {
|
||||
private final I2PAppContext _context;
|
||||
private final Log _log;
|
||||
private final StatEvent _events[];
|
||||
private int _eventNext;
|
||||
private int _lastWrite;
|
||||
/** flush stat events to disk after this many events (or 30s)*/
|
||||
private int _flushFrequency;
|
||||
private final List<String> _statFilters;
|
||||
private String _lastFilters;
|
||||
private BufferedWriter _out;
|
||||
private String _outFile;
|
||||
/** short circuit for adding data, set to true if some filters are set, false if its empty (so we can skip the sync) */
|
||||
private volatile boolean _filtersSpecified;
|
||||
|
||||
private static final int BUFFER_SIZE = 1024;
|
||||
private static final boolean DISABLE_LOGGING = false;
|
||||
|
||||
public BufferedStatLog(I2PAppContext ctx) {
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(BufferedStatLog.class);
|
||||
_events = new StatEvent[BUFFER_SIZE];
|
||||
if (DISABLE_LOGGING) return;
|
||||
for (int i = 0; i < BUFFER_SIZE; i++)
|
||||
_events[i] = new StatEvent();
|
||||
_eventNext = 0;
|
||||
_lastWrite = _events.length-1;
|
||||
_statFilters = new ArrayList<String>(10);
|
||||
_flushFrequency = 500;
|
||||
updateFilters();
|
||||
I2PThread writer = new I2PThread(new StatLogWriter(), "StatLogWriter");
|
||||
writer.setDaemon(true);
|
||||
writer.start();
|
||||
}
|
||||
|
||||
public void addData(String scope, String stat, long value, long duration) {
|
||||
if (DISABLE_LOGGING) return;
|
||||
if (!shouldLog(stat)) return;
|
||||
synchronized (_events) {
|
||||
_events[_eventNext].init(scope, stat, value, duration);
|
||||
_eventNext = (_eventNext + 1) % _events.length;
|
||||
|
||||
if (_eventNext == _lastWrite)
|
||||
_lastWrite = (_lastWrite + 1) % _events.length; // drop an event
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("AddData next=" + _eventNext + " lastWrite=" + _lastWrite);
|
||||
|
||||
if (_eventNext > _lastWrite) {
|
||||
if (_eventNext - _lastWrite >= _flushFrequency)
|
||||
_events.notifyAll();
|
||||
} else {
|
||||
if (_events.length - 1 - _lastWrite + _eventNext >= _flushFrequency)
|
||||
_events.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldLog(String stat) {
|
||||
if (!_filtersSpecified) return false;
|
||||
synchronized (_statFilters) {
|
||||
return _statFilters.contains(stat) || _statFilters.contains("*");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateFilters() {
|
||||
String val = _context.getProperty(StatManager.PROP_STAT_FILTER);
|
||||
if (val != null) {
|
||||
if ( (_lastFilters != null) && (_lastFilters.equals(val)) ) {
|
||||
// noop
|
||||
} else {
|
||||
StringTokenizer tok = new StringTokenizer(val, ",");
|
||||
synchronized (_statFilters) {
|
||||
_statFilters.clear();
|
||||
while (tok.hasMoreTokens())
|
||||
_statFilters.add(tok.nextToken().trim());
|
||||
_filtersSpecified = !_statFilters.isEmpty();
|
||||
}
|
||||
}
|
||||
_lastFilters = val;
|
||||
} else {
|
||||
synchronized (_statFilters) {
|
||||
_statFilters.clear();
|
||||
_filtersSpecified = false;
|
||||
}
|
||||
}
|
||||
|
||||
String filename = _context.getProperty(StatManager.PROP_STAT_FILE, StatManager.DEFAULT_STAT_FILE);
|
||||
File foo = new File(filename);
|
||||
if (!foo.isAbsolute())
|
||||
filename = (new File(_context.getRouterDir(), filename)).getAbsolutePath();
|
||||
if ( (_outFile != null) && (_outFile.equals(filename)) ) {
|
||||
// noop
|
||||
} else {
|
||||
if (_out != null) try { _out.close(); } catch (IOException ioe) {}
|
||||
_outFile = filename;
|
||||
try {
|
||||
_out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(_outFile, true), "UTF-8"), 32*1024);
|
||||
} catch (IOException ioe) { ioe.printStackTrace(); }
|
||||
}
|
||||
}
|
||||
|
||||
private class StatLogWriter implements Runnable {
|
||||
public void run() {
|
||||
int writeStart = -1;
|
||||
int writeEnd = -1;
|
||||
while (true) {
|
||||
try {
|
||||
synchronized (_events) {
|
||||
if (_eventNext > _lastWrite) {
|
||||
if (_eventNext - _lastWrite < _flushFrequency)
|
||||
_events.wait(30*1000);
|
||||
} else {
|
||||
if (_events.length - 1 - _lastWrite + _eventNext < _flushFrequency)
|
||||
_events.wait(30*1000);
|
||||
}
|
||||
writeStart = (_lastWrite + 1) % _events.length;
|
||||
writeEnd = _eventNext;
|
||||
_lastWrite = (writeEnd == 0 ? _events.length-1 : writeEnd - 1);
|
||||
}
|
||||
if (writeStart != writeEnd) {
|
||||
try {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("writing " + writeStart +"->"+ writeEnd);
|
||||
writeEvents(writeStart, writeEnd);
|
||||
} catch (RuntimeException e) {
|
||||
_log.error("error writing " + writeStart +"->"+ writeEnd, e);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeEvents(int start, int end) {
|
||||
try {
|
||||
updateFilters();
|
||||
int cur = start;
|
||||
while (cur != end) {
|
||||
//if (shouldLog(_events[cur].getStat())) {
|
||||
String when = DataHelper.formatTime(_events[cur].getTime());
|
||||
_out.write(when);
|
||||
_out.write(" ");
|
||||
if (_events[cur].getScope() == null)
|
||||
_out.write("noScope");
|
||||
else
|
||||
_out.write(_events[cur].getScope());
|
||||
_out.write(" ");
|
||||
_out.write(_events[cur].getStat());
|
||||
_out.write(" ");
|
||||
_out.write(Long.toString(_events[cur].getValue()));
|
||||
_out.write(" ");
|
||||
_out.write(Long.toString(_events[cur].getDuration()));
|
||||
_out.write("\n");
|
||||
//}
|
||||
cur = (cur + 1) % _events.length;
|
||||
}
|
||||
_out.flush();
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error writing out", ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class StatEvent {
|
||||
private long _time;
|
||||
private String _scope;
|
||||
private String _stat;
|
||||
private long _value;
|
||||
private long _duration;
|
||||
|
||||
public long getTime() { return _time; }
|
||||
public String getScope() { return _scope; }
|
||||
public String getStat() { return _stat; }
|
||||
public long getValue() { return _value; }
|
||||
public long getDuration() { return _duration; }
|
||||
|
||||
public void init(String scope, String stat, long value, long duration) {
|
||||
_scope = scope;
|
||||
_stat = stat;
|
||||
_value = value;
|
||||
_duration = duration;
|
||||
_time = _context.clock().now();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,6 @@ public class RateStat {
|
||||
private final String _description;
|
||||
/** actual rate objects for this statistic */
|
||||
protected final Rate[] _rates;
|
||||
/** component we tell about events as they occur */
|
||||
private StatLog _statLog;
|
||||
|
||||
public RateStat(String name, String description, String group, long periods[]) {
|
||||
_statName = name;
|
||||
@@ -39,17 +37,10 @@ public class RateStat {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default stat log for this RateStat.
|
||||
* Deprecated, unused, to be disabled in a future release.
|
||||
*/
|
||||
public void setStatLog(StatLog sl) { _statLog = sl; }
|
||||
|
||||
/**
|
||||
* update all of the rates for the various periods with the given value.
|
||||
*/
|
||||
public void addData(long value, long eventDuration) {
|
||||
if (_statLog != null) _statLog.addData(_groupName, _statName, value, eventDuration);
|
||||
for (Rate r: _rates)
|
||||
r.addData(value, eventDuration);
|
||||
}
|
||||
@@ -60,7 +51,6 @@ public class RateStat {
|
||||
* @since 0.8.10
|
||||
*/
|
||||
public void addData(long value) {
|
||||
if (_statLog != null) _statLog.addData(_groupName, _statName, value, 0);
|
||||
for (Rate r: _rates)
|
||||
r.addData(value);
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package net.i2p.stat;
|
||||
|
||||
/**
|
||||
* Component to be notified when a particular event occurs
|
||||
*/
|
||||
public interface StatLog {
|
||||
public void addData(String scope, String stat, long value, long duration);
|
||||
}
|
||||
@@ -29,22 +29,11 @@ public class StatManager {
|
||||
private final ConcurrentHashMap<String, FrequencyStat> _frequencyStats;
|
||||
/** stat name to RateStat */
|
||||
private final ConcurrentHashMap<String, RateStat> _rateStats;
|
||||
/** may be null */
|
||||
private StatLog _statLog;
|
||||
|
||||
private int coalesceCounter;
|
||||
/** every this many minutes for frequencies */
|
||||
private static final int FREQ_COALESCE_RATE = 9;
|
||||
|
||||
|
||||
/**
|
||||
* Comma-separated stats or * for all.
|
||||
* This property must be set at startup, or
|
||||
* logging is disabled.
|
||||
*/
|
||||
public static final String PROP_STAT_FILTER = "stat.logFilters";
|
||||
public static final String PROP_STAT_FILE = "stat.logFile";
|
||||
public static final String DEFAULT_STAT_FILE = "stats.log";
|
||||
/** default false */
|
||||
public static final String PROP_STAT_FULL = "stat.full";
|
||||
|
||||
@@ -59,9 +48,6 @@ public class StatManager {
|
||||
_log = context.logManager().getLog(getClass());
|
||||
_frequencyStats = new ConcurrentHashMap<String,FrequencyStat>(8);
|
||||
_rateStats = new ConcurrentHashMap<String,RateStat>(128);
|
||||
String filter = getStatFilter();
|
||||
if (filter != null && filter.length() > 0)
|
||||
_statLog = new BufferedStatLog(context);
|
||||
}
|
||||
|
||||
/** @since 0.8.8 */
|
||||
@@ -70,26 +56,6 @@ public class StatManager {
|
||||
_rateStats.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default stat log for RateStats
|
||||
* Deprecated, unused
|
||||
* @return null always
|
||||
*/
|
||||
public synchronized StatLog getStatLog() { return _statLog; }
|
||||
|
||||
/**
|
||||
* Sets the default stat log for ALL known RateStats.
|
||||
* Deprecated, unused
|
||||
* @deprecated unused
|
||||
*/
|
||||
@Deprecated
|
||||
public synchronized void setStatLog(StatLog log) {
|
||||
_statLog = log;
|
||||
for (RateStat rs : _rateStats.values()) {
|
||||
rs.setStatLog(log);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new statistic to monitor the frequency of some event.
|
||||
* The stat is ONLY created if the stat.full property is true or we are not in the router context.
|
||||
@@ -146,7 +112,6 @@ public class StatManager {
|
||||
public void createRequiredRateStat(String name, String description, String group, long periods[]) {
|
||||
if (_rateStats.containsKey(name)) return;
|
||||
RateStat rs = new RateStat(name, description, group, periods);
|
||||
if (_statLog != null) rs.setStatLog(_statLog);
|
||||
_rateStats.putIfAbsent(name, rs);
|
||||
}
|
||||
|
||||
@@ -263,9 +228,6 @@ public class StatManager {
|
||||
return groups;
|
||||
}
|
||||
|
||||
public String getStatFilter() { return _context.getProperty(PROP_STAT_FILTER); }
|
||||
public String getStatFile() { return _context.getProperty(PROP_STAT_FILE, DEFAULT_STAT_FILE); }
|
||||
|
||||
/**
|
||||
* Save memory by not creating stats unless they are required for router operation.
|
||||
* For backward compatibility of any external clients, always returns false if not in router context.
|
||||
|
||||
Reference in New Issue
Block a user