package com.ctrip.framework.apollo.openapi.util;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Queues;
import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory;
import com.ctrip.framework.apollo.openapi.entity.ConsumerAudit;
import com.ctrip.framework.apollo.openapi.service.ConsumerService;
import com.ctrip.framework.apollo.tracer.Tracer;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.servlet.http.HttpServletRequest;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Service
public class ConsumerAuditUtil implements InitializingBean {
private static final int CONSUMER_AUDIT_MAX_SIZE = 10000;
private BlockingQueue<ConsumerAudit> audits = Queues.newLinkedBlockingQueue(CONSUMER_AUDIT_MAX_SIZE);
private final ExecutorService auditExecutorService;
private final AtomicBoolean auditStopped;
private int BATCH_SIZE = 100;
private long BATCH_TIMEOUT = 5;
private TimeUnit BATCH_TIMEUNIT = TimeUnit.SECONDS;
@Autowired
private ConsumerService consumerService;
public ConsumerAuditUtil() {
auditExecutorService = Executors.newSingleThreadExecutor(
ApolloThreadFactory.create("ConsumerAuditUtil", true));
auditStopped = new AtomicBoolean(false);
}
public boolean audit(HttpServletRequest request, long consumerId) {
//ignore GET request
if ("GET".equalsIgnoreCase(request.getMethod())) {
return true;
}
String uri = request.getRequestURI();
if (!Strings.isNullOrEmpty(request.getQueryString())) {
uri += "?" + request.getQueryString();
}
ConsumerAudit consumerAudit = new ConsumerAudit();
Date now = new Date();
consumerAudit.setConsumerId(consumerId);
consumerAudit.setUri(uri);
consumerAudit.setMethod(request.getMethod());
consumerAudit.setDataChangeCreatedTime(now);
consumerAudit.setDataChangeLastModifiedTime(now);
//throw away audits if exceeds the max size
return this.audits.offer(consumerAudit);
}
@Override
public void afterPropertiesSet() throws Exception {
auditExecutorService.submit(() -> {
while (!auditStopped.get() && !Thread.currentThread().isInterrupted()) {
List<ConsumerAudit> toAudit = Lists.newArrayList();
try {
Queues.drain(audits, toAudit, BATCH_SIZE, BATCH_TIMEOUT, BATCH_TIMEUNIT);
if (!toAudit.isEmpty()) {
consumerService.createConsumerAudits(toAudit);
}
} catch (Throwable ex) {
Tracer.logError(ex);
}
}
});
}
public void stopAudit() {
auditStopped.set(true);
}
}