com.vlkan.hrrs.replayer.cli.Replayer Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2016-2022 Volkan Yazıcı
*
* 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 permits and
* limitations under the License.
*/
package com.vlkan.hrrs.replayer.cli;
import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.MetricRegistry;
import com.google.common.base.Stopwatch;
import com.google.common.util.concurrent.RateLimiter;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.vlkan.hrrs.api.HttpRequestRecord;
import com.vlkan.hrrs.commons.logger.LoggerLevelAccessor;
import com.vlkan.hrrs.commons.logger.LoggerLevels;
import com.vlkan.hrrs.replayer.executor.CloseableExecutor;
import com.vlkan.hrrs.replayer.http.HttpRequestRecordReplayer;
import com.vlkan.hrrs.replayer.metric.MetricReporter;
import com.vlkan.hrrs.replayer.record.HttpRequestRecordStream;
import com.vlkan.hrrs.replayer.record.HttpRequestRecordStreamConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import static com.google.common.base.Preconditions.checkNotNull;
@Singleton
public class Replayer implements Runnable, Closeable, HttpRequestRecordStreamConsumer {
private static final Logger LOGGER = LoggerFactory.getLogger(Replayer.class);
private final Config config;
private final CloseableExecutor closeableExecutor;
private final HttpRequestRecordStream recordStream;
private final HttpRequestRecordReplayer recordReplayer;
private final MetricRegistry metricRegistry;
private final MetricReporter metricReporter;
private volatile boolean closed = false;
@Inject
public Replayer(
Config config,
CloseableExecutor closeableExecutor,
HttpRequestRecordStream recordStream,
HttpRequestRecordReplayer recordReplayer,
MetricRegistry metricRegistry,
MetricReporter metricReporter) {
// Check arguments.
checkNotNull(config, "config");
checkNotNull(closeableExecutor, "closeableExecutor");
checkNotNull(recordStream, "recordStream");
checkNotNull(recordReplayer, "recordReplayer");
checkNotNull(metricRegistry, "metricRegistry");
checkNotNull(metricReporter, "metricReporter");
// Set class fields.
this.config = config;
this.closeableExecutor = closeableExecutor;
this.recordStream = recordStream;
this.recordReplayer = recordReplayer;
this.metricRegistry = metricRegistry;
this.metricReporter = metricReporter;
}
@Override
public void run() {
LOGGER.debug("starting to replay");
Callable consumptionPredicate = createConsumptionPredicate();
metricReporter.start();
recordStream.consumeWhile(config.getInputUri(), config.isReplayOnce(), consumptionPredicate, this);
reportMetric();
}
private Callable createConsumptionPredicate() {
return new Callable() {
private final Stopwatch stopwatch = Stopwatch.createStarted();
private final long totalDurationMillis = config.getTotalDurationSeconds() * 1000L;
private final AtomicLong recordCounter = new AtomicLong();
private final RateLimiter progressReportRateLimiter = RateLimiter.create(10);
@Override
public Boolean call() {
long durationMillis = stopwatch.elapsed(TimeUnit.MILLISECONDS);
reportProgress(durationMillis);
return !closed && durationMillis < totalDurationMillis;
}
private void reportProgress(long durationMillis) {
if (progressReportRateLimiter.tryAcquire()) {
float durationPercentage = Math.max(100.0f, 100.0f * durationMillis / totalDurationMillis);
long recordCount = recordCounter.incrementAndGet();
System.out.format(
"\r%.1f%% (durationMillis=%d, recordCount=%d)",
durationPercentage, durationMillis, recordCount);
}
}
};
}
private void reportMetric() {
System.out.println();
System.out.println();
ConsoleReporter
.forRegistry(metricRegistry)
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS)
.build()
.report();
}
@Override
public void consume(final HttpRequestRecord record) {
closeableExecutor.execute(() -> recordReplayer.replay(record));
}
@Override
public void close() throws IOException {
closeableExecutor.close();
recordReplayer.close();
metricReporter.close();
closed = true;
}
public static void main(String[] args, ReplayerModuleFactory moduleFactory) throws IOException {
Config config = Config.of(args);
config.dump();
ReplayerModule mainModule = moduleFactory.create(config);
Injector injector = Guice.createInjector(mainModule);
LoggerLevelAccessor loggerLevelAccessor = injector.getInstance(LoggerLevelAccessor.class);
LoggerLevels.applyLoggerLevelSpecs(config.getLoggerLevelSpecs(), loggerLevelAccessor);
try (Replayer replayer = injector.getInstance(Replayer.class)) {
replayer.run();
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy