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;
18 
19 import io.opencensus.internal.DefaultVisibilityForTesting;
20 import io.opencensus.internal.Utils;
21 import java.util.Arrays;
22 import javax.annotation.Nullable;
23 import javax.annotation.concurrent.Immutable;
24 
25 /**
26  * A class that represents global trace options. These options are propagated to all child {@link
27  * io.opencensus.trace.Span spans}. These determine features such as whether a {@code Span} should
28  * be traced. It is implemented as a bitmask.
29  *
30  * @since 0.5
31  */
32 @Immutable
33 public final class TraceOptions {
34   // Default options. Nothing set.
35   private static final byte DEFAULT_OPTIONS = 0;
36   // Bit to represent whether trace is sampled or not.
37   private static final byte IS_SAMPLED = 0x1;
38 
39   /**
40    * The size in bytes of the {@code TraceOptions}.
41    *
42    * @since 0.5
43    */
44   public static final int SIZE = 1;
45 
46   /**
47    * The default {@code TraceOptions}.
48    *
49    * @since 0.5
50    */
51   public static final TraceOptions DEFAULT = fromByte(DEFAULT_OPTIONS);
52 
53   // The set of enabled features is determined by all the enabled bits.
54   private final byte options;
55 
56   // Creates a new {@code TraceOptions} with the given options.
TraceOptions(byte options)57   private TraceOptions(byte options) {
58     this.options = options;
59   }
60 
61   /**
62    * Returns a {@code TraceOptions} built from a byte representation.
63    *
64    * <p>Equivalent with:
65    *
66    * <pre>{@code
67    * TraceOptions.fromBytes(buffer, 0);
68    * }</pre>
69    *
70    * @param buffer the representation of the {@code TraceOptions}.
71    * @return a {@code TraceOptions} whose representation is given by the {@code buffer} parameter.
72    * @throws NullPointerException if {@code buffer} is null.
73    * @throws IllegalArgumentException if {@code buffer.length} is not {@link TraceOptions#SIZE}.
74    * @since 0.5
75    * @deprecated use {@link #fromByte(byte)}.
76    */
77   @Deprecated
fromBytes(byte[] buffer)78   public static TraceOptions fromBytes(byte[] buffer) {
79     Utils.checkNotNull(buffer, "buffer");
80     Utils.checkArgument(
81         buffer.length == SIZE, "Invalid size: expected %s, got %s", SIZE, buffer.length);
82     return fromByte(buffer[0]);
83   }
84 
85   /**
86    * Returns a {@code TraceOptions} whose representation is copied from the {@code src} beginning at
87    * the {@code srcOffset} offset.
88    *
89    * @param src the buffer where the representation of the {@code TraceOptions} is copied.
90    * @param srcOffset the offset in the buffer where the representation of the {@code TraceOptions}
91    *     begins.
92    * @return a {@code TraceOptions} whose representation is copied from the buffer.
93    * @throws NullPointerException if {@code src} is null.
94    * @throws IndexOutOfBoundsException if {@code srcOffset+TraceOptions.SIZE} is greater than {@code
95    *     src.length}.
96    * @since 0.5
97    * @deprecated use {@link #fromByte(byte)}.
98    */
99   @Deprecated
fromBytes(byte[] src, int srcOffset)100   public static TraceOptions fromBytes(byte[] src, int srcOffset) {
101     Utils.checkIndex(srcOffset, src.length);
102     return fromByte(src[srcOffset]);
103   }
104 
105   /**
106    * Returns a {@code TraceOptions} whose representation is {@code src}.
107    *
108    * @param src the byte representation of the {@code TraceOptions}.
109    * @return a {@code TraceOptions} whose representation is {@code src}.
110    * @since 0.16
111    */
fromByte(byte src)112   public static TraceOptions fromByte(byte src) {
113     // TODO(bdrutu): OPTIMIZATION: Cache all the 256 possible objects and return from the cache.
114     return new TraceOptions(src);
115   }
116 
117   /**
118    * Returns the one byte representation of the {@code TraceOptions}.
119    *
120    * @return the one byte representation of the {@code TraceOptions}.
121    * @since 0.16
122    */
getByte()123   public byte getByte() {
124     return options;
125   }
126 
127   /**
128    * Returns the 1-byte array representation of the {@code TraceOptions}.
129    *
130    * @return the 1-byte array representation of the {@code TraceOptions}.
131    * @since 0.5
132    * @deprecated use {@link #getByte()}.
133    */
134   @Deprecated
getBytes()135   public byte[] getBytes() {
136     byte[] bytes = new byte[SIZE];
137     bytes[0] = options;
138     return bytes;
139   }
140 
141   /**
142    * Copies the byte representations of the {@code TraceOptions} into the {@code dest} beginning at
143    * the {@code destOffset} offset.
144    *
145    * <p>Equivalent with (but faster because it avoids any new allocations):
146    *
147    * <pre>{@code
148    * System.arraycopy(getBytes(), 0, dest, destOffset, TraceOptions.SIZE);
149    * }</pre>
150    *
151    * @param dest the destination buffer.
152    * @param destOffset the starting offset in the destination buffer.
153    * @throws NullPointerException if {@code dest} is null.
154    * @throws IndexOutOfBoundsException if {@code destOffset+TraceOptions.SIZE} is greater than
155    *     {@code dest.length}.
156    * @since 0.5
157    */
copyBytesTo(byte[] dest, int destOffset)158   public void copyBytesTo(byte[] dest, int destOffset) {
159     Utils.checkIndex(destOffset, dest.length);
160     dest[destOffset] = options;
161   }
162 
163   /**
164    * Returns a new {@link Builder} with default options.
165    *
166    * @return a new {@code Builder} with default options.
167    * @since 0.5
168    */
builder()169   public static Builder builder() {
170     return new Builder(DEFAULT_OPTIONS);
171   }
172 
173   /**
174    * Returns a new {@link Builder} with all given options set.
175    *
176    * @param traceOptions the given options set.
177    * @return a new {@code Builder} with all given options set.
178    * @since 0.5
179    */
builder(TraceOptions traceOptions)180   public static Builder builder(TraceOptions traceOptions) {
181     return new Builder(traceOptions.options);
182   }
183 
184   /**
185    * Returns a boolean indicating whether this {@code Span} is part of a sampled trace and data
186    * should be exported to a persistent store.
187    *
188    * @return a boolean indicating whether the trace is sampled.
189    * @since 0.5
190    */
isSampled()191   public boolean isSampled() {
192     return hasOption(IS_SAMPLED);
193   }
194 
195   @Override
equals(@ullable Object obj)196   public boolean equals(@Nullable Object obj) {
197     if (obj == this) {
198       return true;
199     }
200 
201     if (!(obj instanceof TraceOptions)) {
202       return false;
203     }
204 
205     TraceOptions that = (TraceOptions) obj;
206     return options == that.options;
207   }
208 
209   @Override
hashCode()210   public int hashCode() {
211     return Arrays.hashCode(new byte[] {options});
212   }
213 
214   @Override
toString()215   public String toString() {
216     return "TraceOptions{sampled=" + isSampled() + "}";
217   }
218 
219   /**
220    * Builder class for {@link TraceOptions}.
221    *
222    * @since 0.5
223    */
224   public static final class Builder {
225     private byte options;
226 
Builder(byte options)227     private Builder(byte options) {
228       this.options = options;
229     }
230 
231     /**
232      * Sets the sampling bit in the options to true.
233      *
234      * @deprecated Use {@code Builder.setIsSampled(true)}.
235      * @return this.
236      * @since 0.5
237      */
238     @Deprecated
setIsSampled()239     public Builder setIsSampled() {
240       return setIsSampled(true);
241     }
242 
243     /**
244      * Sets the sampling bit in the options.
245      *
246      * @param isSampled the sampling bit.
247      * @return this.
248      * @since 0.7
249      */
setIsSampled(boolean isSampled)250     public Builder setIsSampled(boolean isSampled) {
251       if (isSampled) {
252         options = (byte) (options | IS_SAMPLED);
253       } else {
254         options = (byte) (options & ~IS_SAMPLED);
255         ;
256       }
257       return this;
258     }
259 
260     /**
261      * Builds and returns a {@code TraceOptions} with the desired options.
262      *
263      * @return a {@code TraceOptions} with the desired options.
264      * @since 0.5
265      */
build()266     public TraceOptions build() {
267       return fromByte(options);
268     }
269   }
270 
271   // Returns the current set of options bitmask.
272   @DefaultVisibilityForTesting
getOptions()273   byte getOptions() {
274     return options;
275   }
276 
hasOption(int mask)277   private boolean hasOption(int mask) {
278     return (this.options & mask) != 0;
279   }
280 }
281