You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@htrace.apache.org by cm...@apache.org on 2015/08/25 04:18:09 UTC
[2/2] incubator-htrace git commit: HTRACE-214. De-globalize
Tracer.java (cmccabe)
HTRACE-214. De-globalize Tracer.java (cmccabe)
Project: http://git-wip-us.apache.org/repos/asf/incubator-htrace/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-htrace/commit/7997d208
Tree: http://git-wip-us.apache.org/repos/asf/incubator-htrace/tree/7997d208
Diff: http://git-wip-us.apache.org/repos/asf/incubator-htrace/diff/7997d208
Branch: refs/heads/master
Commit: 7997d208989b5e5bf6734da64ec9249c0226c21f
Parents: 0f873fd
Author: Masatake Iwasaki <iw...@apache.org>
Authored: Fri Aug 21 16:00:36 2015 +0900
Committer: Colin P. Mccabe <cm...@apache.org>
Committed: Mon Aug 24 19:15:35 2015 -0700
----------------------------------------------------------------------
.../org/apache/htrace/core/AlwaysSampler.java | 3 +-
.../org/apache/htrace/core/CountSampler.java | 2 +-
.../htrace/core/LocalFileSpanReceiver.java | 20 +-
.../java/org/apache/htrace/core/MilliSpan.java | 1 -
.../org/apache/htrace/core/NeverSampler.java | 4 +-
.../java/org/apache/htrace/core/NullScope.java | 41 +-
.../apache/htrace/core/POJOSpanReceiver.java | 2 +-
.../apache/htrace/core/ProbabilitySampler.java | 7 +-
.../java/org/apache/htrace/core/Sampler.java | 96 +++-
.../org/apache/htrace/core/SamplerBuilder.java | 91 ----
.../main/java/org/apache/htrace/core/Span.java | 9 +-
.../java/org/apache/htrace/core/SpanId.java | 3 -
.../org/apache/htrace/core/SpanReceiver.java | 137 ++++-
.../apache/htrace/core/SpanReceiverBuilder.java | 138 -----
.../htrace/core/StandardOutSpanReceiver.java | 2 +-
.../main/java/org/apache/htrace/core/Trace.java | 219 --------
.../org/apache/htrace/core/TraceCallable.java | 39 +-
.../htrace/core/TraceExecutorService.java | 19 +-
.../java/org/apache/htrace/core/TraceProxy.java | 58 --
.../org/apache/htrace/core/TraceRunnable.java | 40 +-
.../java/org/apache/htrace/core/TraceScope.java | 115 ++--
.../java/org/apache/htrace/core/Tracer.java | 528 +++++++++++++++++--
.../org/apache/htrace/core/TracerBuilder.java | 144 +++++
.../java/org/apache/htrace/core/TracerId.java | 44 +-
.../java/org/apache/htrace/core/TracerPool.java | 283 ++++++++++
.../org/apache/htrace/core/TestBadClient.java | 171 ++++--
.../java/org/apache/htrace/core/TestHTrace.java | 152 +++---
.../htrace/core/TestLocalFileSpanReceiver.java | 35 +-
.../org/apache/htrace/core/TestNullScope.java | 25 +-
.../org/apache/htrace/core/TestSampler.java | 89 +++-
.../htrace/core/TestSpanReceiverBuilder.java | 156 +++---
.../org/apache/htrace/core/TestTracerId.java | 21 +-
.../org/apache/htrace/core/TraceCreator.java | 58 +-
.../apache/htrace/impl/FlumeSpanReceiver.java | 7 +-
.../htrace/impl/TestFlumeSpanReceiver.java | 68 +--
.../apache/htrace/HBaseSpanReceiverHost.java | 107 ----
.../apache/htrace/impl/HBaseSpanReceiver.java | 35 +-
.../org/apache/htrace/impl/HBaseTestUtil.java | 4 +-
.../htrace/impl/TestHBaseSpanReceiver.java | 40 +-
.../apache/htrace/impl/HTracedRESTReceiver.java | 10 +-
.../htrace/impl/TestHTracedRESTReceiver.java | 2 +
.../apache/htrace/impl/ZipkinSpanReceiver.java | 9 +-
.../htrace/TestHTraceSpanToZipkinSpan.java | 10 +-
src/main/site/markdown/index.md | 186 ++-----
44 files changed, 1845 insertions(+), 1385 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/AlwaysSampler.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/AlwaysSampler.java b/htrace-core/src/main/java/org/apache/htrace/core/AlwaysSampler.java
index a9259bd..8d5a296 100644
--- a/htrace-core/src/main/java/org/apache/htrace/core/AlwaysSampler.java
+++ b/htrace-core/src/main/java/org/apache/htrace/core/AlwaysSampler.java
@@ -19,8 +19,7 @@ package org.apache.htrace.core;
/**
* A Sampler that always returns true.
*/
-public final class AlwaysSampler implements Sampler {
-
+public final class AlwaysSampler extends Sampler {
public static final AlwaysSampler INSTANCE = new AlwaysSampler(null);
public AlwaysSampler(HTraceConfiguration conf) {
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/CountSampler.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/CountSampler.java b/htrace-core/src/main/java/org/apache/htrace/core/CountSampler.java
index 10d5c98..5a838c7 100644
--- a/htrace-core/src/main/java/org/apache/htrace/core/CountSampler.java
+++ b/htrace-core/src/main/java/org/apache/htrace/core/CountSampler.java
@@ -22,7 +22,7 @@ import java.util.concurrent.ThreadLocalRandom;
* Sampler that returns true every N calls. Specify the frequency interval by configuring a
* {@code long} value for {@link #SAMPLER_FREQUENCY_CONF_KEY}.
*/
-public class CountSampler implements Sampler {
+public class CountSampler extends Sampler {
public final static String SAMPLER_FREQUENCY_CONF_KEY = "sampler.frequency";
final long frequency;
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/LocalFileSpanReceiver.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/LocalFileSpanReceiver.java b/htrace-core/src/main/java/org/apache/htrace/core/LocalFileSpanReceiver.java
index 0aed846..69a43b1 100644
--- a/htrace-core/src/main/java/org/apache/htrace/core/LocalFileSpanReceiver.java
+++ b/htrace-core/src/main/java/org/apache/htrace/core/LocalFileSpanReceiver.java
@@ -41,10 +41,10 @@ import java.util.concurrent.locks.ReentrantLock;
/**
* Writes the spans it receives to a local file.
*/
-public class LocalFileSpanReceiver implements SpanReceiver {
+public class LocalFileSpanReceiver extends SpanReceiver {
private static final Log LOG = LogFactory.getLog(LocalFileSpanReceiver.class);
- public static final String PATH_KEY = "local-file-span-receiver.path";
- public static final String CAPACITY_KEY = "local-file-span-receiver.capacity";
+ public static final String PATH_KEY = "local.file.span.receiver.path";
+ public static final String CAPACITY_KEY = "local.file.span.receiver.capacity";
public static final int CAPACITY_DEFAULT = 5000;
private static ObjectWriter JSON_WRITER = new ObjectMapper().writer();
private final String path;
@@ -56,7 +56,6 @@ public class LocalFileSpanReceiver implements SpanReceiver {
private final FileOutputStream stream;
private final FileChannel channel;
private final ReentrantLock channelLock = new ReentrantLock();
- private final TracerId tracerId;
public LocalFileSpanReceiver(HTraceConfiguration conf) {
int capacity = conf.getInt(CAPACITY_KEY, CAPACITY_DEFAULT);
@@ -64,9 +63,11 @@ public class LocalFileSpanReceiver implements SpanReceiver {
throw new IllegalArgumentException(CAPACITY_KEY + " must not be " +
"less than 1.");
}
- this.path = conf.get(PATH_KEY);
- if (path == null || path.isEmpty()) {
- throw new IllegalArgumentException("must configure " + PATH_KEY);
+ String pathStr = conf.get(PATH_KEY);
+ if (pathStr == null || pathStr.isEmpty()) {
+ path = getUniqueLocalTraceFileName();
+ } else {
+ path = pathStr;
}
boolean success = false;
try {
@@ -91,7 +92,6 @@ public class LocalFileSpanReceiver implements SpanReceiver {
LOG.debug("Created new LocalFileSpanReceiver with path = " + path +
", capacity = " + capacity);
}
- this.tracerId = new TracerId(conf);
}
/**
@@ -134,10 +134,6 @@ public class LocalFileSpanReceiver implements SpanReceiver {
@Override
public void receiveSpan(Span span) {
- if (span.getTracerId().isEmpty()) {
- span.setTracerId(tracerId.get());
- }
-
// Serialize the span data into a byte[]. Note that we're not holding the
// lock here, to improve concurrency.
byte jsonBuf[] = null;
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/MilliSpan.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/MilliSpan.java b/htrace-core/src/main/java/org/apache/htrace/core/MilliSpan.java
index afef809..5dd6bdb 100644
--- a/htrace-core/src/main/java/org/apache/htrace/core/MilliSpan.java
+++ b/htrace-core/src/main/java/org/apache/htrace/core/MilliSpan.java
@@ -170,7 +170,6 @@ public class MilliSpan implements Span {
throw new IllegalStateException("Span for " + description
+ " has not been started");
end = System.currentTimeMillis();
- Tracer.getInstance().deliver(this);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/NeverSampler.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/NeverSampler.java b/htrace-core/src/main/java/org/apache/htrace/core/NeverSampler.java
index 65f6087..60cc7d2 100644
--- a/htrace-core/src/main/java/org/apache/htrace/core/NeverSampler.java
+++ b/htrace-core/src/main/java/org/apache/htrace/core/NeverSampler.java
@@ -19,8 +19,7 @@ package org.apache.htrace.core;
/**
* A Sampler that never returns true.
*/
-public final class NeverSampler implements Sampler {
-
+public final class NeverSampler extends Sampler {
public static final NeverSampler INSTANCE = new NeverSampler(null);
public NeverSampler(HTraceConfiguration conf) {
@@ -30,5 +29,4 @@ public final class NeverSampler implements Sampler {
public boolean next() {
return false;
}
-
}
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/NullScope.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/NullScope.java b/htrace-core/src/main/java/org/apache/htrace/core/NullScope.java
index e7964cf..fe76e46 100644
--- a/htrace-core/src/main/java/org/apache/htrace/core/NullScope.java
+++ b/htrace-core/src/main/java/org/apache/htrace/core/NullScope.java
@@ -17,28 +17,53 @@
package org.apache.htrace.core;
/**
- * Singleton instance representing an empty {@link TraceScope}.
+ * An empty {@link TraceScope}.
*/
-public final class NullScope extends TraceScope {
+class NullScope extends TraceScope {
+ NullScope(Tracer tracer) {
+ super(tracer, null, null);
+ }
- public static final TraceScope INSTANCE = new NullScope();
+ @Override
+ public SpanId getSpanId() {
+ return SpanId.INVALID;
+ }
- private NullScope() {
- super(null, null);
+ @Override
+ public void detach() {
+ if (detached) {
+ Tracer.throwClientError("Can't detach this TraceScope because " +
+ "it is already detached.");
+ }
+ detached = true;
}
@Override
- public Span detach() {
- return null;
+ public void reattach() {
+ if (!detached) {
+ Tracer.throwClientError("Can't reattach this TraceScope because " +
+ "it is not detached.");
+ }
+ detached = false;
}
@Override
public void close() {
- return;
+ tracer.popNullScope();
}
@Override
public String toString() {
return "NullScope";
}
+
+ @Override
+ public void addKVAnnotation(String key, String value) {
+ // do nothing
+ }
+
+ @Override
+ public void addTimelineAnnotation(String msg) {
+ // do nothing
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/POJOSpanReceiver.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/POJOSpanReceiver.java b/htrace-core/src/main/java/org/apache/htrace/core/POJOSpanReceiver.java
index be782ba..34322fa 100644
--- a/htrace-core/src/main/java/org/apache/htrace/core/POJOSpanReceiver.java
+++ b/htrace-core/src/main/java/org/apache/htrace/core/POJOSpanReceiver.java
@@ -24,7 +24,7 @@ import java.util.HashSet;
* SpanReceiver for testing only that just collects the Span objects it
* receives. The spans it receives can be accessed with getSpans();
*/
-public class POJOSpanReceiver implements SpanReceiver {
+public class POJOSpanReceiver extends SpanReceiver {
private final Collection<Span> spans;
public POJOSpanReceiver(HTraceConfiguration conf) {
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/ProbabilitySampler.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/ProbabilitySampler.java b/htrace-core/src/main/java/org/apache/htrace/core/ProbabilitySampler.java
index 5bb0042..c0bb16c 100644
--- a/htrace-core/src/main/java/org/apache/htrace/core/ProbabilitySampler.java
+++ b/htrace-core/src/main/java/org/apache/htrace/core/ProbabilitySampler.java
@@ -16,17 +16,16 @@
*/
package org.apache.htrace.core;
+import java.util.concurrent.ThreadLocalRandom;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import java.util.Random;
-import java.util.concurrent.ThreadLocalRandom;
-
/**
* Sampler that returns true a certain percentage of the time. Specify the frequency interval by
* configuring a {@code double} value for {@link #SAMPLER_FRACTION_CONF_KEY}.
*/
-public class ProbabilitySampler implements Sampler {
+public class ProbabilitySampler extends Sampler {
private static final Log LOG = LogFactory.getLog(ProbabilitySampler.class);
public final double threshold;
public final static String SAMPLER_FRACTION_CONF_KEY = "sampler.fraction";
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/Sampler.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/Sampler.java b/htrace-core/src/main/java/org/apache/htrace/core/Sampler.java
index 91843f5..af0165c 100644
--- a/htrace-core/src/main/java/org/apache/htrace/core/Sampler.java
+++ b/htrace-core/src/main/java/org/apache/htrace/core/Sampler.java
@@ -16,6 +16,11 @@
*/
package org.apache.htrace.core;
+import java.lang.reflect.Constructor;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
/**
* Extremely simple callback to determine the frequency that an action should be
* performed.
@@ -31,9 +36,96 @@ package org.apache.htrace.core;
* </pre>
* This would trace 50% of all gets, 75% of all puts and would not trace any other requests.
*/
-public interface Sampler {
+public abstract class Sampler {
+ /**
+ * A {@link Sampler} builder. It takes a {@link Sampler} class name and
+ * constructs an instance of that class, with the provided configuration.
+ */
+ public static class Builder {
+ private static final Log LOG = LogFactory.getLog(Builder.class);
+
+ private final static String DEFAULT_PACKAGE = "org.apache.htrace.core";
+ private final HTraceConfiguration conf;
+ private String className;
+ private ClassLoader classLoader = Builder.class.getClassLoader();
+
+ public Builder(HTraceConfiguration conf) {
+ this.conf = conf;
+ reset();
+ }
+
+ public Builder reset() {
+ this.className = null;
+ return this;
+ }
+
+ public Builder className(String className) {
+ this.className = className;
+ return this;
+ }
+
+ public Builder classLoader(ClassLoader classLoader) {
+ this.classLoader = classLoader;
+ return this;
+ }
+
+ private void throwError(String errorStr) {
+ LOG.error(errorStr);
+ throw new RuntimeException(errorStr);
+ }
+
+ private void throwError(String errorStr, Throwable e) {
+ LOG.error(errorStr, e);
+ throw new RuntimeException(errorStr, e);
+ }
+
+ public Sampler build() {
+ Sampler sampler = newSampler();
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Created new sampler of type " +
+ sampler.getClass().getName(), new Exception());
+ }
+ return sampler;
+ }
+
+ private Sampler newSampler() {
+ if (className == null || className.isEmpty()) {
+ throwError("No sampler class specified.");
+ }
+ String str = className;
+ if (!str.contains(".")) {
+ str = DEFAULT_PACKAGE + "." + str;
+ }
+ Class cls = null;
+ try {
+ cls = classLoader.loadClass(str);
+ } catch (ClassNotFoundException e) {
+ throwError("Cannot find Sampler class " + str);
+ }
+ Constructor<Sampler> ctor = null;
+ try {
+ ctor = cls.getConstructor(HTraceConfiguration.class);
+ } catch (NoSuchMethodException e) {
+ throwError("Cannot find a constructor for class " +
+ str + "which takes an HTraceConfiguration.");
+ }
+ Sampler sampler = null;
+ try {
+ LOG.debug("Creating new instance of " + str + "...");
+ sampler = ctor.newInstance(conf);
+ } catch (ReflectiveOperationException e) {
+ throwError("Reflection error when constructing " +
+ str + ".", e);
+ } catch (Throwable t) {
+ throwError("NewInstance error when constructing " +
+ str + ".", t);
+ }
+ return sampler;
+ }
+ }
+
public static final Sampler ALWAYS = AlwaysSampler.INSTANCE;
public static final Sampler NEVER = NeverSampler.INSTANCE;
- public boolean next();
+ public abstract boolean next();
}
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/SamplerBuilder.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/SamplerBuilder.java b/htrace-core/src/main/java/org/apache/htrace/core/SamplerBuilder.java
deleted file mode 100644
index 5b53905..0000000
--- a/htrace-core/src/main/java/org/apache/htrace/core/SamplerBuilder.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.htrace.core;
-
-import java.lang.reflect.Constructor;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * A {@link Sampler} builder. It reads a {@link Sampler} class name from the provided
- * configuration using the {@link #SAMPLER_CONF_KEY} key. Unqualified class names
- * are interpreted as members of the {@code org.apache.htrace.impl} package. The {@link #build()}
- * method constructs an instance of that class, initialized with the same configuration.
- */
-public class SamplerBuilder {
-
- // TODO: should follow the same API as SpanReceiverBuilder
-
- public final static String SAMPLER_CONF_KEY = "sampler";
- private final static String DEFAULT_PACKAGE = "org.apache.htrace.core";
- private final static ClassLoader classLoader =
- SamplerBuilder.class.getClassLoader();
- private final HTraceConfiguration conf;
- private static final Log LOG = LogFactory.getLog(SamplerBuilder.class);
-
- public SamplerBuilder(HTraceConfiguration conf) {
- this.conf = conf;
- }
-
- public Sampler build() {
- Sampler sampler = newSampler();
- if (LOG.isTraceEnabled()) {
- LOG.trace("Created new sampler of type " +
- sampler.getClass().getName(), new Exception());
- }
- return sampler;
- }
-
- private Sampler newSampler() {
- String str = conf.get(SAMPLER_CONF_KEY);
- if (str == null || str.isEmpty()) {
- return NeverSampler.INSTANCE;
- }
- if (!str.contains(".")) {
- str = DEFAULT_PACKAGE + "." + str;
- }
- Class cls = null;
- try {
- cls = classLoader.loadClass(str);
- } catch (ClassNotFoundException e) {
- LOG.error("SamplerBuilder cannot find sampler class " + str +
- ": falling back on NeverSampler.");
- return NeverSampler.INSTANCE;
- }
- Constructor<Sampler> ctor = null;
- try {
- ctor = cls.getConstructor(HTraceConfiguration.class);
- } catch (NoSuchMethodException e) {
- LOG.error("SamplerBuilder cannot find a constructor for class " + str +
- "which takes an HTraceConfiguration. Falling back on " +
- "NeverSampler.");
- return NeverSampler.INSTANCE;
- }
- try {
- return ctor.newInstance(conf);
- } catch (ReflectiveOperationException e) {
- LOG.error("SamplerBuilder reflection error when constructing " + str +
- ". Falling back on NeverSampler.", e);
- return NeverSampler.INSTANCE;
- } catch (Throwable e) {
- LOG.error("SamplerBuilder constructor error when constructing " + str +
- ". Falling back on NeverSampler.", e);
- return NeverSampler.INSTANCE;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/Span.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/Span.java b/htrace-core/src/main/java/org/apache/htrace/core/Span.java
index db1a961..4971983 100644
--- a/htrace-core/src/main/java/org/apache/htrace/core/Span.java
+++ b/htrace-core/src/main/java/org/apache/htrace/core/Span.java
@@ -16,15 +16,14 @@
*/
package org.apache.htrace.core;
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-
import java.io.IOException;
import java.util.List;
import java.util.Map;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
/**
* Base interface for gathering and reporting statistics about a block of
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/SpanId.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/SpanId.java b/htrace-core/src/main/java/org/apache/htrace/core/SpanId.java
index e10f894..ed31ad3 100644
--- a/htrace-core/src/main/java/org/apache/htrace/core/SpanId.java
+++ b/htrace-core/src/main/java/org/apache/htrace/core/SpanId.java
@@ -16,10 +16,7 @@
*/
package org.apache.htrace.core;
-import java.math.BigInteger;
-import java.lang.Void;
import java.util.concurrent.ThreadLocalRandom;
-import java.util.Random;
/**
* Uniquely identifies an HTrace span.
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/SpanReceiver.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/SpanReceiver.java b/htrace-core/src/main/java/org/apache/htrace/core/SpanReceiver.java
index 5547c51..a955ddf 100644
--- a/htrace-core/src/main/java/org/apache/htrace/core/SpanReceiver.java
+++ b/htrace-core/src/main/java/org/apache/htrace/core/SpanReceiver.java
@@ -16,9 +16,12 @@
*/
package org.apache.htrace.core;
-
import java.io.Closeable;
+import java.lang.reflect.Constructor;
+import java.util.concurrent.atomic.AtomicLong;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
/**
* The collector within a process that is the destination of Spans when a trace is running.
@@ -27,13 +30,135 @@ import java.io.Closeable;
* <pre>
* <code>public SpanReceiverImpl(HTraceConfiguration)</code>
* </pre>
- * The helper class {@link org.apache.htrace.SpanReceiverBuilder} provides convenient factory
- * methods for creating {@code SpanReceiver} instances from configuration.
- * @see org.apache.htrace.SpanReceiverBuilder
*/
-public interface SpanReceiver extends Closeable {
+public abstract class SpanReceiver implements Closeable {
+ /**
+ * A {@link SpanReceiver} builder. It takes a {@link SpanReceiver} class name
+ * and constructs an instance of that class, with the provided configuration.
+ */
+ public static class Builder {
+ private static final Log LOG = LogFactory.getLog(Builder.class);
+
+ private final static String DEFAULT_PACKAGE = "org.apache.htrace.core";
+ private final HTraceConfiguration conf;
+ private boolean logErrors;
+ private String className;
+ private ClassLoader classLoader = Builder.class.getClassLoader();
+
+ public Builder(HTraceConfiguration conf) {
+ this.conf = conf;
+ reset();
+ }
+
+ /**
+ * Set this builder back to defaults.
+ *
+ * @return this instance.
+ */
+ public Builder reset() {
+ this.logErrors = true;
+ this.className = null;
+ return this;
+ }
+
+ public Builder className(final String className) {
+ this.className = className;
+ return this;
+ }
+
+ /**
+ * Configure whether we should log errors during build().
+ * @return This instance
+ */
+ public Builder logErrors(boolean logErrors) {
+ this.logErrors = logErrors;
+ return this;
+ }
+
+ public Builder classLoader(ClassLoader classLoader) {
+ this.classLoader = classLoader;
+ return this;
+ }
+
+ private void throwError(String errorStr) {
+ if (logErrors) {
+ LOG.error(errorStr);
+ }
+ throw new RuntimeException(errorStr);
+ }
+
+ private void throwError(String errorStr, Throwable e) {
+ if (logErrors) {
+ LOG.error(errorStr, e);
+ }
+ throw new RuntimeException(errorStr, e);
+ }
+
+ public SpanReceiver build() {
+ SpanReceiver spanReceiver = newSpanReceiver();
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Created new span receiver of type " +
+ spanReceiver.getClass().getName());
+ }
+ return spanReceiver;
+ }
+
+ private SpanReceiver newSpanReceiver() {
+ if ((className == null) || className.isEmpty()) {
+ throwError("No span receiver class specified.");
+ }
+ String str = className;
+ if (!str.contains(".")) {
+ str = DEFAULT_PACKAGE + "." + str;
+ }
+ Class cls = null;
+ try {
+ cls = classLoader.loadClass(str);
+ } catch (ClassNotFoundException e) {
+ throwError("Cannot find SpanReceiver class " + str);
+ }
+ Constructor<SpanReceiver> ctor = null;
+ try {
+ ctor = cls.getConstructor(HTraceConfiguration.class);
+ } catch (NoSuchMethodException e) {
+ throwError("Cannot find a constructor for class " +
+ str + "which takes an HTraceConfiguration.");
+ }
+ SpanReceiver receiver = null;
+ try {
+ LOG.debug("Creating new instance of " + str + "...");
+ receiver = ctor.newInstance(conf);
+ } catch (ReflectiveOperationException e) {
+ throwError("Reflection error when constructing " +
+ str + ".", e);
+ } catch (Throwable t) {
+ throwError("NewInstance error when constructing " +
+ str + ".", t);
+ }
+ return receiver;
+ }
+ }
+
+ /**
+ * An ID which uniquely identifies this SpanReceiver.
+ */
+ private final long id;
+
+ private static final AtomicLong HIGHEST_SPAN_RECEIVER_ID = new AtomicLong(0);
+
+ /**
+ * Get an ID uniquely identifying this SpanReceiver.
+ */
+ public final long getId() {
+ return id;
+ }
+
+ protected SpanReceiver() {
+ this.id = HIGHEST_SPAN_RECEIVER_ID.incrementAndGet();
+ }
+
/**
* Called when a Span is stopped and can now be stored.
*/
- public void receiveSpan(Span span);
+ public abstract void receiveSpan(Span span);
}
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/SpanReceiverBuilder.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/SpanReceiverBuilder.java b/htrace-core/src/main/java/org/apache/htrace/core/SpanReceiverBuilder.java
deleted file mode 100644
index 3ab0b07..0000000
--- a/htrace-core/src/main/java/org/apache/htrace/core/SpanReceiverBuilder.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.htrace.core;
-
-import java.lang.reflect.Constructor;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * A {@link SpanReceiver} builder. It reads a {@link SpanReceiver} class name from the provided
- * configuration using the {@link #SPAN_RECEIVER_CONF_KEY} key. Unqualified class names
- * are interpreted as members of the {@code org.apache.htrace.impl} package. The {@link #build()}
- * method constructs an instance of that class, initialized with the same configuration.
- */
-public class SpanReceiverBuilder {
- private static final Log LOG = LogFactory.getLog(SpanReceiverBuilder.class);
-
- public final static String SPAN_RECEIVER_CONF_KEY = "span.receiver";
- private final static String DEFAULT_PACKAGE = "org.apache.htrace.core";
- private final static ClassLoader classLoader =
- SpanReceiverBuilder.class.getClassLoader();
- private final HTraceConfiguration conf;
- private boolean logErrors;
- private String spanReceiverClass;
-
- public SpanReceiverBuilder(HTraceConfiguration conf) {
- this.conf = conf;
- reset();
- }
-
- /**
- * Set this builder back to defaults. Any previous calls to {@link #spanReceiverClass(String)}
- * are overridden by the value provided by configuration.
- * @return This instance
- */
- public SpanReceiverBuilder reset() {
- this.logErrors = true;
- this.spanReceiverClass = this.conf.get(SPAN_RECEIVER_CONF_KEY);
- return this;
- }
-
- /**
- * Override the {@code SpanReceiver} class name provided in configuration with a new value.
- * @return This instance
- */
- public SpanReceiverBuilder spanReceiverClass(final String spanReceiverClass) {
- this.spanReceiverClass = spanReceiverClass;
- return this;
- }
-
- /**
- * Configure whether we should log errors during build().
- * @return This instance
- */
- public SpanReceiverBuilder logErrors(boolean logErrors) {
- this.logErrors = logErrors;
- return this;
- }
-
- private void logError(String errorStr) {
- if (!logErrors) {
- return;
- }
- LOG.error(errorStr);
- }
-
- private void logError(String errorStr, Throwable e) {
- if (!logErrors) {
- return;
- }
- LOG.error(errorStr, e);
- }
-
- public SpanReceiver build() {
- SpanReceiver spanReceiver = newSpanReceiver();
- if (LOG.isTraceEnabled()) {
- LOG.trace("Created new span receiver of type " +
- ((spanReceiver == null) ? "(none)" :
- spanReceiver.getClass().getName()));
- }
- return spanReceiver;
- }
-
- private SpanReceiver newSpanReceiver() {
- if ((this.spanReceiverClass == null) ||
- this.spanReceiverClass.isEmpty()) {
- LOG.debug("No span receiver class specified.");
- return null;
- }
- String str = spanReceiverClass;
- if (!str.contains(".")) {
- str = DEFAULT_PACKAGE + "." + str;
- }
- Class cls = null;
- try {
- cls = classLoader.loadClass(str);
- } catch (ClassNotFoundException e) {
- logError("SpanReceiverBuilder cannot find SpanReceiver class " + str +
- ": disabling span receiver.");
- return null;
- }
- Constructor<SpanReceiver> ctor = null;
- try {
- ctor = cls.getConstructor(HTraceConfiguration.class);
- } catch (NoSuchMethodException e) {
- logError("SpanReceiverBuilder cannot find a constructor for class " +
- str + "which takes an HTraceConfiguration. Disabling span " +
- "receiver.");
- return null;
- }
- try {
- LOG.debug("Creating new instance of " + str + "...");
- return ctor.newInstance(conf);
- } catch (ReflectiveOperationException e) {
- logError("SpanReceiverBuilder reflection error when constructing " + str +
- ". Disabling span receiver.", e);
- return null;
- } catch (Throwable e) {
- logError("SpanReceiverBuilder constructor error when constructing " + str +
- ". Disabling span receiver.", e);
- return null;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/StandardOutSpanReceiver.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/StandardOutSpanReceiver.java b/htrace-core/src/main/java/org/apache/htrace/core/StandardOutSpanReceiver.java
index b084046..f443ec6 100644
--- a/htrace-core/src/main/java/org/apache/htrace/core/StandardOutSpanReceiver.java
+++ b/htrace-core/src/main/java/org/apache/htrace/core/StandardOutSpanReceiver.java
@@ -24,7 +24,7 @@ import java.io.IOException;
/**
* Used for testing. Simply prints to standard out any spans it receives.
*/
-public class StandardOutSpanReceiver implements SpanReceiver {
+public class StandardOutSpanReceiver extends SpanReceiver {
private static final Log LOG = LogFactory.getLog(StandardOutSpanReceiver.class);
public StandardOutSpanReceiver(HTraceConfiguration conf) {
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/Trace.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/Trace.java b/htrace-core/src/main/java/org/apache/htrace/core/Trace.java
deleted file mode 100644
index 9b72afe..0000000
--- a/htrace-core/src/main/java/org/apache/htrace/core/Trace.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.htrace.core;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import java.util.concurrent.Callable;
-
-/**
- * The Trace class is the primary way to interact with the library. It provides
- * methods to create and manipulate spans.
- *
- * A 'Span' represents a length of time. It has many other attributes such as a
- * description, ID, and even potentially a set of key/value strings attached to
- * it.
- *
- * Each thread in your application has a single currently active currentSpan
- * associated with it. When this is non-null, it represents the current
- * operation that the thread is doing. Spans are NOT thread-safe, and must
- * never be used by multiple threads at once. With care, it is possible to
- * safely pass a Span object between threads, but in most cases this is not
- * necessary.
- *
- * A 'TraceScope' can either be empty, or contain a Span. TraceScope objects
- * implement the Java's Closeable interface. Similar to file descriptors, they
- * must be closed after they are created. When a TraceScope contains a Span,
- * this span is closed when the scope is closed.
- *
- * The 'startSpan' methods in this class do a few things:
- * <ul>
- * <li>Create a new Span which has this thread's currentSpan as one of its parents.</li>
- * <li>Set currentSpan to the new Span.</li>
- * <li>Create a TraceSpan object to manage the new Span.</li>
- * </ul>
- *
- * Closing a TraceScope does a few things:
- * <ul>
- * <li>It closes the span which the scope was managing.</li>
- * <li>Set currentSpan to the previous currentSpan (which may be null).</li>
- * </ul>
- */
-public class Trace {
- private static final Log LOG = LogFactory.getLog(Trace.class);
-
- /**
- * Creates a new trace scope.
- *
- * If this thread has a currently active trace span, the trace scope we create
- * here will contain a new span descending from the currently active span.
- * If there is no currently active trace span, the trace scope we create will
- * be empty.
- *
- * @param description The description field for the new span to create.
- */
- public static TraceScope startSpan(String description) {
- return startSpan(description, NeverSampler.INSTANCE);
- }
-
- public static TraceScope startSpan(String description, SpanId parentId) {
- if (parentId == null) {
- return continueSpan(null);
- }
- Span newSpan = new MilliSpan.Builder().
- begin(System.currentTimeMillis()).
- end(0).
- description(description).
- spanId(parentId.newChildId()).
- parents(new SpanId[] { parentId }).
- build();
- return continueSpan(newSpan);
- }
-
- /**
- * Creates a new trace scope.
- *
- * If this thread has a currently active trace span, it must be the 'parent'
- * span that you pass in here as a parameter. The trace scope we create here
- * will contain a new span which is a child of 'parent'.
- *
- * @param description The description field for the new span to create.
- */
- public static TraceScope startSpan(String description, Span parent) {
- if (parent == null) {
- return startSpan(description);
- }
- Span currentSpan = currentSpan();
- if ((currentSpan != null) && (currentSpan != parent)) {
- Tracer.clientError("HTrace client error: thread " +
- Thread.currentThread().getName() + " tried to start a new Span " +
- "with parent " + parent.toString() + ", but there is already a " +
- "currentSpan " + currentSpan);
- }
- return continueSpan(parent.child(description));
- }
-
- public static <T> TraceScope startSpan(String description, Sampler s) {
- Span span = null;
- if (isTracing() || s.next()) {
- span = Tracer.getInstance().createNew(description);
- }
- return continueSpan(span);
- }
-
- /**
- * Pick up an existing span from another thread.
- */
- public static TraceScope continueSpan(Span s) {
- // Return an empty TraceScope that does nothing on close
- if (s == null) return NullScope.INSTANCE;
- return Tracer.getInstance().continueSpan(s);
- }
-
- /**
- * Removes the given SpanReceiver from the list of SpanReceivers.
- */
- public static void removeReceiver(SpanReceiver rcvr) {
- Tracer.getInstance().removeReceiver(rcvr);
- }
-
- /**
- * Adds the given SpanReceiver to the current Tracer instance's list of
- * SpanReceivers.
- */
- public static void addReceiver(SpanReceiver rcvr) {
- Tracer.getInstance().addReceiver(rcvr);
- }
-
- /**
- * Adds a data annotation to the current span if tracing is currently on.
- */
- public static void addKVAnnotation(String key, String value) {
- Span s = currentSpan();
- if (s != null) {
- s.addKVAnnotation(key, value);
- }
- }
-
- /**
- * Annotate the current span with the given message.
- */
- public static void addTimelineAnnotation(String msg) {
- Span s = currentSpan();
- if (s != null) {
- s.addTimelineAnnotation(msg);
- }
- }
-
- /**
- * Returns true if the current thread is a part of a trace, false otherwise.
- */
- public static boolean isTracing() {
- return Tracer.getInstance().isTracing();
- }
-
- /**
- * If we are tracing, return the current span, else null
- *
- * @return Span representing the current trace, or null if not tracing.
- */
- public static Span currentSpan() {
- return Tracer.getInstance().currentSpan();
- }
-
- /**
- * Wrap the callable in a TraceCallable, if tracing.
- *
- * @return The callable provided, wrapped if tracing, 'callable' if not.
- */
- public static <V> Callable<V> wrap(Callable<V> callable) {
- if (isTracing()) {
- return new TraceCallable<V>(Trace.currentSpan(), callable);
- } else {
- return callable;
- }
- }
-
- /**
- * Wrap the runnable in a TraceRunnable, if tracing
- *
- * @return The runnable provided, wrapped if tracing, 'runnable' if not.
- */
- public static Runnable wrap(Runnable runnable) {
- if (isTracing()) {
- return new TraceRunnable(Trace.currentSpan(), runnable);
- } else {
- return runnable;
- }
- }
-
- /**
- * Wrap the runnable in a TraceRunnable, if tracing
- *
- * @param description name of the span to be created.
- * @param runnable The runnable that will have tracing info associated with it if tracing.
- * @return The runnable provided, wrapped if tracing, 'runnable' if not.
- */
- public static Runnable wrap(String description, Runnable runnable) {
- if (isTracing()) {
- return new TraceRunnable(Trace.currentSpan(), runnable, description);
- } else {
- return runnable;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/TraceCallable.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/TraceCallable.java b/htrace-core/src/main/java/org/apache/htrace/core/TraceCallable.java
index 08bcace..a0fec17 100644
--- a/htrace-core/src/main/java/org/apache/htrace/core/TraceCallable.java
+++ b/htrace-core/src/main/java/org/apache/htrace/core/TraceCallable.java
@@ -22,44 +22,35 @@ import java.util.concurrent.Callable;
* Wrap a Callable with a Span that survives a change in threads.
*/
public class TraceCallable<V> implements Callable<V> {
+ private final Tracer tracer;
private final Callable<V> impl;
- private final Span parent;
+ private final TraceScope parent;
private final String description;
- public TraceCallable(Callable<V> impl) {
- this(Trace.currentSpan(), impl);
- }
-
- public TraceCallable(Span parent, Callable<V> impl) {
- this(parent, impl, null);
- }
-
- public TraceCallable(Span parent, Callable<V> impl, String description) {
+ TraceCallable(Tracer tracer, TraceScope parent, Callable<V> impl,
+ String description) {
+ this.tracer = tracer;
this.impl = impl;
this.parent = parent;
- this.description = description;
+ if (description == null) {
+ this.description = Thread.currentThread().getName();
+ } else {
+ this.description = description;
+ }
}
@Override
public V call() throws Exception {
- if (parent != null) {
- TraceScope chunk = Trace.startSpan(getDescription(), parent);
-
- try {
- return impl.call();
- } finally {
- chunk.close();
- }
- } else {
+ TraceScope chunk = tracer.newScope(description,
+ parent.getSpan().getSpanId());
+ try {
return impl.call();
+ } finally {
+ chunk.close();
}
}
public Callable<V> getImpl() {
return impl;
}
-
- private String getDescription() {
- return this.description == null ? Thread.currentThread().getName() : description;
- }
}
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/TraceExecutorService.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/TraceExecutorService.java b/htrace-core/src/main/java/org/apache/htrace/core/TraceExecutorService.java
index 8519d04..81e31ea 100644
--- a/htrace-core/src/main/java/org/apache/htrace/core/TraceExecutorService.java
+++ b/htrace-core/src/main/java/org/apache/htrace/core/TraceExecutorService.java
@@ -26,18 +26,21 @@ import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-
public class TraceExecutorService implements ExecutorService {
-
+ private final Tracer tracer;
+ private final String scopeName;
private final ExecutorService impl;
- public TraceExecutorService(ExecutorService impl) {
+ TraceExecutorService(Tracer tracer, String scopeName,
+ ExecutorService impl) {
+ this.tracer = tracer;
+ this.scopeName = scopeName;
this.impl = impl;
}
@Override
public void execute(Runnable command) {
- impl.execute(new TraceRunnable(command));
+ impl.execute(tracer.wrap(command, scopeName));
}
@Override
@@ -68,24 +71,24 @@ public class TraceExecutorService implements ExecutorService {
@Override
public <T> Future<T> submit(Callable<T> task) {
- return impl.submit(new TraceCallable<T>(task));
+ return impl.submit(tracer.wrap(task, scopeName));
}
@Override
public <T> Future<T> submit(Runnable task, T result) {
- return impl.submit(new TraceRunnable(task), result);
+ return impl.submit(tracer.wrap(task, scopeName), result);
}
@Override
public Future<?> submit(Runnable task) {
- return impl.submit(new TraceRunnable(task));
+ return impl.submit(tracer.wrap(task, scopeName));
}
private <T> Collection<? extends Callable<T>> wrapCollection(
Collection<? extends Callable<T>> tasks) {
List<Callable<T>> result = new ArrayList<Callable<T>>();
for (Callable<T> task : tasks) {
- result.add(new TraceCallable<T>(task));
+ result.add(tracer.wrap(task, scopeName));
}
return result;
}
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/TraceProxy.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/TraceProxy.java b/htrace-core/src/main/java/org/apache/htrace/core/TraceProxy.java
deleted file mode 100644
index de9c980..0000000
--- a/htrace-core/src/main/java/org/apache/htrace/core/TraceProxy.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.htrace.core;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-
-public class TraceProxy {
- /**
- * Returns an object that will trace all calls to itself.
- */
- public static <T> T trace(T instance) {
- return trace(instance, Sampler.ALWAYS);
- }
-
- /**
- * Returns an object that will trace all calls to itself.
- */
- @SuppressWarnings("unchecked")
- public static <T, V> T trace(final T instance, final Sampler sampler) {
- InvocationHandler handler = new InvocationHandler() {
- @Override
- public Object invoke(Object obj, Method method, Object[] args)
- throws Throwable {
- if (!sampler.next()) {
- return method.invoke(instance, args);
- }
-
- TraceScope scope = Trace.startSpan(method.getName(), Sampler.ALWAYS);
- try {
- return method.invoke(instance, args);
- } catch (Throwable ex) {
- ex.printStackTrace();
- throw ex;
- } finally {
- scope.close();
- }
- }
- };
- return (T) Proxy.newProxyInstance(instance.getClass().getClassLoader(),
- instance.getClass().getInterfaces(), handler);
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/TraceRunnable.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/TraceRunnable.java b/htrace-core/src/main/java/org/apache/htrace/core/TraceRunnable.java
index 6accea9..8f98708 100644
--- a/htrace-core/src/main/java/org/apache/htrace/core/TraceRunnable.java
+++ b/htrace-core/src/main/java/org/apache/htrace/core/TraceRunnable.java
@@ -20,44 +20,34 @@ package org.apache.htrace.core;
* Wrap a Runnable with a Span that survives a change in threads.
*/
public class TraceRunnable implements Runnable {
-
- private final Span parent;
+ private final Tracer tracer;
+ private final TraceScope parent;
private final Runnable runnable;
private final String description;
- public TraceRunnable(Runnable runnable) {
- this(Trace.currentSpan(), runnable);
- }
-
- public TraceRunnable(Span parent, Runnable runnable) {
- this(parent, runnable, null);
- }
-
- public TraceRunnable(Span parent, Runnable runnable, String description) {
+ public TraceRunnable(Tracer tracer, TraceScope parent,
+ Runnable runnable, String description) {
+ this.tracer = tracer;
this.parent = parent;
this.runnable = runnable;
- this.description = description;
+ if (description == null) {
+ this.description = Thread.currentThread().getName();
+ } else {
+ this.description = description;
+ }
}
@Override
public void run() {
- if (parent != null) {
- TraceScope chunk = Trace.startSpan(getDescription(), parent);
-
- try {
- runnable.run();
- } finally {
- chunk.close();
- }
- } else {
+ TraceScope chunk = tracer.newScope(description,
+ parent.getSpan().getSpanId());
+ try {
runnable.run();
+ } finally {
+ chunk.close();
}
}
- private String getDescription() {
- return this.description == null ? Thread.currentThread().getName() : description;
- }
-
public Runnable getRunnable() {
return runnable;
}
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/TraceScope.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/TraceScope.java b/htrace-core/src/main/java/org/apache/htrace/core/TraceScope.java
index f41e720..b04d785 100644
--- a/htrace-core/src/main/java/org/apache/htrace/core/TraceScope.java
+++ b/htrace-core/src/main/java/org/apache/htrace/core/TraceScope.java
@@ -18,6 +18,7 @@ package org.apache.htrace.core;
import java.io.Closeable;
import java.lang.Thread;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -25,75 +26,107 @@ public class TraceScope implements Closeable {
private static final Log LOG = LogFactory.getLog(TraceScope.class);
/**
- * the span for this scope
+ * The tracer to use for this scope.
+ */
+ final Tracer tracer;
+
+ /**
+ * The trace span for this scope, or null if the scope is closed.
+ *
+ * If the scope is closed, it must also be detached.
*/
private final Span span;
/**
- * the span that was "current" before this scope was entered
+ * The parent of this trace scope, or null if there is no parent.
*/
- private final Span savedSpan;
+ private TraceScope parent;
- private boolean detached = false;
+ /**
+ * True if this scope is detached.
+ */
+ boolean detached;
- TraceScope(Span span, Span saved) {
+ TraceScope(Tracer tracer, Span span, TraceScope parent) {
+ this.tracer = tracer;
this.span = span;
- this.savedSpan = saved;
+ this.parent = parent;
+ this.detached = false;
}
+ /**
+ * Returns the span which this scope is managing.
+ */
public Span getSpan() {
return span;
}
/**
- * Remove this span as the current thread, but don't stop it yet or
- * send it for collection. This is useful if the span object is then
- * passed to another thread for use with Trace.continueTrace().
+ * Returns the span ID which this scope is managing.
+ */
+ public SpanId getSpanId() {
+ return span.getSpanId();
+ }
+
+ TraceScope getParent() {
+ return parent;
+ }
+
+ void setParent(TraceScope parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * Detach this TraceScope from the current thread.
*
- * @return the same Span object
+ * It is OK to "leak" TraceScopes which have been detached. They will not
+ * consume any resources other than a small amount of memory until they are
+ * garbage collected. On the other hand, trace scopes which are still
+ * attached must never be leaked.
*/
- public Span detach() {
+ public void detach() {
if (detached) {
- Tracer.clientError("Tried to detach trace span " + span + " but " +
- "it has already been detached.");
+ Tracer.throwClientError("Can't detach this TraceScope because " +
+ "it is already detached.");
}
+ tracer.detachScope(this);
detached = true;
+ parent = null;
+ }
- Span cur = Tracer.getInstance().currentSpan();
- if (cur != span) {
- Tracer.clientError("Tried to detach trace span " + span + " but " +
- "it is not the current span for the " +
- Thread.currentThread().getName() + " thread. You have " +
- "probably forgotten to close or detach " + cur);
- } else {
- Tracer.getInstance().setCurrentSpan(savedSpan);
+ /**
+ * Attach this TraceScope to the current thread.
+ */
+ public void reattach() {
+ if (!detached) {
+ Tracer.throwClientError("Can't reattach this TraceScope because " +
+ "it is not detached.");
}
- return span;
+ tracer.reattachScope(this);
+ detached = false;
}
/**
- * Return true when {@link #detach()} has been called. Helpful when debugging
- * multiple threads working on a single span.
+ * Close this TraceScope, ending the trace span it is managing.
*/
- public boolean isDetached() {
- return detached;
+ @Override
+ public void close() {
+ tracer.closeScope(this);
+
+ }
+
+ public void addKVAnnotation(String key, String value) {
+ span.addKVAnnotation(key, value);
+ }
+
+ public void addTimelineAnnotation(String msg) {
+ span.addTimelineAnnotation(msg);
}
@Override
- public void close() {
- if (detached) {
- return;
- }
- detached = true;
- Span cur = Tracer.getInstance().currentSpan();
- if (cur != span) {
- Tracer.clientError("Tried to close trace span " + span + " but " +
- "it is not the current span for the " +
- Thread.currentThread().getName() + " thread. You have " +
- "probably forgotten to close or detach " + cur);
- } else {
- span.stop();
- Tracer.getInstance().setCurrentSpan(savedSpan);
- }
+ public String toString() {
+ return "TraceScope(tracerId=" + tracer.getTracerId() +
+ ", span=" + span.toJson() +
+ ", detached=" + detached + ")";
}
}
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/Tracer.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/Tracer.java b/htrace-core/src/main/java/org/apache/htrace/core/Tracer.java
index b2ef6e6..6054a27 100644
--- a/htrace-core/src/main/java/org/apache/htrace/core/Tracer.java
+++ b/htrace-core/src/main/java/org/apache/htrace/core/Tracer.java
@@ -16,114 +16,526 @@
*/
package org.apache.htrace.core;
+import java.io.Closeable;
+import java.lang.System;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadLocalRandom;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import java.util.List;
-import java.util.Random;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.ThreadLocalRandom;
-
/**
* A Tracer provides the implementation for collecting and distributing Spans
* within a process.
*/
-public class Tracer {
+public class Tracer implements Closeable {
private static final Log LOG = LogFactory.getLog(Tracer.class);
- static long nonZeroRandom64() {
- long id;
- Random random = ThreadLocalRandom.current();
- do {
- id = random.nextLong();
- } while (id == 0);
- return id;
- }
+ /**
+ * The thread-specific context for this Tracer.
+ *
+ * This tracks the current number of trace scopes in a particular thread
+ * created by this tracer. We use this to apply our samplers only for the
+ * "top-level" spans.
+ *
+ * Note that we can't put the TraceScope objects themselves in this context,
+ * since we need to be able to use TraceScopes created by other Tracers, and
+ * this context is per-Tracer.
+ */
+ private static class ThreadContext {
+ private long depth;
- private final List<SpanReceiver> receivers = new CopyOnWriteArrayList<SpanReceiver>();
- private static final ThreadLocal<Span> currentSpan = new ThreadLocal<Span>() {
+ ThreadContext() {
+ this.depth = 0;
+ }
+
+ boolean isTopLevel() {
+ return (depth == 0);
+ }
+
+ void pushScope() {
+ depth++;
+ }
+
+ TraceScope pushNewScope(Tracer tracer, Span span, TraceScope parentScope) {
+ TraceScope scope = new TraceScope(tracer, span, parentScope);
+ threadLocalScope.set(scope);
+ depth++;
+ return scope;
+ }
+
+ void popScope() {
+ if (depth <= 0) {
+ throwClientError("There were more trace scopes closed than " +
+ "were opened.");
+ }
+ depth--;
+ }
+ };
+
+ /**
+ * A subclass of ThreadLocal that starts off with a non-null initial value in
+ * each thread.
+ */
+ private static class ThreadLocalContext extends ThreadLocal<ThreadContext> {
@Override
- protected Span initialValue() {
- return null;
+ protected ThreadContext initialValue() {
+ return new ThreadContext();
}
};
+
+ /**
+ * The current trace scope. This is global, so it is shared amongst all
+ * libraries using HTrace.
+ */
+ final static ThreadLocal<TraceScope> threadLocalScope =
+ new ThreadLocal<TraceScope>();
+
+ /**
+ * An empty array of SpanId objects. Can be used rather than constructing a
+ * new object whenever we need an empty array.
+ */
private static final SpanId EMPTY_PARENT_ARRAY[] = new SpanId[0];
/**
+ * The tracerId.
+ */
+ private final String tracerId;
+
+ /**
+ * The TracerPool which this Tracer belongs to.
+ *
+ * This gets set to null after the Tracer is closed in order to catch some
+ * use-after-close errors. Note that we do not synchronize access on this
+ * field, since it only changes when the Tracer is closed, and the Tracer
+ * should not be used after that.
+ */
+ private TracerPool tracerPool;
+
+ /**
+ * The current thread-local context for this particualr Tracer.
+ */
+ private final ThreadLocalContext threadContext;
+
+ /**
+ * The NullScope instance for this Tracer.
+ */
+ private final NullScope nullScope;
+
+ /**
+ * The currently active Samplers.
+ *
+ * Arrays are immutable once set. You must take the Tracer lock in order to
+ * set this to a new array. If this is null, the Tracer is closed.
+ */
+ private volatile Sampler[] curSamplers;
+
+ /**
* Log a client error, and throw an exception.
*
* @param str The message to use in the log and the exception.
*/
- static void clientError(String str) {
+ static void throwClientError(String str) {
LOG.error(str);
throw new RuntimeException(str);
}
/**
- * Internal class for defered singleton idiom.
- * <p/>
- * https://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom
+ * If the current thread is tracing, this function returns the Tracer that is
+ * being used; otherwise, it returns null.
*/
- private static class TracerHolder {
- private static final Tracer INSTANCE = new Tracer();
+ public static Tracer curThreadTracer() {
+ TraceScope traceScope = threadLocalScope.get();
+ if (traceScope == null) {
+ return null;
+ }
+ return traceScope.tracer;
}
- public static Tracer getInstance() {
- return TracerHolder.INSTANCE;
+ Tracer(String tracerId, TracerPool tracerPool, Sampler[] curSamplers) {
+ this.tracerId = tracerId;
+ this.tracerPool = tracerPool;
+ this.threadContext = new ThreadLocalContext();
+ this.nullScope = new NullScope(this);
+ this.curSamplers = curSamplers;
}
- protected Span createNew(String description) {
- Span parent = currentSpan.get();
- if (parent == null) {
- return new MilliSpan.Builder().
- begin(System.currentTimeMillis()).
- end(0).
- description(description).
- parents(EMPTY_PARENT_ARRAY).
- spanId(SpanId.fromRandom()).
- build();
- } else {
- return parent.child(description);
+ public String getTracerId() {
+ return tracerId;
+ }
+
+ private TraceScope newScopeImpl(ThreadContext context, String description) {
+ Span span = new MilliSpan.Builder().
+ tracerId(tracerId).
+ begin(System.currentTimeMillis()).
+ description(description).
+ parents(EMPTY_PARENT_ARRAY).
+ spanId(SpanId.fromRandom()).
+ build();
+ return context.pushNewScope(this, span, null);
+ }
+
+ private TraceScope newScopeImpl(ThreadContext context, String description,
+ TraceScope parentScope) {
+ SpanId parentId = parentScope.getSpan().getSpanId();
+ Span span = new MilliSpan.Builder().
+ tracerId(tracerId).
+ begin(System.currentTimeMillis()).
+ description(description).
+ parents(new SpanId[] { parentId }).
+ spanId(parentId.newChildId()).
+ build();
+ return context.pushNewScope(this, span, parentScope);
+ }
+
+ private TraceScope newScopeImpl(ThreadContext context, String description,
+ SpanId parentId) {
+ Span span = new MilliSpan.Builder().
+ tracerId(tracerId).
+ begin(System.currentTimeMillis()).
+ description(description).
+ parents(new SpanId[] { parentId }).
+ spanId(parentId.newChildId()).
+ build();
+ return context.pushNewScope(this, span, null);
+ }
+
+ private TraceScope newScopeImpl(ThreadContext context, String description,
+ TraceScope parentScope, SpanId secondParentId) {
+ SpanId parentId = parentScope.getSpan().getSpanId();
+ Span span = new MilliSpan.Builder().
+ tracerId(tracerId).
+ begin(System.currentTimeMillis()).
+ description(description).
+ parents(new SpanId[] { parentId, secondParentId }).
+ spanId(parentId.newChildId()).
+ build();
+ return context.pushNewScope(this, span, parentScope);
+ }
+
+ /**
+ * Create a new trace scope.
+ *
+ * If there are no scopes above the current scope, we will apply our
+ * configured samplers. Otherwise, we will create a span only if this thread
+ * is already tracing, or if the passed parentID was valid.
+ *
+ * @param description The description of the new span to create.
+ * @param parentId If this is a valid span ID, it will be added to
+ * the parents of the new span we create.
+ * @return The new trace scope.
+ */
+ public TraceScope newScope(String description, SpanId parentId) {
+ TraceScope parentScope = threadLocalScope.get();
+ ThreadContext context = threadContext.get();
+ if (parentScope != null) {
+ if (parentId.isValid() &&
+ (!parentId.equals(parentScope.getSpan().getSpanId()))) {
+ return newScopeImpl(context, description, parentScope, parentId);
+ } else {
+ return newScopeImpl(context, description, parentScope);
+ }
+ } else if (parentId.isValid()) {
+ return newScopeImpl(context, description, parentId);
+ }
+ if (!context.isTopLevel()) {
+ context.pushScope();
+ return nullScope;
}
+ if (!sample()) {
+ context.pushScope();
+ return nullScope;
+ }
+ return newScopeImpl(context, description);
}
- protected boolean isTracing() {
- return currentSpan.get() != null;
+ /**
+ * Create a new trace scope.
+ *
+ * If there are no scopes above the current scope, we will apply our
+ * configured samplers. Otherwise, we will create a span only if this thread
+ * is already tracing.
+ */
+ public TraceScope newScope(String description) {
+ TraceScope parentScope = threadLocalScope.get();
+ ThreadContext context = threadContext.get();
+ if (parentScope != null) {
+ return newScopeImpl(context, description, parentScope);
+ }
+ if (!context.isTopLevel()) {
+ context.pushScope();
+ return nullScope;
+ }
+ if (!sample()) {
+ context.pushScope();
+ return nullScope;
+ }
+ return newScopeImpl(context, description);
}
- protected Span currentSpan() {
- return currentSpan.get();
+ /**
+ * Return a null trace scope.
+ */
+ public TraceScope newNullScope() {
+ ThreadContext context = threadContext.get();
+ context.pushScope();
+ return nullScope;
}
- public void deliver(Span span) {
+ /**
+ * Wrap the callable in a TraceCallable, if tracing.
+ *
+ * @return The callable provided, wrapped if tracing, 'callable' if not.
+ */
+ public <V> Callable<V> wrap(Callable<V> callable, String description) {
+ TraceScope parentScope = threadLocalScope.get();
+ if (parentScope == null) {
+ return callable;
+ }
+ return new TraceCallable<V>(this, parentScope, callable, description);
+ }
+
+ /**
+ * Wrap the runnable in a TraceRunnable, if tracing
+ *
+ * @return The runnable provided, wrapped if tracing, 'runnable' if not.
+ */
+ public Runnable wrap(Runnable runnable, String description) {
+ TraceScope parentScope = threadLocalScope.get();
+ if (parentScope == null) {
+ return runnable;
+ }
+ return new TraceRunnable(this, parentScope, runnable, description);
+ }
+
+ public TraceExecutorService newTraceExecutorService(ExecutorService impl,
+ String scopeName) {
+ return new TraceExecutorService(this, scopeName, impl);
+ }
+
+ public TracerPool getTracerPool() {
+ if (tracerPool == null) {
+ throwClientError(toString() + " is closed.");
+ }
+ return tracerPool;
+ }
+
+ /**
+ * Returns an object that will trace all calls to itself.
+ */
+ @SuppressWarnings("unchecked")
+ <T, V> T createProxy(final T instance) {
+ final Tracer tracer = this;
+ InvocationHandler handler = new InvocationHandler() {
+ @Override
+ public Object invoke(Object obj, Method method, Object[] args)
+ throws Throwable {
+ TraceScope scope = tracer.newScope(method.getName());
+ try {
+ return method.invoke(instance, args);
+ } catch (Throwable ex) {
+ ex.printStackTrace();
+ throw ex;
+ } finally {
+ scope.close();
+ }
+ }
+ };
+ return (T) Proxy.newProxyInstance(instance.getClass().getClassLoader(),
+ instance.getClass().getInterfaces(), handler);
+ }
+
+ /**
+ * Return true if we should create a new top-level span.
+ *
+ * We will create the span if any configured sampler returns true.
+ */
+ private boolean sample() {
+ Sampler[] samplers = curSamplers;
+ for (Sampler sampler : samplers) {
+ if (sampler.next()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns an array of all the current Samplers.
+ *
+ * Note that if the current Samplers change, those changes will not be
+ * reflected in this array. In other words, this array may be stale.
+ */
+ public Sampler[] getSamplers() {
+ return curSamplers;
+ }
+
+ /**
+ * Add a new Sampler.
+ *
+ * @param sampler The new sampler to add.
+ * You cannot add a particular Sampler object more
+ * than once. You may add multiple Sampler objects
+ * of the same type, although this is not recommended.
+ *
+ * @return True if the sampler was added; false if it already had
+ * been added earlier.
+ */
+ public synchronized boolean addSampler(Sampler sampler) {
+ if (tracerPool == null) {
+ throwClientError(toString() + " is closed.");
+ }
+ Sampler[] samplers = curSamplers;
+ int j = 0;
+ for (int i = 0; i < samplers.length; i++) {
+ if (samplers[i] == sampler) {
+ return false;
+ }
+ }
+ Sampler[] newSamplers =
+ Arrays.copyOf(samplers, samplers.length + 1);
+ newSamplers[samplers.length] = sampler;
+ curSamplers = newSamplers;
+ return true;
+ }
+
+ /**
+ * Remove a SpanReceiver.
+ *
+ * @param sampler The sampler to remove.
+ */
+ public synchronized boolean removeSampler(Sampler sampler) {
+ if (tracerPool == null) {
+ throwClientError(toString() + " is closed.");
+ }
+ Sampler[] samplers = curSamplers;
+ int j = 0;
+ for (int i = 0; i < samplers.length; i++) {
+ if (samplers[i] == sampler) {
+ Sampler[] newSamplers = new Sampler[samplers.length - 1];
+ System.arraycopy(samplers, 0, newSamplers, 0, i);
+ System.arraycopy(samplers, i + 1, newSamplers, i,
+ samplers.length - i - 1);
+ curSamplers = newSamplers;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void detachScope(TraceScope scope) {
+ TraceScope curScope = threadLocalScope.get();
+ if (curScope != scope) {
+ throwClientError("Can't detach TraceScope for " +
+ scope.getSpan().toJson() + " because it is not the current " +
+ "TraceScope in thread " + Thread.currentThread().getName());
+ }
+ ThreadContext context = threadContext.get();
+ context.popScope();
+ threadLocalScope.set(scope.getParent());
+ }
+
+ void reattachScope(TraceScope scope) {
+ TraceScope parent = threadLocalScope.get();
+ Tracer.threadLocalScope.set(scope);
+ ThreadContext context = threadContext.get();
+ context.pushScope();
+ scope.setParent(parent);
+ }
+
+ void closeScope(TraceScope scope) {
+ TraceScope curScope = threadLocalScope.get();
+ if (curScope != scope) {
+ throwClientError("Can't close TraceScope for " +
+ scope.getSpan().toJson() + " because it is not the current " +
+ "TraceScope in thread " + Thread.currentThread().getName());
+ }
+ if (tracerPool == null) {
+ throwClientError(toString() + " is closed.");
+ }
+ SpanReceiver[] receivers = tracerPool.getReceivers();
+ if (receivers == null) {
+ throwClientError(toString() + " is closed.");
+ }
+ ThreadContext context = threadContext.get();
+ context.popScope();
+ threadLocalScope.set(scope.getParent());
+ scope.setParent(null);
+ Span span = scope.getSpan();
+ span.stop();
for (SpanReceiver receiver : receivers) {
receiver.receiveSpan(span);
}
}
- protected void addReceiver(SpanReceiver receiver) {
- receivers.add(receiver);
+ void popNullScope() {
+ TraceScope curScope = threadLocalScope.get();
+ if (curScope != null) {
+ throwClientError("Attempted to close an empty scope, but it was not " +
+ "the current thread scope in thread " +
+ Thread.currentThread().getName());
+ }
+ ThreadContext context = threadContext.get();
+ context.popScope();
}
- protected void removeReceiver(SpanReceiver receiver) {
- receivers.remove(receiver);
+ public static Span getCurrentSpan() {
+ TraceScope curScope = threadLocalScope.get();
+ if (curScope == null) {
+ return null;
+ } else {
+ return curScope.getSpan();
+ }
+ }
+
+ public static SpanId getCurrentSpanId() {
+ TraceScope curScope = threadLocalScope.get();
+ if (curScope == null) {
+ return SpanId.INVALID;
+ } else {
+ return curScope.getSpan().getSpanId();
+ }
}
- protected Span setCurrentSpan(Span span) {
- if (LOG.isTraceEnabled()) {
- LOG.trace("setting current span " + span);
+ @Override
+ public synchronized void close() {
+ if (tracerPool == null) {
+ return;
}
- currentSpan.set(span);
- return span;
+ curSamplers = new Sampler[0];
+ tracerPool.removeTracer(this);
}
- public TraceScope continueSpan(Span s) {
- Span oldCurrent = currentSpan();
- setCurrentSpan(s);
- return new TraceScope(s, oldCurrent);
+ /**
+ * Get the hash code of a Tracer object.
+ *
+ * This hash code is based on object identity.
+ * This is used in TracerPool to create a hash table of Tracers.
+ */
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(this);
}
- protected int numReceivers() {
- return receivers.size();
+ /**
+ * Compare two tracer objects.
+ *
+ * Tracer objects are always compared by object equality.
+ * This is used in TracerPool to create a hash table of Tracers.
+ */
+ @Override
+ public boolean equals(Object other) {
+ return (this == other);
+ }
+
+ @Override
+ public String toString() {
+ return "Tracer(" + tracerId + ")";
}
+
}
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/TracerBuilder.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/TracerBuilder.java b/htrace-core/src/main/java/org/apache/htrace/core/TracerBuilder.java
new file mode 100644
index 0000000..0f12253
--- /dev/null
+++ b/htrace-core/src/main/java/org/apache/htrace/core/TracerBuilder.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.htrace.core;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.lang.reflect.Constructor;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Builds a new Tracer object.
+ */
+public class TracerBuilder {
+ public final static String SPAN_RECEIVER_CLASSES_KEY =
+ "span.receiver.classes";
+ public final static String SAMPLER_CLASSES_KEY =
+ "sampler.classes";
+
+ private static final Log LOG = LogFactory.getLog(TracerBuilder.class);
+
+ private String name;
+ private HTraceConfiguration conf = HTraceConfiguration.EMPTY;
+ private ClassLoader classLoader =
+ TracerBuilder.class.getClassLoader();
+ private TracerPool tracerPool = TracerPool.GLOBAL;
+
+ public TracerBuilder() {
+ }
+
+ public TracerBuilder name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public TracerBuilder conf(HTraceConfiguration conf) {
+ this.conf = conf;
+ return this;
+ }
+
+ public TracerBuilder tracerPool(TracerPool tracerPool) {
+ this.tracerPool = tracerPool;
+ return this;
+ }
+
+ private void loadSamplers(List<Sampler> samplers) {
+ String classNamesStr = conf.get(SAMPLER_CLASSES_KEY, "");
+ List<String> classNames = getClassNamesFromConf(classNamesStr);
+ StringBuilder bld = new StringBuilder();
+ String prefix = "";
+ for (String className : classNames) {
+ try {
+ Sampler sampler = new Sampler.Builder(conf).
+ className(className).
+ classLoader(classLoader).
+ build();
+ samplers.add(sampler);
+ bld.append(prefix).append(className);
+ prefix = ", ";
+ } catch (Throwable e) {
+ LOG.error("Failed to create SpanReceiver of type " + className, e);
+ }
+ }
+ String resultString = bld.toString();
+ if (resultString.isEmpty()) {
+ resultString = "no samplers";
+ }
+ LOG.info(SAMPLER_CLASSES_KEY + " = " + classNamesStr +
+ "; loaded " + resultString);
+ }
+
+ private void loadSpanReceivers() {
+ String classNamesStr = conf.get(SPAN_RECEIVER_CLASSES_KEY, "");
+ List<String> classNames = getClassNamesFromConf(classNamesStr);
+ StringBuilder bld = new StringBuilder();
+ String prefix = "";
+ for (String className : classNames) {
+ try {
+ tracerPool.loadReceiverType(className, conf, classLoader);
+ bld.append(prefix).append(className);
+ prefix = ", ";
+ } catch (Throwable e) {
+ LOG.error("Failed to create SpanReceiver of type " + className, e);
+ }
+ }
+ String resultString = bld.toString();
+ if (resultString.isEmpty()) {
+ resultString = "no span receivers";
+ }
+ LOG.info(SPAN_RECEIVER_CLASSES_KEY + " = " + classNamesStr +
+ "; loaded " + resultString);
+ }
+
+ /**
+ * Get a list of class names from the HTrace configuration.
+ * Entries which are empty will be removed. Entries which lack a package will
+ * be given the default package.
+ *
+ * @param classNamesStr A semicolon-separated string containing a list
+ * of class names.
+ * @return A list of class names.
+ */
+ private List<String> getClassNamesFromConf(String classNamesStr) {
+ String classNames[] = classNamesStr.split(";");
+ LinkedList<String> cleanedClassNames = new LinkedList<String>();
+ for (String className : classNames) {
+ String cleanedClassName = className.trim();
+ if (!cleanedClassName.isEmpty()) {
+ cleanedClassNames.add(cleanedClassName);
+ }
+ }
+ return cleanedClassNames;
+ }
+
+ public Tracer build() {
+ if (name == null) {
+ throw new RuntimeException("You must specify a name for this Tracer.");
+ }
+ LinkedList<SpanReceiver> spanReceivers = new LinkedList<SpanReceiver>();
+ LinkedList<Sampler> samplers = new LinkedList<Sampler>();
+ loadSamplers(samplers);
+ String tracerId = new TracerId(conf, name).get();
+ Tracer tracer = new Tracer(tracerId, tracerPool,
+ samplers.toArray(new Sampler[samplers.size()]));
+ tracerPool.addTracer(tracer);
+ loadSpanReceivers();
+ return tracer;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7997d208/htrace-core/src/main/java/org/apache/htrace/core/TracerId.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/main/java/org/apache/htrace/core/TracerId.java b/htrace-core/src/main/java/org/apache/htrace/core/TracerId.java
index 7cdbd34..da482fe 100644
--- a/htrace-core/src/main/java/org/apache/htrace/core/TracerId.java
+++ b/htrace-core/src/main/java/org/apache/htrace/core/TracerId.java
@@ -16,9 +16,6 @@
*/
package org.apache.htrace.core;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
@@ -30,6 +27,9 @@ import java.util.Enumeration;
import java.util.Locale;
import java.util.TreeSet;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
/**
* The HTrace tracer ID.<p/>
*
@@ -38,17 +38,19 @@ import java.util.TreeSet;
* replace with the correct values at runtime.<p/>
*
* <ul>
- * <li>${ip}: will be replaced with an ip address.</li>
- * <li>${pname}: will be replaced the process name obtained from java.</li>
+ * <li>%{tname}: the tracer name supplied when creating the Tracer.</li>
+ * <li>%{pname}: the process name obtained from the JVM.</li>
+ * <li>%{ip}: will be replaced with an ip address.</li>
+ * <li>%{pid}: the numerical process ID from the operating system.</li>
* </ul><p/>
*
- * For example, the string "${pname}/${ip}" will be replaced with something
+ * For example, the string "%{pname}/%{ip}" will be replaced with something
* like: DataNode/192.168.0.1, assuming that the process' name is DataNode
* and its IP address is 192.168.0.1.<p/>
*
- * Process ID strings can contain backslashes as escapes.
- * For example, "\a" will map to "a". "\${ip}" will map to the literal
- * string "${ip}", not the IP address. A backslash itself can be escaped by a
+ * ID strings can contain backslashes as escapes.
+ * For example, "\a" will map to "a". "\%{ip}" will map to the literal
+ * string "%{ip}", not the IP address. A backslash itself can be escaped by a
* preceding backslash.
*/
public final class TracerId {
@@ -57,16 +59,20 @@ public final class TracerId {
/**
* The configuration key to use for process id
*/
- public static final String TRACER_ID_KEY = "process.id";
+ public static final String TRACER_ID_KEY = "tracer.id";
/**
- * The default process ID to use if no other ID is configured.
+ * The default tracer ID to use if no other ID is configured.
*/
- private static final String DEFAULT_TRACER_ID = "${pname}/${ip}";
+ private static final String DEFAULT_TRACER_ID = "%{tname}/%{ip}";
+
+ private final String tracerName;
private final String tracerId;
- TracerId(String fmt) {
+ public TracerId(HTraceConfiguration conf, String tracerName) {
+ this.tracerName = tracerName;
+ String fmt = conf.get(TRACER_ID_KEY, DEFAULT_TRACER_ID);
StringBuilder bld = new StringBuilder();
StringBuilder varBld = null;
boolean escaping = false;
@@ -81,7 +87,7 @@ public final class TracerId {
}
switch (varSeen) {
case 0:
- if (c == '$') {
+ if (c == '%') {
if (!escaping) {
varSeen = 1;
continue;
@@ -101,7 +107,7 @@ public final class TracerId {
}
escaping = false;
varSeen = 0;
- bld.append("$").append(c);
+ bld.append("%").append(c);
break;
default:
if (c == '}') {
@@ -130,12 +136,10 @@ public final class TracerId {
}
}
- public TracerId(HTraceConfiguration conf) {
- this(conf.get(TRACER_ID_KEY, DEFAULT_TRACER_ID));
- }
-
private String processShellVar(String var) {
- if (var.equals("pname")) {
+ if (var.equals("tname")) {
+ return tracerName;
+ } else if (var.equals("pname")) {
return getProcessName();
} else if (var.equals("ip")) {
return getBestIpString();