/* Copyright 2012 Google, Inc.
*
* 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.arbeitspferde.groningen.eventlog;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import org.arbeitspferde.groningen.proto.Event;
import org.arbeitspferde.groningen.utility.logstream.OutputLogStream;
import org.arbeitspferde.groningen.utility.logstream.OutputLogStreamFactory;
import org.arbeitspferde.groningen.utility.logstream.OutputLogStreamFactory.Specification;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Logger;
/**
* A producer of {@link SafeProtoLogger}.
*
* This class is rather trivial, but it exists to keep the complexity of {@link SafeProtoLogger}'s
* constructor to a minimum.
*/
@Singleton
public class SafeProtoLoggerFactory {
private static final Logger log = Logger.getLogger(SafeProtoLogger.class.getCanonicalName());
private final Provider<Timer> timerProvider;
private final OutputLogStreamFactory outputLogStreamFactory;
/**
* Create factory that produces safe protocol buffer loggers.
*
* @param timerProvider The {@link Provider} or {@link Timer} for testability.
*/
@Inject
SafeProtoLoggerFactory(final Provider<Timer> timerProvider,
final OutputLogStreamFactory outputLogStreamFactory) {
this.timerProvider = timerProvider;
this.outputLogStreamFactory = outputLogStreamFactory;
}
/**
* Create a new {@link SafeProtoLogger} of {@link Event.EventEntry}.
*
* @param basename See {@link Specification#getFilenamePrefix()}.
* @param port See {@link Specification#getServingPort()}.
* @param rotateSize See {@link Specification#rotateFileUponAtSizeBytes()}.
* @param flushIntervalSeconds The interval in seconds between automatic log flush events.
* @param loggerName The human-readable canonical name for the log.
*
* @return A {@link SafeProtoLogger} that meets the supra specifications.
*
* @throws IOException In the event that the RecordIO cannot be provisioned.
*/
public SafeProtoLogger<Event.EventEntry> newEventEntryLogger(final String basename,
final int port, final long rotateSize, final int flushIntervalSeconds,
final String loggerName) throws IOException {
Preconditions.checkNotNull(basename, "basename may not be null.");
Preconditions.checkArgument(port > 0, "port must be > 0.");
Preconditions.checkArgument(rotateSize >= 0, "rotateSize must >= 0.");
Preconditions.checkArgument(flushIntervalSeconds >= 0, "flushIntervalSeconds must >= 0.");
Preconditions.checkNotNull(loggerName, "loggerName may not be null.");
log.info(String.format("Creating RecordIO log around %s.", basename));
final OutputLogStream stream = outputLogStreamFactory.rotatingStreamForSpecification(
new Specification() {
@Override
public String getFilenamePrefix() {
return basename;
}
@Override
public int getServingPort() {
return port;
}
@Override
public long rotateFileUponAtSizeBytes() {
return rotateSize;
}
});
final SafeProtoLogger<Event.EventEntry> logger =
new SafeProtoLogger<>(stream, loggerName);
yieldTimer(flushIntervalSeconds, loggerName, logger);
return logger;
}
/**
* Create a timer that automatically flushes the RecordIO stream.
*
* No hard reference needs to be held onto the {@link Timer} per its Javadoc.
*
* @param flushIntervalSeconds See {@link #newEventEntryLogger(String, int, long, int, String)}.
* @param loggerName See {@link #newEventEntryLogger(String, int, long, int, String)}.
* @param logger A {@link SafeProtoLogger}.
*
* @return The {@link Timer} that manages the automatic flushing.
*/
@VisibleForTesting
Timer yieldTimer(final int flushIntervalSeconds, final String loggerName,
final SafeProtoLogger<?> logger) {
Preconditions.checkNotNull(loggerName, "loggerName may not be null.");
Preconditions.checkNotNull(logger, "stream may not be null.");
final Timer flushEventTimer = timerProvider.get();
if (flushIntervalSeconds > 0) {
flushEventTimer.schedule(new TimerTask() {
@Override
public void run() {
try {
log.info(String.format("Flushing %s...", loggerName));
logger.flush();
log.info(String.format("Finished flushing %s.", loggerName));
} catch (final IOException e) {
log.warning(String.format("Failed to flush log for %s.", loggerName, e));
}
}
}, 0, flushIntervalSeconds * 1000L);
}
return flushEventTimer;
}
}