• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017, 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.stats;
18 
19 import io.opencensus.common.Functions;
20 import io.opencensus.common.Timestamp;
21 import io.opencensus.internal.Utils;
22 import io.opencensus.stats.Measure.MeasureDouble;
23 import io.opencensus.stats.Measure.MeasureLong;
24 import io.opencensus.tags.TagContext;
25 import io.opencensus.tags.TagValue;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Set;
33 import java.util.logging.Level;
34 import java.util.logging.Logger;
35 import javax.annotation.concurrent.GuardedBy;
36 import javax.annotation.concurrent.Immutable;
37 import javax.annotation.concurrent.ThreadSafe;
38 
39 /*>>>
40 import org.checkerframework.checker.nullness.qual.Nullable;
41 */
42 
43 /** No-op implementations of stats classes. */
44 final class NoopStats {
45 
NoopStats()46   private NoopStats() {}
47 
48   /**
49    * Returns a {@code StatsComponent} that has a no-op implementation for {@link StatsRecorder}.
50    *
51    * @return a {@code StatsComponent} that has a no-op implementation for {@code StatsRecorder}.
52    */
newNoopStatsComponent()53   static StatsComponent newNoopStatsComponent() {
54     return new NoopStatsComponent();
55   }
56 
57   /**
58    * Returns a {@code StatsRecorder} that does not record any data.
59    *
60    * @return a {@code StatsRecorder} that does not record any data.
61    */
getNoopStatsRecorder()62   static StatsRecorder getNoopStatsRecorder() {
63     return NoopStatsRecorder.INSTANCE;
64   }
65 
66   /**
67    * Returns a {@code MeasureMap} that ignores all calls to {@link MeasureMap#put}.
68    *
69    * @return a {@code MeasureMap} that ignores all calls to {@code MeasureMap#put}.
70    */
newNoopMeasureMap()71   static MeasureMap newNoopMeasureMap() {
72     return new NoopMeasureMap();
73   }
74 
75   /**
76    * Returns a {@code ViewManager} that maintains a map of views, but always returns empty {@link
77    * ViewData}s.
78    *
79    * @return a {@code ViewManager} that maintains a map of views, but always returns empty {@code
80    *     ViewData}s.
81    */
newNoopViewManager()82   static ViewManager newNoopViewManager() {
83     return new NoopViewManager();
84   }
85 
86   @ThreadSafe
87   private static final class NoopStatsComponent extends StatsComponent {
88     private final ViewManager viewManager = newNoopViewManager();
89     private volatile boolean isRead;
90 
91     @Override
getViewManager()92     public ViewManager getViewManager() {
93       return viewManager;
94     }
95 
96     @Override
getStatsRecorder()97     public StatsRecorder getStatsRecorder() {
98       return getNoopStatsRecorder();
99     }
100 
101     @Override
getState()102     public StatsCollectionState getState() {
103       isRead = true;
104       return StatsCollectionState.DISABLED;
105     }
106 
107     @Override
108     @Deprecated
setState(StatsCollectionState state)109     public void setState(StatsCollectionState state) {
110       Utils.checkNotNull(state, "state");
111       Utils.checkState(!isRead, "State was already read, cannot set state.");
112     }
113   }
114 
115   @Immutable
116   private static final class NoopStatsRecorder extends StatsRecorder {
117     static final StatsRecorder INSTANCE = new NoopStatsRecorder();
118 
119     @Override
newMeasureMap()120     public MeasureMap newMeasureMap() {
121       return newNoopMeasureMap();
122     }
123   }
124 
125   private static final class NoopMeasureMap extends MeasureMap {
126     private static final Logger logger = Logger.getLogger(NoopMeasureMap.class.getName());
127     private boolean hasUnsupportedValues;
128 
129     @Override
put(MeasureDouble measure, double value)130     public MeasureMap put(MeasureDouble measure, double value) {
131       if (value < 0) {
132         hasUnsupportedValues = true;
133       }
134       return this;
135     }
136 
137     @Override
put(MeasureLong measure, long value)138     public MeasureMap put(MeasureLong measure, long value) {
139       if (value < 0) {
140         hasUnsupportedValues = true;
141       }
142       return this;
143     }
144 
145     @Override
record()146     public void record() {}
147 
148     @Override
record(TagContext tags)149     public void record(TagContext tags) {
150       Utils.checkNotNull(tags, "tags");
151 
152       if (hasUnsupportedValues) {
153         // drop all the recorded values
154         logger.log(Level.WARNING, "Dropping values, value to record must be non-negative.");
155       }
156     }
157   }
158 
159   @ThreadSafe
160   private static final class NoopViewManager extends ViewManager {
161     private static final Timestamp ZERO_TIMESTAMP = Timestamp.create(0, 0);
162 
163     @GuardedBy("registeredViews")
164     private final Map<View.Name, View> registeredViews = new HashMap<View.Name, View>();
165 
166     // Cached set of exported views. It must be set to null whenever a view is registered or
167     // unregistered.
168     @javax.annotation.Nullable private volatile Set<View> exportedViews;
169 
170     @Override
registerView(View newView)171     public void registerView(View newView) {
172       Utils.checkNotNull(newView, "newView");
173       synchronized (registeredViews) {
174         exportedViews = null;
175         View existing = registeredViews.get(newView.getName());
176         Utils.checkArgument(
177             existing == null || newView.equals(existing),
178             "A different view with the same name already exists.");
179         if (existing == null) {
180           registeredViews.put(newView.getName(), newView);
181         }
182       }
183     }
184 
185     @Override
186     @javax.annotation.Nullable
187     @SuppressWarnings("deprecation")
getView(View.Name name)188     public ViewData getView(View.Name name) {
189       Utils.checkNotNull(name, "name");
190       synchronized (registeredViews) {
191         View view = registeredViews.get(name);
192         if (view == null) {
193           return null;
194         } else {
195           return ViewData.create(
196               view,
197               Collections.<List</*@Nullable*/ TagValue>, AggregationData>emptyMap(),
198               view.getWindow()
199                   .match(
200                       Functions.<ViewData.AggregationWindowData>returnConstant(
201                           ViewData.AggregationWindowData.CumulativeData.create(
202                               ZERO_TIMESTAMP, ZERO_TIMESTAMP)),
203                       Functions.<ViewData.AggregationWindowData>returnConstant(
204                           ViewData.AggregationWindowData.IntervalData.create(ZERO_TIMESTAMP)),
205                       Functions.<ViewData.AggregationWindowData>throwAssertionError()));
206         }
207       }
208     }
209 
210     @Override
getAllExportedViews()211     public Set<View> getAllExportedViews() {
212       Set<View> views = exportedViews;
213       if (views == null) {
214         synchronized (registeredViews) {
215           exportedViews = views = filterExportedViews(registeredViews.values());
216         }
217       }
218       return views;
219     }
220 
221     // Returns the subset of the given views that should be exported
222     @SuppressWarnings("deprecation")
filterExportedViews(Collection<View> allViews)223     private static Set<View> filterExportedViews(Collection<View> allViews) {
224       Set<View> views = new HashSet<View>();
225       for (View view : allViews) {
226         if (view.getWindow() instanceof View.AggregationWindow.Interval) {
227           continue;
228         }
229         views.add(view);
230       }
231       return Collections.unmodifiableSet(views);
232     }
233   }
234 }
235