Hibernate query span naming (#3106)
* Hibernate query span naming * remove commented out code * modify query sanitizer to accept queries that start with from clause * add sql sanitizer test for queries starting with from * rename hibernate-4.3 to hibernate-procedure-call-4.3
This commit is contained in:
parent
9a05c1a0fd
commit
35d6bdb730
|
@ -295,6 +295,11 @@ WHITESPACE = [ \t\r\n]+
|
||||||
|
|
||||||
"FROM" {
|
"FROM" {
|
||||||
if (!insideComment && !extractionDone) {
|
if (!insideComment && !extractionDone) {
|
||||||
|
if (operation == NoOp.INSTANCE) {
|
||||||
|
// hql/jpql queries may skip SELECT and start with FROM clause
|
||||||
|
// treat such queries as SELECT queries
|
||||||
|
setOperation(new Select());
|
||||||
|
}
|
||||||
extractionDone = operation.handleFrom();
|
extractionDone = operation.handleFrom();
|
||||||
}
|
}
|
||||||
appendCurrentFragment();
|
appendCurrentFragment();
|
||||||
|
|
|
@ -80,6 +80,9 @@ class SqlStatementSanitizerTest extends Specification {
|
||||||
|
|
||||||
// whitespace normalization
|
// whitespace normalization
|
||||||
"SELECT * \t\r\nFROM TABLE WHERE FIELD1 = 12344 AND FIELD2 = 5678" | "SELECT * FROM TABLE WHERE FIELD1 = ? AND FIELD2 = ?"
|
"SELECT * \t\r\nFROM TABLE WHERE FIELD1 = 12344 AND FIELD2 = 5678" | "SELECT * FROM TABLE WHERE FIELD1 = ? AND FIELD2 = ?"
|
||||||
|
|
||||||
|
// hibernate/jpa query language
|
||||||
|
"FROM TABLE WHERE FIELD=1234" | "FROM TABLE WHERE FIELD=?"
|
||||||
}
|
}
|
||||||
|
|
||||||
@Unroll
|
@Unroll
|
||||||
|
@ -110,6 +113,9 @@ class SqlStatementSanitizerTest extends Specification {
|
||||||
'/* update comment */ select * from table1' | SqlStatementInfo.create(sql, 'SELECT', 'table1')
|
'/* update comment */ select * from table1' | SqlStatementInfo.create(sql, 'SELECT', 'table1')
|
||||||
'select /*((*/abc from table' | SqlStatementInfo.create(sql, 'SELECT', 'table')
|
'select /*((*/abc from table' | SqlStatementInfo.create(sql, 'SELECT', 'table')
|
||||||
'SeLeCT * FrOm TAblE' | SqlStatementInfo.create(sql, 'SELECT', 'TAblE')
|
'SeLeCT * FrOm TAblE' | SqlStatementInfo.create(sql, 'SELECT', 'TAblE')
|
||||||
|
// hibernate/jpa
|
||||||
|
'FROM schema.table' | SqlStatementInfo.create(sql, 'SELECT', 'schema.table')
|
||||||
|
'/* update comment */ from table1' | SqlStatementInfo.create(sql, 'SELECT', 'table1')
|
||||||
// Insert
|
// Insert
|
||||||
' insert into table where lalala' | SqlStatementInfo.create(sql, 'INSERT', 'table')
|
' insert into table where lalala' | SqlStatementInfo.create(sql, 'INSERT', 'table')
|
||||||
'insert insert into table where lalala' | SqlStatementInfo.create(sql, 'INSERT', 'table')
|
'insert insert into table where lalala' | SqlStatementInfo.create(sql, 'INSERT', 'table')
|
||||||
|
|
|
@ -24,7 +24,7 @@ dependencies {
|
||||||
testInstrumentation project(':instrumentation:jdbc:javaagent')
|
testInstrumentation project(':instrumentation:jdbc:javaagent')
|
||||||
// Added to ensure cross compatibility:
|
// Added to ensure cross compatibility:
|
||||||
testInstrumentation project(':instrumentation:hibernate:hibernate-4.0:javaagent')
|
testInstrumentation project(':instrumentation:hibernate:hibernate-4.0:javaagent')
|
||||||
testInstrumentation project(':instrumentation:hibernate:hibernate-4.3:javaagent')
|
testInstrumentation project(':instrumentation:hibernate:hibernate-procedure-call-4.3:javaagent')
|
||||||
|
|
||||||
testLibrary "org.hibernate:hibernate-core:3.3.0.SP1"
|
testLibrary "org.hibernate:hibernate-core:3.3.0.SP1"
|
||||||
testImplementation "org.hibernate:hibernate-annotations:3.4.0.GA"
|
testImplementation "org.hibernate:hibernate-annotations:3.4.0.GA"
|
||||||
|
|
|
@ -53,7 +53,7 @@ public class QueryInstrumentation implements TypeInstrumentation {
|
||||||
ContextStore<Query, Context> contextStore =
|
ContextStore<Query, Context> contextStore =
|
||||||
InstrumentationContext.get(Query.class, Context.class);
|
InstrumentationContext.get(Query.class, Context.class);
|
||||||
|
|
||||||
context = SessionMethodUtils.startSpanFrom(contextStore, query, query.getQueryString(), null);
|
context = SessionMethodUtils.startSpanFromQuery(contextStore, query, query.getQueryString());
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
scope = context.makeCurrent();
|
scope = context.makeCurrent();
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,25 +105,25 @@ class QueryTest extends AbstractHibernateTest {
|
||||||
|
|
||||||
where:
|
where:
|
||||||
queryMethodName | expectedSpanName | requiresTransaction | queryInteraction
|
queryMethodName | expectedSpanName | requiresTransaction | queryInteraction
|
||||||
"Query.list" | "from Value" | false | { sess ->
|
"Query.list" | "SELECT Value" | false | { sess ->
|
||||||
Query q = sess.createQuery("from Value")
|
Query q = sess.createQuery("from Value")
|
||||||
q.list()
|
q.list()
|
||||||
}
|
}
|
||||||
"Query.executeUpdate" | "update Value set name = ?" | true | { sess ->
|
"Query.executeUpdate" | "UPDATE Value" | true | { sess ->
|
||||||
Query q = sess.createQuery("update Value set name = ?")
|
Query q = sess.createQuery("update Value set name = ?")
|
||||||
q.setParameter(0, "alyx")
|
q.setParameter(0, "alyx")
|
||||||
q.executeUpdate()
|
q.executeUpdate()
|
||||||
}
|
}
|
||||||
"Query.uniqueResult" | "from Value where id = ?" | false | { sess ->
|
"Query.uniqueResult" | "SELECT Value" | false | { sess ->
|
||||||
Query q = sess.createQuery("from Value where id = ?")
|
Query q = sess.createQuery("from Value where id = ?")
|
||||||
q.setParameter(0, 1L)
|
q.setParameter(0, 1L)
|
||||||
q.uniqueResult()
|
q.uniqueResult()
|
||||||
}
|
}
|
||||||
"Query.iterate" | "from Value" | false | { sess ->
|
"Query.iterate" | "SELECT Value" | false | { sess ->
|
||||||
Query q = sess.createQuery("from Value")
|
Query q = sess.createQuery("from Value")
|
||||||
q.iterate()
|
q.iterate()
|
||||||
}
|
}
|
||||||
"Query.scroll" | "from Value" | false | { sess ->
|
"Query.scroll" | "SELECT Value" | false | { sess ->
|
||||||
Query q = sess.createQuery("from Value")
|
Query q = sess.createQuery("from Value")
|
||||||
q.scroll()
|
q.scroll()
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ class QueryTest extends AbstractHibernateTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span(1) {
|
span(1) {
|
||||||
name "from Value"
|
name "SELECT Value"
|
||||||
kind INTERNAL
|
kind INTERNAL
|
||||||
childOf span(0)
|
childOf span(0)
|
||||||
attributes {
|
attributes {
|
||||||
|
|
|
@ -440,10 +440,10 @@ class SessionTest extends AbstractHibernateTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
where:
|
where:
|
||||||
queryMethodName | expectedSpanName | queryBuildMethod
|
queryMethodName | expectedSpanName | queryBuildMethod
|
||||||
"createQuery" | "from Value" | { sess -> sess.createQuery("from Value") }
|
"createQuery" | "SELECT Value" | { sess -> sess.createQuery("from Value") }
|
||||||
"getNamedQuery" | "from Value" | { sess -> sess.getNamedQuery("TestNamedQuery") }
|
"getNamedQuery" | "SELECT Value" | { sess -> sess.getNamedQuery("TestNamedQuery") }
|
||||||
"createSQLQuery" | "SELECT * FROM Value" | { sess -> sess.createSQLQuery("SELECT * FROM Value") }
|
"createSQLQuery" | "SELECT Value" | { sess -> sess.createSQLQuery("SELECT * FROM Value") }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
apply from: "$rootDir/gradle/instrumentation.gradle"
|
apply from: "$rootDir/gradle/instrumentation.gradle"
|
||||||
|
apply plugin: 'org.unbroken-dome.test-sets'
|
||||||
|
|
||||||
muzzle {
|
muzzle {
|
||||||
pass {
|
pass {
|
||||||
|
@ -9,21 +10,53 @@ muzzle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testSets {
|
||||||
|
version5Test {
|
||||||
|
dirName = 'test'
|
||||||
|
}
|
||||||
|
version6Test {
|
||||||
|
dirName = 'hibernate6Test'
|
||||||
|
}
|
||||||
|
|
||||||
|
latestDepTest {
|
||||||
|
dirName = 'test'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test.dependsOn version5Test, version6Test
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
library "org.hibernate:hibernate-core:4.0.0.Final"
|
compileOnly "org.hibernate:hibernate-core:4.0.0.Final"
|
||||||
|
|
||||||
implementation project(':instrumentation:hibernate:hibernate-common:javaagent')
|
implementation project(':instrumentation:hibernate:hibernate-common:javaagent')
|
||||||
|
|
||||||
testInstrumentation project(':instrumentation:jdbc:javaagent')
|
testInstrumentation project(':instrumentation:jdbc:javaagent')
|
||||||
// Added to ensure cross compatibility:
|
// Added to ensure cross compatibility:
|
||||||
testInstrumentation project(':instrumentation:hibernate:hibernate-3.3:javaagent')
|
testInstrumentation project(':instrumentation:hibernate:hibernate-3.3:javaagent')
|
||||||
testInstrumentation project(':instrumentation:hibernate:hibernate-4.3:javaagent')
|
testInstrumentation project(':instrumentation:hibernate:hibernate-procedure-call-4.3:javaagent')
|
||||||
|
|
||||||
testImplementation "com.h2database:h2:1.4.197"
|
testImplementation "com.h2database:h2:1.4.197"
|
||||||
testImplementation "javax.xml.bind:jaxb-api:2.2.11"
|
testImplementation "javax.xml.bind:jaxb-api:2.2.11"
|
||||||
testImplementation "com.sun.xml.bind:jaxb-core:2.2.11"
|
testImplementation "com.sun.xml.bind:jaxb-core:2.2.11"
|
||||||
testImplementation "com.sun.xml.bind:jaxb-impl:2.2.11"
|
testImplementation "com.sun.xml.bind:jaxb-impl:2.2.11"
|
||||||
testImplementation "javax.activation:activation:1.1.1"
|
testImplementation "javax.activation:activation:1.1.1"
|
||||||
|
testImplementation "org.hsqldb:hsqldb:2.0.0"
|
||||||
|
//First version to work with Java 14
|
||||||
|
testImplementation "org.springframework.data:spring-data-jpa:1.8.0.RELEASE"
|
||||||
|
|
||||||
latestDepTestLibrary "org.hibernate:hibernate-core:4.2.+"
|
testImplementation "org.hibernate:hibernate-core:4.0.0.Final"
|
||||||
|
testImplementation "org.hibernate:hibernate-entitymanager:4.0.0.Final"
|
||||||
|
|
||||||
|
version5TestImplementation "org.hibernate:hibernate-core:5.0.0.Final"
|
||||||
|
version5TestImplementation "org.hibernate:hibernate-entitymanager:5.0.0.Final"
|
||||||
|
version5TestImplementation "org.springframework.data:spring-data-jpa:2.3.0.RELEASE"
|
||||||
|
|
||||||
|
version6TestImplementation "org.hibernate:hibernate-core:6.0.0.Alpha6"
|
||||||
|
version6TestImplementation "org.hibernate:hibernate-entitymanager:6.0.0.Alpha6"
|
||||||
|
version6TestImplementation "org.springframework.data:spring-data-jpa:2.3.0.RELEASE"
|
||||||
|
|
||||||
|
// hibernate 6 is alpha so use 5 as latest version
|
||||||
|
latestDepTestImplementation "org.hibernate:hibernate-core:5.+"
|
||||||
|
latestDepTestImplementation "org.hibernate:hibernate-entitymanager:5.+"
|
||||||
|
latestDepTestImplementation "org.springframework.data:spring-data-jpa:(2.4.0,)"
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import org.hibernate.annotations.GenericGenerator;
|
||||||
|
import org.hibernate.annotations.NamedQuery;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table
|
||||||
|
@NamedQuery(name = "TestNamedQuery", query = "FROM Value")
|
||||||
|
public class Value {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public Value() {}
|
||||||
|
|
||||||
|
public Value(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(generator = "increment")
|
||||||
|
@GenericGenerator(name = "increment", strategy = "increment")
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String title) {
|
||||||
|
name = title;
|
||||||
|
}
|
||||||
|
}
|
|
@ -57,9 +57,6 @@ public class PersistenceConfig {
|
||||||
properties.setProperty("hibernate.show_sql", "true");
|
properties.setProperty("hibernate.show_sql", "true");
|
||||||
properties.setProperty("hibernate.hbm2ddl.auto", "create");
|
properties.setProperty("hibernate.hbm2ddl.auto", "create");
|
||||||
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
|
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
|
||||||
// properties.setProperty(
|
|
||||||
// "hibernate.format_sql",
|
|
||||||
// env.getProperty("spring.jpa.properties.hibernate.format_sql"));
|
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -53,7 +53,7 @@ public class QueryInstrumentation implements TypeInstrumentation {
|
||||||
ContextStore<Query, Context> contextStore =
|
ContextStore<Query, Context> contextStore =
|
||||||
InstrumentationContext.get(Query.class, Context.class);
|
InstrumentationContext.get(Query.class, Context.class);
|
||||||
|
|
||||||
context = SessionMethodUtils.startSpanFrom(contextStore, query, query.getQueryString(), null);
|
context = SessionMethodUtils.startSpanFromQuery(contextStore, query, query.getQueryString());
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
scope = context.makeCurrent();
|
scope = context.makeCurrent();
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,25 +105,25 @@ class QueryTest extends AbstractHibernateTest {
|
||||||
|
|
||||||
where:
|
where:
|
||||||
queryMethodName | expectedSpanName | requiresTransaction | queryInteraction
|
queryMethodName | expectedSpanName | requiresTransaction | queryInteraction
|
||||||
"query/list" | "from Value" | false | { sess ->
|
"query/list" | "SELECT Value" | false | { sess ->
|
||||||
Query q = sess.createQuery("from Value")
|
Query q = sess.createQuery("from Value")
|
||||||
q.list()
|
q.list()
|
||||||
}
|
}
|
||||||
"query/executeUpdate" | "update Value set name = ?" | true | { sess ->
|
"query/executeUpdate" | "UPDATE Value" | true | { sess ->
|
||||||
Query q = sess.createQuery("update Value set name = ?")
|
Query q = sess.createQuery("update Value set name = :name")
|
||||||
q.setParameter(0, "alyx")
|
q.setParameter("name", "alyx")
|
||||||
q.executeUpdate()
|
q.executeUpdate()
|
||||||
}
|
}
|
||||||
"query/uniqueResult" | "from Value where id = ?" | false | { sess ->
|
"query/uniqueResult" | "SELECT Value" | false | { sess ->
|
||||||
Query q = sess.createQuery("from Value where id = ?")
|
Query q = sess.createQuery("from Value where id = :id")
|
||||||
q.setParameter(0, 1L)
|
q.setParameter("id", 1L)
|
||||||
q.uniqueResult()
|
q.uniqueResult()
|
||||||
}
|
}
|
||||||
"iterate" | "from Value" | false | { sess ->
|
"iterate" | "SELECT Value" | false | { sess ->
|
||||||
Query q = sess.createQuery("from Value")
|
Query q = sess.createQuery("from Value")
|
||||||
q.iterate()
|
q.iterate()
|
||||||
}
|
}
|
||||||
"query/scroll" | "from Value" | false | { sess ->
|
"query/scroll" | "SELECT Value" | false | { sess ->
|
||||||
Query q = sess.createQuery("from Value")
|
Query q = sess.createQuery("from Value")
|
||||||
q.scroll()
|
q.scroll()
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ class QueryTest extends AbstractHibernateTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span(1) {
|
span(1) {
|
||||||
name "from Value"
|
name "SELECT Value"
|
||||||
kind INTERNAL
|
kind INTERNAL
|
||||||
childOf span(0)
|
childOf span(0)
|
||||||
attributes {
|
attributes {
|
||||||
|
|
|
@ -379,10 +379,10 @@ class SessionTest extends AbstractHibernateTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
where:
|
where:
|
||||||
queryMethodName | resource | queryBuildMethod
|
queryMethodName | resource | queryBuildMethod
|
||||||
"createQuery" | "from Value" | { sess -> sess.createQuery("from Value") }
|
"createQuery" | "SELECT Value" | { sess -> sess.createQuery("from Value") }
|
||||||
"getNamedQuery" | "from Value" | { sess -> sess.getNamedQuery("TestNamedQuery") }
|
"getNamedQuery" | "SELECT Value" | { sess -> sess.getNamedQuery("TestNamedQuery") }
|
||||||
"createSQLQuery" | "SELECT * FROM Value" | { sess -> sess.createSQLQuery("SELECT * FROM Value") }
|
"createSQLQuery" | "SELECT Value" | { sess -> sess.createSQLQuery("SELECT * FROM Value") }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,198 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import static io.opentelemetry.api.trace.SpanKind.CLIENT
|
||||||
|
|
||||||
|
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
|
||||||
|
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
|
||||||
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext
|
||||||
|
import spock.lang.Shared
|
||||||
|
import spring.jpa.Customer
|
||||||
|
import spring.jpa.CustomerRepository
|
||||||
|
import spring.jpa.PersistenceConfig
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unfortunately this test verifies that our hibernate instrumentation doesn't currently work with Spring Data Repositories.
|
||||||
|
*/
|
||||||
|
class SpringJpaTest extends AgentInstrumentationSpecification {
|
||||||
|
|
||||||
|
@Shared
|
||||||
|
def context = new AnnotationConfigApplicationContext(PersistenceConfig)
|
||||||
|
|
||||||
|
@Shared
|
||||||
|
def repo = context.getBean(CustomerRepository)
|
||||||
|
|
||||||
|
def "test CRUD"() {
|
||||||
|
setup:
|
||||||
|
def customer = new Customer("Bob", "Anonymous")
|
||||||
|
|
||||||
|
expect:
|
||||||
|
customer.id == null
|
||||||
|
!repo.findAll().iterator().hasNext()
|
||||||
|
|
||||||
|
assertTraces(1) {
|
||||||
|
trace(0, 1) {
|
||||||
|
span(0) {
|
||||||
|
name "SELECT test.Customer"
|
||||||
|
kind CLIENT
|
||||||
|
attributes {
|
||||||
|
"${SemanticAttributes.DB_SYSTEM.key}" "hsqldb"
|
||||||
|
"${SemanticAttributes.DB_NAME.key}" "test"
|
||||||
|
"${SemanticAttributes.DB_USER.key}" "sa"
|
||||||
|
"${SemanticAttributes.DB_CONNECTION_STRING.key}" "hsqldb:mem:"
|
||||||
|
"${SemanticAttributes.DB_STATEMENT.key}" ~/select ([^\.]+)\.id([^\,]*), ([^\.]+)\.firstName([^\,]*), ([^\.]+)\.lastName(.*)from Customer(.*)/
|
||||||
|
"${SemanticAttributes.DB_OPERATION.key}" "SELECT"
|
||||||
|
"${SemanticAttributes.DB_SQL_TABLE.key}" "Customer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clearExportedData()
|
||||||
|
|
||||||
|
when:
|
||||||
|
repo.save(customer)
|
||||||
|
def savedId = customer.id
|
||||||
|
|
||||||
|
then:
|
||||||
|
customer.id != null
|
||||||
|
// Behavior changed in new version:
|
||||||
|
def extraTrace = traces.size() == 2
|
||||||
|
assertTraces(extraTrace ? 2 : 1) {
|
||||||
|
if (extraTrace) {
|
||||||
|
trace(0, 1) {
|
||||||
|
span(0) {
|
||||||
|
name "test"
|
||||||
|
kind CLIENT
|
||||||
|
attributes {
|
||||||
|
"${SemanticAttributes.DB_SYSTEM.key}" "hsqldb"
|
||||||
|
"${SemanticAttributes.DB_NAME.key}" "test"
|
||||||
|
"${SemanticAttributes.DB_USER.key}" "sa"
|
||||||
|
"${SemanticAttributes.DB_STATEMENT.key}" "call next value for hibernate_sequence"
|
||||||
|
"${SemanticAttributes.DB_CONNECTION_STRING.key}" "hsqldb:mem:"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trace(extraTrace ? 1 : 0, 1) {
|
||||||
|
span(0) {
|
||||||
|
name "INSERT test.Customer"
|
||||||
|
kind CLIENT
|
||||||
|
attributes {
|
||||||
|
"${SemanticAttributes.DB_SYSTEM.key}" "hsqldb"
|
||||||
|
"${SemanticAttributes.DB_NAME.key}" "test"
|
||||||
|
"${SemanticAttributes.DB_USER.key}" "sa"
|
||||||
|
"${SemanticAttributes.DB_CONNECTION_STRING.key}" "hsqldb:mem:"
|
||||||
|
"${SemanticAttributes.DB_STATEMENT.key}" ~/insert into Customer \(.*\) values \(.*, \?, \?\)/
|
||||||
|
"${SemanticAttributes.DB_OPERATION.key}" "INSERT"
|
||||||
|
"${SemanticAttributes.DB_SQL_TABLE.key}" "Customer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clearExportedData()
|
||||||
|
|
||||||
|
when:
|
||||||
|
customer.firstName = "Bill"
|
||||||
|
repo.save(customer)
|
||||||
|
|
||||||
|
then:
|
||||||
|
customer.id == savedId
|
||||||
|
assertTraces(2) {
|
||||||
|
trace(0, 1) {
|
||||||
|
span(0) {
|
||||||
|
name "SELECT test.Customer"
|
||||||
|
kind CLIENT
|
||||||
|
attributes {
|
||||||
|
"${SemanticAttributes.DB_SYSTEM.key}" "hsqldb"
|
||||||
|
"${SemanticAttributes.DB_NAME.key}" "test"
|
||||||
|
"${SemanticAttributes.DB_USER.key}" "sa"
|
||||||
|
"${SemanticAttributes.DB_CONNECTION_STRING.key}" "hsqldb:mem:"
|
||||||
|
"${SemanticAttributes.DB_STATEMENT.key}" ~/select ([^\.]+)\.id([^\,]*), ([^\.]+)\.firstName([^\,]*), ([^\.]+)\.lastName (.*)from Customer (.*)where ([^\.]+)\.id( ?)=( ?)\?/
|
||||||
|
"${SemanticAttributes.DB_OPERATION.key}" "SELECT"
|
||||||
|
"${SemanticAttributes.DB_SQL_TABLE.key}" "Customer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trace(1, 1) {
|
||||||
|
span(0) {
|
||||||
|
name "UPDATE test.Customer"
|
||||||
|
kind CLIENT
|
||||||
|
attributes {
|
||||||
|
"${SemanticAttributes.DB_SYSTEM.key}" "hsqldb"
|
||||||
|
"${SemanticAttributes.DB_NAME.key}" "test"
|
||||||
|
"${SemanticAttributes.DB_USER.key}" "sa"
|
||||||
|
"${SemanticAttributes.DB_CONNECTION_STRING.key}" "hsqldb:mem:"
|
||||||
|
"${SemanticAttributes.DB_STATEMENT.key}" "update Customer set firstName=?, lastName=? where id=?"
|
||||||
|
"${SemanticAttributes.DB_OPERATION.key}" "UPDATE"
|
||||||
|
"${SemanticAttributes.DB_SQL_TABLE.key}" "Customer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clearExportedData()
|
||||||
|
|
||||||
|
when:
|
||||||
|
customer = repo.findByLastName("Anonymous")[0]
|
||||||
|
|
||||||
|
then:
|
||||||
|
customer.id == savedId
|
||||||
|
customer.firstName == "Bill"
|
||||||
|
assertTraces(1) {
|
||||||
|
trace(0, 1) {
|
||||||
|
span(0) {
|
||||||
|
name "SELECT test.Customer"
|
||||||
|
kind CLIENT
|
||||||
|
attributes {
|
||||||
|
"${SemanticAttributes.DB_SYSTEM.key}" "hsqldb"
|
||||||
|
"${SemanticAttributes.DB_NAME.key}" "test"
|
||||||
|
"${SemanticAttributes.DB_USER.key}" "sa"
|
||||||
|
"${SemanticAttributes.DB_CONNECTION_STRING.key}" "hsqldb:mem:"
|
||||||
|
"${SemanticAttributes.DB_STATEMENT.key}" ~/select ([^\.]+)\.id([^\,]*), ([^\.]+)\.firstName([^\,]*), ([^\.]+)\.lastName (.*)from Customer (.*)(where ([^\.]+)\.lastName( ?)=( ?)\?|)/
|
||||||
|
"${SemanticAttributes.DB_OPERATION.key}" "SELECT"
|
||||||
|
"${SemanticAttributes.DB_SQL_TABLE.key}" "Customer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clearExportedData()
|
||||||
|
|
||||||
|
when:
|
||||||
|
repo.delete(customer)
|
||||||
|
|
||||||
|
then:
|
||||||
|
assertTraces(2) {
|
||||||
|
trace(0, 1) {
|
||||||
|
span(0) {
|
||||||
|
name "SELECT test.Customer"
|
||||||
|
kind CLIENT
|
||||||
|
attributes {
|
||||||
|
"${SemanticAttributes.DB_SYSTEM.key}" "hsqldb"
|
||||||
|
"${SemanticAttributes.DB_NAME.key}" "test"
|
||||||
|
"${SemanticAttributes.DB_USER.key}" "sa"
|
||||||
|
"${SemanticAttributes.DB_CONNECTION_STRING.key}" "hsqldb:mem:"
|
||||||
|
"${SemanticAttributes.DB_STATEMENT.key}" ~/select ([^\.]+)\.id([^\,]*), ([^\.]+)\.firstName([^\,]*), ([^\.]+)\.lastName (.*)from Customer (.*)where ([^\.]+)\.id( ?)=( ?)\?/
|
||||||
|
"${SemanticAttributes.DB_OPERATION.key}" "SELECT"
|
||||||
|
"${SemanticAttributes.DB_SQL_TABLE.key}" "Customer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trace(1, 1) {
|
||||||
|
span(0) {
|
||||||
|
name "DELETE test.Customer"
|
||||||
|
kind CLIENT
|
||||||
|
attributes {
|
||||||
|
"${SemanticAttributes.DB_SYSTEM.key}" "hsqldb"
|
||||||
|
"${SemanticAttributes.DB_NAME.key}" "test"
|
||||||
|
"${SemanticAttributes.DB_USER.key}" "sa"
|
||||||
|
"${SemanticAttributes.DB_CONNECTION_STRING.key}" "hsqldb:mem:"
|
||||||
|
"${SemanticAttributes.DB_STATEMENT.key}" "delete from Customer where id=?"
|
||||||
|
"${SemanticAttributes.DB_OPERATION.key}" "DELETE"
|
||||||
|
"${SemanticAttributes.DB_SQL_TABLE.key}" "Customer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spring.jpa;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class Customer {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String firstName;
|
||||||
|
private String lastName;
|
||||||
|
|
||||||
|
protected Customer() {}
|
||||||
|
|
||||||
|
public Customer(String firstName, String lastName) {
|
||||||
|
this.firstName = firstName;
|
||||||
|
this.lastName = lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFirstName() {
|
||||||
|
return firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFirstName(String firstName) {
|
||||||
|
this.firstName = firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastName() {
|
||||||
|
return lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastName(String lastName) {
|
||||||
|
this.lastName = lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("Customer[id=%d, firstName='%s', lastName='%s']", id, firstName, lastName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof Customer)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Customer other = (Customer) obj;
|
||||||
|
return Objects.equals(id, other.id)
|
||||||
|
&& Objects.equals(firstName, other.firstName)
|
||||||
|
&& Objects.equals(lastName, other.lastName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(id, firstName, lastName);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spring.jpa;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
|
||||||
|
public interface CustomerRepository extends CrudRepository<Customer, Long> {
|
||||||
|
|
||||||
|
List<Customer> findByLastName(String lastName);
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spring.jpa;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||||
|
import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||||
|
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||||
|
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||||
|
import org.springframework.orm.jpa.vendor.Database;
|
||||||
|
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
|
||||||
|
@EnableJpaRepositories(basePackages = "spring/jpa")
|
||||||
|
public class PersistenceConfig {
|
||||||
|
|
||||||
|
@Bean(name = "transactionManager")
|
||||||
|
public PlatformTransactionManager dbTransactionManager() {
|
||||||
|
JpaTransactionManager transactionManager = new JpaTransactionManager();
|
||||||
|
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
|
||||||
|
return transactionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||||
|
|
||||||
|
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
|
||||||
|
vendorAdapter.setDatabase(Database.HSQL);
|
||||||
|
vendorAdapter.setGenerateDdl(true);
|
||||||
|
|
||||||
|
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
|
||||||
|
em.setDataSource(dataSource());
|
||||||
|
em.setPackagesToScan("spring/jpa");
|
||||||
|
em.setJpaVendorAdapter(vendorAdapter);
|
||||||
|
em.setJpaProperties(additionalProperties());
|
||||||
|
|
||||||
|
return em;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DataSource dataSource() {
|
||||||
|
DriverManagerDataSource dataSource = new DriverManagerDataSource();
|
||||||
|
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||||
|
dataSource.setUrl("jdbc:hsqldb:mem:test");
|
||||||
|
dataSource.setUsername("sa");
|
||||||
|
dataSource.setPassword("1");
|
||||||
|
return dataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Properties additionalProperties() {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.setProperty("hibernate.show_sql", "true");
|
||||||
|
properties.setProperty("hibernate.hbm2ddl.auto", "create");
|
||||||
|
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,60 +0,0 @@
|
||||||
apply from: "$rootDir/gradle/instrumentation.gradle"
|
|
||||||
apply plugin: 'org.unbroken-dome.test-sets'
|
|
||||||
|
|
||||||
muzzle {
|
|
||||||
pass {
|
|
||||||
group = "org.hibernate"
|
|
||||||
module = "hibernate-core"
|
|
||||||
versions = "[4.3.0.Final,)"
|
|
||||||
assertInverse = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
testSets {
|
|
||||||
version5Test {
|
|
||||||
dirName = 'test'
|
|
||||||
}
|
|
||||||
version6Test {
|
|
||||||
dirName = 'test'
|
|
||||||
}
|
|
||||||
|
|
||||||
latestDepTest {
|
|
||||||
dirName = 'test'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test.dependsOn version5Test, version6Test
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
compileOnly "org.hibernate:hibernate-core:4.3.0.Final"
|
|
||||||
|
|
||||||
implementation project(':instrumentation:hibernate:hibernate-common:javaagent')
|
|
||||||
|
|
||||||
testInstrumentation project(':instrumentation:jdbc:javaagent')
|
|
||||||
// Added to ensure cross compatibility:
|
|
||||||
testInstrumentation project(':instrumentation:hibernate:hibernate-3.3:javaagent')
|
|
||||||
testInstrumentation project(':instrumentation:hibernate:hibernate-4.0:javaagent')
|
|
||||||
|
|
||||||
testImplementation "org.hibernate:hibernate-core:4.3.0.Final"
|
|
||||||
testImplementation "org.hibernate:hibernate-entitymanager:4.3.0.Final"
|
|
||||||
testImplementation "org.hsqldb:hsqldb:2.0.0"
|
|
||||||
//First version to work with Java 14
|
|
||||||
testImplementation "org.springframework.data:spring-data-jpa:1.8.0.RELEASE"
|
|
||||||
|
|
||||||
version5TestImplementation "org.hibernate:hibernate-core:5.0.0.Final"
|
|
||||||
version5TestImplementation "org.hibernate:hibernate-entitymanager:5.0.0.Final"
|
|
||||||
version5TestImplementation "org.springframework.data:spring-data-jpa:2.3.0.RELEASE"
|
|
||||||
|
|
||||||
version6TestImplementation "org.hibernate:hibernate-core:6.0.0.Alpha6"
|
|
||||||
version6TestImplementation "org.hibernate:hibernate-entitymanager:6.0.0.Alpha6"
|
|
||||||
version6TestImplementation "org.springframework.data:spring-data-jpa:2.3.0.RELEASE"
|
|
||||||
|
|
||||||
testImplementation "javax.activation:javax.activation-api:1.2.0"
|
|
||||||
testImplementation "javax.xml.bind:jaxb-api:2.3.1"
|
|
||||||
testImplementation "org.glassfish.jaxb:jaxb-runtime:2.3.3"
|
|
||||||
|
|
||||||
// hibernate 6 is alpha so use 5 as latest version
|
|
||||||
latestDepTestImplementation "org.hibernate:hibernate-core:5.+"
|
|
||||||
latestDepTestImplementation "org.hibernate:hibernate-entitymanager:5.+"
|
|
||||||
latestDepTestImplementation "org.springframework.data:spring-data-jpa:(2.4.0,)"
|
|
||||||
}
|
|
|
@ -9,11 +9,14 @@ import static io.opentelemetry.javaagent.instrumentation.hibernate.HibernateTrac
|
||||||
|
|
||||||
import io.opentelemetry.api.trace.Span;
|
import io.opentelemetry.api.trace.Span;
|
||||||
import io.opentelemetry.context.Context;
|
import io.opentelemetry.context.Context;
|
||||||
|
import io.opentelemetry.instrumentation.api.db.SqlStatementInfo;
|
||||||
|
import io.opentelemetry.instrumentation.api.db.SqlStatementSanitizer;
|
||||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
|
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
|
||||||
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
|
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
public class SessionMethodUtils {
|
public class SessionMethodUtils {
|
||||||
|
@ -26,6 +29,14 @@ public class SessionMethodUtils {
|
||||||
TARGET spanKey,
|
TARGET spanKey,
|
||||||
String operationName,
|
String operationName,
|
||||||
ENTITY entity) {
|
ENTITY entity) {
|
||||||
|
return startSpanFrom(contextStore, spanKey, () -> operationName, entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <TARGET, ENTITY> Context startSpanFrom(
|
||||||
|
ContextStore<TARGET, Context> contextStore,
|
||||||
|
TARGET spanKey,
|
||||||
|
Supplier<String> operationNameSupplier,
|
||||||
|
ENTITY entity) {
|
||||||
|
|
||||||
Context sessionContext = contextStore.get(spanKey);
|
Context sessionContext = contextStore.get(spanKey);
|
||||||
if (sessionContext == null) {
|
if (sessionContext == null) {
|
||||||
|
@ -37,7 +48,26 @@ public class SessionMethodUtils {
|
||||||
return null; // This method call is being traced already.
|
return null; // This method call is being traced already.
|
||||||
}
|
}
|
||||||
|
|
||||||
return tracer().startSpan(sessionContext, operationName, entity);
|
return tracer().startSpan(sessionContext, operationNameSupplier.get(), entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <TARGET> Context startSpanFromQuery(
|
||||||
|
ContextStore<TARGET, Context> contextStore, TARGET spanKey, String query) {
|
||||||
|
Supplier<String> operationNameSupplier =
|
||||||
|
() -> {
|
||||||
|
// set operation to default value that is used when sql sanitizer fails to extract
|
||||||
|
// operation name
|
||||||
|
String operation = "Hibernate Query";
|
||||||
|
SqlStatementInfo info = SqlStatementSanitizer.sanitize(query);
|
||||||
|
if (info.getOperation() != null) {
|
||||||
|
operation = info.getOperation();
|
||||||
|
if (info.getTable() != null) {
|
||||||
|
operation += " " + info.getTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return operation;
|
||||||
|
};
|
||||||
|
return startSpanFrom(contextStore, spanKey, operationNameSupplier, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void end(
|
public static void end(
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
apply from: "$rootDir/gradle/instrumentation.gradle"
|
||||||
|
|
||||||
|
muzzle {
|
||||||
|
pass {
|
||||||
|
group = "org.hibernate"
|
||||||
|
module = "hibernate-core"
|
||||||
|
versions = "[4.3.0.Final,)"
|
||||||
|
assertInverse = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
library "org.hibernate:hibernate-core:4.3.0.Final"
|
||||||
|
|
||||||
|
implementation project(':instrumentation:hibernate:hibernate-common:javaagent')
|
||||||
|
|
||||||
|
testInstrumentation project(':instrumentation:jdbc:javaagent')
|
||||||
|
// Added to ensure cross compatibility:
|
||||||
|
testInstrumentation project(':instrumentation:hibernate:hibernate-3.3:javaagent')
|
||||||
|
testInstrumentation project(':instrumentation:hibernate:hibernate-4.0:javaagent')
|
||||||
|
|
||||||
|
testLibrary "org.hibernate:hibernate-entitymanager:4.3.0.Final"
|
||||||
|
|
||||||
|
testImplementation "org.hsqldb:hsqldb:2.0.0"
|
||||||
|
testImplementation "javax.xml.bind:jaxb-api:2.3.1"
|
||||||
|
testImplementation "org.glassfish.jaxb:jaxb-runtime:2.3.3"
|
||||||
|
|
||||||
|
// hibernate 6 is alpha so use 5 as latest version
|
||||||
|
latestDepTestLibrary "org.hibernate:hibernate-core:5.+"
|
||||||
|
latestDepTestLibrary "org.hibernate:hibernate-entitymanager:5.+"
|
||||||
|
}
|
|
@ -23,7 +23,6 @@ import spock.lang.Shared
|
||||||
|
|
||||||
class ProcedureCallTest extends AgentInstrumentationSpecification {
|
class ProcedureCallTest extends AgentInstrumentationSpecification {
|
||||||
|
|
||||||
|
|
||||||
@Shared
|
@Shared
|
||||||
protected SessionFactory sessionFactory
|
protected SessionFactory sessionFactory
|
||||||
|
|
|
@ -141,8 +141,8 @@ include ':instrumentation:guava-10.0:library'
|
||||||
include ':instrumentation:gwt-2.0:javaagent'
|
include ':instrumentation:gwt-2.0:javaagent'
|
||||||
include ':instrumentation:hibernate:hibernate-3.3:javaagent'
|
include ':instrumentation:hibernate:hibernate-3.3:javaagent'
|
||||||
include ':instrumentation:hibernate:hibernate-4.0:javaagent'
|
include ':instrumentation:hibernate:hibernate-4.0:javaagent'
|
||||||
include ':instrumentation:hibernate:hibernate-4.3:javaagent'
|
|
||||||
include ':instrumentation:hibernate:hibernate-common:javaagent'
|
include ':instrumentation:hibernate:hibernate-common:javaagent'
|
||||||
|
include ':instrumentation:hibernate:hibernate-procedure-call-4.3:javaagent'
|
||||||
include ':instrumentation:http-url-connection:javaagent'
|
include ':instrumentation:http-url-connection:javaagent'
|
||||||
include ':instrumentation:hystrix-1.4:javaagent'
|
include ':instrumentation:hystrix-1.4:javaagent'
|
||||||
include ':instrumentation:java-http-client:javaagent'
|
include ':instrumentation:java-http-client:javaagent'
|
||||||
|
|
Loading…
Reference in New Issue