package org.skywalking.apm.collector.worker.segment.persistence; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.RangeQueryBuilder; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.sort.SortOrder; import org.skywalking.apm.collector.actor.*; import org.skywalking.apm.collector.actor.selector.RollingSelector; import org.skywalking.apm.collector.actor.selector.WorkerSelector; import org.skywalking.apm.collector.worker.segment.SegmentCostIndex; import org.skywalking.apm.collector.worker.segment.SegmentExceptionIndex; import org.skywalking.apm.collector.worker.segment.SegmentIndex; import org.skywalking.apm.collector.worker.segment.entity.GlobalTraceId; import org.skywalking.apm.collector.worker.segment.entity.Segment; import org.skywalking.apm.collector.worker.segment.entity.SegmentDeserialize; import org.skywalking.apm.collector.worker.storage.EsClient; import org.skywalking.apm.collector.worker.tools.CollectionTools; import java.util.List; /** * @author pengys5 */ public class SegmentTopSearchWithTimeSlice extends AbstractLocalSyncWorker { private SegmentTopSearchWithTimeSlice(Role role, ClusterWorkerContext clusterContext, LocalWorkerContext selfContext) { super(role, clusterContext, selfContext); } @Override public void preStart() throws ProviderNotFoundException { getClusterContext().findProvider(SegmentExceptionWithSegId.WorkerRole.INSTANCE).create(this); } @Override protected void onWork(Object request, Object response) throws Exception { if (request instanceof RequestEntity) { RequestEntity search = (RequestEntity) request; SearchRequestBuilder searchRequestBuilder = EsClient.INSTANCE.getClient().prepareSearch(SegmentCostIndex.INDEX); searchRequestBuilder.setTypes(SegmentCostIndex.TYPE_RECORD); searchRequestBuilder.setSearchType(SearchType.DFS_QUERY_THEN_FETCH); BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); searchRequestBuilder.setQuery(boolQueryBuilder); boolQueryBuilder.must().add(QueryBuilders.rangeQuery(SegmentCostIndex.TIME_SLICE).gte(search.startTime).lte(search.endTime)); if (search.minCost != -1 || search.maxCost != -1) { RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(SegmentCostIndex.COST); if (search.minCost != -1) { rangeQueryBuilder.gte(search.minCost); } if (search.maxCost != -1) { rangeQueryBuilder.lte(search.maxCost); } boolQueryBuilder.must().add(rangeQueryBuilder); } searchRequestBuilder.addSort(SegmentCostIndex.COST, SortOrder.DESC); searchRequestBuilder.setSize(search.limit); searchRequestBuilder.setFrom(search.from); SearchResponse searchResponse = searchRequestBuilder.execute().actionGet(); JsonObject topSegPaging = new JsonObject(); topSegPaging.addProperty("recordsTotal", searchResponse.getHits().totalHits()); JsonArray topSegArray = new JsonArray(); topSegPaging.add("data", topSegArray); int num = search.from; for (SearchHit searchHit : searchResponse.getHits().getHits()) { JsonObject topSegmentJson = new JsonObject(); topSegmentJson.addProperty("num", num); String segId = (String) searchHit.getSource().get(SegmentCostIndex.SEG_ID); topSegmentJson.addProperty(SegmentCostIndex.SEG_ID, segId); topSegmentJson.addProperty(SegmentCostIndex.START_TIME, (Number) searchHit.getSource().get(SegmentCostIndex.START_TIME)); if (searchHit.getSource().containsKey(SegmentCostIndex.END_TIME)) { topSegmentJson.addProperty(SegmentCostIndex.END_TIME, (Number) searchHit.getSource().get(SegmentCostIndex.END_TIME)); } topSegmentJson.addProperty(SegmentCostIndex.OPERATION_NAME, (String) searchHit.getSource().get(SegmentCostIndex.OPERATION_NAME)); topSegmentJson.addProperty(SegmentCostIndex.COST, (Number) searchHit.getSource().get(SegmentCostIndex.COST)); String segmentSource = EsClient.INSTANCE.getClient().prepareGet(SegmentIndex.INDEX, SegmentIndex.TYPE_RECORD, segId).get().getSourceAsString(); logger().debug("segmentSource:" + segmentSource); Segment segment = SegmentDeserialize.INSTANCE.deserializeSingle(segmentSource); List<GlobalTraceId> distributedTraceIdList = segment.getRelatedGlobalTraces(); JsonArray distributedTraceIdArray = new JsonArray(); if (CollectionTools.isNotEmpty(distributedTraceIdList)) { for (GlobalTraceId distributedTraceId : distributedTraceIdList) { distributedTraceIdArray.add(distributedTraceId.get()); } } topSegmentJson.add("traceIds", distributedTraceIdArray); boolean isError = false; JsonObject resJsonObj = new JsonObject(); getSelfContext().lookup(SegmentExceptionWithSegId.WorkerRole.INSTANCE).ask(new SegmentExceptionWithSegId.RequestEntity(segId), resJsonObj); if (resJsonObj.has("result")) { JsonObject segExJson = resJsonObj.get("result").getAsJsonObject(); if (segExJson.has(SegmentExceptionIndex.IS_ERROR)) { isError = segExJson.get(SegmentExceptionIndex.IS_ERROR).getAsBoolean(); } } topSegmentJson.addProperty(SegmentExceptionIndex.IS_ERROR, isError); num++; topSegArray.add(topSegmentJson); } JsonObject resJsonObj = (JsonObject) response; resJsonObj.add("result", topSegPaging); } } public static class RequestEntity { private int from; private int limit; private long startTime; private long endTime; private int minCost; private int maxCost; public RequestEntity(int from, int limit, long startTime, long endTime) { this.from = from; this.limit = limit; this.startTime = startTime; this.endTime = endTime; } public void setMinCost(int minCost) { this.minCost = minCost; } public void setMaxCost(int maxCost) { this.maxCost = maxCost; } public int getFrom() { return from; } public int getLimit() { return limit; } public long getStartTime() { return startTime; } public long getEndTime() { return endTime; } public int getMinCost() { return minCost; } public int getMaxCost() { return maxCost; } } public static class Factory extends AbstractLocalSyncWorkerProvider<SegmentTopSearchWithTimeSlice> { @Override public Role role() { return WorkerRole.INSTANCE; } @Override public SegmentTopSearchWithTimeSlice workerInstance(ClusterWorkerContext clusterContext) { return new SegmentTopSearchWithTimeSlice(role(), clusterContext, new LocalWorkerContext()); } } public enum WorkerRole implements Role { INSTANCE; @Override public String roleName() { return SegmentTopSearchWithTimeSlice.class.getSimpleName(); } @Override public WorkerSelector workerSelector() { return new RollingSelector(); } } }