You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
common-smartgears/src/main/java/org/gcube/smartgears/handlers/application/request/RequestAccounting.java

148 lines
5.4 KiB
Java

package org.gcube.smartgears.handlers.application.request;
import org.gcube.accounting.datamodel.UsageRecord.OperationResult;
import org.gcube.accounting.datamodel.usagerecords.ServiceUsageRecord;
import org.gcube.accounting.persistence.AccountingPersistence;
import org.gcube.accounting.persistence.AccountingPersistenceFactory;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.smartgears.Constants;
import org.gcube.smartgears.configuration.Mode;
import org.gcube.smartgears.context.application.ApplicationContext;
import org.gcube.smartgears.handlers.application.RequestEvent;
import org.gcube.smartgears.handlers.application.RequestHandler;
import org.gcube.smartgears.handlers.application.ResponseEvent;
import org.gcube.smartgears.utils.InnerMethodName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RequestAccounting extends RequestHandler {
private static Logger log = LoggerFactory.getLogger(RequestAccounting.class);
private static ThreadLocal<Long> startCallThreadLocal = new ThreadLocal<Long>();
private static final String UNKNOWN = "Unknown";
@Override
public String getName() {
return Constants.request_accounting;
}
@Override
public void handleRequest(RequestEvent e) {
ApplicationContext appContext = e.context();
String context = getContext(appContext);
if (InnerMethodName.get() == null) {
String calledMethod = e.request().getRequestURI().substring(e.request().getContextPath().length());
if (calledMethod.isEmpty())
calledMethod = "/";
calledMethod = e.request().getMethod() + " " + calledMethod;
InnerMethodName.set(calledMethod);
}
String caller = SecretManagerProvider.get() != null
? SecretManagerProvider.get().getOwner().getId()
: UNKNOWN;
startCallThreadLocal.set(System.currentTimeMillis());
log.info("REQUEST START ON {}:{}({}) CALLED FROM {}@{} IN SCOPE {} ", appContext.configuration().name(),
appContext.configuration().group(), InnerMethodName.get(), caller,
e.request().getRemoteHost(), context);
}
@Override
public void handleResponse(ResponseEvent e) {
ApplicationContext appContext = e.context();
try {
String context = getContext(appContext);
String caller = SecretManagerProvider.get() != null
? SecretManagerProvider.get().getOwner().getId()
: UNKNOWN;
String callerQualifier = UNKNOWN;
// retieves caller Ip when there is a proxy
String callerIp = e.request().getHeader("x-forwarded-for");
if (callerIp == null)
callerIp = e.request().getRemoteHost();
boolean success = e.response().getStatus() < 400;
if (appContext.container().configuration().mode() != Mode.offline)
generateAccounting(caller, callerQualifier, callerIp == null ? UNKNOWN : callerIp, success, context,
appContext);
long durationInMillis = System.currentTimeMillis() - startCallThreadLocal.get();
/*
* Metrics.globalRegistry.timer("smartgears.requests",
* "response",Integer.toString(e.response().getStatus()) , "context", context,
* "result", success?"SUCCEDED":"FAILED", "caller-ip", callerIp,
* "caller-username", caller, "service-class",
* appContext.configuration().serviceClass(), "service-name",
* appContext.configuration().name(), "method",
* InnerMethodName.instance.get()).record(durationInMillis,
* TimeUnit.MILLISECONDS);
*/
log.info("REQUEST SERVED ON {}:{}({}) CALLED FROM {}@{} IN SCOPE {} {}(CODE {}) IN {} millis",
appContext.configuration().name(), appContext.configuration().group(),
InnerMethodName.get(), caller, callerIp, context, success ? "SUCCEDED" : "FAILED",
e.response().getStatus(), durationInMillis);
} catch (Exception e1) {
log.error("error on accounting", e);
throw e1;
} finally {
startCallThreadLocal.remove();
InnerMethodName.reset();
}
}
void generateAccounting(String caller, String callerQualifier, String remoteHost, boolean success,
String gcubeContext, ApplicationContext appContext) {
AccountingPersistenceFactory
.setFallbackLocation(appContext.container().configuration().accountingFallbackLocation());
AccountingPersistence persistence = AccountingPersistenceFactory.getPersistence();
ServiceUsageRecord serviceUsageRecord = new ServiceUsageRecord();
try {
serviceUsageRecord.setConsumerId(caller);
serviceUsageRecord.setCallerQualifier(callerQualifier);
serviceUsageRecord.setScope(gcubeContext);
serviceUsageRecord.setServiceClass(appContext.configuration().group());
serviceUsageRecord.setServiceName(appContext.configuration().name());
serviceUsageRecord.setHost(appContext.container().configuration().hostname() + ":"
+ appContext.container().configuration().port());
serviceUsageRecord.setCalledMethod(InnerMethodName.get());
serviceUsageRecord.setCallerHost(remoteHost);
serviceUsageRecord.setOperationResult(success ? OperationResult.SUCCESS : OperationResult.FAILED);
serviceUsageRecord.setDuration(System.currentTimeMillis() - startCallThreadLocal.get());
persistence.account(serviceUsageRecord);
} catch (Exception ex) {
log.warn("invalid record passed to accounting ", ex);
}
}
private String getContext(ApplicationContext appContext) {
String infrastructure = appContext.container().configuration().infrastructure();
String context = "/" + infrastructure;
if (SecretManagerProvider.get() != null)
context = SecretManagerProvider.get().getContext();
return context;
}
@Override
public String toString() {
return getName();
}
}