blob: 9463f418c001eab397e2f015f086efea33e839d8 [file] [log] [blame]
/*
* 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;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.htrace.impl.MilliSpan;
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 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;
}
private final List<SpanReceiver> receivers = new CopyOnWriteArrayList<SpanReceiver>();
private static final ThreadLocal<Span> currentSpan = new ThreadLocal<Span>() {
@Override
protected Span initialValue() {
return null;
}
};
public static final TraceInfo DONT_TRACE = new TraceInfo(-1, -1);
private static final long EMPTY_PARENT_ARRAY[] = new long[0];
/**
* 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) {
LOG.error(str);
throw new RuntimeException(str);
}
/**
* Internal class for defered singleton idiom.
* <p/>
* https://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom
*/
private static class TracerHolder {
private static final Tracer INSTANCE = new Tracer();
}
public static Tracer getInstance() {
return TracerHolder.INSTANCE;
}
protected Span createNew(String description) {
Span parent = currentSpan.get();
if (parent == null) {
return new MilliSpan.Builder().
begin(System.currentTimeMillis()).
end(0).
description(description).
traceId(nonZeroRandom64()).
parents(EMPTY_PARENT_ARRAY).
spanId(nonZeroRandom64()).
build();
} else {
return parent.child(description);
}
}
protected boolean isTracing() {
return currentSpan.get() != null;
}
protected Span currentSpan() {
return currentSpan.get();
}
public void deliver(Span span) {
for (SpanReceiver receiver : receivers) {
receiver.receiveSpan(span);
}
}
protected void addReceiver(SpanReceiver receiver) {
receivers.add(receiver);
}
protected void removeReceiver(SpanReceiver receiver) {
receivers.remove(receiver);
}
protected Span setCurrentSpan(Span span) {
if (LOG.isTraceEnabled()) {
LOG.trace("setting current span " + span);
}
currentSpan.set(span);
return span;
}
public TraceScope continueSpan(Span s) {
Span oldCurrent = currentSpan();
setCurrentSpan(s);
return new TraceScope(s, oldCurrent);
}
protected int numReceivers() {
return receivers.size();
}
}