• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019, OpenCensus Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package io.opencensus.implcore.trace.export;
18 
19 import static com.google.common.base.Preconditions.checkArgument;
20 
21 import io.opencensus.implcore.trace.RecordEventsSpanImpl;
22 import io.opencensus.implcore.trace.internal.ConcurrentIntrusiveList;
23 import io.opencensus.trace.export.RunningSpanStore;
24 import io.opencensus.trace.export.SpanData;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31 import javax.annotation.Nullable;
32 import javax.annotation.concurrent.ThreadSafe;
33 
34 /** In-process implementation of the {@link RunningSpanStore}. */
35 @ThreadSafe
36 public final class InProcessRunningSpanStore extends RunningSpanStore {
37   private static final Summary EMPTY_SUMMARY =
38       RunningSpanStore.Summary.create(Collections.<String, PerSpanNameSummary>emptyMap());
39 
40   @Nullable private volatile InProcessRunningSpanStoreImpl impl = null;
41 
create()42   static InProcessRunningSpanStore create() {
43     return new InProcessRunningSpanStore();
44   }
45 
46   /**
47    * Adds the {@code Span} into the running spans list when the {@code Span} starts.
48    *
49    * @param span the {@code Span} that started.
50    */
onStart(RecordEventsSpanImpl span)51   public void onStart(RecordEventsSpanImpl span) {
52     InProcessRunningSpanStoreImpl impl = this.impl;
53     if (impl != null) {
54       impl.onStart(span);
55     }
56   }
57 
58   /**
59    * Removes the {@code Span} from the running spans list when the {@code Span} ends.
60    *
61    * @param span the {@code Span} that ended.
62    */
onEnd(RecordEventsSpanImpl span)63   public void onEnd(RecordEventsSpanImpl span) {
64     InProcessRunningSpanStoreImpl impl = this.impl;
65     if (impl != null) {
66       impl.onEnd(span);
67     }
68   }
69 
70   /**
71    * Returns {@code true} if the RunningSpanStore is enabled.
72    *
73    * @return {@code true} if the RunningSpanStore is enabled.
74    */
getEnabled()75   public boolean getEnabled() {
76     return this.impl != null;
77   }
78 
79   @Override
getSummary()80   public Summary getSummary() {
81     InProcessRunningSpanStoreImpl impl = this.impl;
82     if (impl != null) {
83       return impl.getSummary();
84     }
85     return EMPTY_SUMMARY;
86   }
87 
88   @Override
getRunningSpans(Filter filter)89   public Collection<SpanData> getRunningSpans(Filter filter) {
90     InProcessRunningSpanStoreImpl impl = this.impl;
91     if (impl != null) {
92       return impl.getRunningSpans(filter);
93     }
94     return Collections.emptyList();
95   }
96 
97   @Override
setMaxNumberOfSpans(int maxNumberOfSpans)98   public void setMaxNumberOfSpans(int maxNumberOfSpans) {
99     checkArgument(maxNumberOfSpans >= 0, "Invalid negative maxNumberOfElements");
100     synchronized (this) {
101       InProcessRunningSpanStoreImpl currentImpl = this.impl;
102       if (currentImpl != null) {
103         currentImpl.clear();
104       }
105       this.impl = null;
106       if (maxNumberOfSpans > 0) {
107         impl = new InProcessRunningSpanStoreImpl(maxNumberOfSpans);
108       }
109     }
110   }
111 
112   private static final class InProcessRunningSpanStoreImpl {
113     private final ConcurrentIntrusiveList<RecordEventsSpanImpl> runningSpans;
114 
InProcessRunningSpanStoreImpl(int maxNumberOfElements)115     private InProcessRunningSpanStoreImpl(int maxNumberOfElements) {
116       runningSpans = new ConcurrentIntrusiveList<>(maxNumberOfElements);
117     }
118 
onStart(RecordEventsSpanImpl span)119     private void onStart(RecordEventsSpanImpl span) {
120       runningSpans.addElement(span);
121     }
122 
onEnd(RecordEventsSpanImpl span)123     private void onEnd(RecordEventsSpanImpl span) {
124       // TODO: Count and display when try to remove span that was not present.
125       runningSpans.removeElement(span);
126     }
127 
getSummary()128     private Summary getSummary() {
129       Collection<RecordEventsSpanImpl> allRunningSpans = runningSpans.getAll();
130       Map<String, Integer> numSpansPerName = new HashMap<String, Integer>();
131       for (RecordEventsSpanImpl span : allRunningSpans) {
132         Integer prevValue = numSpansPerName.get(span.getName());
133         numSpansPerName.put(span.getName(), prevValue != null ? prevValue + 1 : 1);
134       }
135       Map<String, PerSpanNameSummary> perSpanNameSummary =
136           new HashMap<String, PerSpanNameSummary>();
137       for (Map.Entry<String, Integer> it : numSpansPerName.entrySet()) {
138         perSpanNameSummary.put(it.getKey(), PerSpanNameSummary.create(it.getValue()));
139       }
140       return Summary.create(perSpanNameSummary);
141     }
142 
getRunningSpans(Filter filter)143     private Collection<SpanData> getRunningSpans(Filter filter) {
144       Collection<RecordEventsSpanImpl> allRunningSpans = runningSpans.getAll();
145       int maxSpansToReturn =
146           filter.getMaxSpansToReturn() == 0 ? allRunningSpans.size() : filter.getMaxSpansToReturn();
147       List<SpanData> ret = new ArrayList<SpanData>(maxSpansToReturn);
148       for (RecordEventsSpanImpl span : allRunningSpans) {
149         if (ret.size() == maxSpansToReturn) {
150           break;
151         }
152         if (span.getName().equals(filter.getSpanName())) {
153           ret.add(span.toSpanData());
154         }
155       }
156       return ret;
157     }
158 
clear()159     private void clear() {
160       runningSpans.clear();
161     }
162   }
163 }
164