Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom Span Name #4

Merged
merged 15 commits into from
Jul 5, 2018
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ MongoClient mongoClient = new TracingAsyncMongoClient(tracer, ...);

```

### Mongo Span Name
By default, span names are set to the operation performed by the Mongo client. To customize the span name, provide a MongoSpanNameProvider to the client that alters the span name. If a provder is not provided, the span name will remain the default.

```java
//Create TracingMongoClient with custom span name
TracingMongoClient client = new TracingMongoClient(tracer, replicaSetAddresses, credentials, clientOptions, new PrefixSpanNameProvider("mongo."));
Document doc = new Document();
client.getDatabase("db").getCollection("collection).insertOne(doc);
//Span name is now set to "mongo.insert"
```

[ci-img]: https://travis-ci.org/opentracing-contrib/java-mongo-driver.svg?branch=master
[ci]: https://travis-ci.org/opentracing-contrib/java-mongo-driver
[maven-img]: https://img.shields.io/maven-central/v/io.opentracing.contrib/opentracing-mongo-driver.svg
Expand Down
7 changes: 7 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@
<version>${mongo.driver.version}</version>
</dependency>

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.19.0</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-async</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,6 @@
*/
package io.opentracing.contrib.mongo;

import com.mongodb.event.CommandFailedEvent;
import com.mongodb.event.CommandListener;
import com.mongodb.event.CommandStartedEvent;
import com.mongodb.event.CommandSucceededEvent;
import io.opentracing.Span;
import io.opentracing.Tracer;
import io.opentracing.tag.Tags;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.Inet4Address;
Expand All @@ -29,20 +22,39 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.mongodb.event.CommandFailedEvent;
import com.mongodb.event.CommandListener;
import com.mongodb.event.CommandStartedEvent;
import com.mongodb.event.CommandSucceededEvent;

import io.opentracing.Span;
import io.opentracing.Tracer;
import io.opentracing.contrib.mongo.providers.MongoSpanNameProvider;
import io.opentracing.contrib.mongo.providers.NoopSpanNameProvider;
import io.opentracing.tag.Tags;

/**
* In Async Mongo driver methods of this Listener run in different threads therefore cache is used
*/
public class TracingCommandListener implements CommandListener {

static final String COMPONENT_NAME = "java-mongo";
private final Tracer tracer;

private final MongoSpanNameProvider mongoSpanNameProvider;
/**
* Cache for (request id, span) pairs
*/
private final Map<Integer, Span> cache = new ConcurrentHashMap<>();

TracingCommandListener(Tracer tracer) {
this.tracer = tracer;
this.mongoSpanNameProvider = new NoopSpanNameProvider();
}

TracingCommandListener(Tracer tracer, MongoSpanNameProvider customNameProvider) {
this.tracer = tracer;
this.mongoSpanNameProvider = customNameProvider;
}

@Override
Expand All @@ -68,8 +80,8 @@ public void commandFailed(CommandFailedEvent event) {
}
}

private Span buildSpan(CommandStartedEvent event) {
Tracer.SpanBuilder spanBuilder = tracer.buildSpan(event.getCommandName())
Span buildSpan(CommandStartedEvent event) {
Tracer.SpanBuilder spanBuilder = tracer.buildSpan(mongoSpanNameProvider.generateName(event.getCommandName()))
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT);

Span span = spanBuilder.start();
Expand Down
22 changes: 18 additions & 4 deletions src/main/java/io/opentracing/contrib/mongo/TracingMongoClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,19 @@
*/
package io.opentracing.contrib.mongo;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoClientURI;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoDriverInformation;

import io.opentracing.Tracer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import io.opentracing.contrib.mongo.providers.MongoSpanNameProvider;

/**
* Tracing Mongo Client
Expand Down Expand Up @@ -71,7 +73,6 @@ public TracingMongoClient(Tracer tracer, final ServerAddress addr,
tracer)).build());
}


public TracingMongoClient(Tracer tracer, final ServerAddress addr,
final MongoCredential credential, final MongoClientOptions options) {
super(addr, credential,
Expand All @@ -94,6 +95,12 @@ public TracingMongoClient(Tracer tracer, final List<ServerAddress> seeds,
tracer)).build());
}

public TracingMongoClient(Tracer tracer, final List<ServerAddress> seeds,
final MongoClientOptions options, MongoSpanNameProvider spanNameProvider) {
super(seeds, MongoClientOptions.builder(options).addCommandListener(new TracingCommandListener(
tracer, spanNameProvider)).build());
}

@Deprecated
public TracingMongoClient(Tracer tracer, final List<ServerAddress> seeds,
final List<MongoCredential> credentialsList, final MongoClientOptions options) {
Expand All @@ -102,6 +109,13 @@ public TracingMongoClient(Tracer tracer, final List<ServerAddress> seeds,
tracer)).build());
}

public TracingMongoClient(Tracer tracer, final List<ServerAddress> seeds,
final List<MongoCredential> credentialsList, final MongoClientOptions options, MongoSpanNameProvider spanNameProvider) {
super(seeds, credentialsList,
MongoClientOptions.builder(options).addCommandListener(new TracingCommandListener(
tracer, spanNameProvider)).build());
}

public TracingMongoClient(Tracer tracer, final List<ServerAddress> seeds,
final MongoCredential credential, final MongoClientOptions options) {
super(seeds, credential,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2017-2018 The OpenTracing Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package io.opentracing.contrib.mongo.providers;

public interface MongoSpanNameProvider {

String NO_OPERATION = "unknown";

String generateName(final String operationName);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright 2017-2018 The OpenTracing Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package io.opentracing.contrib.mongo.providers;

public class NoopSpanNameProvider implements MongoSpanNameProvider {

@Override
public String generateName(String operationName) {
return ((operationName == null) ? NO_OPERATION : operationName);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2017-2018 The OpenTracing Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package io.opentracing.contrib.mongo.providers;

public class PrefixSpanNameProvider implements MongoSpanNameProvider {

private static final String NO_OPERATION = "unknown";

private final String prefix;

public PrefixSpanNameProvider(String prefix) {
this.prefix = prefix;
}

@Override
public String generateName(String operationName) {
return ((prefix == null) ? "" : prefix)
+ ((operationName == null) ? NO_OPERATION : operationName);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright 2017-2018 The OpenTracing Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package io.opentracing.contrib.mongo;

import org.bson.BsonDocument;
import org.junit.Before;
import org.junit.Test;

import com.mongodb.ServerAddress;
import com.mongodb.connection.ClusterId;
import com.mongodb.connection.ConnectionDescription;
import com.mongodb.connection.ServerId;
import com.mongodb.event.CommandStartedEvent;

import io.opentracing.Span;
import io.opentracing.Tracer;
import io.opentracing.contrib.mongo.providers.MongoSpanNameProvider;
import io.opentracing.contrib.mongo.providers.NoopSpanNameProvider;
import io.opentracing.contrib.mongo.providers.PrefixSpanNameProvider;
import io.opentracing.mock.MockSpan;
import io.opentracing.mock.MockTracer;

import static org.junit.Assert.assertEquals;

public class TracingCommandListenerTest {

private Tracer tracer = new MockTracer();

private MongoSpanNameProvider prefixSpanName;

private MongoSpanNameProvider operationName;
private TracingCommandListener withProvider;
private TracingCommandListener withoutProvider;
private CommandStartedEvent event;
private Span span;

@Before
public void setUp() {
operationName = new NoopSpanNameProvider();
prefixSpanName = new PrefixSpanNameProvider("mongo.");
withProvider = new TracingCommandListener(tracer, prefixSpanName);
withoutProvider = new TracingCommandListener(tracer);
event = new CommandStartedEvent(
1
, new ConnectionDescription(new ServerId(new ClusterId(), new ServerAddress()))
, "databaseName"
, "commandName"
, new BsonDocument()
);
}

@Test
public void testDefault() {
span = withoutProvider.buildSpan(event);
MockSpan mockSpan = (MockSpan) span;
assertEquals(mockSpan.operationName(), operationName.generateName(event.getCommandName()));
}

@Test
public void testPrefix() {
span = withProvider.buildSpan(event);
MockSpan mockSpan = (MockSpan) span;
assertEquals(mockSpan.operationName(), prefixSpanName.generateName(event.getCommandName()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2017-2018 The OpenTracing Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package io.opentracing.contrib.mongo.providers;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class NoopSpanNameProviderTest {

private final MongoSpanNameProvider provider = new NoopSpanNameProvider();

@Test
public void testOperationNameExists() {
assertEquals("insert", provider.generateName("insert"));
}

@Test
public void testNullOperationName() {
assertEquals("unknown", provider.generateName(null));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2017-2018 The OpenTracing Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package io.opentracing.contrib.mongo.providers;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class PrefixSpanNameProviderTest {

private final MongoSpanNameProvider provider = new PrefixSpanNameProvider("mongo.");

@Test
public void testOperationNameExists() {
assertEquals("mongo.insert", provider.generateName("insert"));
}

@Test
public void testNullOperationName() {
assertEquals("mongo.unknown", provider.generateName(null));
}

@Test
public void testNullPrefixName() {
assertEquals("insert", new PrefixSpanNameProvider(null).generateName("insert"));
}
}