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:
Mateusz Rzeszutek 2021-02-26 15:36:24 +01:00 committed by GitHub
parent 605485b998
commit fd55ce226a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 430 additions and 312 deletions

View File

@ -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;
}
}

View File

@ -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) {

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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";

View File

@ -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

View File

@ -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";

View File

@ -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);
}
}
}

View File

@ -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();
}

View File

@ -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) {

View File

@ -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";

View File

@ -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";

View File

@ -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

View File

@ -16,7 +16,7 @@ public class LettuceConnectionDatabaseClientTracer
}
@Override
protected String normalizeQuery(String command) {
protected String sanitizeStatement(String command) {
return command;
}
}

View File

@ -17,7 +17,7 @@ public class LettuceDatabaseClientTracer
}
@Override
protected String normalizeQuery(RedisCommand<?, ?, ?> command) {
protected String sanitizeStatement(RedisCommand<?, ?, ?> command) {
return command.getType().name();
}
}

View File

@ -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;
}
}

View File

@ -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 {

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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(' :', ':')

View File

@ -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";

View File

@ -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);
}
}
}

View File

@ -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)

View File

@ -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