/* * Copyright 2014 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.navercorp.pinpoint.profiler.context; import com.navercorp.pinpoint.bootstrap.context.AsyncTraceId; import com.navercorp.pinpoint.bootstrap.context.Trace; import com.navercorp.pinpoint.bootstrap.context.TraceId; import com.navercorp.pinpoint.common.annotations.InterfaceAudience; import com.navercorp.pinpoint.exception.PinpointException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author emeroad * @author Taejin Koo */ public class ThreadLocalTraceFactory implements TraceFactory { private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final Binder<Trace> threadLocalBinder = new ThreadLocalBinder<Trace>(); private final BaseTraceFactory baseTraceFactory; public ThreadLocalTraceFactory(BaseTraceFactory baseTraceFactory) { if (baseTraceFactory == null) { throw new NullPointerException("baseTraceFactory must not be null"); } this.baseTraceFactory = baseTraceFactory; } /** * Return Trace object AFTER validating whether it can be sampled or not. * * @return Trace */ @Override public Trace currentTraceObject() { final Trace trace = threadLocalBinder.get(); if (trace == null) { return null; } if (trace.canSampled()) { return trace; } return null; } /** * Return Trace object without validating * * @return */ @Override public Trace currentRpcTraceObject() { final Trace trace = threadLocalBinder.get(); if (trace == null) { return null; } return trace; } @Override public Trace currentRawTraceObject() { return threadLocalBinder.get(); } @Override public Trace disableSampling() { checkBeforeTraceObject(); final Trace trace = this.baseTraceFactory.disableSampling(); bind(trace); return trace; } // continue to trace the request that has been determined to be sampled on previous nodes @Override public Trace continueTraceObject(final TraceId traceId) { checkBeforeTraceObject(); Trace trace = this.baseTraceFactory.continueTraceObject(traceId); bind(trace); return trace; } @Override public Trace continueTraceObject(Trace trace) { checkBeforeTraceObject(); bind(trace); return trace; } private void checkBeforeTraceObject() { final Trace old = this.threadLocalBinder.get(); if (old != null) { final PinpointException exception = new PinpointException("already Trace Object exist."); if (logger.isWarnEnabled()) { logger.warn("beforeTrace:{}", old, exception); } throw exception; } } @Override public Trace newTraceObject() { checkBeforeTraceObject(); final Trace trace = this.baseTraceFactory.newTraceObject(); bind(trace); return trace; } private void bind(Trace trace) { threadLocalBinder.set(trace); // // TODO traceChain example // Trace traceChain = new TraceChain(trace); // threadLocalBinder.set(traceChain); // // // MetricTraceFactory // final Trace delegatedTrace = this.delegate.newTraceObject(); // if (delegatedTrace instanceof TraceChain) { // TraceChain chain = (TraceChain)delegatedTrace; // TraceWrap metricTrace = new MetricTraceWrap(); // // add metricTraceWrap to traceChain // chain.addFirst(metricTrace); // return chain; // } else { // logger.warn("error???"); // return delegatedTrace; // } } @Override public Trace removeTraceObject() { return this.threadLocalBinder.remove(); } // internal async trace. @Override public Trace continueAsyncTraceObject(AsyncTraceId traceId, int asyncId, long startTime) { checkBeforeTraceObject(); final Trace trace = this.baseTraceFactory.continueAsyncTraceObject(traceId, asyncId, startTime); bind(trace); return trace; } // entry point async trace. @InterfaceAudience.LimitedPrivate("vert.x") @Override public Trace continueAsyncTraceObject(final TraceId traceId) { checkBeforeTraceObject(); final Trace trace = this.baseTraceFactory.continueAsyncTraceObject(traceId); bind(trace); return trace; } // entry point async trace. @InterfaceAudience.LimitedPrivate("vert.x") @Override public Trace newAsyncTraceObject() { checkBeforeTraceObject(); final Trace trace = this.baseTraceFactory.newAsyncTraceObject(); bind(trace); return trace; } }