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 <[email protected]> Authored: Fri Aug 21 16:00:36 2015 +0900 Committer: Colin P. Mccabe <[email protected]> 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();
