Skip to content

Commit

Permalink
Added tracing support for JedisSentinelPool (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
avnandu authored and malafeev committed Jul 25, 2018
1 parent a671c1a commit 0330ee5
Show file tree
Hide file tree
Showing 3 changed files with 298 additions and 0 deletions.
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ Tracer tracer = ...

```

### Span Name
By default, span names are set to the operation performed by the Jedis object. To customize the span name, provide a Function to the Jedis object that alters the span name. If a function is not provided, the span name will remain the default. Refer to the RedisSpanNameProvider class for a function that prefixes the operation name.
```java
//Create Tracing Jedis with custom span name
Jedis jedis = new TracingJedis(tracer, false, RedisSpanNameProvider.PREFIX_OPERATION_NAME("redis.");
jedis.set("foo", "bar");
//Span name is now set to "redis.set"

```

### Jedis
```java

Expand Down Expand Up @@ -81,6 +91,18 @@ try (Jedis jedis = pool.getResource()) {
}
```

### Jedis Sentinel Pool
```java
// Create Tracing Jedis Sentinel Pool
JedisSentinelPool pool = new TracingJedisSentinelPool(tracer, false, MASTER_NAME, sentinels, poolConfig);

try (Jedis jedis = pool.getResource()) {
// jedis will be automatically closed and returned to the pool at the end of "try" block
jedis.set("foo", "bar"));
String value = jedis.get("foo"));
}
```

### Jedis Span Name
By default, span names are set to the operation performed by the Jedis object. To customize the span name, provide a Function to the Jedis object that alters the span name. If a function is not provided, the span name will remain the default. Refer to the RedisSpanNameProvider class for a function that prefixes the operation name.
```java
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
/*
* 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.redis.jedis;

import java.util.Set;
import java.util.function.Function;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import io.opentracing.Tracer;
import io.opentracing.contrib.redis.common.RedisSpanNameProvider;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.Protocol;

public class TracingJedisSentinelPool extends JedisSentinelPool {

private final Tracer tracer;
private final boolean traceWithActiveSpanOnly;
private Function<String, String> spanNameProvider;

public TracingJedisSentinelPool(Tracer tracer, boolean traceWithActiveSpanOnly, String masterName, Set<String> sentinels,
final GenericObjectPoolConfig poolConfig) {
super(masterName, sentinels, poolConfig, Protocol.DEFAULT_TIMEOUT, null,
Protocol.DEFAULT_DATABASE);
this.tracer = tracer;
this.traceWithActiveSpanOnly = traceWithActiveSpanOnly;
spanNameProvider = RedisSpanNameProvider.OPERATION_NAME;
}

public TracingJedisSentinelPool(Tracer tracer, boolean traceWithActiveSpanOnly, String masterName, Set<String> sentinels) {
super(masterName, sentinels, new GenericObjectPoolConfig(), Protocol.DEFAULT_TIMEOUT, null,
Protocol.DEFAULT_DATABASE);
this.tracer = tracer;
this.traceWithActiveSpanOnly = traceWithActiveSpanOnly;
spanNameProvider = RedisSpanNameProvider.OPERATION_NAME;
}

public TracingJedisSentinelPool(Tracer tracer, boolean traceWithActiveSpanOnly, String masterName, Set<String> sentinels, String password) {
super(masterName, sentinels, new GenericObjectPoolConfig(), Protocol.DEFAULT_TIMEOUT, password);
this.tracer = tracer;
this.traceWithActiveSpanOnly = traceWithActiveSpanOnly;
spanNameProvider = RedisSpanNameProvider.OPERATION_NAME;
}

public TracingJedisSentinelPool(Tracer tracer, boolean traceWithActiveSpanOnly, String masterName, Set<String> sentinels,
final GenericObjectPoolConfig poolConfig, int timeout, final String password) {
super(masterName, sentinels, poolConfig, timeout, password, Protocol.DEFAULT_DATABASE);
this.tracer = tracer;
this.traceWithActiveSpanOnly = traceWithActiveSpanOnly;
spanNameProvider = RedisSpanNameProvider.OPERATION_NAME;
}

public TracingJedisSentinelPool(Tracer tracer, boolean traceWithActiveSpanOnly, String masterName, Set<String> sentinels,
final GenericObjectPoolConfig poolConfig, final int timeout) {
super(masterName, sentinels, poolConfig, timeout, null, Protocol.DEFAULT_DATABASE);
this.tracer = tracer;
this.traceWithActiveSpanOnly = traceWithActiveSpanOnly;
spanNameProvider = RedisSpanNameProvider.OPERATION_NAME;
}

public TracingJedisSentinelPool(Tracer tracer, boolean traceWithActiveSpanOnly, String masterName, Set<String> sentinels,
final GenericObjectPoolConfig poolConfig, final String password) {
super(masterName, sentinels, poolConfig, Protocol.DEFAULT_TIMEOUT, password);
this.tracer = tracer;
this.traceWithActiveSpanOnly = traceWithActiveSpanOnly;
spanNameProvider = RedisSpanNameProvider.OPERATION_NAME;
}

public TracingJedisSentinelPool(Tracer tracer, boolean traceWithActiveSpanOnly, String masterName, Set<String> sentinels,
final GenericObjectPoolConfig poolConfig, int timeout, final String password,
final int database) {
super(masterName, sentinels, poolConfig, timeout, timeout, password, database);
this.tracer = tracer;
this.traceWithActiveSpanOnly = traceWithActiveSpanOnly;
spanNameProvider = RedisSpanNameProvider.OPERATION_NAME;
}

public TracingJedisSentinelPool(Tracer tracer, boolean traceWithActiveSpanOnly, String masterName, Set<String> sentinels,
final GenericObjectPoolConfig poolConfig, int timeout, final String password,
final int database, Function<String, String> customSpanName) {
super(masterName, sentinels, poolConfig, timeout, timeout, password, database);
this.tracer = tracer;
this.traceWithActiveSpanOnly = traceWithActiveSpanOnly;
spanNameProvider = customSpanName;
}

public TracingJedisSentinelPool(Tracer tracer, boolean traceWithActiveSpanOnly, String masterName, Set<String> sentinels,
final GenericObjectPoolConfig poolConfig, int timeout, final String password,
final int database, final String clientName) {
super(masterName, sentinels, poolConfig, timeout, timeout, password, database, clientName);
this.tracer = tracer;
this.traceWithActiveSpanOnly = traceWithActiveSpanOnly;
spanNameProvider = RedisSpanNameProvider.OPERATION_NAME;
}

public TracingJedisSentinelPool(Tracer tracer, boolean traceWithActiveSpanOnly, String masterName, Set<String> sentinels,
final GenericObjectPoolConfig poolConfig, final int timeout, final int soTimeout,
final String password, final int database) {
super(masterName, sentinels, poolConfig, timeout, soTimeout, password, database, null);
this.tracer = tracer;
this.traceWithActiveSpanOnly = traceWithActiveSpanOnly;
spanNameProvider = RedisSpanNameProvider.OPERATION_NAME;
}

public TracingJedisSentinelPool(Tracer tracer, boolean traceWithActiveSpanOnly, String masterName, Set<String> sentinels,
final GenericObjectPoolConfig poolConfig, final int connectionTimeout, final int soTimeout,
final String password, final int database, final String clientName) {
super(masterName, sentinels, poolConfig, connectionTimeout, soTimeout, password, database, clientName);
this.tracer = tracer;
this.traceWithActiveSpanOnly = traceWithActiveSpanOnly;
spanNameProvider = RedisSpanNameProvider.OPERATION_NAME;
}

public TracingJedisSentinelPool(Tracer tracer, boolean traceWithActiveSpanOnly, String masterName, Set<String> sentinels,
final GenericObjectPoolConfig poolConfig, final int connectionTimeout, final int soTimeout,
final String password, final int database, final String clientName, Function<String, String> customSpanName) {
super(masterName, sentinels, poolConfig, connectionTimeout, soTimeout, password, database, clientName);
this.tracer = tracer;
this.traceWithActiveSpanOnly = traceWithActiveSpanOnly;
spanNameProvider = customSpanName;
}

@Override
public Jedis getResource() {
Jedis resource = super.getResource();
return new TracingJedisWrapper(resource, tracer, traceWithActiveSpanOnly);
}

@Override
public void returnBrokenResource(final Jedis resource) {
super.returnBrokenResource(unwrapResource(resource));
}

@Override
public void returnResource(final Jedis resource) {
super.returnResource(unwrapResource(resource));
}

private Jedis unwrapResource(Jedis resource) {
return (resource instanceof TracingJedisSentinelPool.TracingJedisWrapper)
? ((TracingJedisSentinelPool.TracingJedisWrapper) resource).getWrapped()
: resource;
}


private class TracingJedisWrapper extends TracingJedis {
private final Jedis wrapped;

public TracingJedisWrapper(Jedis jedis, Tracer tracer, boolean traceWithActiveSpanOnly) {
super(tracer, traceWithActiveSpanOnly, spanNameProvider);
this.client = jedis.getClient();
this.wrapped = jedis;
}

@Override
public void close() {
super.close();
wrapped.close();
}

public Jedis getWrapped() {
return wrapped;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* 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.redis.jedis;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import io.opentracing.mock.MockSpan;
import io.opentracing.mock.MockTracer;
import io.opentracing.util.ThreadLocalScopeManager;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.Protocol;
import redis.embedded.RedisSentinel;
import redis.embedded.RedisServer;

import static org.junit.Assert.assertEquals;

public class TracingJedisSentinelPoolTest {

private MockTracer mockTracer = new MockTracer(new ThreadLocalScopeManager(), MockTracer.Propagator.TEXT_MAP);

private RedisServer redisServer;

private RedisSentinel redisSentinel;

private static final String MASTER_NAME = "mymaster";

private Set<String> sentinels = new HashSet<String>() {{
add("127.0.0.1:" + (Protocol.DEFAULT_PORT + 1));
}};

@Before
public void before() {
mockTracer.reset();

redisServer = RedisServer.builder().build();
redisServer.start();
redisSentinel = RedisSentinel.builder().port(Protocol.DEFAULT_PORT + 1).build();
redisSentinel.start();
}

@After
public void after() {
if (redisSentinel != null) {
redisSentinel.stop();
}
if (redisServer != null) {
redisServer.stop();
}
}

@Test
public void testSentinelPoolReturnsTracedJedis() {
JedisSentinelPool pool = new TracingJedisSentinelPool(mockTracer, false, MASTER_NAME, sentinels, new GenericObjectPoolConfig());
Jedis jedis = pool.getResource();
assertEquals("OK", jedis.set("key", "value"));
assertEquals("value", jedis.get("key"));

jedis.close();

List<MockSpan> spans = mockTracer.finishedSpans();
assertEquals(2, spans.size());
}

@Test
public void testClosingTracedJedisClosesUnderlyingJedis() {
JedisSentinelPool pool = new TracingJedisSentinelPool(mockTracer, false, MASTER_NAME, sentinels, new GenericObjectPoolConfig());
Jedis resource = pool.getResource();
assertEquals(1, pool.getNumActive());

resource.close();
assertEquals(0, pool.getNumActive());
assertEquals(1, pool.getNumIdle());

// ensure that resource is reused
Jedis nextResource = pool.getResource();
assertEquals(1, pool.getNumActive());
assertEquals(0, pool.getNumIdle());
nextResource.close();
}
}

0 comments on commit 0330ee5

Please sign in to comment.