Hibernate: set span name only on method entry (#3603)
This commit is contained in:
parent
26dc106399
commit
3555c251c9
|
@ -21,9 +21,9 @@ import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
|
|||
import io.opentelemetry.javaagent.instrumentation.hibernate.SessionMethodUtils;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import org.hibernate.Criteria;
|
||||
import org.hibernate.impl.CriteriaImpl;
|
||||
|
||||
public class CriteriaInstrumentation implements TypeInstrumentation {
|
||||
|
||||
|
@ -63,7 +63,13 @@ public class CriteriaInstrumentation implements TypeInstrumentation {
|
|||
ContextStore<Criteria, Context> contextStore =
|
||||
InstrumentationContext.get(Criteria.class, Context.class);
|
||||
|
||||
context = SessionMethodUtils.startSpanFrom(contextStore, criteria, "Criteria." + name, null);
|
||||
String entityName = null;
|
||||
if (criteria instanceof CriteriaImpl) {
|
||||
entityName = ((CriteriaImpl) criteria).getEntityOrClassName();
|
||||
}
|
||||
|
||||
context =
|
||||
SessionMethodUtils.startSpanFrom(contextStore, criteria, "Criteria." + name, entityName);
|
||||
if (context != null) {
|
||||
scope = context.makeCurrent();
|
||||
}
|
||||
|
@ -72,7 +78,6 @@ public class CriteriaInstrumentation implements TypeInstrumentation {
|
|||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void endMethod(
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Return(typing = Assigner.Typing.DYNAMIC) Object entity,
|
||||
@Advice.Origin("#m") String name,
|
||||
@Advice.Local("otelCallDepth") CallDepth callDepth,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
|
@ -84,7 +89,7 @@ public class CriteriaInstrumentation implements TypeInstrumentation {
|
|||
|
||||
if (scope != null) {
|
||||
scope.close();
|
||||
SessionMethodUtils.end(context, throwable, "Criteria." + name, entity);
|
||||
SessionMethodUtils.end(context, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.hibernate.v3_3;
|
||||
|
||||
import java.util.function.Function;
|
||||
import org.hibernate.impl.AbstractSessionImpl;
|
||||
|
||||
public final class EntityNameUtil {
|
||||
|
||||
private EntityNameUtil() {}
|
||||
|
||||
private static String bestGuessEntityName(Object session, Object entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (session instanceof AbstractSessionImpl) {
|
||||
return ((AbstractSessionImpl) session).bestGuessEntityName(entity);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Function<Object, String> bestGuessEntityName(Object session) {
|
||||
return (entity) -> bestGuessEntityName(session, entity);
|
||||
}
|
||||
}
|
|
@ -80,7 +80,7 @@ public class QueryInstrumentation implements TypeInstrumentation {
|
|||
|
||||
if (scope != null) {
|
||||
scope.close();
|
||||
SessionMethodUtils.end(context, throwable, null, null);
|
||||
SessionMethodUtils.end(context, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.
|
|||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface;
|
||||
import static io.opentelemetry.javaagent.instrumentation.hibernate.HibernateTracer.tracer;
|
||||
import static io.opentelemetry.javaagent.instrumentation.hibernate.SessionMethodUtils.SCOPE_ONLY_METHODS;
|
||||
import static io.opentelemetry.javaagent.instrumentation.hibernate.SessionMethodUtils.getEntityName;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.namedOneOf;
|
||||
|
@ -26,7 +27,6 @@ import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
|
|||
import io.opentelemetry.javaagent.instrumentation.hibernate.SessionMethodUtils;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import org.hibernate.Criteria;
|
||||
import org.hibernate.Query;
|
||||
|
@ -131,7 +131,9 @@ public class SessionInstrumentation implements TypeInstrumentation {
|
|||
public static void startMethod(
|
||||
@Advice.This Object session,
|
||||
@Advice.Origin("#m") String name,
|
||||
@Advice.Argument(0) Object entity,
|
||||
@Advice.Origin("#d") String descriptor,
|
||||
@Advice.Argument(0) Object arg0,
|
||||
@Advice.Argument(value = 1, optional = true) Object arg1,
|
||||
@Advice.Local("otelCallDepth") CallDepth callDepth,
|
||||
@Advice.Local("otelContext") Context spanContext,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
|
@ -157,7 +159,9 @@ public class SessionInstrumentation implements TypeInstrumentation {
|
|||
}
|
||||
|
||||
if (!SCOPE_ONLY_METHODS.contains(name)) {
|
||||
spanContext = tracer().startSpan(sessionContext, "Session." + name, entity);
|
||||
String entityName =
|
||||
getEntityName(descriptor, arg0, arg1, EntityNameUtil.bestGuessEntityName(session));
|
||||
spanContext = tracer().startSpan(sessionContext, "Session." + name, entityName);
|
||||
scope = spanContext.makeCurrent();
|
||||
} else {
|
||||
scope = sessionContext.makeCurrent();
|
||||
|
@ -167,8 +171,6 @@ public class SessionInstrumentation implements TypeInstrumentation {
|
|||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void endMethod(
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Return(typing = Assigner.Typing.DYNAMIC) Object returned,
|
||||
@Advice.Origin("#m") String name,
|
||||
@Advice.Local("otelCallDepth") CallDepth callDepth,
|
||||
@Advice.Local("otelContext") Context spanContext,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
|
@ -179,7 +181,7 @@ public class SessionInstrumentation implements TypeInstrumentation {
|
|||
|
||||
if (scope != null) {
|
||||
scope.close();
|
||||
SessionMethodUtils.end(spanContext, throwable, "Session." + name, returned);
|
||||
SessionMethodUtils.end(spanContext, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ public class TransactionInstrumentation implements TypeInstrumentation {
|
|||
|
||||
if (scope != null) {
|
||||
scope.close();
|
||||
SessionMethodUtils.end(context, throwable, null, null);
|
||||
SessionMethodUtils.end(context, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ class CriteriaTest extends AbstractHibernateTest {
|
|||
}
|
||||
}
|
||||
span(1) {
|
||||
name "Criteria.$methodName"
|
||||
name "Criteria.$methodName Value"
|
||||
kind INTERNAL
|
||||
childOf span(0)
|
||||
attributes {
|
||||
|
|
|
@ -283,7 +283,7 @@ class SessionTest extends AbstractHibernateTest {
|
|||
}
|
||||
}
|
||||
span(1) {
|
||||
name "Session.replicate"
|
||||
name "Session.replicate java.lang.Long"
|
||||
kind INTERNAL
|
||||
childOf span(0)
|
||||
status ERROR
|
||||
|
|
|
@ -21,9 +21,9 @@ import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
|
|||
import io.opentelemetry.javaagent.instrumentation.hibernate.SessionMethodUtils;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import org.hibernate.Criteria;
|
||||
import org.hibernate.internal.CriteriaImpl;
|
||||
|
||||
public class CriteriaInstrumentation implements TypeInstrumentation {
|
||||
|
||||
|
@ -63,7 +63,13 @@ public class CriteriaInstrumentation implements TypeInstrumentation {
|
|||
ContextStore<Criteria, Context> contextStore =
|
||||
InstrumentationContext.get(Criteria.class, Context.class);
|
||||
|
||||
context = SessionMethodUtils.startSpanFrom(contextStore, criteria, "Criteria." + name, null);
|
||||
String entityName = null;
|
||||
if (criteria instanceof CriteriaImpl) {
|
||||
entityName = ((CriteriaImpl) criteria).getEntityOrClassName();
|
||||
}
|
||||
|
||||
context =
|
||||
SessionMethodUtils.startSpanFrom(contextStore, criteria, "Criteria." + name, entityName);
|
||||
if (context != null) {
|
||||
scope = context.makeCurrent();
|
||||
}
|
||||
|
@ -72,8 +78,6 @@ public class CriteriaInstrumentation implements TypeInstrumentation {
|
|||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void endMethod(
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Return(typing = Assigner.Typing.DYNAMIC) Object entity,
|
||||
@Advice.Origin("#m") String name,
|
||||
@Advice.Local("otelCallDepth") CallDepth callDepth,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
|
@ -84,7 +88,7 @@ public class CriteriaInstrumentation implements TypeInstrumentation {
|
|||
|
||||
if (scope != null) {
|
||||
scope.close();
|
||||
SessionMethodUtils.end(context, throwable, "Criteria." + name, entity);
|
||||
SessionMethodUtils.end(context, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.hibernate.v4_0;
|
||||
|
||||
import java.util.function.Function;
|
||||
import org.hibernate.SharedSessionContract;
|
||||
import org.hibernate.internal.SessionImpl;
|
||||
import org.hibernate.internal.StatelessSessionImpl;
|
||||
|
||||
public final class EntityNameUtil {
|
||||
|
||||
private EntityNameUtil() {}
|
||||
|
||||
private static String bestGuessEntityName(SharedSessionContract session, Object entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (session instanceof SessionImpl) {
|
||||
return ((SessionImpl) session).bestGuessEntityName(entity);
|
||||
} else if (session instanceof StatelessSessionImpl) {
|
||||
return ((StatelessSessionImpl) session).bestGuessEntityName(entity);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Function<Object, String> bestGuessEntityName(SharedSessionContract session) {
|
||||
return (entity) -> bestGuessEntityName(session, entity);
|
||||
}
|
||||
}
|
|
@ -80,7 +80,7 @@ public class QueryInstrumentation implements TypeInstrumentation {
|
|||
|
||||
if (scope != null) {
|
||||
scope.close();
|
||||
SessionMethodUtils.end(context, throwable, null, null);
|
||||
SessionMethodUtils.end(context, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.
|
|||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface;
|
||||
import static io.opentelemetry.javaagent.instrumentation.hibernate.HibernateTracer.tracer;
|
||||
import static io.opentelemetry.javaagent.instrumentation.hibernate.SessionMethodUtils.SCOPE_ONLY_METHODS;
|
||||
import static io.opentelemetry.javaagent.instrumentation.hibernate.SessionMethodUtils.getEntityName;
|
||||
import static io.opentelemetry.javaagent.instrumentation.hibernate.SessionMethodUtils.getSessionMethodSpanName;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
@ -27,7 +28,6 @@ import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
|
|||
import io.opentelemetry.javaagent.instrumentation.hibernate.SessionMethodUtils;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import org.hibernate.Criteria;
|
||||
import org.hibernate.Query;
|
||||
|
@ -125,7 +125,9 @@ public class SessionInstrumentation implements TypeInstrumentation {
|
|||
public static void startMethod(
|
||||
@Advice.This SharedSessionContract session,
|
||||
@Advice.Origin("#m") String name,
|
||||
@Advice.Argument(0) Object entity,
|
||||
@Advice.Origin("#d") String descriptor,
|
||||
@Advice.Argument(0) Object arg0,
|
||||
@Advice.Argument(value = 1, optional = true) Object arg1,
|
||||
@Advice.Local("otelCallDepth") CallDepth callDepth,
|
||||
@Advice.Local("otelContext") Context spanContext,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
|
@ -144,7 +146,10 @@ public class SessionInstrumentation implements TypeInstrumentation {
|
|||
}
|
||||
|
||||
if (!SCOPE_ONLY_METHODS.contains(name)) {
|
||||
spanContext = tracer().startSpan(sessionContext, getSessionMethodSpanName(name), entity);
|
||||
String entityName =
|
||||
getEntityName(descriptor, arg0, arg1, EntityNameUtil.bestGuessEntityName(session));
|
||||
spanContext =
|
||||
tracer().startSpan(sessionContext, getSessionMethodSpanName(name), entityName);
|
||||
scope = spanContext.makeCurrent();
|
||||
} else {
|
||||
scope = sessionContext.makeCurrent();
|
||||
|
@ -154,8 +159,6 @@ public class SessionInstrumentation implements TypeInstrumentation {
|
|||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void endMethod(
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Return(typing = Assigner.Typing.DYNAMIC) Object returned,
|
||||
@Advice.Origin("#m") String name,
|
||||
@Advice.Local("otelCallDepth") CallDepth callDepth,
|
||||
@Advice.Local("otelContext") Context spanContext,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
|
@ -166,7 +169,7 @@ public class SessionInstrumentation implements TypeInstrumentation {
|
|||
|
||||
if (scope != null) {
|
||||
scope.close();
|
||||
SessionMethodUtils.end(spanContext, throwable, getSessionMethodSpanName(name), returned);
|
||||
SessionMethodUtils.end(spanContext, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ public class TransactionInstrumentation implements TypeInstrumentation {
|
|||
|
||||
if (scope != null) {
|
||||
scope.close();
|
||||
SessionMethodUtils.end(context, throwable, null, null);
|
||||
SessionMethodUtils.end(context, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ abstract class AbstractHibernateTest extends AgentInstrumentationSpecification {
|
|||
Session writer = sessionFactory.openSession()
|
||||
writer.beginTransaction()
|
||||
prepopulated = new ArrayList<>()
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
prepopulated.add(new Value("Hello :) " + i))
|
||||
writer.save(prepopulated.get(i))
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ class CriteriaTest extends AbstractHibernateTest {
|
|||
}
|
||||
}
|
||||
span(1) {
|
||||
name "Criteria.$methodName"
|
||||
name "Criteria.$methodName Value"
|
||||
kind INTERNAL
|
||||
childOf span(0)
|
||||
attributes {
|
||||
|
|
|
@ -9,6 +9,7 @@ import static io.opentelemetry.api.trace.StatusCode.ERROR
|
|||
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
|
||||
import org.hibernate.LockMode
|
||||
import org.hibernate.LockOptions
|
||||
import org.hibernate.MappingException
|
||||
import org.hibernate.Query
|
||||
import org.hibernate.ReplicationMode
|
||||
|
@ -84,29 +85,56 @@ class SessionTest extends AbstractHibernateTest {
|
|||
}
|
||||
|
||||
where:
|
||||
testName | methodName | resource | sessionImplementations | sessionMethodTest
|
||||
"lock" | "lock" | "Value" | [sessionBuilder] | { sesh, val ->
|
||||
testName | methodName | resource | sessionImplementations | sessionMethodTest
|
||||
"lock" | "lock" | "Value" | [sessionBuilder] | { sesh, val ->
|
||||
sesh.lock(val, LockMode.READ)
|
||||
}
|
||||
"refresh" | "refresh" | "Value" | [sessionBuilder, statelessSessionBuilder] | { sesh, val ->
|
||||
"lock with entity name" | "lock" | "Value" | [sessionBuilder] | { sesh, val ->
|
||||
sesh.lock("Value", val, LockMode.READ)
|
||||
}
|
||||
"lock with null name" | "lock" | "Value" | [sessionBuilder] | { sesh, val ->
|
||||
sesh.lock(null, val, LockMode.READ)
|
||||
}
|
||||
"buildLockRequest" | "lock" | "Value" | [sessionBuilder] | { sesh, val ->
|
||||
sesh.buildLockRequest(LockOptions.READ)
|
||||
.lock(val)
|
||||
}
|
||||
"refresh" | "refresh" | "Value" | [sessionBuilder, statelessSessionBuilder] | { sesh, val ->
|
||||
sesh.refresh(val)
|
||||
}
|
||||
"get" | "get" | "Value" | [sessionBuilder, statelessSessionBuilder] | { sesh, val ->
|
||||
"refresh with entity name" | "refresh" | "Value" | [sessionBuilder, statelessSessionBuilder] | { sesh, val ->
|
||||
sesh.refresh("Value", val)
|
||||
}
|
||||
"get with entity name" | "get" | "Value" | [sessionBuilder, statelessSessionBuilder] | { sesh, val ->
|
||||
sesh.get("Value", val.getId())
|
||||
}
|
||||
"insert" | "insert" | "Value" | [statelessSessionBuilder] | { sesh, val ->
|
||||
"get with entity class" | "get" | "Value" | [sessionBuilder, statelessSessionBuilder] | { sesh, val ->
|
||||
sesh.get(Value, val.getId())
|
||||
}
|
||||
"insert" | "insert" | "Value" | [statelessSessionBuilder] | { sesh, val ->
|
||||
sesh.insert(new Value("insert me"))
|
||||
}
|
||||
"insert with entity name" | "insert" | "Value" | [statelessSessionBuilder] | { sesh, val ->
|
||||
sesh.insert("Value", new Value("insert me"))
|
||||
}
|
||||
"update (StatelessSession)" | "update" | "Value" | [statelessSessionBuilder] | { sesh, val ->
|
||||
"insert with null entity name" | "insert" | "Value" | [statelessSessionBuilder] | { sesh, val ->
|
||||
sesh.insert(null, new Value("insert me"))
|
||||
}
|
||||
"update (StatelessSession)" | "update" | "Value" | [statelessSessionBuilder] | { sesh, val ->
|
||||
val.setName("New name")
|
||||
sesh.update(val)
|
||||
}
|
||||
"update by entityName (StatelessSession)" | "update" | "Value" | [statelessSessionBuilder] | { sesh, val ->
|
||||
"update with entity name (StatelessSession)" | "update" | "Value" | [statelessSessionBuilder] | { sesh, val ->
|
||||
val.setName("New name")
|
||||
sesh.update("Value", val)
|
||||
}
|
||||
"delete (Session)" | "delete" | "Value" | [statelessSessionBuilder] | { sesh, val ->
|
||||
"delete (Session)" | "delete" | "Value" | [statelessSessionBuilder] | { sesh, val ->
|
||||
sesh.delete(val)
|
||||
prepopulated.remove(val)
|
||||
}
|
||||
"delete with entity name (Session)" | "delete" | "Value" | [statelessSessionBuilder] | { sesh, val ->
|
||||
sesh.delete("Value", val)
|
||||
prepopulated.remove(val)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,7 +250,7 @@ class SessionTest extends AbstractHibernateTest {
|
|||
}
|
||||
}
|
||||
span(1) {
|
||||
name "Session.replicate"
|
||||
name "Session.replicate java.lang.Long"
|
||||
kind INTERNAL
|
||||
childOf span(0)
|
||||
status ERROR
|
||||
|
@ -297,33 +325,53 @@ class SessionTest extends AbstractHibernateTest {
|
|||
}
|
||||
|
||||
where:
|
||||
testName | methodName | resource | sessionMethodTest
|
||||
"save" | "save" | "Value" | { sesh, val ->
|
||||
testName | methodName | resource | sessionMethodTest
|
||||
"save" | "save" | "Value" | { sesh, val ->
|
||||
sesh.save(new Value("Another value"))
|
||||
}
|
||||
"saveOrUpdate save" | "saveOrUpdate" | "Value" | { sesh, val ->
|
||||
"save with entity name" | "save" | "Value" | { sesh, val ->
|
||||
sesh.save("Value", new Value("Another value"))
|
||||
}
|
||||
"saveOrUpdate save" | "saveOrUpdate" | "Value" | { sesh, val ->
|
||||
sesh.saveOrUpdate(new Value("Value"))
|
||||
}
|
||||
"saveOrUpdate update" | "saveOrUpdate" | "Value" | { sesh, val ->
|
||||
val.setName("New name")
|
||||
sesh.saveOrUpdate(val)
|
||||
"saveOrUpdate save with entity name" | "saveOrUpdate" | "Value" | { sesh, val ->
|
||||
sesh.saveOrUpdate("Value", new Value("Value"))
|
||||
}
|
||||
"merge" | "merge" | "Value" | { sesh, val ->
|
||||
"saveOrUpdate update with entity name" | "saveOrUpdate" | "Value" | { sesh, val ->
|
||||
val.setName("New name")
|
||||
sesh.saveOrUpdate("Value", val)
|
||||
}
|
||||
"merge" | "merge" | "Value" | { sesh, val ->
|
||||
sesh.merge(new Value("merge me in"))
|
||||
}
|
||||
"persist" | "persist" | "Value" | { sesh, val ->
|
||||
"merge with entity name" | "merge" | "Value" | { sesh, val ->
|
||||
sesh.merge("Value", new Value("merge me in"))
|
||||
}
|
||||
"persist" | "persist" | "Value" | { sesh, val ->
|
||||
sesh.persist(new Value("merge me in"))
|
||||
}
|
||||
"update (Session)" | "update" | "Value" | { sesh, val ->
|
||||
"persist with entity name" | "persist" | "Value" | { sesh, val ->
|
||||
sesh.persist("Value", new Value("merge me in"))
|
||||
}
|
||||
"persist with null entity name" | "persist" | "Value" | { sesh, val ->
|
||||
sesh.persist(null, new Value("merge me in"))
|
||||
}
|
||||
"update (Session)" | "update" | "Value" | { sesh, val ->
|
||||
val.setName("New name")
|
||||
sesh.update(val)
|
||||
}
|
||||
"update by entityName (Session)" | "update" | "Value" | { sesh, val ->
|
||||
"update by entityName (Session)" | "update" | "Value" | { sesh, val ->
|
||||
val.setName("New name")
|
||||
sesh.update("Value", val)
|
||||
}
|
||||
"delete (Session)" | "delete" | "Value" | { sesh, val ->
|
||||
"delete (Session)" | "delete" | "Value" | { sesh, val ->
|
||||
sesh.delete(val)
|
||||
prepopulated.remove(val)
|
||||
}
|
||||
"delete by entityName (Session)" | "delete" | "Value" | { sesh, val ->
|
||||
sesh.delete("Value", val)
|
||||
prepopulated.remove(val)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,10 +8,6 @@ package io.opentelemetry.javaagent.instrumentation.hibernate;
|
|||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class HibernateTracer extends BaseTracer {
|
||||
private static final HibernateTracer TRACER = new HibernateTracer();
|
||||
|
@ -20,48 +16,21 @@ public class HibernateTracer extends BaseTracer {
|
|||
return TRACER;
|
||||
}
|
||||
|
||||
public Context startSpan(Context parentContext, String operationName, Object entity) {
|
||||
return startSpan(parentContext, spanNameForOperation(operationName, entity));
|
||||
public Context startSpan(Context parentContext, String operationName, String entityName) {
|
||||
return startSpan(parentContext, spanNameForOperation(operationName, entityName));
|
||||
}
|
||||
|
||||
public Context startSpan(Context parentContext, String spanName) {
|
||||
return startSpan(parentContext, spanName, SpanKind.INTERNAL);
|
||||
}
|
||||
|
||||
private String spanNameForOperation(String operationName, Object entity) {
|
||||
if (entity != null) {
|
||||
String entityName = entityName(entity);
|
||||
if (entityName != null) {
|
||||
return operationName + " " + entityName;
|
||||
}
|
||||
private static String spanNameForOperation(String operationName, String entityName) {
|
||||
if (entityName != null) {
|
||||
return operationName + " " + entityName;
|
||||
}
|
||||
return operationName;
|
||||
}
|
||||
|
||||
String entityName(Object entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
String name = null;
|
||||
Set<String> annotations = new HashSet<>();
|
||||
for (Annotation annotation : entity.getClass().getDeclaredAnnotations()) {
|
||||
annotations.add(annotation.annotationType().getName());
|
||||
}
|
||||
|
||||
if (entity instanceof String) {
|
||||
// We were given an entity name, not the entity itself.
|
||||
name = (String) entity;
|
||||
} else if (annotations.contains("javax.persistence.Entity")) {
|
||||
// We were given an instance of an entity.
|
||||
name = entity.getClass().getName();
|
||||
} else if (entity instanceof List && !((List) entity).isEmpty()) {
|
||||
// We have a list of entities.
|
||||
name = entityName(((List) entity).get(0));
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getInstrumentationName() {
|
||||
return "io.opentelemetry.hibernate-common";
|
||||
|
|
|
@ -7,7 +7,6 @@ package io.opentelemetry.javaagent.instrumentation.hibernate;
|
|||
|
||||
import static io.opentelemetry.javaagent.instrumentation.hibernate.HibernateTracer.tracer;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.instrumentation.api.db.SqlStatementInfo;
|
||||
import io.opentelemetry.instrumentation.api.db.SqlStatementSanitizer;
|
||||
|
@ -15,6 +14,7 @@ import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
|
|||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
|
@ -27,22 +27,22 @@ public final class SessionMethodUtils {
|
|||
ContextStore<TARGET, Context> contextStore,
|
||||
TARGET spanKey,
|
||||
String operationName,
|
||||
ENTITY entity) {
|
||||
return startSpanFrom(contextStore, spanKey, () -> operationName, entity);
|
||||
String entityName) {
|
||||
return startSpanFrom(contextStore, spanKey, () -> operationName, entityName);
|
||||
}
|
||||
|
||||
private static <TARGET, ENTITY> Context startSpanFrom(
|
||||
ContextStore<TARGET, Context> contextStore,
|
||||
TARGET spanKey,
|
||||
Supplier<String> operationNameSupplier,
|
||||
ENTITY entity) {
|
||||
String entityName) {
|
||||
|
||||
Context sessionContext = contextStore.get(spanKey);
|
||||
if (sessionContext == null) {
|
||||
return null; // No state found. We aren't in a Session.
|
||||
}
|
||||
|
||||
return tracer().startSpan(sessionContext, operationNameSupplier.get(), entity);
|
||||
return tracer().startSpan(sessionContext, operationNameSupplier.get(), entityName);
|
||||
}
|
||||
|
||||
public static <TARGET> Context startSpanFromQuery(
|
||||
|
@ -64,19 +64,12 @@ public final class SessionMethodUtils {
|
|||
return startSpanFrom(contextStore, spanKey, operationNameSupplier, null);
|
||||
}
|
||||
|
||||
public static void end(
|
||||
@Nullable Context context, Throwable throwable, String operationName, Object entity) {
|
||||
public static void end(@Nullable Context context, Throwable throwable) {
|
||||
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (operationName != null && entity != null) {
|
||||
String entityName = tracer().entityName(entity);
|
||||
if (entityName != null) {
|
||||
Span.fromContext(context).updateName(operationName + " " + entityName);
|
||||
}
|
||||
}
|
||||
if (throwable != null) {
|
||||
tracer().endExceptionally(context, throwable);
|
||||
} else {
|
||||
|
@ -107,5 +100,27 @@ public final class SessionMethodUtils {
|
|||
return "Session." + methodName;
|
||||
}
|
||||
|
||||
public static String getEntityName(
|
||||
String descriptor, Object arg0, Object arg1, Function<Object, String> nameFromEntity) {
|
||||
String entityName = null;
|
||||
// methods like save(String entityName, Object object)
|
||||
// that take entity name as first argument and entity as second
|
||||
// if given entity name is null compute it from entity object
|
||||
if (descriptor.startsWith("(Ljava/lang/String;Ljava/lang/Object;")) {
|
||||
entityName = arg0 == null ? nameFromEntity.apply(arg1) : (String) arg0;
|
||||
// methods like save(Object obj)
|
||||
} else if (descriptor.startsWith("(Ljava/lang/Object;")) {
|
||||
entityName = nameFromEntity.apply(arg0);
|
||||
// methods like get(String entityName, Serializable id)
|
||||
} else if (descriptor.startsWith("(Ljava/lang/String;")) {
|
||||
entityName = (String) arg0;
|
||||
// methods like get(Class entityClass, Serializable id)
|
||||
} else if (descriptor.startsWith("(Ljava/lang/Class;") && arg0 != null) {
|
||||
entityName = ((Class<?>) arg0).getName();
|
||||
}
|
||||
|
||||
return entityName;
|
||||
}
|
||||
|
||||
private SessionMethodUtils() {}
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ public class ProcedureCallInstrumentation implements TypeInstrumentation {
|
|||
|
||||
if (scope != null) {
|
||||
scope.close();
|
||||
SessionMethodUtils.end(context, throwable, null, null);
|
||||
SessionMethodUtils.end(context, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue