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