Home | History | Annotate | Download | only in export
      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.trace.export;
     18 
     19 import com.google.auto.value.AutoValue;
     20 import io.opencensus.internal.Utils;
     21 import io.opencensus.trace.Span;
     22 import io.opencensus.trace.Status;
     23 import io.opencensus.trace.Status.CanonicalCode;
     24 import java.util.Collection;
     25 import java.util.Collections;
     26 import java.util.HashMap;
     27 import java.util.HashSet;
     28 import java.util.Map;
     29 import java.util.Set;
     30 import java.util.concurrent.TimeUnit;
     31 import javax.annotation.Nullable;
     32 import javax.annotation.concurrent.GuardedBy;
     33 import javax.annotation.concurrent.Immutable;
     34 import javax.annotation.concurrent.ThreadSafe;
     35 
     36 /**
     37  * This class allows users to access in-process information such as latency based sampled spans and
     38  * error based sampled spans.
     39  *
     40  * <p>For all completed spans with the option {@link Span.Options#RECORD_EVENTS} the library can
     41  * store samples based on latency for succeeded operations or based on error code for failed
     42  * operations. To activate this, users MUST manually configure all the span names for which samples
     43  * will be collected (see {@link #registerSpanNamesForCollection(Collection)}).
     44  *
     45  * @since 0.5
     46  */
     47 @ThreadSafe
     48 public abstract class SampledSpanStore {
     49 
     50   protected SampledSpanStore() {}
     51 
     52   /**
     53    * Returns a {@code SampledSpanStore} that maintains a set of span names, but always returns an
     54    * empty list of {@link SpanData}.
     55    *
     56    * @return a {@code SampledSpanStore} that maintains a set of span names, but always returns an
     57    *     empty list of {@code SpanData}.
     58    */
     59   static SampledSpanStore newNoopSampledSpanStore() {
     60     return new NoopSampledSpanStore();
     61   }
     62 
     63   /**
     64    * Returns the summary of all available data, such as number of sampled spans in the latency based
     65    * samples or error based samples.
     66    *
     67    * <p>Data available only for span names registered using {@link
     68    * #registerSpanNamesForCollection(Collection)}.
     69    *
     70    * @return the summary of all available data.
     71    * @since 0.5
     72    */
     73   public abstract Summary getSummary();
     74 
     75   /**
     76    * Returns a list of succeeded spans (spans with {@link Status} equal to {@link Status#OK}) that
     77    * match the {@code filter}.
     78    *
     79    * <p>Latency based sampled spans are available only for span names registered using {@link
     80    * #registerSpanNamesForCollection(Collection)}.
     81    *
     82    * @param filter used to filter the returned sampled spans.
     83    * @return a list of succeeded spans that match the {@code filter}.
     84    * @since 0.5
     85    */
     86   public abstract Collection<SpanData> getLatencySampledSpans(LatencyFilter filter);
     87 
     88   /**
     89    * Returns a list of failed spans (spans with {@link Status} other than {@link Status#OK}) that
     90    * match the {@code filter}.
     91    *
     92    * <p>Error based sampled spans are available only for span names registered using {@link
     93    * #registerSpanNamesForCollection(Collection)}.
     94    *
     95    * @param filter used to filter the returned sampled spans.
     96    * @return a list of failed spans that match the {@code filter}.
     97    * @since 0.5
     98    */
     99   public abstract Collection<SpanData> getErrorSampledSpans(ErrorFilter filter);
    100 
    101   /**
    102    * Appends a list of span names for which the library will collect latency based sampled spans and
    103    * error based sampled spans.
    104    *
    105    * <p>If called multiple times the library keeps the list of unique span names from all the calls.
    106    *
    107    * @param spanNames list of span names for which the library will collect samples.
    108    * @since 0.5
    109    */
    110   public abstract void registerSpanNamesForCollection(Collection<String> spanNames);
    111 
    112   /**
    113    * Removes a list of span names for which the library will collect latency based sampled spans and
    114    * error based sampled spans.
    115    *
    116    * <p>The library keeps the list of unique registered span names for which samples will be called.
    117    * This method allows users to remove span names from that list.
    118    *
    119    * @param spanNames list of span names for which the library will no longer collect samples.
    120    * @since 0.5
    121    */
    122   public abstract void unregisterSpanNamesForCollection(Collection<String> spanNames);
    123 
    124   /**
    125    * Returns the set of unique span names registered to the library, for use in tests. For this set
    126    * of span names the library will collect latency based sampled spans and error based sampled
    127    * spans.
    128    *
    129    * <p>This method is only meant for testing code that uses OpenCensus, and it is not performant.
    130    *
    131    * @return the set of unique span names registered to the library.
    132    * @since 0.7
    133    */
    134   public abstract Set<String> getRegisteredSpanNamesForCollection();
    135 
    136   /**
    137    * The summary of all available data.
    138    *
    139    * @since 0.5
    140    */
    141   @AutoValue
    142   @Immutable
    143   public abstract static class Summary {
    144 
    145     Summary() {}
    146 
    147     /**
    148      * Returns a new instance of {@code Summary}.
    149      *
    150      * @param perSpanNameSummary a map with summary for each span name.
    151      * @return a new instance of {@code Summary}.
    152      * @throws NullPointerException if {@code perSpanNameSummary} is {@code null}.
    153      * @since 0.5
    154      */
    155     public static Summary create(Map<String, PerSpanNameSummary> perSpanNameSummary) {
    156       return new AutoValue_SampledSpanStore_Summary(
    157           Collections.unmodifiableMap(
    158               new HashMap<String, PerSpanNameSummary>(
    159                   Utils.checkNotNull(perSpanNameSummary, "perSpanNameSummary"))));
    160     }
    161 
    162     /**
    163      * Returns a map with summary of available data for each span name.
    164      *
    165      * @return a map with all the span names and the summary.
    166      * @since 0.5
    167      */
    168     public abstract Map<String, PerSpanNameSummary> getPerSpanNameSummary();
    169   }
    170 
    171   /**
    172    * Summary of all available data for a span name.
    173    *
    174    * @since 0.5
    175    */
    176   @AutoValue
    177   @Immutable
    178   public abstract static class PerSpanNameSummary {
    179 
    180     PerSpanNameSummary() {}
    181 
    182     /**
    183      * Returns a new instance of {@code PerSpanNameSummary}.
    184      *
    185      * @param numbersOfLatencySampledSpans the summary for the latency buckets.
    186      * @param numbersOfErrorSampledSpans the summary for the error buckets.
    187      * @return a new instance of {@code PerSpanNameSummary}.
    188      * @throws NullPointerException if {@code numbersOfLatencySampledSpans} or {@code
    189      *     numbersOfErrorSampledSpans} are {@code null}.
    190      * @since 0.5
    191      */
    192     public static PerSpanNameSummary create(
    193         Map<LatencyBucketBoundaries, Integer> numbersOfLatencySampledSpans,
    194         Map<CanonicalCode, Integer> numbersOfErrorSampledSpans) {
    195       return new AutoValue_SampledSpanStore_PerSpanNameSummary(
    196           Collections.unmodifiableMap(
    197               new HashMap<LatencyBucketBoundaries, Integer>(
    198                   Utils.checkNotNull(
    199                       numbersOfLatencySampledSpans, "numbersOfLatencySampledSpans"))),
    200           Collections.unmodifiableMap(
    201               new HashMap<CanonicalCode, Integer>(
    202                   Utils.checkNotNull(numbersOfErrorSampledSpans, "numbersOfErrorSampledSpans"))));
    203     }
    204 
    205     /**
    206      * Returns the number of sampled spans in all the latency buckets.
    207      *
    208      * <p>Data available only for span names registered using {@link
    209      * #registerSpanNamesForCollection(Collection)}.
    210      *
    211      * @return the number of sampled spans in all the latency buckets.
    212      * @since 0.5
    213      */
    214     public abstract Map<LatencyBucketBoundaries, Integer> getNumbersOfLatencySampledSpans();
    215 
    216     /**
    217      * Returns the number of sampled spans in all the error buckets.
    218      *
    219      * <p>Data available only for span names registered using {@link
    220      * #registerSpanNamesForCollection(Collection)}.
    221      *
    222      * @return the number of sampled spans in all the error buckets.
    223      * @since 0.5
    224      */
    225     public abstract Map<CanonicalCode, Integer> getNumbersOfErrorSampledSpans();
    226   }
    227 
    228   /**
    229    * The latency buckets boundaries. Samples based on latency for successful spans (the status of
    230    * the span has a canonical code equal to {@link CanonicalCode#OK}) are collected in one of these
    231    * latency buckets.
    232    *
    233    * @since 0.5
    234    */
    235   public enum LatencyBucketBoundaries {
    236     /**
    237      * Stores finished successful requests of duration within the interval [0, 10us).
    238      *
    239      * @since 0.5
    240      */
    241     ZERO_MICROSx10(0, TimeUnit.MICROSECONDS.toNanos(10)),
    242 
    243     /**
    244      * Stores finished successful requests of duration within the interval [10us, 100us).
    245      *
    246      * @since 0.5
    247      */
    248     MICROSx10_MICROSx100(TimeUnit.MICROSECONDS.toNanos(10), TimeUnit.MICROSECONDS.toNanos(100)),
    249 
    250     /**
    251      * Stores finished successful requests of duration within the interval [100us, 1ms).
    252      *
    253      * @since 0.5
    254      */
    255     MICROSx100_MILLIx1(TimeUnit.MICROSECONDS.toNanos(100), TimeUnit.MILLISECONDS.toNanos(1)),
    256 
    257     /**
    258      * Stores finished successful requests of duration within the interval [1ms, 10ms).
    259      *
    260      * @since 0.5
    261      */
    262     MILLIx1_MILLIx10(TimeUnit.MILLISECONDS.toNanos(1), TimeUnit.MILLISECONDS.toNanos(10)),
    263 
    264     /**
    265      * Stores finished successful requests of duration within the interval [10ms, 100ms).
    266      *
    267      * @since 0.5
    268      */
    269     MILLIx10_MILLIx100(TimeUnit.MILLISECONDS.toNanos(10), TimeUnit.MILLISECONDS.toNanos(100)),
    270 
    271     /**
    272      * Stores finished successful requests of duration within the interval [100ms, 1sec).
    273      *
    274      * @since 0.5
    275      */
    276     MILLIx100_SECONDx1(TimeUnit.MILLISECONDS.toNanos(100), TimeUnit.SECONDS.toNanos(1)),
    277 
    278     /**
    279      * Stores finished successful requests of duration within the interval [1sec, 10sec).
    280      *
    281      * @since 0.5
    282      */
    283     SECONDx1_SECONDx10(TimeUnit.SECONDS.toNanos(1), TimeUnit.SECONDS.toNanos(10)),
    284 
    285     /**
    286      * Stores finished successful requests of duration within the interval [10sec, 100sec).
    287      *
    288      * @since 0.5
    289      */
    290     SECONDx10_SECONDx100(TimeUnit.SECONDS.toNanos(10), TimeUnit.SECONDS.toNanos(100)),
    291 
    292     /**
    293      * Stores finished successful requests of duration &gt;= 100sec.
    294      *
    295      * @since 0.5
    296      */
    297     SECONDx100_MAX(TimeUnit.SECONDS.toNanos(100), Long.MAX_VALUE);
    298 
    299     /**
    300      * Constructs a {@code LatencyBucketBoundaries} with the given boundaries and label.
    301      *
    302      * @param latencyLowerNs the latency lower bound of the bucket.
    303      * @param latencyUpperNs the latency upper bound of the bucket.
    304      */
    305     LatencyBucketBoundaries(long latencyLowerNs, long latencyUpperNs) {
    306       this.latencyLowerNs = latencyLowerNs;
    307       this.latencyUpperNs = latencyUpperNs;
    308     }
    309 
    310     /**
    311      * Returns the latency lower bound of the bucket.
    312      *
    313      * @return the latency lower bound of the bucket.
    314      * @since 0.5
    315      */
    316     public long getLatencyLowerNs() {
    317       return latencyLowerNs;
    318     }
    319 
    320     /**
    321      * Returns the latency upper bound of the bucket.
    322      *
    323      * @return the latency upper bound of the bucket.
    324      * @since 0.5
    325      */
    326     public long getLatencyUpperNs() {
    327       return latencyUpperNs;
    328     }
    329 
    330     private final long latencyLowerNs;
    331     private final long latencyUpperNs;
    332   }
    333 
    334   /**
    335    * Filter for latency based sampled spans. Used to filter results returned by the {@link
    336    * #getLatencySampledSpans(LatencyFilter)} request.
    337    *
    338    * @since 0.5
    339    */
    340   @AutoValue
    341   @Immutable
    342   public abstract static class LatencyFilter {
    343 
    344     LatencyFilter() {}
    345 
    346     /**
    347      * Returns a new instance of {@code LatencyFilter}.
    348      *
    349      * <p>Filters all the spans based on {@code spanName} and latency in the interval
    350      * [latencyLowerNs, latencyUpperNs) and returns a maximum of {@code maxSpansToReturn}.
    351      *
    352      * @param spanName the name of the span.
    353      * @param latencyLowerNs the latency lower bound.
    354      * @param latencyUpperNs the latency upper bound.
    355      * @param maxSpansToReturn the maximum number of results to be returned. {@code 0} means all.
    356      * @return a new instance of {@code LatencyFilter}.
    357      * @throws NullPointerException if {@code spanName} is {@code null}.
    358      * @throws IllegalArgumentException if {@code maxSpansToReturn} or {@code latencyLowerNs} or
    359      *     {@code latencyUpperNs} are negative.
    360      * @since 0.5
    361      */
    362     public static LatencyFilter create(
    363         String spanName, long latencyLowerNs, long latencyUpperNs, int maxSpansToReturn) {
    364       Utils.checkArgument(maxSpansToReturn >= 0, "Negative maxSpansToReturn.");
    365       Utils.checkArgument(latencyLowerNs >= 0, "Negative latencyLowerNs");
    366       Utils.checkArgument(latencyUpperNs >= 0, "Negative latencyUpperNs");
    367       return new AutoValue_SampledSpanStore_LatencyFilter(
    368           spanName, latencyLowerNs, latencyUpperNs, maxSpansToReturn);
    369     }
    370 
    371     /**
    372      * Returns the span name used by this filter.
    373      *
    374      * @return the span name used by this filter.
    375      * @since 0.5
    376      */
    377     public abstract String getSpanName();
    378 
    379     /**
    380      * Returns the latency lower bound of this bucket (inclusive).
    381      *
    382      * @return the latency lower bound of this bucket.
    383      * @since 0.5
    384      */
    385     public abstract long getLatencyLowerNs();
    386 
    387     /**
    388      * Returns the latency upper bound of this bucket (exclusive).
    389      *
    390      * @return the latency upper bound of this bucket.
    391      * @since 0.5
    392      */
    393     public abstract long getLatencyUpperNs();
    394 
    395     /**
    396      * Returns the maximum number of spans to be returned. {@code 0} means all.
    397      *
    398      * @return the maximum number of spans to be returned.
    399      * @since 0.5
    400      */
    401     public abstract int getMaxSpansToReturn();
    402   }
    403 
    404   /**
    405    * Filter for error based sampled spans. Used to filter results returned by the {@link
    406    * #getErrorSampledSpans(ErrorFilter)} request.
    407    *
    408    * @since 0.5
    409    */
    410   @AutoValue
    411   @Immutable
    412   public abstract static class ErrorFilter {
    413 
    414     ErrorFilter() {}
    415 
    416     /**
    417      * Returns a new instance of {@code ErrorFilter}.
    418      *
    419      * <p>Filters all the spans based on {@code spanName} and {@code canonicalCode} and returns a
    420      * maximum of {@code maxSpansToReturn}.
    421      *
    422      * @param spanName the name of the span.
    423      * @param canonicalCode the error code of the span. {@code null} can be used to query all error
    424      *     codes.
    425      * @param maxSpansToReturn the maximum number of results to be returned. {@code 0} means all.
    426      * @return a new instance of {@code ErrorFilter}.
    427      * @throws NullPointerException if {@code spanName} is {@code null}.
    428      * @throws IllegalArgumentException if {@code canonicalCode} is {@link CanonicalCode#OK} or
    429      *     {@code maxSpansToReturn} is negative.
    430      * @since 0.5
    431      */
    432     public static ErrorFilter create(
    433         String spanName, @Nullable CanonicalCode canonicalCode, int maxSpansToReturn) {
    434       if (canonicalCode != null) {
    435         Utils.checkArgument(canonicalCode != CanonicalCode.OK, "Invalid canonical code.");
    436       }
    437       Utils.checkArgument(maxSpansToReturn >= 0, "Negative maxSpansToReturn.");
    438       return new AutoValue_SampledSpanStore_ErrorFilter(spanName, canonicalCode, maxSpansToReturn);
    439     }
    440 
    441     /**
    442      * Returns the span name used by this filter.
    443      *
    444      * @return the span name used by this filter.
    445      * @since 0.5
    446      */
    447     public abstract String getSpanName();
    448 
    449     /**
    450      * Returns the canonical code used by this filter. Always different than {@link
    451      * CanonicalCode#OK}. If {@code null} then all errors match.
    452      *
    453      * @return the canonical code used by this filter.
    454      * @since 0.5
    455      */
    456     @Nullable
    457     public abstract CanonicalCode getCanonicalCode();
    458 
    459     /**
    460      * Returns the maximum number of spans to be returned. Used to enforce the number of returned
    461      * {@code SpanData}. {@code 0} means all.
    462      *
    463      * @return the maximum number of spans to be returned.
    464      * @since 0.5
    465      */
    466     public abstract int getMaxSpansToReturn();
    467   }
    468 
    469   @ThreadSafe
    470   private static final class NoopSampledSpanStore extends SampledSpanStore {
    471     private static final PerSpanNameSummary EMPTY_PER_SPAN_NAME_SUMMARY =
    472         PerSpanNameSummary.create(
    473             Collections.<SampledSpanStore.LatencyBucketBoundaries, Integer>emptyMap(),
    474             Collections.<CanonicalCode, Integer>emptyMap());
    475 
    476     @GuardedBy("registeredSpanNames")
    477     private final Set<String> registeredSpanNames = new HashSet<String>();
    478 
    479     @Override
    480     public Summary getSummary() {
    481       Map<String, PerSpanNameSummary> result = new HashMap<String, PerSpanNameSummary>();
    482       synchronized (registeredSpanNames) {
    483         for (String registeredSpanName : registeredSpanNames) {
    484           result.put(registeredSpanName, EMPTY_PER_SPAN_NAME_SUMMARY);
    485         }
    486       }
    487       return Summary.create(result);
    488     }
    489 
    490     @Override
    491     public Collection<SpanData> getLatencySampledSpans(LatencyFilter filter) {
    492       Utils.checkNotNull(filter, "latencyFilter");
    493       return Collections.<SpanData>emptyList();
    494     }
    495 
    496     @Override
    497     public Collection<SpanData> getErrorSampledSpans(ErrorFilter filter) {
    498       Utils.checkNotNull(filter, "errorFilter");
    499       return Collections.<SpanData>emptyList();
    500     }
    501 
    502     @Override
    503     public void registerSpanNamesForCollection(Collection<String> spanNames) {
    504       Utils.checkNotNull(spanNames, "spanNames");
    505       synchronized (registeredSpanNames) {
    506         registeredSpanNames.addAll(spanNames);
    507       }
    508     }
    509 
    510     @Override
    511     public void unregisterSpanNamesForCollection(Collection<String> spanNames) {
    512       Utils.checkNotNull(spanNames, "spanNames");
    513       synchronized (registeredSpanNames) {
    514         registeredSpanNames.removeAll(spanNames);
    515       }
    516     }
    517 
    518     @Override
    519     public Set<String> getRegisteredSpanNamesForCollection() {
    520       synchronized (registeredSpanNames) {
    521         return Collections.<String>unmodifiableSet(new HashSet<String>(registeredSpanNames));
    522       }
    523     }
    524   }
    525 }
    526