diff --git a/changelog.html b/changelog.html index e1cf485e1e00c3451aceb8a7a90760b7c363be74..2dc45f12fb05abfff073c281d8cfdece1dd8cbf7 100644 --- a/changelog.html +++ b/changelog.html @@ -79,6 +79,8 @@ Upcoming changes (pull request #119)
  • Plugins can now override where jobs are executed. +
  • + Rotate the slave log files instead of deleting them.
  • Added a mechanism to control the XML parser behaviour (pull request #67) diff --git a/core/src/main/java/hudson/slaves/SlaveComputer.java b/core/src/main/java/hudson/slaves/SlaveComputer.java index 0354d4534915fc602bf12cc6eafc05a07c7f4946..efb26660bb73ce6217f935ef4754e341742ce160 100644 --- a/core/src/main/java/hudson/slaves/SlaveComputer.java +++ b/core/src/main/java/hudson/slaves/SlaveComputer.java @@ -24,6 +24,7 @@ package hudson.slaves; import hudson.model.*; +import hudson.util.io.ReopenableRotatingFileOutputStream; import jenkins.model.Jenkins.MasterComputer; import hudson.remoting.Channel; import hudson.remoting.VirtualChannel; @@ -115,7 +116,7 @@ public class SlaveComputer extends Computer { public SlaveComputer(Slave slave) { super(slave); - this.log = new ReopenableFileOutputStream(getLogFile()); + this.log = new ReopenableRotatingFileOutputStream(getLogFile(),10); this.taskListener = new StreamTaskListener(log); } diff --git a/core/src/main/java/hudson/util/io/ReopenableFileOutputStream.java b/core/src/main/java/hudson/util/io/ReopenableFileOutputStream.java index 27d53bcfa691278ef614e6d69ba0db84bcd01e2c..9a68052653d6011851e9789e186c29ab4a2a501f 100644 --- a/core/src/main/java/hudson/util/io/ReopenableFileOutputStream.java +++ b/core/src/main/java/hudson/util/io/ReopenableFileOutputStream.java @@ -41,7 +41,7 @@ import java.io.OutputStream; * @author Kohsuke Kawaguchi */ public class ReopenableFileOutputStream extends OutputStream { - private final File out; + protected final File out; private OutputStream current; private boolean appendOnNextOpen = false; diff --git a/core/src/main/java/hudson/util/io/ReopenableRotatingFileOutputStream.java b/core/src/main/java/hudson/util/io/ReopenableRotatingFileOutputStream.java new file mode 100644 index 0000000000000000000000000000000000000000..3fecde3ea1bbb1c9795428d1d1db176c60648b09 --- /dev/null +++ b/core/src/main/java/hudson/util/io/ReopenableRotatingFileOutputStream.java @@ -0,0 +1,70 @@ +/* + * The MIT License + * + * Copyright (c) 2011, CloudBees, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package hudson.util.io; + +import java.io.File; +import java.io.IOException; + +/** + * {@link ReopenableFileOutputStream} that does log rotation upon rewind. + * + * @author Kohsuke Kawaguchi + * @since 1.416 + */ +public class ReopenableRotatingFileOutputStream extends ReopenableFileOutputStream { + /** + * Number of log files to keep. + */ + private final int size; + + public ReopenableRotatingFileOutputStream(File out, int size) { + super(out); + this.size = size; + } + + protected File getNumberedFileName(int n) { + if (n==0) return out; + return new File(out.getPath()+"."+n); + } + + @Override + public void rewind() throws IOException { + super.rewind(); + for (int i=size-1;i>=0;i--) { + File fi = getNumberedFileName(i); + if (fi.exists()) { + fi.renameTo(getNumberedFileName(i+1)); + } + } + } + + /** + * Deletes all the log files, including rotated files. + */ + public void deleteAll() { + for (int i=0; i<=size; i++) { + getNumberedFileName(i).delete(); + } + } +} diff --git a/core/src/test/java/hudson/util/io/ReopenableRotatingFileOutputStreamTest.java b/core/src/test/java/hudson/util/io/ReopenableRotatingFileOutputStreamTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3cbebc60acc9a170ea95521b64ccd498d3b12dab --- /dev/null +++ b/core/src/test/java/hudson/util/io/ReopenableRotatingFileOutputStreamTest.java @@ -0,0 +1,32 @@ +package hudson.util.io; + +import hudson.FilePath; +import junit.framework.TestCase; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; + +/** + * @author Kohsuke Kawaguchi + */ +public class ReopenableRotatingFileOutputStreamTest extends TestCase { + public void testRotation() throws IOException { + File base = File.createTempFile("test", "log"); + ReopenableRotatingFileOutputStream os = new ReopenableRotatingFileOutputStream(base,3); + PrintWriter w = new PrintWriter(os,true); + for (int i=0; i<=4; i++) { + w.println("Content"+i); + os.rewind(); + } + w.println("Content5"); + + assertEquals("Content5", new FilePath(base).readToString().trim()); + assertEquals("Content4", new FilePath(new File(base.getPath() + ".1")).readToString().trim()); + assertEquals("Content3", new FilePath(new File(base.getPath() + ".2")).readToString().trim()); + assertEquals("Content2", new FilePath(new File(base.getPath() + ".3")).readToString().trim()); + assertFalse(new File(base.getPath() + ".4").exists()); + + os.deleteAll(); + } +}