mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-10-29 00:08:50 +00:00
#1237 - ENH: Add ProfileLocation - support for relating performance metrics for queries and transactions back to source line of code
This commit is contained in:
@@ -5,6 +5,7 @@ import io.ebean.EbeanServer;
|
||||
import io.ebean.ExpressionList;
|
||||
import io.ebean.OrderBy;
|
||||
import io.ebean.PersistenceContextScope;
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.bean.CallStack;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
@@ -173,6 +174,11 @@ public interface SpiQuery<T> extends Query<T>, TxnProfileEventCodes {
|
||||
*/
|
||||
short getProfileId();
|
||||
|
||||
/**
|
||||
* Return the profile location for this query.
|
||||
*/
|
||||
ProfileLocation getProfileLocation();
|
||||
|
||||
/**
|
||||
* Check for a single "equal to" expression for the Id.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.annotation.DocStoreMode;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
@@ -298,4 +299,14 @@ public interface SpiTransaction extends Transaction {
|
||||
* Return the stream that profiling events are written to.
|
||||
*/
|
||||
ProfileStream profileStream();
|
||||
|
||||
/**
|
||||
* Set the profile location for this transaction.
|
||||
*/
|
||||
void setProfileLocation(ProfileLocation profileLocation);
|
||||
|
||||
/**
|
||||
* Return the profile location for this transaction.
|
||||
*/
|
||||
ProfileLocation getProfileLocation();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.TransactionCallback;
|
||||
import io.ebean.annotation.DocStoreMode;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
@@ -54,6 +55,16 @@ abstract class SpiTransactionProxy implements SpiTransaction {
|
||||
return transaction.profileStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProfileLocation(ProfileLocation profileLocation) {
|
||||
transaction.setProfileLocation(profileLocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfileLocation getProfileLocation() {
|
||||
return transaction.getProfileLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTenantId(Object tenantId) {
|
||||
transaction.setTenantId(tenantId);
|
||||
|
||||
@@ -12,6 +12,7 @@ import io.ebean.FutureList;
|
||||
import io.ebean.FutureRowCount;
|
||||
import io.ebean.PagedList;
|
||||
import io.ebean.PersistenceContextScope;
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.QueryIterator;
|
||||
import io.ebean.SqlQuery;
|
||||
@@ -834,6 +835,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
break;
|
||||
default:
|
||||
transaction = transactionManager.createTransaction(txScope.getProfileId(), true, txScope.getIsolationLevel());
|
||||
initNewTransaction(transaction, txScope);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -844,6 +846,14 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
return txnContainer;
|
||||
}
|
||||
|
||||
private void initNewTransaction(SpiTransaction transaction, TxScope txScope) {
|
||||
|
||||
ProfileLocation profileLocation = txScope.getProfileLocation();
|
||||
if (profileLocation != null) {
|
||||
transaction.setProfileLocation(profileLocation);
|
||||
}
|
||||
}
|
||||
|
||||
private TxScope initTxScope(TxScope txScope) {
|
||||
if (txScope == null) {
|
||||
return new TxScope();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.TransactionCallback;
|
||||
import io.ebean.annotation.DocStoreMode;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
@@ -416,4 +417,14 @@ class NoTransaction implements SpiTransaction {
|
||||
public ProfileStream profileStream() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProfileLocation(ProfileLocation profileLocation) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfileLocation getProfileLocation() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package io.ebeaninternal.server.profile;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
|
||||
/**
|
||||
* Fixed / given location. Used internally for find by id and find all.
|
||||
*/
|
||||
class BasicProfileLocation implements ProfileLocation {
|
||||
|
||||
private final String location;
|
||||
|
||||
BasicProfileLocation(String location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "location: " + location;
|
||||
}
|
||||
|
||||
public String obtain() {
|
||||
return location;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package io.ebeaninternal.server.profile;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
|
||||
/**
|
||||
* Default profile location that uses stack trace.
|
||||
*/
|
||||
class DProfileLocation implements ProfileLocation {
|
||||
|
||||
private static final String IO_EBEAN = "io.ebean";
|
||||
|
||||
private static final String UNKNOWN = "unknown";
|
||||
|
||||
private String location;
|
||||
|
||||
private final int lineNumber;
|
||||
|
||||
DProfileLocation() {
|
||||
this.lineNumber = 0;
|
||||
}
|
||||
|
||||
DProfileLocation(int lineNumber) {
|
||||
this.lineNumber = lineNumber;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "location: " + location;
|
||||
}
|
||||
|
||||
public String obtain() {
|
||||
// atomic assignment so happy with this
|
||||
if (location == null) {
|
||||
location = create();
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
private String create() {
|
||||
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
|
||||
for (int i = 3; i < trace.length; i++) {
|
||||
if (!trace[i].getClassName().startsWith(IO_EBEAN)) {
|
||||
return withLineNumber(trace[i].toString());
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
private String withLineNumber(String traceLine) {
|
||||
if (lineNumber == 0 || traceLine.contains(":")) {
|
||||
return traceLine;
|
||||
} else {
|
||||
return traceLine.substring(0, traceLine.length() - 1) + ":" + lineNumber + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package io.ebeaninternal.server.profile;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.service.SpiProfileLocationFactory;
|
||||
|
||||
/**
|
||||
* Default implementation of the profile location factory.
|
||||
*/
|
||||
public class DProfileLocationFactory implements SpiProfileLocationFactory {
|
||||
|
||||
@Override
|
||||
public ProfileLocation create() {
|
||||
return new DProfileLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfileLocation create(int lineNumber) {
|
||||
return new DProfileLocation(lineNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfileLocation create(String location) {
|
||||
return new BasicProfileLocation(location);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import io.ebean.OrderBy;
|
||||
import io.ebean.OrderBy.Property;
|
||||
import io.ebean.PagedList;
|
||||
import io.ebean.PersistenceContextScope;
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.QueryIterator;
|
||||
import io.ebean.RawSql;
|
||||
@@ -257,6 +258,8 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
*/
|
||||
private short profileId;
|
||||
|
||||
private ProfileLocation profileLocation;
|
||||
|
||||
public DefaultOrmQuery(BeanDescriptor<T> desc, EbeanServer server, ExpressionFactory expressionFactory) {
|
||||
this.beanDescriptor = desc;
|
||||
this.beanType = desc.getBeanType();
|
||||
@@ -304,6 +307,12 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setProfileLocation(ProfileLocation profileLocation) {
|
||||
this.profileLocation = profileLocation;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoTunable() {
|
||||
return nativeSql == null && beanDescriptor.isAutoTunable();
|
||||
@@ -1732,4 +1741,9 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
public OrmUpdateProperties getUpdateProperties() {
|
||||
return updateProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfileLocation getProfileLocation() {
|
||||
return profileLocation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.querydefn;
|
||||
|
||||
import io.ebean.ExpressionList;
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.UpdateQuery;
|
||||
|
||||
/**
|
||||
@@ -41,6 +42,12 @@ public class DefaultUpdateQuery<T> implements UpdateQuery<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpdateQuery<T> setProfileLocation(ProfileLocation profileLocation) {
|
||||
query.setProfileLocation(profileLocation);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> where() {
|
||||
return query.where();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.transaction;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.TransactionCallback;
|
||||
import io.ebean.annotation.DocStoreMode;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
@@ -92,6 +93,16 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProfileLocation(ProfileLocation profileLocation) {
|
||||
throw new IllegalStateException(notExpectedMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfileLocation getProfileLocation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSkipCache() {
|
||||
return false;
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
package io.ebeaninternal.server.transaction;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.TransactionCallback;
|
||||
import io.ebean.annotation.DocStoreMode;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform.OnQueryOnly;
|
||||
import io.ebean.event.changelog.BeanChange;
|
||||
import io.ebean.event.changelog.ChangeSet;
|
||||
import io.ebeaninternal.api.SpiTransaction;
|
||||
import io.ebeaninternal.api.SpiProfileTransactionEvent;
|
||||
import io.ebeaninternal.api.SpiTransaction;
|
||||
import io.ebeaninternal.api.TransactionEvent;
|
||||
import io.ebeaninternal.api.TxnProfileEventCodes;
|
||||
import io.ebeaninternal.server.core.PersistDeferredRelationship;
|
||||
@@ -173,6 +174,8 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
|
||||
|
||||
private final ProfileStream profileStream;
|
||||
|
||||
protected ProfileLocation profileLocation;
|
||||
|
||||
/**
|
||||
* Create without ProfileStream option (no profiling).
|
||||
*/
|
||||
@@ -230,6 +233,16 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
|
||||
return profileStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProfileLocation(ProfileLocation profileLocation) {
|
||||
this.profileLocation = profileLocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfileLocation getProfileLocation() {
|
||||
return profileLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden in AutoCommitJdbcTransaction as that expects to run/operate with autocommit true.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user