Stats: Remove ancient stat log

From the jrandom days, to log every stat to a file.
Disabled and hidden from the UI a long long time ago.
Along with it goes the stat log filter, which selected
the stats to log.
This commit is contained in:
zzz
2025-04-26 14:52:18 -04:00
parent 508fe2ce52
commit 06457548d2
7 changed files with 6 additions and 392 deletions

View File

@ -15,18 +15,12 @@ import net.i2p.stat.StatManager;
*
*/
public class ConfigStatsHandler extends FormHandler {
private String _filename;
private List<String> _stats;
private String _graphs;
private boolean _explicitFilter;
private String _explicitFilterValue;
private boolean _isFull;
public ConfigStatsHandler() {
super();
_stats = new ArrayList<String>();
_graphs = "";
_explicitFilter = false;
_isFull = false;
}
@ -36,20 +30,6 @@ public class ConfigStatsHandler extends FormHandler {
saveChanges();
}
}
public void setFilename(String filename) {
_filename = (filename != null ? filename.trim() : null);
}
public void setStatList(String stats[]) {
if (stats != null) {
for (int i = 0; i < stats.length; i++) {
String cur = stats[i].trim();
if ( (cur.length() > 0) && (!_stats.contains(cur)) )
_stats.add(cur);
}
}
}
public void setGraphList(String stats[]) {
if (stats != null) {
@ -68,8 +48,6 @@ public class ConfigStatsHandler extends FormHandler {
}
}
public void setExplicitFilter(String foo) { _explicitFilter = true; }
public void setExplicitFilterValue(String filter) { _explicitFilterValue = filter; }
public void setIsFull(String foo) { _isFull = true; }
/**
@ -79,44 +57,11 @@ public class ConfigStatsHandler extends FormHandler {
*/
private void saveChanges() {
Map<String, String> changes = new HashMap<String, String>();
if (_filename == null)
_filename = StatManager.DEFAULT_STAT_FILE;
changes.put(StatManager.PROP_STAT_FILE, _filename);
if (_explicitFilter) {
_stats.clear();
if (_explicitFilterValue == null)
_explicitFilterValue = "";
if (_explicitFilterValue.indexOf(',') != -1) {
StringTokenizer tok = new StringTokenizer(_explicitFilterValue, ",");
while (tok.hasMoreTokens()) {
String cur = tok.nextToken().trim();
if ( (cur.length() > 0) && (!_stats.contains(cur)) )
_stats.add(cur);
}
} else {
String stat = _explicitFilterValue.trim();
if ( (stat.length() > 0) && (!_stats.contains(stat)) )
_stats.add(stat);
}
}
StringBuilder stats = new StringBuilder();
for (int i = 0; i < _stats.size(); i++) {
stats.append(_stats.get(i));
if (i + 1 < _stats.size())
stats.append(',');
}
changes.put(StatManager.PROP_STAT_FILTER, stats.toString());
boolean graphsChanged = !_graphs.equals(_context.getProperty("stat.summaries"));
changes.put("stat.summaries", _graphs);
boolean fullChanged = _context.getBooleanProperty(StatManager.PROP_STAT_FULL) != _isFull;
changes.put(StatManager.PROP_STAT_FULL, Boolean.toString(_isFull));
_context.router().saveConfig(changes, null);
if (!_stats.isEmpty())
addFormNotice(_t("Stat filter and location updated successfully to") + ": " + stats.toString());
if (fullChanged) {
if (_isFull)
addFormNotice(_t("Full statistics enabled"));

View File

@ -22,8 +22,6 @@ import net.i2p.util.Log;
public class ConfigStatsHelper extends HelperBase {
private Log _log;
private String _filter;
private final Set<String> _filters;
private final Set<String> _graphs;
/** list of names of stats which are remaining, ordered by nested groups */
private final List<String> _stats;
@ -33,14 +31,11 @@ public class ConfigStatsHelper extends HelperBase {
private String _currentGroup;
/** true if the current stat is the first in the group */
private boolean _currentIsFirstInGroup;
/** true if the stat is being logged */
private boolean _currentIsLogged;
private boolean _currentIsGraphed;
private boolean _currentCanBeGraphed;
public ConfigStatsHelper() {
_stats = new ArrayList<String>();
_filters = new HashSet<String>();
_graphs = new HashSet<String>();
}
@ -61,35 +56,16 @@ public class ConfigStatsHelper extends HelperBase {
for (Set<String> stats : groups.values()) {
_stats.addAll(stats);
}
_filter = _context.statManager().getStatFilter();
if (_filter == null)
_filter = "";
StringTokenizer tok = new StringTokenizer(_filter, ",");
while (tok.hasMoreTokens())
_filters.add(tok.nextToken().trim());
// create a local copy of the config. Querying r.getSummaryListener()
// lags behind, as StatSummarizer only runs once a minute.
String specs = _context.getProperty("stat.summaries", StatSummarizer.DEFAULT_DATABASES);
tok = new StringTokenizer(specs, ",");
StringTokenizer tok = new StringTokenizer(specs, ",");
while (tok.hasMoreTokens()) {
_graphs.add(tok.nextToken().trim());
}
}
/**
* Just hide for everybody unless already set.
* To enable set advanced config stat.logFilters=foo before starting...
* it has to be set at startup anyway for logging to be enabled at all
* @since 0.9
*/
public boolean shouldShowLog() {
return !_filters.isEmpty();
}
public String getFilename() { return _context.statManager().getStatFile(); }
/**
* move the cursor to the next known stat, returning true if a valid
* stat is available.
@ -143,10 +119,6 @@ public class ConfigStatsHelper extends HelperBase {
}
}
if (_filters.contains("*") || _filters.contains(_currentStatName))
_currentIsLogged = true;
else
_currentIsLogged = false;
return true;
}
@ -172,10 +144,8 @@ public class ConfigStatsHelper extends HelperBase {
public String getCurrentStatName() { return _currentStatName; }
public String getCurrentGraphName() { return _currentGraphName; }
public String getCurrentStatDescription() { return _currentStatDescription; }
public boolean getCurrentIsLogged() { return _currentIsLogged; }
public boolean getCurrentIsGraphed() { return _currentIsGraphed; }
public boolean getCurrentCanBeGraphed() { return _currentCanBeGraphed; }
public String getExplicitFilter() { return _filter; }
public boolean getIsFull() {
return _context.getBooleanProperty(StatManager.PROP_STAT_FULL);
}

View File

@ -27,19 +27,8 @@
<input type="checkbox" class="optbox" id="enableFull" name="isFull" value="true" <%
if (statshelper.getIsFull()) { %>checked="checked" <% } %> >
(<%=intl._t("change requires restart to take effect")%>)</label><br>
<%
// stats.log for devs only and grows without bounds, not recommended
boolean shouldShowLog = statshelper.shouldShowLog();
if (shouldShowLog) {
%><%=intl._t("Stat file")%>: <input type="text" name="filename" value="<%=statshelper.getFilename()%>" >
Warning - Log with care, stat file grows without limit.<br>
<%
} // shouldShowLog
%></p>
</p>
<div class="wideload">
<table id="configstats">
<% while (statshelper.hasMoreStats()) {
@ -50,47 +39,21 @@ Warning - Log with care, stat file grows without limit.<br>
<a class="script" id="toggle-<%=statshelper.getCurrentGroupName()%>" title="<%=intl._t("Toggle section graphing options")%>" href="#">[<%=intl._t("toggle all")%>]</a>
</th></tr>
<tr class="tablefooter">
<%
if (shouldShowLog) {
%> <td align="center"><b><%=intl._t("Log")%></b></td>
<%
} // shouldShowLog
%> <td align="center"><b title="<%=intl._t("Select stats for visualization on /graphs")%>"><%=intl._t("Graph")%></b></td>
<td align="center"><b title="<%=intl._t("Select stats for visualization on /graphs")%>"><%=intl._t("Graph")%></b></td>
<td></td></tr>
<%
} // end iterating over required groups for the current stat %>
<tr>
<%
if (shouldShowLog) {
%> <td align="center"><a name="<%=statshelper.getCurrentStatName()%>"></a><input type="checkbox" class="optbox <%=statshelper.getCurrentGroupName()%>" name="statList" value="<%=statshelper.getCurrentStatName()%>" <%
if (statshelper.getCurrentIsLogged()) { %>checked="checked" <% } %> ></td>
<%
} // shouldShowLog
%> <td align="center"><% if (statshelper.getCurrentCanBeGraphed()) { %><input type="checkbox" class="optbox <%=statshelper.getCurrentGroupName()%>" id="<%=statshelper.getCurrentStatName()%>" name="graphList" value="<%=statshelper.getCurrentGraphName()%>" <%
<td align="center"><% if (statshelper.getCurrentCanBeGraphed()) { %><input type="checkbox" class="optbox <%=statshelper.getCurrentGroupName()%>" id="<%=statshelper.getCurrentStatName()%>" name="graphList" value="<%=statshelper.getCurrentGraphName()%>" <%
if (statshelper.getCurrentIsGraphed()) { %>checked="checked" <% } %> ><% } %></td> <% // no whitespace here so we can use td:empty to remove css pointer from inert labels %>
<td align="left"><label for="<%=statshelper.getCurrentStatName()%>"><b><%=statshelper.getCurrentStatName()%>:</b>&nbsp;
<%=statshelper.getCurrentStatDescription()%></label></td></tr><%
} // end iterating over all stats
%>
if (shouldShowLog) {
%> <tr><td colspan="3"></td></tr>
<tr><td align="center"><label><input type="checkbox" class="optbox" name="explicitFilter" ></td>
<td colspan="2"><%=intl._t("Advanced filter")%>:</label>
<input type="text" name="explicitFilterValue" value="<%=statshelper.getExplicitFilter()%>" size="40" ></td></tr>
<%
} // shouldShowLog
%> <tr class="tablefooter"><td colspan="3" align="right" class="optionsave">
<tr class="tablefooter"><td colspan="3" align="right" class="optionsave">
<input type="reset" class="cancel" value="<%=intl._t("Cancel")%>" >
<input type="submit" name="shouldsave" class="accept" value="<%=intl._t("Save changes")%>" >
</td></tr>

View File

@ -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();
}
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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.