Author: toad
Date: 2005-12-07 21:55:27 +0000 (Wed, 07 Dec 2005)
New Revision: 7687
Added:
trunk/freenet/src/freenet/node/TestnetHandler.java
Modified:
trunk/freenet/src/freenet/io/comm/PeerParseException.java
trunk/freenet/src/freenet/node/Node.java
trunk/freenet/src/freenet/node/PeerNode.java
trunk/freenet/src/freenet/node/RealNodePingTest.java
trunk/freenet/src/freenet/node/RealNodeRequestInsertTest.java
trunk/freenet/src/freenet/node/RealNodeRoutingTest.java
trunk/freenet/src/freenet/node/TextModeClientInterface.java
trunk/freenet/src/freenet/node/Version.java
trunk/freenet/src/freenet/support/FileLoggerHook.java
trunk/freenet/src/freenet/support/Logger.java
Log:
286:
Basic testnet support.
Limit compressed log files to 1GB.
Minor bugfixes.
Note that this will wipe your peers file, as testnet nodes and non-testnet
nodes are strictly incompatible.
Modified: trunk/freenet/src/freenet/io/comm/PeerParseException.java
===================================================================
--- trunk/freenet/src/freenet/io/comm/PeerParseException.java 2005-12-07
19:03:04 UTC (rev 7686)
+++ trunk/freenet/src/freenet/io/comm/PeerParseException.java 2005-12-07
21:55:27 UTC (rev 7687)
@@ -14,4 +14,8 @@
super();
}
+ public PeerParseException(String string) {
+ super(string);
+ }
+
}
Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java 2005-12-07 19:03:04 UTC (rev
7686)
+++ trunk/freenet/src/freenet/node/Node.java 2005-12-07 21:55:27 UTC (rev
7687)
@@ -145,6 +145,9 @@
final NodePinger nodePinger;
final String filenamesPrefix;
final FilenameGenerator tempFilenameGenerator;
+ final FileLoggerHook fileLoggerHook;
+ final boolean testnetEnabled;
+ final int testnetPort;
static short MAX_HTL = 10;
static final int EXIT_STORE_FILE_NOT_FOUND = 1;
static final int EXIT_STORE_IOEXCEPTION = 2;
@@ -152,6 +155,7 @@
static final int EXIT_USM_DIED = 4;
public static final int EXIT_YARROW_INIT_FAILED = 5;
static final int EXIT_TEMP_INIT_ERROR = 6;
+ static final int EXIT_TESTNET_FAILED = 7;
public final long bootID;
public final long startupTime;
@@ -164,6 +168,7 @@
final RequestThrottle insertThrottle;
final RequestStarter insertStarter;
final File downloadDir;
+ final TestnetHandler testnetHandler;
// Client stuff that needs to be configged - FIXME
static final int MAX_ARCHIVE_HANDLERS = 200; // don't take up much RAM...
FIXME
@@ -281,7 +286,9 @@
System.out.println("Port number: "+port);
File logDir = new File("logs-"+port);
logDir.mkdir();
- FileLoggerHook logger = new FileLoggerHook(true, new File(logDir,
"freenet-"+port).getAbsolutePath(), "d (c, t, p): m", "MMM dd, yyyy
HH:mm:ss:SSS", Logger.MINOR, false, true);
+ FileLoggerHook logger = new FileLoggerHook(true, new File(logDir,
"freenet-"+port).getAbsolutePath(),
+ "d (c, t, p): m", "MMM dd, yyyy HH:mm:ss:SSS",
Logger.MINOR, false, true,
+ 1024*1024*1024 /* 1GB of old compressed logfiles */);
logger.setInterval("5MINUTES");
Logger.setupChain();
Logger.globalSetThreshold(Logger.MINOR);
@@ -299,7 +306,7 @@
}
}
DiffieHellman.init(yarrow);
- Node n = new Node(port, yarrow, overrideIP, "", 1000 /
packetsPerSecond);
+ Node n = new Node(port, yarrow, overrideIP, "", 1000 /
packetsPerSecond, true, logger);
n.start(new StaticSwapRequestInterval(2000));
new TextModeClientInterface(n);
Thread t = new Thread(new MemoryChecker(), "Memory checker");
@@ -309,7 +316,18 @@
// FIXME - the whole overrideIP thing is a hack to avoid config
// Implement the config!
- Node(int port, RandomSource rand, InetAddress overrideIP, String prefix,
int throttleInterval) {
+ Node(int port, RandomSource rand, InetAddress overrideIP, String prefix,
int throttleInterval, boolean enableTestnet, FileLoggerHook logger) {
+ this.fileLoggerHook = logger;
+ if(enableTestnet) {
+ Logger.error(this, "WARNING: ENABLING TESTNET CODE! This may
seriously jeopardize your anonymity!");
+ testnetEnabled = true;
+ testnetPort = 1024 + (port-1024+1000) % (65536 - 1024);
+ testnetHandler = new TestnetHandler(this, testnetPort);
+ } else {
+ testnetEnabled = false;
+ testnetPort = -1;
+ testnetHandler = null;
+ }
portNumber = port;
startupTime = System.currentTimeMillis();
recentlyCompletedIDs = new LRUQueue();
@@ -318,6 +336,7 @@
filenamesPrefix = prefix;
this.overrideIPAddress = overrideIP;
downloadDir = new File("downloads");
+ downloadDir.mkdir();
try {
datastore = new
BaseFreenetStore(prefix+"freenet-"+portNumber,16384); // 512MB
} catch (FileNotFoundException e1) {
@@ -647,6 +666,9 @@
fs.put("identity", HexUtil.bytesToHex(myIdentity));
fs.put("location", Double.toString(lm.getLocation().getValue()));
fs.put("version", Version.getVersionString());
+ fs.put("testnet", Boolean.toString(testnetEnabled));
+ if(testnetEnabled)
+ fs.put("testnetPort", Integer.toString(testnetPort));
fs.put("myName", myName);
Logger.minor(this, "My reference: "+fs);
return fs;
Modified: trunk/freenet/src/freenet/node/PeerNode.java
===================================================================
--- trunk/freenet/src/freenet/node/PeerNode.java 2005-12-07 19:03:04 UTC
(rev 7686)
+++ trunk/freenet/src/freenet/node/PeerNode.java 2005-12-07 21:55:27 UTC
(rev 7687)
@@ -54,6 +54,9 @@
/** My low-level address for SocketManager purposes */
private Peer peer;
+ /** Is this a testnet node? */
+ public final boolean testnetEnabled;
+
/** Name of this node */
String myName;
@@ -194,6 +197,12 @@
String name = fs.get("myName");
if(name == null) throw new FSParseException("No name");
myName = name;
+ String testnet = fs.get("testnet");
+ testnetEnabled = Boolean.getBoolean(testnet);
+ if(testnetEnabled != node.testnetEnabled) {
+ Logger.error(this, "Ignoring incompatible node "+peer+" -
peer.testnet="+testnetEnabled+" but node.testnet="+node.testnetEnabled);
+ throw new PeerParseException("Ignoring incompatible node
"+peer+" - peer.testnet="+testnetEnabled+" but
node.testnet="+node.testnetEnabled);
+ }
// Setup incoming and outgoing setup ciphers
byte[] nodeKey = node.identityHash;
Modified: trunk/freenet/src/freenet/node/RealNodePingTest.java
===================================================================
--- trunk/freenet/src/freenet/node/RealNodePingTest.java 2005-12-07
19:03:04 UTC (rev 7686)
+++ trunk/freenet/src/freenet/node/RealNodePingTest.java 2005-12-07
21:55:27 UTC (rev 7687)
@@ -4,6 +4,7 @@
import freenet.crypt.Yarrow;
import freenet.io.comm.NotConnectedException;
import freenet.io.comm.PeerParseException;
+import freenet.support.FileLoggerHook;
import freenet.support.Logger;
import freenet.support.SimpleFieldSet;
@@ -20,12 +21,12 @@
public class RealNodePingTest {
public static void main(String[] args) throws FSParseException,
PeerParseException, InterruptedException {
- Logger.setupStdoutLogging(Logger.MINOR, "");
+ FileLoggerHook fh = Logger.setupStdoutLogging(Logger.MINOR, "");
Yarrow yarrow = new Yarrow();
DiffieHellman.init(yarrow);
// Create 2 nodes
- Node node1 = new Node(5001, yarrow, null, "pingtest-", 0);
- Node node2 = new Node(5002, yarrow, null, "pingtest-", 0);
+ Node node1 = new Node(5001, yarrow, null, "pingtest-", 0, false, fh);
+ Node node2 = new Node(5002, yarrow, null, "pingtest-", 0, false, fh);
SimpleFieldSet node1ref = node1.exportFieldSet();
SimpleFieldSet node2ref = node2.exportFieldSet();
// Connect
Modified: trunk/freenet/src/freenet/node/RealNodeRequestInsertTest.java
===================================================================
--- trunk/freenet/src/freenet/node/RealNodeRequestInsertTest.java
2005-12-07 19:03:04 UTC (rev 7686)
+++ trunk/freenet/src/freenet/node/RealNodeRequestInsertTest.java
2005-12-07 21:55:27 UTC (rev 7687)
@@ -12,6 +12,7 @@
import freenet.keys.ClientKey;
import freenet.node.PeerNode;
import freenet.support.Fields;
+import freenet.support.FileLoggerHook;
import freenet.support.HexUtil;
import freenet.support.Logger;
import freenet.support.SimpleFieldSet;
@@ -32,7 +33,7 @@
new File(wd).mkdir();
// Don't clobber nearby nodes!
Node.MAX_HTL = 5;
- Logger.setupStdoutLogging(Logger.DEBUG,
"freenet.store:minor,freenet.node.Location:normal"
/*"freenet.node.LocationManager:debug,freenet.node.FNPPacketManager:normal,freenet.io.comm.UdpSocketManager:debug"*/);
+ FileLoggerHook fh = Logger.setupStdoutLogging(Logger.DEBUG,
"freenet.store:minor,freenet.node.Location:normal"
/*"freenet.node.LocationManager:debug,freenet.node.FNPPacketManager:normal,freenet.io.comm.UdpSocketManager:debug"*/);
Logger.globalSetThreshold(Logger.DEBUG);
System.out.println("Insert/retrieve test");
System.out.println();
@@ -41,7 +42,7 @@
Node[] nodes = new Node[NUMBER_OF_NODES];
Logger.normal(RealNodeRoutingTest.class, "Creating nodes...");
for(int i=0;i<NUMBER_OF_NODES;i++) {
- nodes[i] = new Node(5000+i, random, null, wd+File.separator, 0);
+ nodes[i] = new Node(5000+i, random, null, wd+File.separator, 0,
false, fh);
nodes[i].usm.setDropProbability(20); // 5%
Logger.normal(RealNodeRoutingTest.class, "Created node "+i);
}
Modified: trunk/freenet/src/freenet/node/RealNodeRoutingTest.java
===================================================================
--- trunk/freenet/src/freenet/node/RealNodeRoutingTest.java 2005-12-07
19:03:04 UTC (rev 7686)
+++ trunk/freenet/src/freenet/node/RealNodeRoutingTest.java 2005-12-07
21:55:27 UTC (rev 7687)
@@ -5,6 +5,7 @@
import freenet.crypt.DiffieHellman;
import freenet.crypt.DummyRandomSource;
import freenet.io.comm.PeerParseException;
+import freenet.support.FileLoggerHook;
import freenet.support.Logger;
import freenet.support.SimpleFieldSet;
import freenet.support.math.BootstrappingDecayingRunningAverage;
@@ -25,7 +26,7 @@
public static void main(String[] args) throws FSParseException,
PeerParseException {
PeerNode.disableProbabilisticHTLs = true;
Node.MAX_HTL = 6;
- Logger.setupStdoutLogging(Logger.NORMAL,
"freenet.node.CPUAdjustingSwapRequestInterval:minor"
/*"freenet.node.LocationManager:debug,freenet.node.FNPPacketManager:normal,freenet.io.comm.UdpSocketManager:debug"*/);
+ FileLoggerHook fh = Logger.setupStdoutLogging(Logger.NORMAL,
"freenet.node.CPUAdjustingSwapRequestInterval:minor"
/*"freenet.node.LocationManager:debug,freenet.node.FNPPacketManager:normal,freenet.io.comm.UdpSocketManager:debug"*/);
System.out.println("Routing test using real nodes:");
System.out.println();
String wd = "realNodeRequestInsertTest";
@@ -35,7 +36,7 @@
Node[] nodes = new Node[NUMBER_OF_NODES];
Logger.normal(RealNodeRoutingTest.class, "Creating nodes...");
for(int i=0;i<NUMBER_OF_NODES;i++) {
- nodes[i] = new Node(5000+i, random, null, wd+File.separator, 0);
+ nodes[i] = new Node(5000+i, random, null, wd+File.separator, 0,
false, fh);
Logger.normal(RealNodeRoutingTest.class, "Created node "+i);
}
SimpleFieldSet refs[] = new SimpleFieldSet[NUMBER_OF_NODES];
Added: trunk/freenet/src/freenet/node/TestnetHandler.java
===================================================================
--- trunk/freenet/src/freenet/node/TestnetHandler.java 2005-12-07 19:03:04 UTC
(rev 7686)
+++ trunk/freenet/src/freenet/node/TestnetHandler.java 2005-12-07 21:55:27 UTC
(rev 7687)
@@ -0,0 +1,130 @@
+package freenet.node;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import freenet.support.Logger;
+
+/**
+ * Testnet handler.
+ * This is a simple server used for debugging. It allows remote developers
+ * to access logfiles stored on this node, and may in future give more options
+ * such as triggering an auto-update.
+ *
+ * NOTE THAT IF THIS IS ENABLED, YOU HAVE NO ANONYMITY! It may also be possible
+ * to exploit this for denial of service, as it is not authenticated in any
way.
+ *
+ * Currently provides two simple commands:
+ * LIST\n - list all currently available logfiles, with size etc.
+ * GET <date> - get the log file containing the given date.
+ * No headers are sent, so you can simply capture netcat's output.
+ * The idea is that this should be as simple as possible...
+ */
+public class TestnetHandler implements Runnable {
+
+ public TestnetHandler(Node node2, int testnetPort) {
+ this.node = node2;
+ this.testnetPort = testnetPort;
+ Logger.error(this, "STARTING TESTNET SERVER!");
+ Logger.error(this, "ANONYMITY MODE: OFF");
+ System.err.println("STARTING TESTNET SERVER!");
+ System.err.println("ANONYMITY MODE: OFF");
+ System.err.println("You have no anonymity. Thank you for
running a testnet node, this will help the developers to efficiently debug
Freenet.");
+ System.err.println("We repeat: YOU HAVE NO ANONYMITY
WHATSOEVER. DO NOT POST ANYTHING YOU DO NOT WANT TO BE ASSOCIATED WITH.");
+ System.err.println("If you want a real freenet node, with
anonymity, turn off testnet mode.");
+ System.err.println("Note, this node will not connect to
non-testnet nodes, for security reasons. You can of course run a testnet node
and a non-testnet node.");
+ serverThread = new Thread(this, "Testnet handler thread");
+ serverThread.setDaemon(true);
+ serverThread.start();
+ }
+
+ private final Node node;
+ private final Thread serverThread;
+ private final int testnetPort;
+
+ public void run() {
+ // Set up server socket
+ ServerSocket server;
+ try {
+ server = new ServerSocket(testnetPort);
+ } catch (IOException e) {
+ Logger.error(this, "Could not bind to testnet port:
"+testnetPort);
+ System.err.println("Could not bind to testnet port:
"+testnetPort);
+ System.exit(Node.EXIT_TESTNET_FAILED);
+ return;
+ }
+ while(true) {
+ try {
+ Socket s = server.accept();
+ TestnetSocketHandler tsh = new
TestnetSocketHandler(s);
+ } catch (IOException e) {
+ Logger.error(this, "Testnet failed to accept
socket: "+e, e);
+ }
+
+ }
+ }
+
+ public class TestnetSocketHandler implements Runnable {
+
+ private Socket s;
+
+ public TestnetSocketHandler(Socket s2) {
+ this.s = s2;
+ }
+
+ public void run() {
+ InputStream is = null;
+ OutputStream os = null;
+ try {
+ is = s.getInputStream();
+ os = s.getOutputStream();
+ // Read command
+ InputStreamReader isr = new
InputStreamReader(is, "ISO-8859-1");
+ BufferedReader br = new BufferedReader(isr);
+ String command = br.readLine();
+ if(command.equalsIgnoreCase("LIST")) {
+
node.fileLoggerHook.listAvailableLogs(new OutputStreamWriter(os, "ISO-8859-1"));
+ } else if(command.startsWith("GET:")) {
+ String date =
command.substring("GET:".length());
+ DateFormat df =
DateFormat.getDateTimeInstance();
+
df.setTimeZone(TimeZone.getTimeZone("GMT"));
+ Date d;
+ try {
+ d = df.parse(date);
+ } catch (ParseException e) {
+ return;
+ }
+
node.fileLoggerHook.sendLogByContainedDate(d.getTime(), os);
+ }
+ } catch (IOException e) {
+ Logger.normal(this, "Failure handling testnet
connection: "+e);
+ } finally {
+ if(is != null)
+ try {
+ is.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ if(os != null)
+ try {
+ os.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+
+ }
+
+}
Modified: trunk/freenet/src/freenet/node/TextModeClientInterface.java
===================================================================
--- trunk/freenet/src/freenet/node/TextModeClientInterface.java 2005-12-07
19:03:04 UTC (rev 7686)
+++ trunk/freenet/src/freenet/node/TextModeClientInterface.java 2005-12-07
21:55:27 UTC (rev 7687)
@@ -102,7 +102,10 @@
// System.out.println("SAY:<text> - send text to the last
created/pushed stream");
System.out.println("STATUS - display some status information on the
node including its reference and connections.");
System.out.println("QUIT - exit the program");
- }
+ if(n.testnetEnabled) {
+ System.out.println("WARNING: TESTNET MODE ENABLED. YOU HAVE NO
ANONYMITY.");
+ }
+ }
/**
* Process a single command.
Modified: trunk/freenet/src/freenet/node/Version.java
===================================================================
--- trunk/freenet/src/freenet/node/Version.java 2005-12-07 19:03:04 UTC (rev
7686)
+++ trunk/freenet/src/freenet/node/Version.java 2005-12-07 21:55:27 UTC (rev
7687)
@@ -20,10 +20,10 @@
public static final String protocolVersion = "1.0";
/** The build number of the current revision */
- public static final int buildNumber = 285;
+ public static final int buildNumber = 286;
/** Oldest build of Fred we will talk to */
- public static final int lastGoodBuild = 285;
+ public static final int lastGoodBuild = 286;
/** The highest reported build of fred */
public static int highestSeenBuild = buildNumber;
Modified: trunk/freenet/src/freenet/support/FileLoggerHook.java
===================================================================
--- trunk/freenet/src/freenet/support/FileLoggerHook.java 2005-12-07
19:03:04 UTC (rev 7686)
+++ trunk/freenet/src/freenet/support/FileLoggerHook.java 2005-12-07
21:55:27 UTC (rev 7687)
@@ -2,10 +2,14 @@
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.InetAddress;
@@ -14,12 +18,15 @@
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.Vector;
import java.util.zip.GZIPOutputStream;
+import freenet.node.Version;
+
/**
* Converted the old StandardLogger to Ian's loggerhook interface.
*
@@ -82,13 +89,30 @@
* Something wierd happens when the disk gets full, also we don't want
to
* block So run the actual write on another thread
*/
- protected LinkedList list = new LinkedList();
+ protected final LinkedList list = new LinkedList();
protected long listBytes = 0;
protected int MAX_LIST_SIZE = 100000;
protected long MAX_LIST_BYTES = 10 * (1 << 20);
// FIXME: should reimplement LinkedList with minimal locking
+ final long maxOldLogfilesDiskUsage;
+ protected final LinkedList logFiles = new LinkedList();
+ private long oldLogFilesDiskSpaceUsage = 0;
+
+ class OldLogFile {
+ public OldLogFile(File currentFilename, long startTime, long
endTime, long length) {
+ this.filename = currentFilename;
+ this.start = startTime;
+ this.end = endTime;
+ this.size = length;
+ }
+ final File filename;
+ final long start; // inclusive
+ final long end; // exclusive
+ final long size;
+ }
+
public void setMaxListLength(int len) {
MAX_LIST_SIZE = len;
}
@@ -134,6 +158,7 @@
protected String getHourLogName(Calendar c, boolean compressed) {
StringBuffer buf = new StringBuffer(50);
buf.append(baseFilename).append('-');
+ buf.append(Version.buildNumber);
buf.append(c.get(Calendar.YEAR)).append('-');
pad2digits(buf, c.get(Calendar.MONTH) + 1);
buf.append('-');
@@ -164,8 +189,11 @@
}
public void run() {
+ findOldLogFiles();
+ File currentFilename = null;
Object o = null;
long thisTime = System.currentTimeMillis();
+ long startTime = -1;
long nextHour = -1;
GregorianCalendar gc = null;
String filename = null;
@@ -194,11 +222,13 @@
gc.set(INTERVAL, (x /
INTERVAL_MULTIPLIER) * INTERVAL_MULTIPLIER);
}
filename = getHourLogName(gc, true);
- logStream = openNewLogFile(new File(filename),
true);
+ currentFilename = new File(filename);
+ logStream = openNewLogFile(currentFilename,
true);
if(latestFilename != null) {
altLogStream =
openNewLogFile(latestFilename, false);
}
System.err.println("Created log files");
+ startTime = gc.getTimeInMillis();
gc.add(INTERVAL, INTERVAL_MULTIPLIER);
nextHour = gc.getTimeInMillis();
}
@@ -216,14 +246,21 @@
"Flushing on change caught " + e);
}
String oldFilename =
filename;
- // Rotate primary log
stream
- filename =
getHourLogName(gc, true);
+ long length =
currentFilename.length();
+ OldLogFile olf = new
OldLogFile(currentFilename, startTime, thisTime, length);
+ synchronized(logFiles) {
+
logFiles.addLast(olf);
+ }
+
oldLogFilesDiskSpaceUsage += length;
+ trimOldLogFiles();
try {
logStream.close();
} catch (IOException e)
{
System.err.println(
"Closing on change caught " + e);
}
+ // Rotate primary log
stream
+ filename =
getHourLogName(gc, true);
logStream =
openNewLogFile(new File(filename), true);
if(latestFilename !=
null) {
try {
@@ -370,7 +407,8 @@
String dfmt,
int threshold,
boolean assumeWorking,
- boolean logOverwrite)
+ boolean logOverwrite,
+ long maxOldLogfilesDiskUsage)
throws IOException {
this(
false,
@@ -379,23 +417,127 @@
dfmt,
threshold,
assumeWorking,
- logOverwrite);
+ logOverwrite,
+ maxOldLogfilesDiskUsage);
}
+ public void trimOldLogFiles() {
+ while(oldLogFilesDiskSpaceUsage > maxOldLogfilesDiskUsage) {
+ OldLogFile olf;
+ synchronized(logFiles) {
+ olf = (OldLogFile) logFiles.removeFirst();
+ }
+ olf.filename.delete();
+ oldLogFilesDiskSpaceUsage -= olf.size;
+ Logger.minor(this, "Deleting "+olf.filename+" - saving
"+olf.size+
+ " bytes, disk usage now:
"+oldLogFilesDiskSpaceUsage+" of "+maxOldLogfilesDiskUsage);
+ }
+ }
+
+ /** Initialize oldLogFiles */
+ public void findOldLogFiles() {
+ int slashIndex = baseFilename.lastIndexOf(File.separatorChar);
+ File dir;
+ String prefix;
+ if(slashIndex == -1) {
+ dir = new File(System.getProperty("user.dir"));
+ prefix = baseFilename.toLowerCase();
+ } else {
+ dir = new File(baseFilename.substring(0, slashIndex));
+ prefix =
baseFilename.substring(slashIndex+1).toLowerCase();
+ }
+ File[] files = dir.listFiles();
+ java.util.Arrays.sort(files);
+ long lastStartTime = -1;
+ File oldFile = null;
+ for(int i=0;i<files.length;i++) {
+ File f = files[i];
+ String name = f.getName();
+ if(name.toLowerCase().startsWith(prefix)) {
+ if(name.equals(previousFilename)) {
+ f.delete();
+ continue;
+ } else if(name.equals(latestFilename)) {
+ f.renameTo(previousFilename);
+ continue;
+ }
+ if(!name.endsWith(".log.gz")) {
+ f.delete();
+ continue;
+ } else {
+ name = name.substring(0,
name.length()-".log.gz".length());
+ }
+ String[] tokens = name.split("-");
+ int[] nums = new int[tokens.length];
+ for(int j=0;j<tokens.length;j++) {
+ try {
+ nums[j] =
Integer.parseInt(tokens[j]);
+ } catch (NumberFormatException e) {
+ // Broken
+ f.delete();
+ continue;
+ }
+ }
+ // First field: version
+ if(nums.length < 1) {
+ f.delete();
+ continue;
+ }
+ if(nums[0] != Version.buildNumber) {
+ // Logs that old are useless
+ f.delete();
+ continue;
+ }
+ GregorianCalendar gc = new GregorianCalendar();
+ if(nums.length > 1)
+ gc.set(Calendar.YEAR, nums[1]);
+ if(nums.length > 2)
+ gc.set(Calendar.MONTH, nums[2]);
+ if(nums.length > 3)
+ gc.set(Calendar.DAY_OF_MONTH, nums[3]);
+ if(nums.length > 4)
+ gc.set(Calendar.HOUR_OF_DAY, nums[4]);
+ if(nums.length > 5)
+ gc.set(Calendar.MINUTE, nums[5]);
+ long startTime = gc.getTimeInMillis();
+ if(oldFile != null) {
+ long l = oldFile.length();
+ OldLogFile olf = new
OldLogFile(oldFile, lastStartTime, startTime, l);
+ logFiles.addLast(olf);
+ oldLogFilesDiskSpaceUsage += l;
+ }
+ lastStartTime = -1;
+ oldFile = f;
+ } else {
+ // Nothing to do with us
+ Logger.normal(this, "Unknown file: "+name+" in
our log directory");
+ }
+ }
+ if(oldFile != null) {
+ long l = oldFile.length();
+ OldLogFile olf = new OldLogFile(oldFile, lastStartTime,
System.currentTimeMillis(), l);
+ logFiles.addLast(olf);
+ oldLogFilesDiskSpaceUsage += l;
+ }
+ trimOldLogFiles();
+ }
+
public FileLoggerHook(
String filename,
String fmt,
String dfmt,
String threshold,
boolean assumeWorking,
- boolean logOverwrite)
+ boolean logOverwrite,
+ long maxOldLogFilesDiskUsage)
throws IOException {
this(filename,
fmt,
dfmt,
priorityOf(threshold),
assumeWorking,
- logOverwrite);
+ logOverwrite,
+ maxOldLogFilesDiskUsage);
}
private void checkStdStreams() {
@@ -447,7 +589,7 @@
String dfmt,
int threshold,
boolean overwrite) {
- this(fmt, dfmt, threshold, overwrite);
+ this(fmt, dfmt, threshold, overwrite, -1);
logStream = stream;
}
@@ -470,9 +612,10 @@
String dfmt,
int threshold,
boolean assumeWorking,
- boolean logOverwrite)
+ boolean logOverwrite,
+ long maxOldLogfilesDiskUsage)
throws IOException {
- this(fmt, dfmt, threshold, logOverwrite);
+ this(fmt, dfmt, threshold, logOverwrite,
maxOldLogfilesDiskUsage);
//System.err.println("Creating FileLoggerHook with threshold
// "+threshold);
if (!assumeWorking)
@@ -491,12 +634,14 @@
String dfmt,
String threshold,
boolean assumeWorking,
- boolean logOverwrite) throws IOException{
-
this(rotate,baseFilename,fmt,dfmt,priorityOf(threshold),assumeWorking,logOverwrite);
+ boolean logOverwrite,
+ long maxOldLogFilesDiskUsage) throws IOException{
+
this(rotate,baseFilename,fmt,dfmt,priorityOf(threshold),assumeWorking,logOverwrite,maxOldLogFilesDiskUsage);
}
- private FileLoggerHook(String fmt, String dfmt, int threshold, boolean
overwrite) {
+ private FileLoggerHook(String fmt, String dfmt, int threshold, boolean
overwrite, long maxOldLogfilesDiskUsage) {
super(threshold);
+ this.maxOldLogfilesDiskUsage = maxOldLogfilesDiskUsage;
this.logOverwrite = overwrite;
if (dfmt != null && dfmt.length() != 0) {
try {
@@ -686,4 +831,53 @@
closed = true;
}
}
+
+ /**
+ * Print a human- and script- readable list of available log files.
+ * @throws IOException
+ */
+ public void listAvailableLogs(OutputStreamWriter writer) throws
IOException {
+ OldLogFile[] oldLogFiles;
+ synchronized(logFiles) {
+ oldLogFiles = (OldLogFile[]) logFiles.toArray(new
OldLogFile[logFiles.size()]);
+ }
+ DateFormat df = DateFormat.getDateTimeInstance();
+ df.setTimeZone(TimeZone.getTimeZone("GMT"));
+ for(int i=0;i<oldLogFiles.length;i++) {
+ OldLogFile olf = oldLogFiles[i];
+ writer.write(olf.filename.getName()+" : "+df.format(new
Date(olf.start))+" to "+df.format(new Date(olf.end))+ " - "+olf.size+" bytes");
+ }
+ }
+
+ public void sendLogByContainedDate(long time, OutputStream os) throws
IOException {
+ OldLogFile toReturn = null;
+ synchronized(logFiles) {
+ Iterator i = logFiles.iterator();
+ while(i.hasNext()) {
+ OldLogFile olf = (OldLogFile) i.next();
+ if(time >= olf.start && time < olf.end) {
+ toReturn = olf;
+ break;
+ }
+ }
+ if(toReturn == null)
+ return; // couldn't find it
+ }
+ FileInputStream fis = new FileInputStream(toReturn.filename);
+ DataInputStream dis = new DataInputStream(fis);
+ long written = 0;
+ long size = toReturn.size;
+ byte[] buf = new byte[4096];
+ while(written < size) {
+ int toRead = (int) Math.min(buf.length, (size -
written));
+ try {
+ dis.readFully(buf, 0, toRead);
+ } catch (IOException e) {
+ Logger.error(this, "Could not read bytes
"+written+" to "+(written + toRead)+" from file "+toReturn.filename+" which is
supposed to be "+size+" bytes ("+toReturn.filename.length()+")");
+ return;
+ }
+ os.write(buf, 0, toRead);
+ written += toRead;
+ }
+ }
}
Modified: trunk/freenet/src/freenet/support/Logger.java
===================================================================
--- trunk/freenet/src/freenet/support/Logger.java 2005-12-07 19:03:04 UTC
(rev 7686)
+++ trunk/freenet/src/freenet/support/Logger.java 2005-12-07 21:55:27 UTC
(rev 7687)
@@ -28,7 +28,7 @@
*/
static Logger logger = new VoidLogger();
- public static void setupStdoutLogging(int level, String detail) {
+ public static FileLoggerHook setupStdoutLogging(int level, String
detail) {
setupChain();
logger.setThreshold(level);
logger.setDetailedThresholds(detail);
@@ -38,6 +38,7 @@
fh.setDetailedThresholds(detail);
((LoggerHookChain) logger).addHook(fh);
fh.start();
+ return fh;
}
public static void setupChain() {