/* * 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 com.google.common.collect.Ordering; import com.navercorp.pinpoint.common.server.util.AgentLifeCycleState; import com.navercorp.pinpoint.web.dao.AgentInfoDao; import com.navercorp.pinpoint.web.dao.AgentLifeCycleDao; import com.navercorp.pinpoint.web.dao.ApplicationIndexDao; import com.navercorp.pinpoint.web.filter.agent.AgentEventFilter; import com.navercorp.pinpoint.web.vo.AgentEvent; import com.navercorp.pinpoint.web.vo.AgentInfo; import com.navercorp.pinpoint.web.vo.AgentStatus; import com.navercorp.pinpoint.web.vo.Application; import com.navercorp.pinpoint.web.vo.ApplicationAgentHostList; import com.navercorp.pinpoint.web.vo.ApplicationAgentList; import com.navercorp.pinpoint.web.vo.Range; import com.navercorp.pinpoint.web.vo.timeline.inspector.AgentEventTimeline; import com.navercorp.pinpoint.web.vo.timeline.inspector.AgentEventTimelineBuilder; import com.navercorp.pinpoint.web.vo.timeline.inspector.AgentStatusTimeline; import com.navercorp.pinpoint.web.vo.timeline.inspector.InspectorTimeline; import com.navercorp.pinpoint.web.vo.timeline.inspector.AgentStatusTimelineBuilder; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.PredicateUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.Assert; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; /** * @author netspider * @author HyunGil Jeong */ @Service public class AgentInfoServiceImpl implements AgentInfoService { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private AgentEventService agentEventService; @Autowired private ApplicationIndexDao applicationIndexDao; @Autowired private AgentInfoDao agentInfoDao; @Autowired private AgentLifeCycleDao agentLifeCycleDao; @Override public ApplicationAgentList getApplicationAgentList(ApplicationAgentList.Key key) { return this.getApplicationAgentList(key, System.currentTimeMillis()); } @Override public ApplicationAgentList getApplicationAgentList(ApplicationAgentList.Key key, long timestamp) { ApplicationAgentList applicationAgentList = new ApplicationAgentList(); List<Application> applications = applicationIndexDao.selectAllApplicationNames(); for (Application application : applications) { applicationAgentList.merge(this.getApplicationAgentList(key, application.getName(), timestamp)); } return applicationAgentList; } @Override public ApplicationAgentList getApplicationAgentList(ApplicationAgentList.Key key, String applicationName) { return this.getApplicationAgentList(key, applicationName, System.currentTimeMillis()); } @Override public ApplicationAgentList getApplicationAgentList(ApplicationAgentList.Key applicationAgentListKey, String applicationName, long timestamp) { if (applicationName == null) { throw new NullPointerException("applicationName must not be null"); } if (applicationAgentListKey == null) { throw new NullPointerException("applicationAgentListKey must not be null"); } final List<String> agentIdList = this.applicationIndexDao.selectAgentIds(applicationName); if (logger.isDebugEnabled()) { logger.debug("agentIdList={}", agentIdList); } if (CollectionUtils.isEmpty(agentIdList)) { logger.debug("agentIdList is empty. applicationName={}", applicationName); return new ApplicationAgentList(new TreeMap<String, List<AgentInfo>>()); } // key = hostname // value= list fo agentinfo SortedMap<String, List<AgentInfo>> result = new TreeMap<>(); List<AgentInfo> agentInfos = this.agentInfoDao.getAgentInfos(agentIdList, timestamp); this.agentLifeCycleDao.populateAgentStatuses(agentInfos, timestamp); for (AgentInfo agentInfo : agentInfos) { if (agentInfo != null) { String hostname = applicationAgentListKey.getKey(agentInfo); if (result.containsKey(hostname)) { result.get(hostname).add(agentInfo); } else { List<AgentInfo> list = new ArrayList<>(); list.add(agentInfo); result.put(hostname, list); } } } for (List<AgentInfo> agentInfoList : result.values()) { Collections.sort(agentInfoList, AgentInfo.AGENT_NAME_ASC_COMPARATOR); } logger.info("getApplicationAgentList={}", result); return new ApplicationAgentList(result); } @Override public ApplicationAgentHostList getApplicationAgentHostList(int offset, int limit) { if (offset <= 0 || limit <= 0) { throw new IllegalArgumentException("Value must be greater than 0."); } List<String> applicationNameList = getApplicationNameList(applicationIndexDao.selectAllApplicationNames()); if (offset > applicationNameList.size()) { return new ApplicationAgentHostList(offset, offset, applicationNameList.size()); } long timeStamp = System.currentTimeMillis(); int startIndex = offset - 1; int endIndex = Math.min(startIndex + limit, applicationNameList.size()); ApplicationAgentHostList applicationAgentHostList = new ApplicationAgentHostList(offset, endIndex, applicationNameList.size()); for (int i = startIndex ; i < endIndex; i++) { String applicationName = applicationNameList.get(i); List<String> agentIds = this.applicationIndexDao.selectAgentIds(applicationName); List<AgentInfo> agentInfoList = this.agentInfoDao.getAgentInfos(agentIds, timeStamp); applicationAgentHostList.put(applicationName, agentInfoList); } return applicationAgentHostList; } private List<String> getApplicationNameList(List<Application> applications) { List<String> applicationNameList = new ArrayList<>(applications.size()); for (Application application : applications) { if (!applicationNameList.contains(application.getName())) { applicationNameList.add(application.getName()); } } Collections.sort(applicationNameList, Ordering.usingToString()); return applicationNameList; } @Override public Set<AgentInfo> getAgentsByApplicationName(String applicationName, long timestamp) { Set<AgentInfo> agentInfos = this.getAgentsByApplicationNameWithoutStatus(applicationName, timestamp); this.agentLifeCycleDao.populateAgentStatuses(agentInfos, timestamp); return agentInfos; } @Override public Set<AgentInfo> getAgentsByApplicationNameWithoutStatus(String applicationName, long timestamp) { if (applicationName == null) { throw new NullPointerException("applicationName must not be null"); } if (timestamp < 0) { throw new IllegalArgumentException("timestamp must not be less than 0"); } List<String> agentIds = this.applicationIndexDao.selectAgentIds(applicationName); List<AgentInfo> agentInfos = this.agentInfoDao.getAgentInfos(agentIds, timestamp); CollectionUtils.filter(agentInfos, PredicateUtils.notNullPredicate()); if (CollectionUtils.isEmpty(agentInfos)) { return Collections.emptySet(); } return new HashSet<>(agentInfos); } @Override public Set<AgentInfo> getRecentAgentsByApplicationName(String applicationName, long timestamp, long timeDiff) { if (timeDiff > timestamp) { throw new IllegalArgumentException("timeDiff must not be greater than timestamp"); } Set<AgentInfo> unfilteredAgentInfos = this.getAgentsByApplicationName(applicationName, timestamp); final long eventTimestampFloor = timestamp - timeDiff; Set<AgentInfo> filteredAgentInfos = new HashSet<>(); for (AgentInfo agentInfo : unfilteredAgentInfos) { AgentStatus agentStatus = agentInfo.getStatus(); if (AgentLifeCycleState.UNKNOWN == agentStatus.getState() || eventTimestampFloor <= agentStatus.getEventTimestamp()) { filteredAgentInfos.add(agentInfo); } } return filteredAgentInfos; } @Override public AgentInfo getAgentInfo(String agentId, long timestamp) { if (agentId == null) { throw new NullPointerException("agentId must not be null"); } if (timestamp < 0) { throw new IllegalArgumentException("timestamp must not be less than 0"); } AgentInfo agentInfo = this.agentInfoDao.getAgentInfo(agentId, timestamp); if (agentInfo != null) { this.agentLifeCycleDao.populateAgentStatus(agentInfo, timestamp); } return agentInfo; } @Override public AgentStatus getAgentStatus(String agentId, long timestamp) { if (agentId == null) { throw new NullPointerException("agentId must not be null"); } if (timestamp < 0) { throw new IllegalArgumentException("timestamp must not be less than 0"); } return this.agentLifeCycleDao.getAgentStatus(agentId, timestamp); } @Override public InspectorTimeline getAgentStatusTimeline(String agentId, Range range, int... excludeAgentEventTypeCodes) { Assert.notNull(agentId, "agentId must not be null"); Assert.notNull(range, "range must not be null"); AgentStatus initialStatus = getAgentStatus(agentId, range.getFrom()); List<AgentEvent> agentEvents = agentEventService.getAgentEvents(agentId, range); AgentStatusTimelineBuilder agentStatusTimelinebuilder = new AgentStatusTimelineBuilder(range, initialStatus); agentStatusTimelinebuilder.from(agentEvents); AgentStatusTimeline agentStatusTimeline = agentStatusTimelinebuilder.build(); AgentEventTimelineBuilder agentEventTimelineBuilder = new AgentEventTimelineBuilder(range); agentEventTimelineBuilder.from(agentEvents); agentEventTimelineBuilder.addFilter(new AgentEventFilter.ExcludeFilter(excludeAgentEventTypeCodes)); AgentEventTimeline agentEventTimeline = agentEventTimelineBuilder.build(); return new InspectorTimeline(agentStatusTimeline, agentEventTimeline); } }