com.navercorp.pinpoint.web.service.TransactionInfoServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.navercorp.pinpoint.web.service.TransactionInfoServiceImpl.java

Source

/*
 * 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.web.service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import com.navercorp.pinpoint.common.server.bo.AnnotationBo;
import com.navercorp.pinpoint.common.server.bo.Event;
import com.navercorp.pinpoint.common.server.bo.SpanBo;
import com.navercorp.pinpoint.loader.service.AnnotationKeyRegistryService;
import com.navercorp.pinpoint.loader.service.ServiceTypeRegistryService;
import com.navercorp.pinpoint.common.trace.AnnotationKeyMatcher;
import com.navercorp.pinpoint.common.trace.LoggingInfo;
import com.navercorp.pinpoint.common.util.TransactionId;
import com.navercorp.pinpoint.web.calltree.span.Align;
import com.navercorp.pinpoint.web.calltree.span.CallTreeIterator;
import com.navercorp.pinpoint.web.calltree.span.CallTreeNode;
import com.navercorp.pinpoint.web.dao.TraceDao;
import com.navercorp.pinpoint.web.filter.Filter;
import com.navercorp.pinpoint.web.security.MetaDataFilter;
import com.navercorp.pinpoint.web.security.MetaDataFilter.MetaData;
import com.navercorp.pinpoint.web.vo.BusinessTransactions;
import com.navercorp.pinpoint.web.vo.Range;
import com.navercorp.pinpoint.web.vo.callstacks.Record;
import com.navercorp.pinpoint.web.vo.callstacks.RecordFactory;
import com.navercorp.pinpoint.web.vo.callstacks.RecordSet;

import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

/**
 *
 * @author jaehong.kim
 */
@Service
public class TransactionInfoServiceImpl implements TransactionInfoService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    @Qualifier("hbaseTraceDaoFactory")
    private TraceDao traceDao;

    @Autowired
    private AnnotationKeyMatcherService annotationKeyMatcherService;

    @Autowired
    private ServiceTypeRegistryService registry;

    @Autowired
    private AnnotationKeyRegistryService annotationKeyRegistryService;

    @Autowired(required = false)
    private MetaDataFilter metaDataFilter;

    @Autowired
    private ProxyRequestTypeRegistryService proxyRequestTypeRegistryService;

    // Temporarily disabled Because We need to solve authentication problem inter system.
    // @Value("#{pinpointWebProps['log.enable'] ?: false}")
    // private boolean logLinkEnable;

    // @Value("#{pinpointWebProps['log.button.name'] ?: ''}")
    // private String logButtonName;

    // @Value("#{pinpointWebProps['log.page.url'] ?: ''}")
    // private String logPageUrl;

    @Override
    public BusinessTransactions selectBusinessTransactions(List<TransactionId> transactionIdList,
            String applicationName, Range range, Filter filter) {
        if (transactionIdList == null) {
            throw new NullPointerException("transactionIdList must not be null");
        }
        if (applicationName == null) {
            throw new NullPointerException("applicationName must not be null");
        }
        if (filter == null) {
            throw new NullPointerException("filter must not be null");
        }
        if (range == null) {
            // TODO range is not used - check the logic again
            throw new NullPointerException("range must not be null");
        }

        List<List<SpanBo>> traceList;

        if (filter == Filter.NONE) {
            traceList = this.traceDao.selectSpans(transactionIdList);
        } else {
            traceList = this.traceDao.selectAllSpans(transactionIdList);
        }

        BusinessTransactions businessTransactions = new BusinessTransactions();
        for (List<SpanBo> trace : traceList) {
            if (!filter.include(trace)) {
                continue;
            }

            for (SpanBo spanBo : trace) {
                // show application's incoming requests
                if (applicationName.equals(spanBo.getApplicationId())) {
                    businessTransactions.add(spanBo);
                }
            }
        }

        return businessTransactions;
    }

    @Override
    public RecordSet createRecordSet(CallTreeIterator callTreeIterator, long focusTimestamp, String agentId,
            long spanId) {
        if (callTreeIterator == null) {
            throw new NullPointerException("callTreeIterator must not be null");
        }

        RecordSet recordSet = new RecordSet();
        final List<Align> alignList = callTreeIterator.values();

        // finds and marks the viewPoint.base on focusTimestamp.
        // focusTimestamp is needed to determine which span to use as reference when there are more than 2 spans making up a transaction.
        // for cases where focus cannot be found due to an error, a separate marker is needed.
        // TODO potential error - because server time is used, there may be more than 2 focusTime due to differences in server times.
        Align viewPointAlign = findViewPoint(alignList, focusTimestamp, agentId, spanId);
        // FIXME patched temporarily for cases where focusTimeSpanBo is not found. Need a more complete solution.
        if (viewPointAlign != null) {
            recordSet.setAgentId(viewPointAlign.getAgentId());
            recordSet.setApplicationId(viewPointAlign.getApplicationId());

            final String applicationName = getRpcArgument(viewPointAlign);
            recordSet.setApplicationName(applicationName);
        }

        // find the startTime to use as reference
        long startTime = getStartTime(alignList);
        recordSet.setStartTime(startTime);

        // find the endTime to use as reference
        long endTime = getEndTime(alignList);
        recordSet.setEndTime(endTime);

        recordSet.setLoggingTransactionInfo(findIsLoggingTransactionInfo(alignList));

        final SpanAlignPopulate spanAlignPopulate = new SpanAlignPopulate();
        List<Record> recordList = spanAlignPopulate.populateSpanRecord(callTreeIterator);
        if (viewPointAlign != null) {
            // mark the record to be used as focus
            long beginTimeStamp = viewPointAlign.getStartTime();

            markFocusRecord(recordList, viewPointAlign);
            recordSet.setBeginTimestamp(beginTimeStamp);
        }

        recordSet.setRecordList(recordList);

        return recordSet;
    }

    private boolean findIsLoggingTransactionInfo(List<Align> alignList) {
        for (Align align : alignList) {
            if (align.isSpan()) {
                if (align.getLoggingTransactionInfo() == LoggingInfo.LOGGED.getCode()) {
                    return true;
                }
            }
        }

        return false;
    }

    private void markFocusRecord(List<Record> recordList, final Align viewPointTimeAlign) {
        final String agentId = viewPointTimeAlign.getAgentId();
        for (Record record : recordList) {
            if (viewPointTimeAlign.getSpanId() == record.getSpanId()
                    && record.getBegin() == viewPointTimeAlign.getStartTime()) {
                if (agentId == null) {
                    if (record.getAgent() == null) {
                        record.setFocused(true);
                        break;
                    }
                } else {
                    if (record.getAgent() != null && agentId.equals(record.getAgent())) {
                        record.setFocused(true);
                        break;
                    }
                }
            }
        }
    }

    // private void addlogLink(RecordSet recordSet) {
    // List<Record> records = recordSet.getRecordList();
    // List<TransactionInfo> transactionInfoes = new LinkedList<TransactionInfo>();
    //
    // for (Iterator<Record> iterator = records.iterator(); iterator.hasNext();) {
    // Record record = (Record) iterator.next();
    //
    // if(record.getTransactionId() == null) {
    // continue;
    // }
    //
    // TransactionInfo transactionInfo = new TransactionInfo(record.getTransactionId(), record.getSpanId());
    //
    // if (transactionInfoes.contains(transactionInfo)) {
    // continue;
    // };
    //
    // record.setLogPageUrl(logPageUrl);
    // record.setLogButtonName(logButtonName);
    //
    // transactionInfoes.add(transactionInfo);
    // }
    // }

    private long getStartTime(List<Align> alignList) {
        if (CollectionUtils.isEmpty(alignList)) {
            return 0;
        }
        Align align = alignList.get(0);
        return align.getStartTime();
    }

    private long getEndTime(List<Align> alignList) {
        if (CollectionUtils.isEmpty(alignList)) {
            return 0;
        }
        Align align = alignList.get(0);
        return align.getEndTime();
    }

    private Align findViewPoint(List<Align> alignList, long focusTimestamp, String agentId, long spanId) {
        Align firstSpan = null;
        for (Align align : alignList) {
            if (align.isSpan()) {
                if (isViewPoint(align, focusTimestamp, agentId, spanId)) {
                    return align;
                }
                if (firstSpan == null) {
                    firstSpan = align;
                }
            }
        }
        // return firstSpan when focus Span could not be found.
        return firstSpan;
    }

    private boolean isViewPoint(final Align align, long focusTimestamp, String agentId, long spanId) {
        if (align.getCollectorAcceptTime() != focusTimestamp) {
            return false;
        }

        if (logger.isDebugEnabled()) {
            logger.debug(
                    "Matched focusTimestamp of view point. focusTimestamp={}, spanAlign={focusTimestamp={}, agentId={}, spanId={}}",
                    focusTimestamp, align.getCollectorAcceptTime(), align.getAgentId(), align.getSpanId());
        }

        // agentId
        if (agentId != null) {
            if (align.getAgentId() == null || !align.getAgentId().equals(agentId)) {
                return false;
            }
            if (logger.isDebugEnabled()) {
                logger.debug(
                        "Matched agentId of view point. agentId={}, spanAlign={focusTimestamp={}, agentId={}, spanId={}}",
                        agentId, align.getCollectorAcceptTime(), align.getAgentId(), align.getSpanId());
            }
        }

        // spanId
        if (spanId != -1) {
            if (align.getSpanId() != spanId) {
                return false;
            }
            if (logger.isDebugEnabled()) {
                logger.debug(
                        "Matched spanId of view point. spanId={}, spanAlign={focusTimestamp={}, agentId={}, spanId={}}",
                        spanId, align.getCollectorAcceptTime(), align.getAgentId(), align.getSpanId());
            }
        }

        return true;
    }

    private String getRpcArgument(Align align) {
        final String rpc = align.getRpc();
        if (rpc != null) {
            return rpc;
        }
        SpanBo spanBo = align.getSpanBo();
        return getDisplayArgument(spanBo);
    }

    private String getDisplayArgument(Event event) {
        AnnotationBo displayArgument = getDisplayArgument0(event);
        if (displayArgument == null) {
            return "";
        }
        return Objects.toString(displayArgument.getValue(), "");
    }

    private AnnotationBo getDisplayArgument0(Event event) {
        // TODO needs a more generalized implementation for Arcus
        List<AnnotationBo> list = event.getAnnotationBoList();
        if (list == null) {
            return null;
        }

        final AnnotationKeyMatcher matcher = annotationKeyMatcherService
                .findAnnotationKeyMatcher(event.getServiceType());
        if (matcher == null) {
            return null;
        }

        for (AnnotationBo annotation : list) {
            int key = annotation.getKey();

            if (matcher.matches(key)) {
                return annotation;
            }
        }
        return null;
    }

    private class SpanAlignPopulate {
        private List<Record> populateSpanRecord(CallTreeIterator callTreeIterator) {
            if (callTreeIterator == null) {
                throw new NullPointerException("callTreeIterator must not be null");
            }

            final List<Record> recordList = new ArrayList<>(callTreeIterator.size() * 2);
            final RecordFactory factory = new RecordFactory(annotationKeyMatcherService, registry,
                    annotationKeyRegistryService, proxyRequestTypeRegistryService);

            // annotation id has nothing to do with spanAlign's seq and thus may be incremented as long as they don't overlap.
            while (callTreeIterator.hasNext()) {
                final CallTreeNode node = callTreeIterator.next();
                if (node == null) {
                    logger.warn("Corrupt CallTree found : {}", callTreeIterator.toString());
                    throw new IllegalStateException("CallTree corrupted");
                }
                final Align align = node.getAlign();

                if (metaDataFilter != null && metaDataFilter.filter(align, MetaData.API)) {
                    if (align.isSpan()) {
                        Record record = metaDataFilter.createRecord(node, factory);
                        recordList.add(record);
                    }
                    continue;
                }

                if (metaDataFilter != null && metaDataFilter.filter(align, MetaData.PARAM)) {
                    metaDataFilter.replaceAnnotationBo(align, MetaData.PARAM);
                }

                final Record record = factory.get(node);
                recordList.add(record);

                // add exception record.
                if (align.hasException()) {
                    final Record exceptionRecord = factory.getException(record.getTab() + 1, record.getId(), align);
                    if (exceptionRecord != null) {
                        recordList.add(exceptionRecord);
                    }
                }

                // add annotation record.
                if (!align.getAnnotationBoList().isEmpty()) {
                    final List<Record> annotations = factory.getAnnotations(record.getTab() + 1, record.getId(),
                            align);
                    recordList.addAll(annotations);
                }

                // add remote record.(span only)
                if (align.getRemoteAddr() != null) {
                    final Record remoteAddressRecord = factory.getParameter(record.getTab() + 1, record.getId(),
                            "REMOTE_ADDRESS", align.getRemoteAddr());
                    recordList.add(remoteAddressRecord);
                }
            }

            return recordList;
        }
    }
}