in core/src/main/java/hudson/tasks/LogRotator.java [144:225]
public void perform(Job<?,?> job) throws IOException, InterruptedException {
//Exceptions thrown by the deletion submethods are collated and reported
HashMultimap<Run<?,?>, IOException> exceptionMap = HashMultimap.create();
LOGGER.log(FINE, "Running the log rotation for {0} with numToKeep={1} daysToKeep={2} artifactNumToKeep={3} artifactDaysToKeep={4}", new Object[] {job, numToKeep, daysToKeep, artifactNumToKeep, artifactDaysToKeep});
// always keep the last successful and the last stable builds
Run lsb = job.getLastSuccessfulBuild();
Run lstb = job.getLastStableBuild();
if(numToKeep!=-1) {
// Note that RunList.size is deprecated, and indeed here we are loading all the builds of the job.
// However we would need to load the first numToKeep anyway, just to skip over them;
// and we would need to load the rest anyway, to delete them.
// (Using RunMap.headMap would not suffice, since we do not know if some recent builds have been deleted for other reasons,
// so simply subtracting numToKeep from the currently last build number might cause us to delete too many.)
List<? extends Run<?,?>> builds = job.getBuilds();
for (Run r : copy(builds.subList(Math.min(builds.size(), numToKeep), builds.size()))) {
if (shouldKeepRun(r, lsb, lstb)) {
continue;
}
LOGGER.log(FINE, "{0} is to be removed", r);
try { r.delete(); }
catch (IOException ex) { exceptionMap.put(r, ex); }
}
}
if(daysToKeep!=-1) {
Calendar cal = new GregorianCalendar();
cal.add(Calendar.DAY_OF_YEAR,-daysToKeep);
Run r = job.getFirstBuild();
while (r != null) {
if (tooNew(r, cal)) {
break;
}
if (!shouldKeepRun(r, lsb, lstb)) {
LOGGER.log(FINE, "{0} is to be removed", r);
try { r.delete(); }
catch (IOException ex) { exceptionMap.put(r, ex); }
}
r = r.getNextBuild();
}
}
if(artifactNumToKeep!=null && artifactNumToKeep!=-1) {
List<? extends Run<?,?>> builds = job.getBuilds();
for (Run r : copy(builds.subList(Math.min(builds.size(), artifactNumToKeep), builds.size()))) {
if (shouldKeepRun(r, lsb, lstb)) {
continue;
}
LOGGER.log(FINE, "{0} is to be purged of artifacts", r);
try { r.deleteArtifacts(); }
catch (IOException ex) { exceptionMap.put(r, ex); }
}
}
if(artifactDaysToKeep!=null && artifactDaysToKeep!=-1) {
Calendar cal = new GregorianCalendar();
cal.add(Calendar.DAY_OF_YEAR,-artifactDaysToKeep);
Run r = job.getFirstBuild();
while (r != null) {
if (tooNew(r, cal)) {
break;
}
if (!shouldKeepRun(r, lsb, lstb)) {
LOGGER.log(FINE, "{0} is to be purged of artifacts", r);
try { r.deleteArtifacts(); }
catch (IOException ex) { exceptionMap.put(r, ex); }
}
r = r.getNextBuild();
}
}
if (!exceptionMap.isEmpty()) {
//Collate all encountered exceptions into a single exception and throw that
String msg = String.format(
"Failed to rotate logs for [%s]",
Joiner.on(", ").join(exceptionMap.keySet())
);
throw new CompositeIOException(msg, new ArrayList<>(exceptionMap.values()));
}
}