Refactor DatabaseClientTracer (in preparation for low-cardinality span names) (#2398)
* Refactor DatabaseClientTracer (in preparation for low-cardinality span names) * spotless
This commit is contained in:
parent
605485b998
commit
fd55ce226a
|
@ -8,16 +8,22 @@ package io.opentelemetry.instrumentation.api.tracer;
|
|||
import static io.opentelemetry.api.trace.SpanKind.CLIENT;
|
||||
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import io.opentelemetry.api.trace.SpanBuilder;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.instrumentation.api.tracer.utils.NetPeerUtils;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public abstract class DatabaseClientTracer<CONNECTION, QUERY> extends BaseTracer {
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Base class for implementing Tracers for database clients.
|
||||
*
|
||||
* @param <CONNECTION> type of the database connection.
|
||||
* @param <STATEMENT> type of the database statement being executed.
|
||||
* @param <SANITIZEDSTATEMENT> type of the database statement after sanitization.
|
||||
*/
|
||||
public abstract class DatabaseClientTracer<CONNECTION, STATEMENT, SANITIZEDSTATEMENT>
|
||||
extends BaseTracer {
|
||||
protected static final String DB_QUERY = "DB Query";
|
||||
|
||||
public DatabaseClientTracer() {}
|
||||
|
@ -30,61 +36,68 @@ public abstract class DatabaseClientTracer<CONNECTION, QUERY> extends BaseTracer
|
|||
return shouldStartSpan(CLIENT, parentContext);
|
||||
}
|
||||
|
||||
public Context startSpan(Context parentContext, CONNECTION connection, QUERY query) {
|
||||
String normalizedQuery = normalizeQuery(query);
|
||||
public Context startSpan(Context parentContext, CONNECTION connection, STATEMENT statement) {
|
||||
SANITIZEDSTATEMENT sanitizedStatement = sanitizeStatement(statement);
|
||||
|
||||
Span span =
|
||||
SpanBuilder span =
|
||||
tracer
|
||||
.spanBuilder(spanName(connection, query, normalizedQuery))
|
||||
.spanBuilder(spanName(connection, statement, sanitizedStatement))
|
||||
.setParent(parentContext)
|
||||
.setSpanKind(CLIENT)
|
||||
.setAttribute(SemanticAttributes.DB_SYSTEM, dbSystem(connection))
|
||||
.startSpan();
|
||||
.setAttribute(SemanticAttributes.DB_SYSTEM, dbSystem(connection));
|
||||
|
||||
if (connection != null) {
|
||||
onConnection(span, connection);
|
||||
setNetSemanticConvention(span, connection);
|
||||
}
|
||||
onStatement(span, normalizedQuery);
|
||||
onStatement(span, connection, statement, sanitizedStatement);
|
||||
|
||||
return withClientSpan(parentContext, span);
|
||||
return withClientSpan(parentContext, span.startSpan());
|
||||
}
|
||||
|
||||
public void endExceptionally(Context context, Throwable throwable) {
|
||||
Span span = Span.fromContext(context);
|
||||
onError(span, throwable);
|
||||
end(span);
|
||||
protected abstract SANITIZEDSTATEMENT sanitizeStatement(STATEMENT statement);
|
||||
|
||||
protected String spanName(
|
||||
CONNECTION connection, STATEMENT statement, SANITIZEDSTATEMENT sanitizedStatement) {
|
||||
return conventionSpanName(
|
||||
dbName(connection), dbOperation(connection, statement, sanitizedStatement), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method for constructing the span name formatting according to DB semantic conventions:
|
||||
* {@code <db.operation> <db.name><table>}.
|
||||
*/
|
||||
public static String conventionSpanName(
|
||||
@Nullable String dbName, @Nullable String operation, @Nullable String table) {
|
||||
if (operation == null) {
|
||||
return dbName == null ? DB_QUERY : dbName;
|
||||
}
|
||||
|
||||
StringBuilder name = new StringBuilder(operation);
|
||||
if (dbName != null || table != null) {
|
||||
name.append(' ');
|
||||
}
|
||||
if (dbName != null) {
|
||||
name.append(dbName);
|
||||
if (table != null) {
|
||||
name.append('.');
|
||||
}
|
||||
}
|
||||
if (table != null) {
|
||||
name.append(table);
|
||||
}
|
||||
return name.toString();
|
||||
}
|
||||
|
||||
protected abstract String dbSystem(CONNECTION connection);
|
||||
|
||||
/** This should be called when the connection is being used, not when it's created. */
|
||||
protected Span onConnection(Span span, CONNECTION connection) {
|
||||
protected void onConnection(SpanBuilder span, CONNECTION connection) {
|
||||
span.setAttribute(SemanticAttributes.DB_USER, dbUser(connection));
|
||||
span.setAttribute(SemanticAttributes.DB_NAME, dbName(connection));
|
||||
span.setAttribute(SemanticAttributes.DB_CONNECTION_STRING, dbConnectionString(connection));
|
||||
return span;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onError(Span span, Throwable throwable) {
|
||||
if (throwable != null) {
|
||||
span.setStatus(StatusCode.ERROR);
|
||||
addThrowable(
|
||||
span, throwable instanceof ExecutionException ? throwable.getCause() : throwable);
|
||||
}
|
||||
}
|
||||
|
||||
protected void setNetSemanticConvention(Span span, CONNECTION connection) {
|
||||
NetPeerUtils.INSTANCE.setNetPeer(span, peerAddress(connection));
|
||||
}
|
||||
|
||||
protected void onStatement(Span span, String statement) {
|
||||
span.setAttribute(SemanticAttributes.DB_STATEMENT, statement);
|
||||
}
|
||||
|
||||
protected abstract String normalizeQuery(QUERY query);
|
||||
|
||||
protected abstract String dbSystem(CONNECTION connection);
|
||||
|
||||
protected String dbUser(CONNECTION connection) {
|
||||
return null;
|
||||
}
|
||||
|
@ -97,17 +110,30 @@ public abstract class DatabaseClientTracer<CONNECTION, QUERY> extends BaseTracer
|
|||
return null;
|
||||
}
|
||||
|
||||
protected void setNetSemanticConvention(SpanBuilder span, CONNECTION connection) {
|
||||
NetPeerUtils.INSTANCE.setNetPeer(span, peerAddress(connection));
|
||||
}
|
||||
|
||||
protected abstract InetSocketAddress peerAddress(CONNECTION connection);
|
||||
|
||||
protected String spanName(CONNECTION connection, QUERY query, String normalizedQuery) {
|
||||
if (normalizedQuery != null) {
|
||||
return normalizedQuery;
|
||||
}
|
||||
protected void onStatement(
|
||||
SpanBuilder span,
|
||||
CONNECTION connection,
|
||||
STATEMENT statement,
|
||||
SANITIZEDSTATEMENT sanitizedStatement) {
|
||||
span.setAttribute(
|
||||
SemanticAttributes.DB_STATEMENT, dbStatement(connection, statement, sanitizedStatement));
|
||||
span.setAttribute(
|
||||
SemanticAttributes.DB_OPERATION, dbOperation(connection, statement, sanitizedStatement));
|
||||
}
|
||||
|
||||
String result = null;
|
||||
if (connection != null) {
|
||||
result = dbName(connection);
|
||||
}
|
||||
return result == null ? DB_QUERY : result;
|
||||
protected String dbStatement(
|
||||
CONNECTION connection, STATEMENT statement, SANITIZEDSTATEMENT sanitizedStatement) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected String dbOperation(
|
||||
CONNECTION connection, STATEMENT statement, SANITIZEDSTATEMENT sanitizedStatement) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,15 +9,18 @@ import com.datastax.driver.core.ExecutionInfo;
|
|||
import com.datastax.driver.core.Host;
|
||||
import com.datastax.driver.core.Session;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.SpanBuilder;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.instrumentation.api.tracer.DatabaseClientTracer;
|
||||
import io.opentelemetry.instrumentation.api.tracer.utils.NetPeerUtils;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.db.SqlStatementInfo;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.db.SqlStatementSanitizer;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes.DbSystemValues;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
public class CassandraDatabaseClientTracer extends DatabaseClientTracer<Session, String> {
|
||||
public class CassandraDatabaseClientTracer
|
||||
extends DatabaseClientTracer<Session, String, SqlStatementInfo> {
|
||||
private static final CassandraDatabaseClientTracer TRACER = new CassandraDatabaseClientTracer();
|
||||
|
||||
public static CassandraDatabaseClientTracer tracer() {
|
||||
|
@ -30,8 +33,23 @@ public class CassandraDatabaseClientTracer extends DatabaseClientTracer<Session,
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String normalizeQuery(String query) {
|
||||
return SqlStatementSanitizer.sanitize(query).getFullStatement();
|
||||
protected SqlStatementInfo sanitizeStatement(String statement) {
|
||||
return SqlStatementSanitizer.sanitize(statement);
|
||||
}
|
||||
|
||||
// TODO: use the <operation> <db.name>.<table> naming scheme
|
||||
protected String spanName(
|
||||
Session connection, String statement, SqlStatementInfo sanitizedStatement) {
|
||||
String fullStatement = sanitizedStatement.getFullStatement();
|
||||
if (fullStatement != null) {
|
||||
return fullStatement;
|
||||
}
|
||||
|
||||
String result = null;
|
||||
if (connection != null) {
|
||||
result = dbName(connection);
|
||||
}
|
||||
return result == null ? DB_QUERY : result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -39,20 +57,26 @@ public class CassandraDatabaseClientTracer extends DatabaseClientTracer<Session,
|
|||
return DbSystemValues.CASSANDRA;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConnection(SpanBuilder span, Session session) {
|
||||
span.setAttribute(SemanticAttributes.DB_CASSANDRA_KEYSPACE, session.getLoggedKeyspace());
|
||||
super.onConnection(span, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String dbName(Session session) {
|
||||
return session.getLoggedKeyspace();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Span onConnection(Span span, Session session) {
|
||||
span.setAttribute(SemanticAttributes.DB_CASSANDRA_KEYSPACE, session.getLoggedKeyspace());
|
||||
return super.onConnection(span, session);
|
||||
protected InetSocketAddress peerAddress(Session session) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InetSocketAddress peerAddress(Session session) {
|
||||
return null;
|
||||
protected String dbStatement(
|
||||
Session connection, String statement, SqlStatementInfo sanitizedStatement) {
|
||||
return sanitizedStatement.getFullStatement();
|
||||
}
|
||||
|
||||
public void end(Context context, ExecutionInfo executionInfo) {
|
||||
|
|
|
@ -14,16 +14,19 @@ import com.datastax.oss.driver.api.core.cql.ExecutionInfo;
|
|||
import com.datastax.oss.driver.api.core.cql.Statement;
|
||||
import com.datastax.oss.driver.api.core.metadata.Node;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.SpanBuilder;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.instrumentation.api.tracer.DatabaseClientTracer;
|
||||
import io.opentelemetry.instrumentation.api.tracer.utils.NetPeerUtils;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.db.SqlStatementInfo;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.db.SqlStatementSanitizer;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes.DbSystemValues;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
|
||||
public class CassandraDatabaseClientTracer extends DatabaseClientTracer<CqlSession, String> {
|
||||
public class CassandraDatabaseClientTracer
|
||||
extends DatabaseClientTracer<CqlSession, String, SqlStatementInfo> {
|
||||
|
||||
private static final CassandraDatabaseClientTracer TRACER = new CassandraDatabaseClientTracer();
|
||||
|
||||
|
@ -37,8 +40,23 @@ public class CassandraDatabaseClientTracer extends DatabaseClientTracer<CqlSessi
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String normalizeQuery(String query) {
|
||||
return SqlStatementSanitizer.sanitize(query).getFullStatement();
|
||||
protected SqlStatementInfo sanitizeStatement(String statement) {
|
||||
return SqlStatementSanitizer.sanitize(statement);
|
||||
}
|
||||
|
||||
// TODO: use the <operation> <db.name>.<table> naming scheme
|
||||
protected String spanName(
|
||||
CqlSession connection, String statement, SqlStatementInfo sanitizedStatement) {
|
||||
String fullStatement = sanitizedStatement.getFullStatement();
|
||||
if (fullStatement != null) {
|
||||
return fullStatement;
|
||||
}
|
||||
|
||||
String result = null;
|
||||
if (connection != null) {
|
||||
result = dbName(connection);
|
||||
}
|
||||
return result == null ? DB_QUERY : result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -127,9 +145,13 @@ public class CassandraDatabaseClientTracer extends DatabaseClientTracer<CqlSessi
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void onStatement(Span span, String statement) {
|
||||
super.onStatement(span, statement);
|
||||
String table = SqlStatementSanitizer.sanitize(statement).getTable();
|
||||
protected void onStatement(
|
||||
SpanBuilder span,
|
||||
CqlSession connection,
|
||||
String statement,
|
||||
SqlStatementInfo sanitizedStatement) {
|
||||
super.onStatement(span, connection, statement, sanitizedStatement);
|
||||
String table = sanitizedStatement.getTable();
|
||||
if (table != null) {
|
||||
// account for splitting out the keyspace, <keyspace>.<table>
|
||||
int i = table.indexOf('.');
|
||||
|
@ -139,4 +161,10 @@ public class CassandraDatabaseClientTracer extends DatabaseClientTracer<CqlSessi
|
|||
span.setAttribute(SemanticAttributes.DB_CASSANDRA_TABLE, table);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String dbStatement(
|
||||
CqlSession connection, String statement, SqlStatementInfo sanitizedStatement) {
|
||||
return sanitizedStatement.getFullStatement();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import io.opentelemetry.semconv.trace.attributes.SemanticAttributes.DbSystemValu
|
|||
import java.lang.reflect.Method;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
public class CouchbaseClientTracer extends DatabaseClientTracer<Void, Method> {
|
||||
public class CouchbaseClientTracer extends DatabaseClientTracer<Void, Method, Void> {
|
||||
private static final CouchbaseClientTracer TRACER = new CouchbaseClientTracer();
|
||||
|
||||
public static CouchbaseClientTracer tracer() {
|
||||
|
@ -18,13 +18,18 @@ public class CouchbaseClientTracer extends DatabaseClientTracer<Void, Method> {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String normalizeQuery(Method method) {
|
||||
protected String spanName(Void connection, Method method, Void sanitizedStatement) {
|
||||
Class<?> declaringClass = method.getDeclaringClass();
|
||||
String className =
|
||||
declaringClass.getSimpleName().replace("CouchbaseAsync", "").replace("DefaultAsync", "");
|
||||
return className + "." + method.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void sanitizeStatement(Method method) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String dbSystem(Void connection) {
|
||||
return DbSystemValues.COUCHBASE;
|
||||
|
|
|
@ -13,7 +13,7 @@ import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
|||
import java.net.InetSocketAddress;
|
||||
import org.elasticsearch.client.Response;
|
||||
|
||||
public class ElasticsearchRestClientTracer extends DatabaseClientTracer<Void, String> {
|
||||
public class ElasticsearchRestClientTracer extends DatabaseClientTracer<Void, String, String> {
|
||||
private static final ElasticsearchRestClientTracer TRACER = new ElasticsearchRestClientTracer();
|
||||
|
||||
public static ElasticsearchRestClientTracer tracer() {
|
||||
|
@ -29,13 +29,8 @@ public class ElasticsearchRestClientTracer extends DatabaseClientTracer<Void, St
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void onStatement(Span span, String statement) {
|
||||
span.setAttribute(SemanticAttributes.DB_OPERATION, statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String normalizeQuery(String query) {
|
||||
return query;
|
||||
protected String sanitizeStatement(String operation) {
|
||||
return operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -48,6 +43,11 @@ public class ElasticsearchRestClientTracer extends DatabaseClientTracer<Void, St
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String dbOperation(Void connection, String operation, String ignored) {
|
||||
return operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getInstrumentationName() {
|
||||
return "io.opentelemetry.javaagent.elasticsearch";
|
||||
|
|
|
@ -8,12 +8,11 @@ package io.opentelemetry.javaagent.instrumentation.elasticsearch.transport;
|
|||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.instrumentation.api.tracer.DatabaseClientTracer;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import java.net.InetSocketAddress;
|
||||
import org.elasticsearch.action.Action;
|
||||
|
||||
public class ElasticsearchTransportClientTracer
|
||||
extends DatabaseClientTracer<Void, Action<?, ?, ?>> {
|
||||
extends DatabaseClientTracer<Void, Action<?, ?, ?>, String> {
|
||||
private static final ElasticsearchTransportClientTracer TRACER =
|
||||
new ElasticsearchTransportClientTracer();
|
||||
|
||||
|
@ -21,15 +20,15 @@ public class ElasticsearchTransportClientTracer
|
|||
return TRACER;
|
||||
}
|
||||
|
||||
public void onRequest(Context context, Class action, Class request) {
|
||||
public void onRequest(Context context, Class<?> action, Class<?> request) {
|
||||
Span span = Span.fromContext(context);
|
||||
span.setAttribute("elasticsearch.action", action.getSimpleName());
|
||||
span.setAttribute("elasticsearch.request", request.getSimpleName());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String normalizeQuery(Action<?, ?, ?> query) {
|
||||
return query.getClass().getSimpleName();
|
||||
protected String sanitizeStatement(Action<?, ?, ?> action) {
|
||||
return action.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -43,8 +42,8 @@ public class ElasticsearchTransportClientTracer
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void onStatement(Span span, String statement) {
|
||||
span.setAttribute(SemanticAttributes.DB_OPERATION, statement);
|
||||
protected String dbOperation(Void connection, Action<?, ?, ?> action, String operation) {
|
||||
return operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,13 +8,15 @@ package io.opentelemetry.javaagent.instrumentation.geode;
|
|||
import static io.opentelemetry.api.trace.SpanKind.CLIENT;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.SpanBuilder;
|
||||
import io.opentelemetry.instrumentation.api.tracer.DatabaseClientTracer;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.db.SqlStatementInfo;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.db.SqlStatementSanitizer;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import java.net.InetSocketAddress;
|
||||
import org.apache.geode.cache.Region;
|
||||
|
||||
public class GeodeTracer extends DatabaseClientTracer<Region<?, ?>, String> {
|
||||
public class GeodeTracer extends DatabaseClientTracer<Region<?, ?>, String, SqlStatementInfo> {
|
||||
private static final GeodeTracer TRACER = new GeodeTracer();
|
||||
|
||||
public static GeodeTracer tracer() {
|
||||
|
@ -22,33 +24,30 @@ public class GeodeTracer extends DatabaseClientTracer<Region<?, ?>, String> {
|
|||
}
|
||||
|
||||
public Span startSpan(String operation, Region<?, ?> connection, String query) {
|
||||
String normalizedQuery = normalizeQuery(query);
|
||||
SqlStatementInfo sanitizedStatement = sanitizeStatement(query);
|
||||
|
||||
Span span =
|
||||
SpanBuilder span =
|
||||
tracer
|
||||
.spanBuilder(operation)
|
||||
.setSpanKind(CLIENT)
|
||||
.setAttribute(SemanticAttributes.DB_SYSTEM, dbSystem(connection))
|
||||
.setAttribute(SemanticAttributes.DB_OPERATION, operation)
|
||||
.startSpan();
|
||||
.setAttribute(SemanticAttributes.DB_OPERATION, operation);
|
||||
|
||||
onConnection(span, connection);
|
||||
setNetSemanticConvention(span, connection);
|
||||
onStatement(span, normalizedQuery);
|
||||
onStatement(span, connection, query, sanitizedStatement);
|
||||
|
||||
return span;
|
||||
return span.startSpan();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String normalizeQuery(String query) {
|
||||
return SqlStatementSanitizer.sanitize(query).getFullStatement();
|
||||
protected SqlStatementInfo sanitizeStatement(String statement) {
|
||||
return SqlStatementSanitizer.sanitize(statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String dbSystem(Region<?, ?> region) {
|
||||
// TODO(anuraaga): Replace with semantic attribute
|
||||
// https://github.com/open-telemetry/opentelemetry-specification/pull/1321
|
||||
return "geode";
|
||||
return SemanticAttributes.DbSystemValues.GEODE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -61,6 +60,12 @@ public class GeodeTracer extends DatabaseClientTracer<Region<?, ?>, String> {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String dbStatement(
|
||||
Region<?, ?> connection, String statement, SqlStatementInfo sanitizedStatement) {
|
||||
return sanitizedStatement.getFullStatement();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getInstrumentationName() {
|
||||
return "io.opentelemetry.javaagent.geode";
|
||||
|
|
|
@ -14,7 +14,6 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
|||
import static net.bytebuddy.matcher.ElementMatchers.returns;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||
|
||||
import io.opentelemetry.javaagent.instrumentation.api.db.SqlStatementSanitizer;
|
||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.util.Map;
|
||||
|
@ -49,7 +48,7 @@ public class ConnectionInstrumentation implements TypeInstrumentation {
|
|||
@Advice.OnMethodExit(suppress = Throwable.class)
|
||||
public static void addDbInfo(
|
||||
@Advice.Argument(0) String sql, @Advice.Return PreparedStatement statement) {
|
||||
JdbcMaps.preparedStatements.put(statement, SqlStatementSanitizer.sanitize(sql));
|
||||
JdbcMaps.preparedStatements.put(statement, sql);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ package io.opentelemetry.javaagent.instrumentation.jdbc;
|
|||
import static io.opentelemetry.javaagent.instrumentation.api.WeakMap.Provider.newWeakMap;
|
||||
|
||||
import io.opentelemetry.javaagent.instrumentation.api.WeakMap;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.db.SqlStatementInfo;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
|
||||
|
@ -19,6 +18,5 @@ import java.sql.PreparedStatement;
|
|||
*/
|
||||
public class JdbcMaps {
|
||||
public static final WeakMap<Connection, DbInfo> connectionInfo = newWeakMap();
|
||||
public static final WeakMap<PreparedStatement, SqlStatementInfo> preparedStatements =
|
||||
newWeakMap();
|
||||
public static final WeakMap<PreparedStatement, String> preparedStatements = newWeakMap();
|
||||
}
|
||||
|
|
|
@ -9,8 +9,6 @@ import static io.opentelemetry.javaagent.instrumentation.jdbc.JdbcUtils.connecti
|
|||
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.instrumentation.api.tracer.DatabaseClientTracer;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepth;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.db.SqlStatementInfo;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.db.SqlStatementSanitizer;
|
||||
import java.net.InetSocketAddress;
|
||||
|
@ -20,7 +18,7 @@ import java.sql.PreparedStatement;
|
|||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
public class JdbcTracer extends DatabaseClientTracer<DbInfo, SqlStatementInfo> {
|
||||
public class JdbcTracer extends DatabaseClientTracer<DbInfo, String, SqlStatementInfo> {
|
||||
private static final JdbcTracer TRACER = new JdbcTracer();
|
||||
|
||||
public static JdbcTracer tracer() {
|
||||
|
@ -32,6 +30,33 @@ public class JdbcTracer extends DatabaseClientTracer<DbInfo, SqlStatementInfo> {
|
|||
return "io.opentelemetry.javaagent.jdbc";
|
||||
}
|
||||
|
||||
public Context startSpan(Context parentContext, PreparedStatement statement) {
|
||||
return startSpan(parentContext, statement, JdbcMaps.preparedStatements.get(statement));
|
||||
}
|
||||
|
||||
public Context startSpan(Context parentContext, Statement statement, String query) {
|
||||
Connection connection = connectionFromStatement(statement);
|
||||
if (connection == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
DbInfo dbInfo = extractDbInfo(connection);
|
||||
|
||||
return startSpan(parentContext, dbInfo, query);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SqlStatementInfo sanitizeStatement(String statement) {
|
||||
return SqlStatementSanitizer.sanitize(statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String spanName(
|
||||
DbInfo connection, String statement, SqlStatementInfo sanitizedStatement) {
|
||||
return conventionSpanName(
|
||||
dbName(connection), sanitizedStatement.getOperation(), sanitizedStatement.getTable());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String dbSystem(DbInfo info) {
|
||||
return info.getSystem();
|
||||
|
@ -51,6 +76,11 @@ public class JdbcTracer extends DatabaseClientTracer<DbInfo, SqlStatementInfo> {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String dbConnectionString(DbInfo info) {
|
||||
return info.getShortUrl();
|
||||
}
|
||||
|
||||
// TODO find a way to implement
|
||||
@Override
|
||||
protected InetSocketAddress peerAddress(DbInfo dbInfo) {
|
||||
|
@ -58,58 +88,9 @@ public class JdbcTracer extends DatabaseClientTracer<DbInfo, SqlStatementInfo> {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String dbConnectionString(DbInfo info) {
|
||||
return info.getShortUrl();
|
||||
}
|
||||
|
||||
public CallDepth getCallDepth() {
|
||||
return CallDepthThreadLocalMap.getCallDepth(Statement.class);
|
||||
}
|
||||
|
||||
public Context startSpan(Context parentContext, PreparedStatement statement) {
|
||||
return startSpan(parentContext, statement, JdbcMaps.preparedStatements.get(statement));
|
||||
}
|
||||
|
||||
public Context startSpan(Context parentContext, Statement statement, String query) {
|
||||
return startSpan(parentContext, statement, SqlStatementSanitizer.sanitize(query));
|
||||
}
|
||||
|
||||
private Context startSpan(
|
||||
Context parentContext, Statement statement, SqlStatementInfo queryInfo) {
|
||||
Connection connection = connectionFromStatement(statement);
|
||||
if (connection == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
DbInfo dbInfo = extractDbInfo(connection);
|
||||
|
||||
return startSpan(parentContext, dbInfo, queryInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String normalizeQuery(SqlStatementInfo query) {
|
||||
return query.getFullStatement();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String spanName(DbInfo connection, SqlStatementInfo query, String normalizedQuery) {
|
||||
String dbName = dbName(connection);
|
||||
if (query.getOperation() == null) {
|
||||
return dbName == null ? DB_QUERY : dbName;
|
||||
}
|
||||
|
||||
StringBuilder name = new StringBuilder();
|
||||
name.append(query.getOperation()).append(' ');
|
||||
if (dbName != null) {
|
||||
name.append(dbName);
|
||||
if (query.getTable() != null) {
|
||||
name.append('.');
|
||||
}
|
||||
}
|
||||
if (query.getTable() != null) {
|
||||
name.append(query.getTable());
|
||||
}
|
||||
return name.toString();
|
||||
protected String dbStatement(
|
||||
DbInfo connection, String statement, SqlStatementInfo sanitizedStatement) {
|
||||
return sanitizedStatement.getFullStatement();
|
||||
}
|
||||
|
||||
private DbInfo extractDbInfo(Connection connection) {
|
||||
|
|
|
@ -15,7 +15,7 @@ import java.util.List;
|
|||
import redis.clients.jedis.Connection;
|
||||
import redis.clients.jedis.Protocol.Command;
|
||||
|
||||
public class JedisClientTracer extends DatabaseClientTracer<Connection, CommandWithArgs> {
|
||||
public class JedisClientTracer extends DatabaseClientTracer<Connection, CommandWithArgs, String> {
|
||||
private static final JedisClientTracer TRACER = new JedisClientTracer();
|
||||
|
||||
public static JedisClientTracer tracer() {
|
||||
|
@ -23,13 +23,14 @@ public class JedisClientTracer extends DatabaseClientTracer<Connection, CommandW
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String spanName(Connection connection, CommandWithArgs query, String normalizedQuery) {
|
||||
return query.getStringCommand();
|
||||
protected String sanitizeStatement(CommandWithArgs command) {
|
||||
return RedisCommandSanitizer.sanitize(command.getStringCommand(), command.getArgs());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String normalizeQuery(CommandWithArgs command) {
|
||||
return RedisCommandSanitizer.sanitize(command.getStringCommand(), command.getArgs());
|
||||
protected String spanName(
|
||||
Connection connection, CommandWithArgs command, String sanitizedStatement) {
|
||||
return command.getStringCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -47,6 +48,12 @@ public class JedisClientTracer extends DatabaseClientTracer<Connection, CommandW
|
|||
return new InetSocketAddress(connection.getHost(), connection.getPort());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String dbStatement(
|
||||
Connection connection, CommandWithArgs command, String sanitizedStatement) {
|
||||
return sanitizedStatement;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getInstrumentationName() {
|
||||
return "io.opentelemetry.javaagent.jedis";
|
||||
|
|
|
@ -17,7 +17,7 @@ import redis.clients.jedis.Connection;
|
|||
import redis.clients.jedis.Protocol;
|
||||
import redis.clients.jedis.commands.ProtocolCommand;
|
||||
|
||||
public class JedisClientTracer extends DatabaseClientTracer<Connection, CommandWithArgs> {
|
||||
public class JedisClientTracer extends DatabaseClientTracer<Connection, CommandWithArgs, String> {
|
||||
private static final JedisClientTracer TRACER = new JedisClientTracer();
|
||||
|
||||
public static JedisClientTracer tracer() {
|
||||
|
@ -25,13 +25,14 @@ public class JedisClientTracer extends DatabaseClientTracer<Connection, CommandW
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String spanName(Connection connection, CommandWithArgs query, String normalizedQuery) {
|
||||
return query.getStringCommand();
|
||||
protected String sanitizeStatement(CommandWithArgs command) {
|
||||
return RedisCommandSanitizer.sanitize(command.getStringCommand(), command.getArgs());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String normalizeQuery(CommandWithArgs command) {
|
||||
return RedisCommandSanitizer.sanitize(command.getStringCommand(), command.getArgs());
|
||||
protected String spanName(
|
||||
Connection connection, CommandWithArgs command, String sanitizedStatement) {
|
||||
return command.getStringCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -49,6 +50,12 @@ public class JedisClientTracer extends DatabaseClientTracer<Connection, CommandW
|
|||
return new InetSocketAddress(connection.getHost(), connection.getPort());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String dbStatement(
|
||||
Connection connection, CommandWithArgs command, String sanitizedStatement) {
|
||||
return sanitizedStatement;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getInstrumentationName() {
|
||||
return "io.opentelemetry.javaagent.jedis";
|
||||
|
|
|
@ -6,14 +6,28 @@
|
|||
package io.opentelemetry.javaagent.instrumentation.lettuce.v4_0;
|
||||
|
||||
import com.lambdaworks.redis.RedisURI;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.SpanBuilder;
|
||||
import io.opentelemetry.instrumentation.api.tracer.DatabaseClientTracer;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes.DbSystemValues;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
public abstract class LettuceAbstractDatabaseClientTracer<QUERY>
|
||||
extends DatabaseClientTracer<RedisURI, QUERY> {
|
||||
public abstract class LettuceAbstractDatabaseClientTracer<STATEMENT>
|
||||
extends DatabaseClientTracer<RedisURI, STATEMENT, String> {
|
||||
|
||||
@Override
|
||||
protected String spanName(RedisURI connection, STATEMENT statement, String operation) {
|
||||
return operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnection(SpanBuilder span, RedisURI connection) {
|
||||
if (connection != null && connection.getDatabase() != 0) {
|
||||
span.setAttribute(
|
||||
SemanticAttributes.DB_REDIS_DATABASE_INDEX, (long) connection.getDatabase());
|
||||
}
|
||||
super.onConnection(span, connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String dbSystem(RedisURI connection) {
|
||||
|
@ -26,11 +40,8 @@ public abstract class LettuceAbstractDatabaseClientTracer<QUERY>
|
|||
}
|
||||
|
||||
@Override
|
||||
public Span onConnection(Span span, RedisURI connection) {
|
||||
if (connection != null && connection.getDatabase() != 0) {
|
||||
span.setAttribute(SemanticAttributes.DB_REDIS_DATABASE_INDEX, connection.getDatabase());
|
||||
}
|
||||
return super.onConnection(span, connection);
|
||||
protected String dbStatement(RedisURI connection, STATEMENT statement, String operation) {
|
||||
return operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,7 +16,7 @@ public class LettuceConnectionDatabaseClientTracer
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String normalizeQuery(String command) {
|
||||
protected String sanitizeStatement(String command) {
|
||||
return command;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ public class LettuceDatabaseClientTracer
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String normalizeQuery(RedisCommand<?, ?, ?> command) {
|
||||
protected String sanitizeStatement(RedisCommand<?, ?, ?> command) {
|
||||
return command.getType().name();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
package io.opentelemetry.javaagent.instrumentation.lettuce.v5_0;
|
||||
|
||||
import io.lettuce.core.RedisURI;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.SpanBuilder;
|
||||
import io.opentelemetry.instrumentation.api.tracer.DatabaseClientTracer;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes.DbSystemValues;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
public abstract class LettuceAbstractDatabaseClientTracer<QUERY>
|
||||
extends DatabaseClientTracer<RedisURI, QUERY> {
|
||||
public abstract class LettuceAbstractDatabaseClientTracer<STATEMENT>
|
||||
extends DatabaseClientTracer<RedisURI, STATEMENT, String> {
|
||||
@Override
|
||||
protected String getInstrumentationName() {
|
||||
return "io.opentelemetry.javaagent.lettuce";
|
||||
|
@ -30,10 +30,17 @@ public abstract class LettuceAbstractDatabaseClientTracer<QUERY>
|
|||
}
|
||||
|
||||
@Override
|
||||
public Span onConnection(Span span, RedisURI connection) {
|
||||
public void onConnection(SpanBuilder span, RedisURI connection) {
|
||||
if (connection != null && connection.getDatabase() != 0) {
|
||||
span.setAttribute(SemanticAttributes.DB_REDIS_DATABASE_INDEX, connection.getDatabase());
|
||||
span.setAttribute(
|
||||
SemanticAttributes.DB_REDIS_DATABASE_INDEX, (long) connection.getDatabase());
|
||||
}
|
||||
return super.onConnection(span, connection);
|
||||
super.onConnection(span, connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String dbStatement(
|
||||
RedisURI connection, STATEMENT statement, String sanitizedStatement) {
|
||||
return sanitizedStatement;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,10 +37,11 @@ public class LettuceAsyncBiFunction<T, U extends Throwable, R>
|
|||
|
||||
@Override
|
||||
public R apply(T t, Throwable throwable) {
|
||||
if (throwable instanceof CancellationException) {
|
||||
if (throwable == null) {
|
||||
tracer().end(context);
|
||||
} else if (throwable instanceof CancellationException) {
|
||||
if (CAPTURE_EXPERIMENTAL_SPAN_ATTRIBUTES) {
|
||||
Span span = Span.fromContext(context);
|
||||
span.setAttribute("lettuce.command.cancelled", true);
|
||||
Span.fromContext(context).setAttribute("lettuce.command.cancelled", true);
|
||||
}
|
||||
tracer().end(context);
|
||||
} else {
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.lettuce.v5_0;
|
||||
|
||||
import io.lettuce.core.RedisURI;
|
||||
|
||||
public class LettuceConnectionDatabaseClientTracer
|
||||
extends LettuceAbstractDatabaseClientTracer<String> {
|
||||
private static final LettuceConnectionDatabaseClientTracer TRACER =
|
||||
|
@ -15,7 +17,12 @@ public class LettuceConnectionDatabaseClientTracer
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String normalizeQuery(String query) {
|
||||
return query;
|
||||
protected String sanitizeStatement(String command) {
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String spanName(RedisURI connection, String command, String ignored) {
|
||||
return command;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,13 +21,7 @@ public class LettuceDatabaseClientTracer
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String spanName(
|
||||
RedisURI connection, RedisCommand<?, ?, ?> query, String normalizedQuery) {
|
||||
return LettuceInstrumentationUtil.getCommandName(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String normalizeQuery(RedisCommand<?, ?, ?> redisCommand) {
|
||||
protected String sanitizeStatement(RedisCommand<?, ?, ?> redisCommand) {
|
||||
String command = LettuceInstrumentationUtil.getCommandName(redisCommand);
|
||||
List<String> args =
|
||||
redisCommand.getArgs() == null
|
||||
|
@ -35,4 +29,10 @@ public class LettuceDatabaseClientTracer
|
|||
: LettuceArgSplitter.splitArgs(redisCommand.getArgs().toCommandString());
|
||||
return RedisCommandSanitizer.sanitize(command, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String spanName(
|
||||
RedisURI connection, RedisCommand<?, ?, ?> command, String sanitizedStatement) {
|
||||
return LettuceInstrumentationUtil.getCommandName(command);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import static java.util.Arrays.asList;
|
|||
import com.mongodb.ServerAddress;
|
||||
import com.mongodb.connection.ConnectionDescription;
|
||||
import com.mongodb.event.CommandStartedEvent;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.SpanBuilder;
|
||||
import io.opentelemetry.instrumentation.api.tracer.DatabaseClientTracer;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes.DbSystemValues;
|
||||
|
@ -20,7 +20,6 @@ import java.lang.reflect.Method;
|
|||
import java.net.InetSocketAddress;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
@ -30,7 +29,8 @@ import org.bson.BsonValue;
|
|||
import org.bson.json.JsonWriter;
|
||||
import org.bson.json.JsonWriterSettings;
|
||||
|
||||
public class MongoClientTracer extends DatabaseClientTracer<CommandStartedEvent, BsonDocument> {
|
||||
public class MongoClientTracer
|
||||
extends DatabaseClientTracer<CommandStartedEvent, BsonDocument, String> {
|
||||
private static final MongoClientTracer TRACER = new MongoClientTracer();
|
||||
|
||||
private final int maxNormalizedQueryLength;
|
||||
|
@ -54,19 +54,34 @@ public class MongoClientTracer extends DatabaseClientTracer<CommandStartedEvent,
|
|||
return "io.opentelemetry.javaagent.mongo";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String sanitizeStatement(BsonDocument command) {
|
||||
StringWriter stringWriter = new StringWriter(128);
|
||||
writeScrubbed(command, new JsonWriter(stringWriter, jsonWriterSettings), true);
|
||||
// If using MongoDB driver >= 3.7, the substring invocation will be a no-op due to use of
|
||||
// JsonWriterSettings.Builder.maxLength in the static initializer for JSON_WRITER_SETTINGS
|
||||
return stringWriter
|
||||
.getBuffer()
|
||||
.substring(0, Math.min(maxNormalizedQueryLength, stringWriter.getBuffer().length()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String spanName(CommandStartedEvent event, BsonDocument document, String normalizedQuery) {
|
||||
return conventionSpanName(dbName(event), event.getCommandName(), collectionName(event));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String dbSystem(CommandStartedEvent event) {
|
||||
return DbSystemValues.MONGODB;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Span onConnection(Span span, CommandStartedEvent event) {
|
||||
span.setAttribute(SemanticAttributes.DB_OPERATION, event.getCommandName());
|
||||
protected void onConnection(SpanBuilder span, CommandStartedEvent event) {
|
||||
String collection = collectionName(event);
|
||||
if (collection != null) {
|
||||
span.setAttribute(SemanticAttributes.DB_MONGODB_COLLECTION, collection);
|
||||
}
|
||||
return super.onConnection(span, event);
|
||||
super.onConnection(span, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -74,41 +89,6 @@ public class MongoClientTracer extends DatabaseClientTracer<CommandStartedEvent,
|
|||
return event.getDatabaseName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InetSocketAddress peerAddress(CommandStartedEvent event) {
|
||||
if (event.getConnectionDescription() != null
|
||||
&& event.getConnectionDescription().getServerAddress() != null) {
|
||||
return event.getConnectionDescription().getServerAddress().getSocketAddress();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String spanName(CommandStartedEvent event, BsonDocument document, String normalizedQuery) {
|
||||
String dbName = dbName(event);
|
||||
if (event.getCommandName() == null) {
|
||||
return dbName == null ? DB_QUERY : dbName;
|
||||
}
|
||||
|
||||
String collectionName = collectionName(event);
|
||||
StringBuilder name = new StringBuilder();
|
||||
name.append(event.getCommandName());
|
||||
if (dbName != null || collectionName != null) {
|
||||
name.append(' ');
|
||||
}
|
||||
if (dbName != null) {
|
||||
name.append(dbName);
|
||||
if (collectionName != null) {
|
||||
name.append('.');
|
||||
}
|
||||
}
|
||||
if (collectionName != null) {
|
||||
name.append(collectionName);
|
||||
}
|
||||
return name.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String dbConnectionString(CommandStartedEvent event) {
|
||||
ConnectionDescription connectionDescription = event.getConnectionDescription();
|
||||
|
@ -126,6 +106,28 @@ public class MongoClientTracer extends DatabaseClientTracer<CommandStartedEvent,
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InetSocketAddress peerAddress(CommandStartedEvent event) {
|
||||
if (event.getConnectionDescription() != null
|
||||
&& event.getConnectionDescription().getServerAddress() != null) {
|
||||
return event.getConnectionDescription().getServerAddress().getSocketAddress();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String dbStatement(
|
||||
CommandStartedEvent event, BsonDocument command, String sanitizedStatement) {
|
||||
return sanitizedStatement;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String dbOperation(
|
||||
CommandStartedEvent event, BsonDocument command, String sanitizedStatement) {
|
||||
return event.getCommandName();
|
||||
}
|
||||
|
||||
private static final Method IS_TRUNCATED_METHOD;
|
||||
|
||||
static {
|
||||
|
@ -136,13 +138,6 @@ public class MongoClientTracer extends DatabaseClientTracer<CommandStartedEvent,
|
|||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* The values of these mongo fields will not be scrubbed out. This allows the non-sensitive
|
||||
* collection names to be captured.
|
||||
*/
|
||||
private static final List<String> UNSCRUBBED_FIELDS =
|
||||
asList("ordered", "insert", "count", "find", "create");
|
||||
|
||||
private JsonWriterSettings createJsonWriterSettings(int maxNormalizedQueryLength) {
|
||||
JsonWriterSettings settings = null;
|
||||
try {
|
||||
|
@ -192,17 +187,6 @@ public class MongoClientTracer extends DatabaseClientTracer<CommandStartedEvent,
|
|||
return settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String normalizeQuery(BsonDocument command) {
|
||||
StringWriter stringWriter = new StringWriter(128);
|
||||
writeScrubbed(command, new JsonWriter(stringWriter, jsonWriterSettings), true);
|
||||
// If using MongoDB driver >= 3.7, the substring invocation will be a no-op due to use of
|
||||
// JsonWriterSettings.Builder.maxLength in the static initializer for JSON_WRITER_SETTINGS
|
||||
return stringWriter
|
||||
.getBuffer()
|
||||
.substring(0, Math.min(maxNormalizedQueryLength, stringWriter.getBuffer().length()));
|
||||
}
|
||||
|
||||
private static final String HIDDEN_CHAR = "?";
|
||||
|
||||
private static boolean writeScrubbed(BsonDocument origin, JsonWriter writer, boolean isRoot) {
|
||||
|
|
|
@ -3,10 +3,9 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import com.mongodb.event.CommandStartedEvent
|
||||
|
||||
import static java.util.Arrays.asList
|
||||
|
||||
import com.mongodb.event.CommandStartedEvent
|
||||
import io.opentelemetry.javaagent.instrumentation.mongo.MongoClientTracer
|
||||
import org.bson.BsonArray
|
||||
import org.bson.BsonDocument
|
||||
|
@ -15,21 +14,21 @@ import org.bson.BsonString
|
|||
import spock.lang.Specification
|
||||
|
||||
class MongoClientTracerTest extends Specification {
|
||||
def 'should normalize queries to json'() {
|
||||
def 'should sanitize statements to json'() {
|
||||
setup:
|
||||
def tracer = new MongoClientTracer()
|
||||
|
||||
expect:
|
||||
normalizeQueryAcrossVersions(tracer,
|
||||
sanitizeStatementAcrossVersions(tracer,
|
||||
new BsonDocument("cmd", new BsonInt32(1))) ==
|
||||
'{"cmd": "?"}'
|
||||
|
||||
normalizeQueryAcrossVersions(tracer,
|
||||
sanitizeStatementAcrossVersions(tracer,
|
||||
new BsonDocument("cmd", new BsonInt32(1))
|
||||
.append("sub", new BsonDocument("a", new BsonInt32(1)))) ==
|
||||
'{"cmd": "?", "sub": {"a": "?"}}'
|
||||
|
||||
normalizeQueryAcrossVersions(tracer,
|
||||
sanitizeStatementAcrossVersions(tracer,
|
||||
new BsonDocument("cmd", new BsonInt32(1))
|
||||
.append("sub", new BsonArray(asList(new BsonInt32(1))))) ==
|
||||
'{"cmd": "?", "sub": ["?"]}'
|
||||
|
@ -40,7 +39,7 @@ class MongoClientTracerTest extends Specification {
|
|||
def tracer = new MongoClientTracer()
|
||||
|
||||
expect:
|
||||
normalizeQueryAcrossVersions(tracer,
|
||||
sanitizeStatementAcrossVersions(tracer,
|
||||
new BsonDocument("cmd", new BsonString("c"))
|
||||
.append("f", new BsonString("c"))
|
||||
.append("sub", new BsonString("c"))) ==
|
||||
|
@ -51,7 +50,7 @@ class MongoClientTracerTest extends Specification {
|
|||
setup:
|
||||
def tracer = new MongoClientTracer(20)
|
||||
|
||||
def normalized = normalizeQueryAcrossVersions(tracer,
|
||||
def normalized = sanitizeStatementAcrossVersions(tracer,
|
||||
new BsonDocument("cmd", new BsonString("c"))
|
||||
.append("f1", new BsonString("c1"))
|
||||
.append("f2", new BsonString("c2")))
|
||||
|
@ -64,7 +63,7 @@ class MongoClientTracerTest extends Specification {
|
|||
setup:
|
||||
def tracer = new MongoClientTracer(27)
|
||||
|
||||
def normalized = normalizeQueryAcrossVersions(tracer,
|
||||
def normalized = sanitizeStatementAcrossVersions(tracer,
|
||||
new BsonDocument("cmd", new BsonString("c"))
|
||||
.append("f1", new BsonArray(Arrays.asList(new BsonString("c1"), new BsonString("c2"))))
|
||||
.append("f2", new BsonString("c3")))
|
||||
|
@ -89,11 +88,11 @@ class MongoClientTracerTest extends Specification {
|
|||
command = "listDatabases"
|
||||
}
|
||||
|
||||
def normalizeQueryAcrossVersions(MongoClientTracer tracer, BsonDocument query) {
|
||||
return normalizeAcrossVersions(tracer.normalizeQuery(query))
|
||||
def sanitizeStatementAcrossVersions(MongoClientTracer tracer, BsonDocument query) {
|
||||
return sanitizeAcrossVersions(tracer.sanitizeStatement(query))
|
||||
}
|
||||
|
||||
def normalizeAcrossVersions(String json) {
|
||||
def sanitizeAcrossVersions(String json) {
|
||||
json = json.replaceAll('\\{ ', '{')
|
||||
json = json.replaceAll(' }', '}')
|
||||
json = json.replaceAll(' :', ':')
|
||||
|
|
|
@ -11,7 +11,7 @@ import java.net.InetSocketAddress;
|
|||
import redis.RedisCommand;
|
||||
|
||||
public class RediscalaClientTracer
|
||||
extends DatabaseClientTracer<RedisCommand<?, ?>, RedisCommand<?, ?>> {
|
||||
extends DatabaseClientTracer<RedisCommand<?, ?>, RedisCommand<?, ?>, String> {
|
||||
|
||||
private static final RediscalaClientTracer TRACER = new RediscalaClientTracer();
|
||||
|
||||
|
@ -20,20 +20,32 @@ public class RediscalaClientTracer
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String normalizeQuery(RedisCommand redisCommand) {
|
||||
protected String sanitizeStatement(RedisCommand<?, ?> redisCommand) {
|
||||
return spanNameForClass(redisCommand.getClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String dbSystem(RedisCommand redisCommand) {
|
||||
protected String spanName(
|
||||
RedisCommand<?, ?> connection, RedisCommand<?, ?> statement, String operation) {
|
||||
return operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String dbSystem(RedisCommand<?, ?> redisCommand) {
|
||||
return DbSystemValues.REDIS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InetSocketAddress peerAddress(RedisCommand redisCommand) {
|
||||
protected InetSocketAddress peerAddress(RedisCommand<?, ?> redisCommand) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String dbStatement(
|
||||
RedisCommand<?, ?> connection, RedisCommand<?, ?> command, String operation) {
|
||||
return operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getInstrumentationName() {
|
||||
return "io.opentelemetry.javaagent.rediscala";
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.redisson;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.Channel;
|
||||
import io.opentelemetry.instrumentation.api.tracer.DatabaseClientTracer;
|
||||
|
@ -13,11 +16,13 @@ import io.opentelemetry.semconv.trace.attributes.SemanticAttributes.DbSystemValu
|
|||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.redisson.client.RedisConnection;
|
||||
import org.redisson.client.protocol.CommandData;
|
||||
import org.redisson.client.protocol.CommandsData;
|
||||
|
||||
public class RedissonClientTracer extends DatabaseClientTracer<RedisConnection, Object> {
|
||||
public class RedissonClientTracer
|
||||
extends DatabaseClientTracer<RedisConnection, Object, List<String>> {
|
||||
private static final String UNKNOWN_COMMAND = "Redis Command";
|
||||
|
||||
private static final RedissonClientTracer TRACER = new RedissonClientTracer();
|
||||
|
@ -27,22 +32,24 @@ public class RedissonClientTracer extends DatabaseClientTracer<RedisConnection,
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String spanName(RedisConnection connection, Object query, String normalizedQuery) {
|
||||
if (query instanceof CommandsData) {
|
||||
List<CommandData<?, ?>> commands = ((CommandsData) query).getCommands();
|
||||
StringBuilder commandStrings = new StringBuilder();
|
||||
for (CommandData<?, ?> commandData : commands) {
|
||||
commandStrings.append(commandData.getCommand().getName()).append(";");
|
||||
}
|
||||
if (commandStrings.length() > 0) {
|
||||
commandStrings.deleteCharAt(commandStrings.length() - 1);
|
||||
}
|
||||
return commandStrings.toString();
|
||||
} else if (query instanceof CommandData) {
|
||||
return ((CommandData<?, ?>) query).getCommand().getName();
|
||||
protected String spanName(
|
||||
RedisConnection connection, Object ignored, List<String> sanitizedStatements) {
|
||||
switch (sanitizedStatements.size()) {
|
||||
case 0:
|
||||
return UNKNOWN_COMMAND;
|
||||
// optimize for the most common case
|
||||
case 1:
|
||||
return getCommandName(sanitizedStatements.get(0));
|
||||
default:
|
||||
return sanitizedStatements.stream()
|
||||
.map(this::getCommandName)
|
||||
.collect(Collectors.joining(";"));
|
||||
}
|
||||
}
|
||||
|
||||
return UNKNOWN_COMMAND;
|
||||
private String getCommandName(String statement) {
|
||||
int spacePos = statement.indexOf(' ');
|
||||
return spacePos == -1 ? statement : statement.substring(0, spacePos);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -51,22 +58,15 @@ public class RedissonClientTracer extends DatabaseClientTracer<RedisConnection,
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String normalizeQuery(Object command) {
|
||||
protected List<String> sanitizeStatement(Object command) {
|
||||
// get command
|
||||
if (command instanceof CommandsData) {
|
||||
List<CommandData<?, ?>> commands = ((CommandsData) command).getCommands();
|
||||
StringBuilder commandStrings = new StringBuilder();
|
||||
for (CommandData<?, ?> commandData : commands) {
|
||||
commandStrings.append(normalizeSingleCommand(commandData)).append(";");
|
||||
}
|
||||
if (commandStrings.length() > 0) {
|
||||
commandStrings.deleteCharAt(commandStrings.length() - 1);
|
||||
}
|
||||
return commandStrings.toString();
|
||||
return commands.stream().map(this::normalizeSingleCommand).collect(Collectors.toList());
|
||||
} else if (command instanceof CommandData) {
|
||||
return normalizeSingleCommand((CommandData<?, ?>) command);
|
||||
return singletonList(normalizeSingleCommand((CommandData<?, ?>) command));
|
||||
}
|
||||
return UNKNOWN_COMMAND;
|
||||
return emptyList();
|
||||
}
|
||||
|
||||
private String normalizeSingleCommand(CommandData<?, ?> command) {
|
||||
|
@ -110,4 +110,18 @@ public class RedissonClientTracer extends DatabaseClientTracer<RedisConnection,
|
|||
InetSocketAddress remoteAddress = (InetSocketAddress) channel.remoteAddress();
|
||||
return remoteAddress.getHostString() + ":" + remoteAddress.getPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String dbStatement(
|
||||
RedisConnection connection, Object ignored, List<String> sanitizedStatements) {
|
||||
switch (sanitizedStatements.size()) {
|
||||
case 0:
|
||||
return UNKNOWN_COMMAND;
|
||||
// optimize for the most common case
|
||||
case 1:
|
||||
return sanitizedStatements.get(0);
|
||||
default:
|
||||
return String.join(";", sanitizedStatements);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,11 @@ public abstract class CompletionListener<T> {
|
|||
}
|
||||
|
||||
protected void closeSyncSpan(Throwable thrown) {
|
||||
tracer().endExceptionally(context, thrown);
|
||||
if (thrown == null) {
|
||||
tracer().end(context);
|
||||
} else {
|
||||
tracer().endExceptionally(context, thrown);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void processResult(Span span, T future)
|
||||
|
|
|
@ -5,19 +5,33 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.spymemcached;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.instrumentation.api.tracer.DatabaseClientTracer;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import java.net.InetSocketAddress;
|
||||
import net.spy.memcached.MemcachedConnection;
|
||||
|
||||
public class MemcacheClientTracer extends DatabaseClientTracer<MemcachedConnection, String> {
|
||||
public class MemcacheClientTracer
|
||||
extends DatabaseClientTracer<MemcachedConnection, String, String> {
|
||||
private static final MemcacheClientTracer TRACER = new MemcacheClientTracer();
|
||||
|
||||
public static MemcacheClientTracer tracer() {
|
||||
return TRACER;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String sanitizeStatement(String methodName) {
|
||||
char[] chars =
|
||||
methodName
|
||||
.replaceFirst("^async", "")
|
||||
// 'CAS' name is special, we have to lowercase whole name
|
||||
.replaceFirst("^CAS", "cas")
|
||||
.toCharArray();
|
||||
|
||||
// Lowercase first letter
|
||||
chars[0] = Character.toLowerCase(chars[0]);
|
||||
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String dbSystem(MemcachedConnection memcachedConnection) {
|
||||
return "memcached";
|
||||
|
@ -29,23 +43,9 @@ public class MemcacheClientTracer extends DatabaseClientTracer<MemcachedConnecti
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void onStatement(Span span, String statement) {
|
||||
span.setAttribute(SemanticAttributes.DB_OPERATION, statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String normalizeQuery(String query) {
|
||||
char[] chars =
|
||||
query
|
||||
.replaceFirst("^async", "")
|
||||
// 'CAS' name is special, we have to lowercase whole name
|
||||
.replaceFirst("^CAS", "cas")
|
||||
.toCharArray();
|
||||
|
||||
// Lowercase first letter
|
||||
chars[0] = Character.toLowerCase(chars[0]);
|
||||
|
||||
return new String(chars);
|
||||
protected String dbOperation(
|
||||
MemcachedConnection connection, String methodName, String operation) {
|
||||
return operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue