All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.wildfly.security.audit.PeriodicRotatingFileAuditEndpoint Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote Jakarta Enterprise Beans and Jakarta Messaging, including all dependencies. It is intended for use by those not using maven, maven users should just import the Jakarta Enterprise Beans and Jakarta Messaging BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 35.0.0.Beta1
Show newest version
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2017 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.wildfly.security.audit;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.WeekFields;
import java.util.Locale;

import static org.wildfly.common.Assert.checkNotNullParam;
import static org.wildfly.security.audit.ElytronMessages.audit;

/**
 * An audit endpoint which rotates the log at a preset time interval.
 * Depending on set suffix, moves old log records into files tagged by timestamp.
 * 

* Based on {@link org.jboss.logmanager.handlers.PeriodicSizeRotatingFileHandler}. * * @author Jan Kalina * @author James R. Perkins * @author Yeray Borges */ public class PeriodicRotatingFileAuditEndpoint extends FileAuditEndpoint { private final DateTimeFormatter format; private final Period period; private final ZoneId timeZone; private long nextRollover = Long.MAX_VALUE; private String nextSuffix; PeriodicRotatingFileAuditEndpoint(Builder builder) throws IOException { super(builder); this.format = builder.format; this.period = builder.period; this.timeZone = builder.timeZone; final File file = getFile(); calcNextRollover(file != null && file.lastModified() > 0 ? file.lastModified() : clock.millis()); } /** * Checks whether time-based log rotation should be done and if so, it moves current log file * into time-tagged file and exchange target file to continue logging into new, non-time-tagged file. * * @param instant time of the message acceptance */ @Override protected void preWrite(Instant instant) { final long recordMillis = instant.toEpochMilli(); if (recordMillis >= nextRollover) { try { final File file = getFile(); if (file == null) { // no file is set; a direct output stream or writer was specified return; } closeStreams(); // close the original file (some OSes won't let you move/rename a file that is open) final Path target = Paths.get(file.toPath() + nextSuffix); Files.move(file.toPath(), target, StandardCopyOption.REPLACE_EXISTING); setFile(file); } catch (IOException e) { audit.unableToRotateLogFile(e); } calcNextRollover(recordMillis); } } /** * For given time and period obtains time when should be new log file started */ private void calcNextRollover(final long fromTime) { if (period == Period.NEVER || format == null) { nextRollover = Long.MAX_VALUE; return; } ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(fromTime), timeZone); nextSuffix = format.format(zonedDateTime); switch (period) { case YEAR: zonedDateTime = zonedDateTime.truncatedTo(ChronoUnit.DAYS) .withDayOfYear(1) .plus(1, ChronoUnit.YEARS); break; case MONTH: zonedDateTime = zonedDateTime.truncatedTo(ChronoUnit.DAYS) .withDayOfMonth(1) .plus(1,ChronoUnit.MONTHS); break; case WEEK: zonedDateTime = zonedDateTime.truncatedTo(ChronoUnit.DAYS) .with(TemporalAdjusters.next(WeekFields.of(Locale.getDefault()).getFirstDayOfWeek())); break; case DAY: zonedDateTime = zonedDateTime.truncatedTo(ChronoUnit.DAYS) .plus(1, ChronoUnit.DAYS); break; case HALF_DAY: ZonedDateTime halfDay = ZonedDateTime.from(zonedDateTime).truncatedTo(ChronoUnit.DAYS) .plus(1, ChronoUnit.HALF_DAYS); if ( zonedDateTime.isBefore(halfDay) ) { zonedDateTime = halfDay; }else{ zonedDateTime = halfDay.plus(1, ChronoUnit.HALF_DAYS); } break; case HOUR: zonedDateTime = zonedDateTime.truncatedTo(ChronoUnit.HOURS) .plus(1, ChronoUnit.HOURS); break; case MINUTE: zonedDateTime = zonedDateTime.truncatedTo(ChronoUnit.MINUTES) .plus(1, ChronoUnit.MINUTES); } nextRollover = zonedDateTime.toInstant().toEpochMilli(); } /** * Possible period values. Keep in strictly ascending order of magnitude. */ enum Period { MINUTE, HOUR, HALF_DAY, DAY, WEEK, MONTH, YEAR, NEVER, } /** * Obtain a new {@link Builder} capable of building a {@link PeriodicRotatingFileAuditEndpoint}. * * @return a new {@link Builder} capable of building a {@link PeriodicRotatingFileAuditEndpoint}. */ public static Builder builder() { return new Builder(); } /** * A builder for periodic rotating file audit endpoints. */ public static class Builder extends FileAuditEndpoint.Builder { DateTimeFormatter format; Period period = Period.NEVER; ZoneId timeZone = ZoneId.systemDefault(); Builder() { super(); } /** * Set the configured time zone for this handler. * * @param timeZone the configured time zone * @return this builder */ public Builder setTimeZone(ZoneId timeZone) { this.timeZone = checkNotNullParam("timeZone", timeZone); return this; } /** * Set the suffix string. The string is in a format which can be understood by {@link java.time.format.DateTimeFormatter}. * The period of the rotation is automatically calculated based on the suffix. * * @param suffix the suffix * @return this builder * @throws IllegalArgumentException if the suffix is not valid */ public Builder setSuffix(String suffix) throws IllegalArgumentException { format = DateTimeFormatter.ofPattern(suffix).withZone(timeZone); final int len = suffix.length(); period = Period.NEVER; for (int i = 0; i < len; i ++) { switch (suffix.charAt(i)) { case 'y': period = min(period, Period.YEAR); break; case 'M': period = min(period, Period.MONTH); break; case 'w': case 'W': period = min(period, Period.WEEK); break; case 'D': case 'd': case 'F': case 'E': period = min(period, Period.DAY); break; case 'a': period = min(period, Period.HALF_DAY); break; case 'H': case 'k': case 'K': case 'h': period = min(period, Period.HOUR); break; case 'm': period = min(period, Period.MINUTE); break; case '\'': while (suffix.charAt(++i) != '\''){} break; case 's': case 'S': throw audit.rotatingBySecondUnsupported(suffix); } } return this; } /** * Construct a new instance. * * @return the built audit endpoint. * @throws IOException if an I/O error occurs. */ @Override public AuditEndpoint build() throws IOException { return new PeriodicRotatingFileAuditEndpoint(this); } } private static > T min(T a, T b) { return a.compareTo(b) <= 0 ? a : b; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy