Add initial OpenCensus API.
This commit is contained in:
parent
505ef89acf
commit
9cb3ad5eb7
|
|
@ -1,5 +1,6 @@
|
|||
# OpenConsensus API
|
||||
OpenCensus API
|
||||
======================================================
|
||||
|
||||
* Java 7 and Android 14 compatible.
|
||||
* Java 6 and Android compatible.
|
||||
* The abstract classes in this directory can be subclassed to create alternative
|
||||
implementations of the OpenCensus library.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,15 @@
|
|||
description = 'OpenConsensus API'
|
||||
description = 'OpenCensus API'
|
||||
|
||||
dependencies {
|
||||
compile project(':openconsensus-context')
|
||||
compile libraries.grpc_context
|
||||
|
||||
compileOnly libraries.auto_value
|
||||
|
||||
signature "org.codehaus.mojo.signature:java17:1.0@signature"
|
||||
signature "net.sf.androidscents.signature:android-api-level-14:4.0_r4@signature"
|
||||
}
|
||||
|
||||
javadoc {
|
||||
exclude 'io/opencensus/internal/**'
|
||||
exclude 'io/opencensus/trace/internal/**'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.common;
|
||||
|
||||
/**
|
||||
* Interface for getting the current time.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract class Clock {
|
||||
|
||||
/**
|
||||
* Obtains the current instant from this clock.
|
||||
*
|
||||
* @return the current instant.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Timestamp now();
|
||||
|
||||
/**
|
||||
* Returns a time measurement with nanosecond precision that can only be used to calculate elapsed
|
||||
* time.
|
||||
*
|
||||
* @return a time measurement with nanosecond precision that can only be used to calculate elapsed
|
||||
* time.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract long nowNanos();
|
||||
}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.common;
|
||||
|
||||
import static openconsensus.common.TimeUtils.MAX_NANOS;
|
||||
import static openconsensus.common.TimeUtils.MAX_SECONDS;
|
||||
import static openconsensus.common.TimeUtils.MILLIS_PER_SECOND;
|
||||
import static openconsensus.common.TimeUtils.NANOS_PER_MILLI;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* Represents a signed, fixed-length span of time represented as a count of seconds and fractions of
|
||||
* seconds at nanosecond resolution. It is independent of any calendar and concepts like "day" or
|
||||
* "month". Range is approximately +-10,000 years.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract class Duration implements Comparable<Duration> {
|
||||
|
||||
/**
|
||||
* Creates a new time duration from given seconds and nanoseconds.
|
||||
*
|
||||
* @param seconds Signed seconds of the span of time. Must be from -315,576,000,000 to
|
||||
* +315,576,000,000 inclusive.
|
||||
* @param nanos Signed fractions of a second at nanosecond resolution of the span of time.
|
||||
* Durations less than one second are represented with a 0 `seconds` field and a positive or
|
||||
* negative `nanos` field. For durations of one second or more, a non-zero value for the
|
||||
* `nanos` field must be of the same sign as the `seconds` field. Must be from -999,999,999 to
|
||||
* +999,999,999 inclusive.
|
||||
* @return new {@code Duration} with specified fields.
|
||||
* @throws IllegalArgumentException if the arguments are out of range or have inconsistent sign.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Duration create(long seconds, int nanos) {
|
||||
if (seconds < -MAX_SECONDS) {
|
||||
throw new IllegalArgumentException(
|
||||
"'seconds' is less than minimum (" + -MAX_SECONDS + "): " + seconds);
|
||||
}
|
||||
if (seconds > MAX_SECONDS) {
|
||||
throw new IllegalArgumentException(
|
||||
"'seconds' is greater than maximum (" + MAX_SECONDS + "): " + seconds);
|
||||
}
|
||||
if (nanos < -MAX_NANOS) {
|
||||
throw new IllegalArgumentException(
|
||||
"'nanos' is less than minimum (" + -MAX_NANOS + "): " + nanos);
|
||||
}
|
||||
if (nanos > MAX_NANOS) {
|
||||
throw new IllegalArgumentException(
|
||||
"'nanos' is greater than maximum (" + MAX_NANOS + "): " + nanos);
|
||||
}
|
||||
if ((seconds < 0 && nanos > 0) || (seconds > 0 && nanos < 0)) {
|
||||
throw new IllegalArgumentException(
|
||||
"'seconds' and 'nanos' have inconsistent sign: seconds=" + seconds + ", nanos=" + nanos);
|
||||
}
|
||||
return new AutoValue_Duration(seconds, nanos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code Duration} from given milliseconds.
|
||||
*
|
||||
* @param millis the duration in milliseconds.
|
||||
* @return a new {@code Duration} from given milliseconds.
|
||||
* @throws IllegalArgumentException if the number of milliseconds is out of the range that can be
|
||||
* represented by {@code Duration}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Duration fromMillis(long millis) {
|
||||
long seconds = millis / MILLIS_PER_SECOND;
|
||||
int nanos = (int) (millis % MILLIS_PER_SECOND * NANOS_PER_MILLI);
|
||||
return Duration.create(seconds, nanos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@link Duration} to milliseconds.
|
||||
*
|
||||
* @return the milliseconds representation of this {@code Duration}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public long toMillis() {
|
||||
return TimeUnit.SECONDS.toMillis(getSeconds()) + TimeUnit.NANOSECONDS.toMillis(getNanos());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of seconds in the {@code Duration}.
|
||||
*
|
||||
* @return the number of seconds in the {@code Duration}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract long getSeconds();
|
||||
|
||||
/**
|
||||
* Returns the number of nanoseconds in the {@code Duration}.
|
||||
*
|
||||
* @return the number of nanoseconds in the {@code Duration}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract int getNanos();
|
||||
|
||||
/**
|
||||
* Compares this {@code Duration} to the specified {@code Duration}.
|
||||
*
|
||||
* @param otherDuration the other {@code Duration} to compare to, not {@code null}.
|
||||
* @return the comparator value: zero if equal, negative if this duration is smaller than
|
||||
* otherDuration, positive if larger.
|
||||
* @throws NullPointerException if otherDuration is {@code null}.
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(Duration otherDuration) {
|
||||
int cmp = TimeUtils.compareLongs(getSeconds(), otherDuration.getSeconds());
|
||||
if (cmp != 0) {
|
||||
return cmp;
|
||||
}
|
||||
return TimeUtils.compareLongs(getNanos(), otherDuration.getNanos());
|
||||
}
|
||||
|
||||
Duration() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.common;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates a public API that can change at any time, and has no guarantee of API stability and
|
||||
* backward-compatibility.
|
||||
*
|
||||
* <p>Usage guidelines:
|
||||
*
|
||||
* <ol>
|
||||
* <li>This annotation is used only on public API. Internal interfaces should not use it.
|
||||
* <li>After OpenCensus has gained API stability, this annotation can only be added to new API.
|
||||
* Adding it to an existing API is considered API-breaking.
|
||||
* <li>Removing this annotation from an API gives it stable status.
|
||||
* </ol>
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Internal
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target({
|
||||
ElementType.ANNOTATION_TYPE,
|
||||
ElementType.CONSTRUCTOR,
|
||||
ElementType.FIELD,
|
||||
ElementType.METHOD,
|
||||
ElementType.PACKAGE,
|
||||
ElementType.TYPE
|
||||
})
|
||||
@Documented
|
||||
public @interface ExperimentalApi {
|
||||
/**
|
||||
* Context information such as links to discussion thread, tracking issue etc.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
String value() default "";
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.common;
|
||||
|
||||
import openconsensus.trace.AttributeValue;
|
||||
|
||||
/**
|
||||
* Used to specify matching functions for use encoding tagged unions (i.e. sum types) in Java. See
|
||||
* {@link AttributeValue#match} for an example of its use.
|
||||
*
|
||||
* <p>Note: This class is based on the java.util.Function class added in Java 1.8. We cannot use the
|
||||
* Function from Java 1.8 because this library is Java 1.6 compatible.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public interface Function<A, B> {
|
||||
|
||||
/**
|
||||
* Applies the function to the given argument.
|
||||
*
|
||||
* @param arg the argument to the function.
|
||||
* @return the result of the function.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
B apply(A arg);
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.common;
|
||||
|
||||
/*>>>
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
*/
|
||||
|
||||
/**
|
||||
* Commonly used {@link Function} instances.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public final class Functions {
|
||||
private Functions() {}
|
||||
|
||||
private static final Function<Object, /*@Nullable*/ Void> RETURN_NULL =
|
||||
new Function<Object, /*@Nullable*/ Void>() {
|
||||
@Override
|
||||
@javax.annotation.Nullable
|
||||
public Void apply(Object ignored) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private static final Function<Object, Void> THROW_ILLEGAL_ARGUMENT_EXCEPTION =
|
||||
new Function<Object, Void>() {
|
||||
@Override
|
||||
public Void apply(Object ignored) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
};
|
||||
|
||||
private static final Function<Object, Void> THROW_ASSERTION_ERROR =
|
||||
new Function<Object, Void>() {
|
||||
@Override
|
||||
public Void apply(Object ignored) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
};
|
||||
|
||||
private static final Function<Object, /*@Nullable*/ String> RETURN_TO_STRING =
|
||||
new Function<Object, /*@Nullable*/ String>() {
|
||||
@Override
|
||||
public /*@Nullable*/ String apply(Object input) {
|
||||
return input == null ? null : input.toString();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A {@code Function} that always ignores its argument and returns {@code null}.
|
||||
*
|
||||
* @return a {@code Function} that always ignores its argument and returns {@code null}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static <T> Function<Object, /*@Nullable*/ T> returnNull() {
|
||||
// It is safe to cast a producer of Void to anything, because Void is always null.
|
||||
@SuppressWarnings("unchecked")
|
||||
Function<Object, /*@Nullable*/ T> function = (Function<Object, /*@Nullable*/ T>) RETURN_NULL;
|
||||
return function;
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@code Function} that always ignores its argument and returns a constant value.
|
||||
*
|
||||
* @return a {@code Function} that always ignores its argument and returns a constant value.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static <T> Function<Object, T> returnConstant(final T constant) {
|
||||
return new Function<Object, T>() {
|
||||
@Override
|
||||
public T apply(Object ignored) {
|
||||
return constant;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@code Function} that always returns the {@link #toString()} value of the input.
|
||||
*
|
||||
* @return a {@code Function} that always returns the {@link #toString()} value of the input.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Function<Object, /*@Nullable*/ String> returnToString() {
|
||||
return RETURN_TO_STRING;
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@code Function} that always ignores its argument and throws an {@link
|
||||
* IllegalArgumentException}.
|
||||
*
|
||||
* @return a {@code Function} that always ignores its argument and throws an {@link
|
||||
* IllegalArgumentException}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static <T> Function<Object, T> throwIllegalArgumentException() {
|
||||
// It is safe to cast this function to have any return type, since it never returns a result.
|
||||
@SuppressWarnings("unchecked")
|
||||
Function<Object, T> function = (Function<Object, T>) THROW_ILLEGAL_ARGUMENT_EXCEPTION;
|
||||
return function;
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@code Function} that always ignores its argument and throws an {@link AssertionError}.
|
||||
*
|
||||
* @return a {@code Function} that always ignores its argument and throws an {@code
|
||||
* AssertionError}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static <T> Function<Object, T> throwAssertionError() {
|
||||
// It is safe to cast this function to have any return type, since it never returns a result.
|
||||
@SuppressWarnings("unchecked")
|
||||
Function<Object, T> function = (Function<Object, T>) THROW_ASSERTION_ERROR;
|
||||
return function;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.common;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotates a program element (class, method, package etc) which is internal to OpenCensus, not
|
||||
* part of the public API, and should not be used by users of the OpenCensus library.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Internal
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target({
|
||||
ElementType.ANNOTATION_TYPE,
|
||||
ElementType.CONSTRUCTOR,
|
||||
ElementType.FIELD,
|
||||
ElementType.METHOD,
|
||||
ElementType.PACKAGE,
|
||||
ElementType.TYPE
|
||||
})
|
||||
@Documented
|
||||
public @interface Internal {}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.common;
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
/**
|
||||
* An {@link Closeable} which cannot throw a checked exception.
|
||||
*
|
||||
* <p>This is useful because such a reversion otherwise requires the caller to catch the
|
||||
* (impossible) Exception in the try-with-resources.
|
||||
*
|
||||
* <p>Example of usage:
|
||||
*
|
||||
* <pre>
|
||||
* try (NonThrowingAutoCloseable ctx = tryEnter()) {
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @deprecated {@link Scope} is a better match for operations involving the current context.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Deprecated
|
||||
public interface NonThrowingCloseable extends Closeable {
|
||||
@Override
|
||||
void close();
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.common;
|
||||
|
||||
/**
|
||||
* Class holder for all common constants (such as the version) for the OpenCensus Java library.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
public final class OpenCensusLibraryInformation {
|
||||
|
||||
/**
|
||||
* The current version of the OpenCensus Java library.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static final String VERSION = "0.20.0-SNAPSHOT"; // CURRENT_OPENCENSUS_VERSION
|
||||
|
||||
private OpenCensusLibraryInformation() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.common;
|
||||
|
||||
/**
|
||||
* A {@link java.io.Closeable} that represents a change to the current context over a scope of code.
|
||||
* {@link Scope#close} cannot throw a checked exception.
|
||||
*
|
||||
* <p>Example of usage:
|
||||
*
|
||||
* <pre>
|
||||
* try (Scope ctx = tryEnter()) {
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public interface Scope extends NonThrowingCloseable {
|
||||
@Override
|
||||
void close();
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.common;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* A representation of stats measured on the server side.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract class ServerStats {
|
||||
|
||||
ServerStats() {}
|
||||
|
||||
/**
|
||||
* Returns Load Balancer latency, a latency observed at Load Balancer.
|
||||
*
|
||||
* @return Load Balancer latency in nanoseconds.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract long getLbLatencyNs();
|
||||
|
||||
/**
|
||||
* Returns Service latency, a latency observed at Server.
|
||||
*
|
||||
* @return Service latency in nanoseconds.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract long getServiceLatencyNs();
|
||||
|
||||
/**
|
||||
* Returns Trace options, a set of bits indicating properties of trace.
|
||||
*
|
||||
* @return Trace options a set of bits indicating properties of trace.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract byte getTraceOption();
|
||||
|
||||
/**
|
||||
* Creates new {@link ServerStats} from specified parameters.
|
||||
*
|
||||
* @param lbLatencyNs Represents request processing latency observed on Load Balancer. It is
|
||||
* measured in nanoseconds. Must not be less than 0. Value of 0 represents that the latency is
|
||||
* not measured.
|
||||
* @param serviceLatencyNs Represents request processing latency observed on Server. It is
|
||||
* measured in nanoseconds. Must not be less than 0. Value of 0 represents that the latency is
|
||||
* not measured.
|
||||
* @param traceOption Represents set of bits to indicate properties of trace. Currently it used
|
||||
* only the least signification bit to represent sampling of the request on the server side.
|
||||
* Other bits are ignored.
|
||||
* @return new {@code ServerStats} with specified fields.
|
||||
* @throws IllegalArgumentException if the arguments are out of range.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static ServerStats create(long lbLatencyNs, long serviceLatencyNs, byte traceOption) {
|
||||
|
||||
if (lbLatencyNs < 0) {
|
||||
throw new IllegalArgumentException("'getLbLatencyNs' is less than zero: " + lbLatencyNs);
|
||||
}
|
||||
|
||||
if (serviceLatencyNs < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"'getServiceLatencyNs' is less than zero: " + serviceLatencyNs);
|
||||
}
|
||||
|
||||
return new AutoValue_ServerStats(lbLatencyNs, serviceLatencyNs, traceOption);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.common;
|
||||
|
||||
/**
|
||||
* Exception thrown when a {@link ServerStats} cannot be parsed.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public final class ServerStatsDeserializationException extends Exception {
|
||||
private static final long serialVersionUID = 0L;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ServerStatsDeserializationException} with the given message.
|
||||
*
|
||||
* @param message a message describing the error.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public ServerStatsDeserializationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ServerStatsDeserializationException} with the given message and cause.
|
||||
*
|
||||
* @param message a message describing the error.
|
||||
* @param cause the cause of the error.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public ServerStatsDeserializationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.common;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* A service class to encode/decode {@link ServerStats} as defined by the spec.
|
||||
*
|
||||
* <p>See <a
|
||||
* href="https://github.com/census-instrumentation/opencensus-specs/blob/master/encodings/CensusServerStatsEncoding.md">opencensus-server-stats-specs</a>
|
||||
* for encoding {@code ServerStats}
|
||||
*
|
||||
* <p>Use {@code ServerStatsEncoding.toBytes(ServerStats stats)} to encode.
|
||||
*
|
||||
* <p>Use {@code ServerStatsEncoding.parseBytes(byte[] serialized)} to decode.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public final class ServerStatsEncoding {
|
||||
|
||||
private ServerStatsEncoding() {}
|
||||
|
||||
/**
|
||||
* The current encoding version. The value is {@value #CURRENT_VERSION}
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static final byte CURRENT_VERSION = (byte) 0;
|
||||
|
||||
/**
|
||||
* Encodes the {@link ServerStats} as per the Opencensus Summary Span specification.
|
||||
*
|
||||
* @param stats {@code ServerStats} to encode.
|
||||
* @return encoded byte array.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static byte[] toBytes(ServerStats stats) {
|
||||
// Should this be optimized to not include invalid values?
|
||||
|
||||
ByteBuffer bb = ByteBuffer.allocate(ServerStatsFieldEnums.getTotalSize() + 1);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
// put version
|
||||
bb.put(CURRENT_VERSION);
|
||||
|
||||
bb.put((byte) ServerStatsFieldEnums.Id.SERVER_STATS_LB_LATENCY_ID.value());
|
||||
bb.putLong(stats.getLbLatencyNs());
|
||||
|
||||
bb.put((byte) ServerStatsFieldEnums.Id.SERVER_STATS_SERVICE_LATENCY_ID.value());
|
||||
bb.putLong(stats.getServiceLatencyNs());
|
||||
|
||||
bb.put((byte) ServerStatsFieldEnums.Id.SERVER_STATS_TRACE_OPTION_ID.value());
|
||||
bb.put(stats.getTraceOption());
|
||||
return bb.array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes serialized byte array to create {@link ServerStats} as per Opencensus Summary Span
|
||||
* specification.
|
||||
*
|
||||
* @param serialized encoded {@code ServerStats} in byte array.
|
||||
* @return decoded {@code ServerStats}. null if decoding fails.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static ServerStats parseBytes(byte[] serialized)
|
||||
throws ServerStatsDeserializationException {
|
||||
final ByteBuffer bb = ByteBuffer.wrap(serialized);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
long serviceLatencyNs = 0L;
|
||||
long lbLatencyNs = 0L;
|
||||
byte traceOption = (byte) 0;
|
||||
|
||||
// Check the version first.
|
||||
if (!bb.hasRemaining()) {
|
||||
throw new ServerStatsDeserializationException("Serialized ServerStats buffer is empty");
|
||||
}
|
||||
byte version = bb.get();
|
||||
|
||||
if (version > CURRENT_VERSION || version < 0) {
|
||||
throw new ServerStatsDeserializationException("Invalid ServerStats version: " + version);
|
||||
}
|
||||
|
||||
while (bb.hasRemaining()) {
|
||||
ServerStatsFieldEnums.Id id = ServerStatsFieldEnums.Id.valueOf((int) bb.get() & 0xFF);
|
||||
if (id == null) {
|
||||
// Skip remaining;
|
||||
bb.position(bb.limit());
|
||||
} else {
|
||||
switch (id) {
|
||||
case SERVER_STATS_LB_LATENCY_ID:
|
||||
lbLatencyNs = bb.getLong();
|
||||
break;
|
||||
case SERVER_STATS_SERVICE_LATENCY_ID:
|
||||
serviceLatencyNs = bb.getLong();
|
||||
break;
|
||||
case SERVER_STATS_TRACE_OPTION_ID:
|
||||
traceOption = bb.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
return ServerStats.create(lbLatencyNs, serviceLatencyNs, traceOption);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ServerStatsDeserializationException(
|
||||
"Serialized ServiceStats contains invalid values: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.common;
|
||||
|
||||
import java.util.TreeMap;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A Enum representation for Ids and Size for attributes of {@code ServerStats}.
|
||||
*
|
||||
* <p>See <a
|
||||
* href="https://github.com/census-instrumentation/opencensus-specs/blob/master/encodings/CensusServerStatsEncoding.md">opencensus-server-stats-specs</a>
|
||||
* for the field ids and their length defined for Server Stats
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public final class ServerStatsFieldEnums {
|
||||
|
||||
/**
|
||||
* Available Ids for {@code ServerStats} attributes.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public enum Id {
|
||||
/**
|
||||
* Id for Latency observed at Load Balancer.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
SERVER_STATS_LB_LATENCY_ID(0),
|
||||
/**
|
||||
* Id for Latency observed at Server.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
SERVER_STATS_SERVICE_LATENCY_ID(1),
|
||||
/**
|
||||
* Id for Trace options.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
SERVER_STATS_TRACE_OPTION_ID(2);
|
||||
|
||||
private final int value;
|
||||
|
||||
private Id(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the numerical value of the {@link Id}.
|
||||
*
|
||||
* @return the numerical value of the {@code Id}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public int value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
private static final TreeMap<Integer, Id> map = new TreeMap<Integer, Id>();
|
||||
|
||||
static {
|
||||
for (Id id : Id.values()) {
|
||||
map.put(id.value, id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Id} representing the value value of the id.
|
||||
*
|
||||
* @param value integer value for which {@code Id} is being requested.
|
||||
* @return the numerical value of the id. null if the id is not valid
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Nullable
|
||||
public static Id valueOf(int value) {
|
||||
return map.get(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Size for each attributes in {@code ServerStats}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public enum Size {
|
||||
/**
|
||||
* Number of bytes used to represent latency observed at Load Balancer.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
SERVER_STATS_LB_LATENCY_SIZE(8),
|
||||
/**
|
||||
* Number of bytes used to represent latency observed at Server.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
SERVER_STATS_SERVICE_LATENCY_SIZE(8),
|
||||
/**
|
||||
* Number of bytes used to represent Trace option.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
SERVER_STATS_TRACE_OPTION_SIZE(1);
|
||||
|
||||
private final int value;
|
||||
|
||||
private Size(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the numerical value of the {@link Size}.
|
||||
*
|
||||
* @return the numerical value of the {@code Size}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public int value() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
private static final int TOTALSIZE = computeTotalSize();
|
||||
|
||||
private ServerStatsFieldEnums() {}
|
||||
|
||||
private static int computeTotalSize() {
|
||||
int sum = 0;
|
||||
for (Size sizeValue : Size.values()) {
|
||||
sum += sizeValue.value();
|
||||
sum += 1; // For Id
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total size required to encode the {@code ServerStats}.
|
||||
*
|
||||
* @return the total size required to encode all fields in {@code ServerStats}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static int getTotalSize() {
|
||||
return TOTALSIZE;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.common;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/** Util class for {@link Timestamp} and {@link Duration}. */
|
||||
final class TimeUtils {
|
||||
static final long MAX_SECONDS = 315576000000L;
|
||||
static final int MAX_NANOS = 999999999;
|
||||
static final long MILLIS_PER_SECOND = 1000L;
|
||||
static final long NANOS_PER_MILLI = 1000 * 1000;
|
||||
static final long NANOS_PER_SECOND = NANOS_PER_MILLI * MILLIS_PER_SECOND;
|
||||
|
||||
private TimeUtils() {}
|
||||
|
||||
/**
|
||||
* Compares two longs. This functionality is provided by {@code Long.compare(long, long)} in Java
|
||||
* 7.
|
||||
*/
|
||||
static int compareLongs(long x, long y) {
|
||||
if (x < y) {
|
||||
return -1;
|
||||
} else if (x == y) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static final BigInteger MAX_LONG_VALUE = BigInteger.valueOf(Long.MAX_VALUE);
|
||||
private static final BigInteger MIN_LONG_VALUE = BigInteger.valueOf(Long.MIN_VALUE);
|
||||
|
||||
/**
|
||||
* Adds two longs and throws an {@link ArithmeticException} if the result overflows. This
|
||||
* functionality is provided by {@code Math.addExact(long, long)} in Java 8.
|
||||
*/
|
||||
static long checkedAdd(long x, long y) {
|
||||
BigInteger sum = BigInteger.valueOf(x).add(BigInteger.valueOf(y));
|
||||
if (sum.compareTo(MAX_LONG_VALUE) > 0 || sum.compareTo(MIN_LONG_VALUE) < 0) {
|
||||
throw new ArithmeticException("Long sum overflow: x=" + x + ", y=" + y);
|
||||
}
|
||||
return x + y;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.common;
|
||||
|
||||
import static openconsensus.common.TimeUtils.MAX_NANOS;
|
||||
import static openconsensus.common.TimeUtils.MAX_SECONDS;
|
||||
import static openconsensus.common.TimeUtils.MILLIS_PER_SECOND;
|
||||
import static openconsensus.common.TimeUtils.NANOS_PER_MILLI;
|
||||
import static openconsensus.common.TimeUtils.NANOS_PER_SECOND;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* A representation of an instant in time. The instant is the number of nanoseconds after the number
|
||||
* of seconds since the Unix Epoch.
|
||||
*
|
||||
* <p>Use {@code Tracing.getClock().now()} to get the current timestamp since epoch
|
||||
* (1970-01-01T00:00:00Z).
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract class Timestamp implements Comparable<Timestamp> {
|
||||
|
||||
Timestamp() {}
|
||||
|
||||
/**
|
||||
* Creates a new timestamp from given seconds and nanoseconds.
|
||||
*
|
||||
* @param seconds Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must be
|
||||
* from from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.
|
||||
* @param nanos Non-negative fractions of a second at nanosecond resolution. Negative second
|
||||
* values with fractions must still have non-negative nanos values that count forward in time.
|
||||
* Must be from 0 to 999,999,999 inclusive.
|
||||
* @return new {@code Timestamp} with specified fields.
|
||||
* @throws IllegalArgumentException if the arguments are out of range.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Timestamp create(long seconds, int nanos) {
|
||||
if (seconds < -MAX_SECONDS) {
|
||||
throw new IllegalArgumentException(
|
||||
"'seconds' is less than minimum (" + -MAX_SECONDS + "): " + seconds);
|
||||
}
|
||||
if (seconds > MAX_SECONDS) {
|
||||
throw new IllegalArgumentException(
|
||||
"'seconds' is greater than maximum (" + MAX_SECONDS + "): " + seconds);
|
||||
}
|
||||
if (nanos < 0) {
|
||||
throw new IllegalArgumentException("'nanos' is less than zero: " + nanos);
|
||||
}
|
||||
if (nanos > MAX_NANOS) {
|
||||
throw new IllegalArgumentException(
|
||||
"'nanos' is greater than maximum (" + MAX_NANOS + "): " + nanos);
|
||||
}
|
||||
return new AutoValue_Timestamp(seconds, nanos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new timestamp from the given milliseconds.
|
||||
*
|
||||
* @param epochMilli the timestamp represented in milliseconds since epoch.
|
||||
* @return new {@code Timestamp} with specified fields.
|
||||
* @throws IllegalArgumentException if the number of milliseconds is out of the range that can be
|
||||
* represented by {@code Timestamp}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Timestamp fromMillis(long epochMilli) {
|
||||
long secs = floorDiv(epochMilli, MILLIS_PER_SECOND);
|
||||
int mos = (int) floorMod(epochMilli, MILLIS_PER_SECOND);
|
||||
return create(secs, (int) (mos * NANOS_PER_MILLI)); // Safe int * NANOS_PER_MILLI
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of seconds since the Unix Epoch represented by this timestamp.
|
||||
*
|
||||
* @return the number of seconds since the Unix Epoch.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract long getSeconds();
|
||||
|
||||
/**
|
||||
* Returns the number of nanoseconds after the number of seconds since the Unix Epoch represented
|
||||
* by this timestamp.
|
||||
*
|
||||
* @return the number of nanoseconds after the number of seconds since the Unix Epoch.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract int getNanos();
|
||||
|
||||
/**
|
||||
* Returns a {@code Timestamp} calculated as this {@code Timestamp} plus some number of
|
||||
* nanoseconds.
|
||||
*
|
||||
* @param nanosToAdd the nanos to add, positive or negative.
|
||||
* @return the calculated {@code Timestamp}. For invalid inputs, a {@code Timestamp} of zero is
|
||||
* returned.
|
||||
* @throws ArithmeticException if numeric overflow occurs.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public Timestamp addNanos(long nanosToAdd) {
|
||||
return plus(0, nanosToAdd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Timestamp} calculated as this {@code Timestamp} plus some {@code Duration}.
|
||||
*
|
||||
* @param duration the {@code Duration} to add.
|
||||
* @return a {@code Timestamp} with the specified {@code Duration} added.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public Timestamp addDuration(Duration duration) {
|
||||
return plus(duration.getSeconds(), duration.getNanos());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Duration} calculated as: {@code this - timestamp}.
|
||||
*
|
||||
* @param timestamp the {@code Timestamp} to subtract.
|
||||
* @return the calculated {@code Duration}. For invalid inputs, a {@code Duration} of zero is
|
||||
* returned.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public Duration subtractTimestamp(Timestamp timestamp) {
|
||||
long durationSeconds = getSeconds() - timestamp.getSeconds();
|
||||
int durationNanos = getNanos() - timestamp.getNanos();
|
||||
if (durationSeconds < 0 && durationNanos > 0) {
|
||||
durationSeconds += 1;
|
||||
durationNanos = (int) (durationNanos - NANOS_PER_SECOND);
|
||||
} else if (durationSeconds > 0 && durationNanos < 0) {
|
||||
durationSeconds -= 1;
|
||||
durationNanos = (int) (durationNanos + NANOS_PER_SECOND);
|
||||
}
|
||||
return Duration.create(durationSeconds, durationNanos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this {@code Timestamp} to the specified {@code Timestamp}.
|
||||
*
|
||||
* @param otherTimestamp the other {@code Timestamp} to compare to, not {@code null}.
|
||||
* @return the comparator value: zero if equal, negative if this timestamp happens before
|
||||
* otherTimestamp, positive if after.
|
||||
* @throws NullPointerException if otherTimestamp is {@code null}.
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(Timestamp otherTimestamp) {
|
||||
int cmp = TimeUtils.compareLongs(getSeconds(), otherTimestamp.getSeconds());
|
||||
if (cmp != 0) {
|
||||
return cmp;
|
||||
}
|
||||
return TimeUtils.compareLongs(getNanos(), otherTimestamp.getNanos());
|
||||
}
|
||||
|
||||
// Returns a Timestamp with the specified duration added.
|
||||
private Timestamp plus(long secondsToAdd, long nanosToAdd) {
|
||||
if ((secondsToAdd | nanosToAdd) == 0) {
|
||||
return this;
|
||||
}
|
||||
long epochSec = TimeUtils.checkedAdd(getSeconds(), secondsToAdd);
|
||||
epochSec = TimeUtils.checkedAdd(epochSec, nanosToAdd / NANOS_PER_SECOND);
|
||||
nanosToAdd = nanosToAdd % NANOS_PER_SECOND;
|
||||
long nanoAdjustment = getNanos() + nanosToAdd; // safe int + NANOS_PER_SECOND
|
||||
return ofEpochSecond(epochSec, nanoAdjustment);
|
||||
}
|
||||
|
||||
// Returns a Timestamp calculated using seconds from the epoch and nanosecond fraction of
|
||||
// second (arbitrary number of nanoseconds).
|
||||
private static Timestamp ofEpochSecond(long epochSecond, long nanoAdjustment) {
|
||||
long secs = TimeUtils.checkedAdd(epochSecond, floorDiv(nanoAdjustment, NANOS_PER_SECOND));
|
||||
int nos = (int) floorMod(nanoAdjustment, NANOS_PER_SECOND);
|
||||
return create(secs, nos);
|
||||
}
|
||||
|
||||
// Returns the result of dividing x by y rounded using floor.
|
||||
private static long floorDiv(long x, long y) {
|
||||
return BigDecimal.valueOf(x).divide(BigDecimal.valueOf(y), 0, RoundingMode.FLOOR).longValue();
|
||||
}
|
||||
|
||||
// Returns the floor modulus "x - (floorDiv(x, y) * y)"
|
||||
private static long floorMod(long x, long y) {
|
||||
return x - floorDiv(x, y) * y;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.common;
|
||||
|
||||
/*>>>
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
*/
|
||||
|
||||
import openconsensus.metrics.MetricRegistry;
|
||||
|
||||
/**
|
||||
* Represents a function that produces a double-valued result. See {@link
|
||||
* MetricRegistry} for an example of its use.
|
||||
*
|
||||
* <p>Note: This class is based on the java.util.ToDoubleFunction class added in Java 1.8. We cannot
|
||||
* use the Function from Java 1.8 because this library is Java 1.6 compatible.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public interface ToDoubleFunction</*@Nullable*/ T> {
|
||||
|
||||
/**
|
||||
* Applies this function to the given argument.
|
||||
*
|
||||
* @param value the function argument.
|
||||
* @return the function result.
|
||||
*/
|
||||
double applyAsDouble(/*@Nullable*/ T value);
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.common;
|
||||
|
||||
/*>>>
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
*/
|
||||
|
||||
import openconsensus.metrics.MetricRegistry;
|
||||
|
||||
/**
|
||||
* Represents a function that produces a long-valued result. See {@link
|
||||
* MetricRegistry} for an example of its use.
|
||||
*
|
||||
* <p>Note: This class is based on the java.util.ToLongFunction class added in Java 1.8. We cannot
|
||||
* use the Function from Java 1.8 because this library is Java 1.6 compatible.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public interface ToLongFunction</*@Nullable*/ T> {
|
||||
/**
|
||||
* Applies this function to the given argument.
|
||||
*
|
||||
* @param value the function argument.
|
||||
* @return the function result.
|
||||
*/
|
||||
long applyAsLong(/*@Nullable*/ T value);
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/** Common API between different packages in this artifact. */
|
||||
package openconsensus.common;
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.internal;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates that an element is package-private instead of private only for the purpose of testing.
|
||||
* This annotation is only meant to be used as documentation in the source code.
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target({
|
||||
ElementType.ANNOTATION_TYPE,
|
||||
ElementType.CONSTRUCTOR,
|
||||
ElementType.FIELD,
|
||||
ElementType.METHOD,
|
||||
ElementType.PACKAGE,
|
||||
ElementType.TYPE
|
||||
})
|
||||
public @interface DefaultVisibilityForTesting {}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.internal;
|
||||
|
||||
import openconsensus.common.Scope;
|
||||
|
||||
/** A {@link Scope} that does nothing when it is created or closed. */
|
||||
public final class NoopScope implements Scope {
|
||||
private static final Scope INSTANCE = new NoopScope();
|
||||
|
||||
private NoopScope() {}
|
||||
|
||||
/**
|
||||
* Returns a {@code NoopScope}.
|
||||
*
|
||||
* @return a {@code NoopScope}.
|
||||
*/
|
||||
public static Scope getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.internal;
|
||||
|
||||
import java.util.ServiceConfigurationError;
|
||||
|
||||
/**
|
||||
* OpenCensus service provider mechanism.
|
||||
*
|
||||
* <pre>{@code
|
||||
* // Initialize a variable using reflection.
|
||||
* foo = Provider.createInstance(
|
||||
* Class.forName("FooImpl", true, classLoader), Foo.class);
|
||||
* }</pre>
|
||||
*/
|
||||
public final class Provider {
|
||||
private Provider() {}
|
||||
|
||||
/**
|
||||
* Tries to create an instance of the given rawClass as a subclass of the given superclass.
|
||||
*
|
||||
* @param rawClass The class that is initialized.
|
||||
* @param superclass The initialized class must be a subclass of this.
|
||||
* @return an instance of the class given rawClass which is a subclass of the given superclass.
|
||||
* @throws ServiceConfigurationError if any error happens.
|
||||
*/
|
||||
public static <T> T createInstance(Class<?> rawClass, Class<T> superclass) {
|
||||
try {
|
||||
return rawClass.asSubclass(superclass).getConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new ServiceConfigurationError(
|
||||
"Provider " + rawClass.getName() + " could not be instantiated.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.internal;
|
||||
|
||||
/** Internal utility methods for working with tag keys, tag values, and metric names. */
|
||||
public final class StringUtils {
|
||||
|
||||
/**
|
||||
* Determines whether the {@code String} contains only printable characters.
|
||||
*
|
||||
* @param str the {@code String} to be validated.
|
||||
* @return whether the {@code String} contains only printable characters.
|
||||
*/
|
||||
public static boolean isPrintableString(String str) {
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
if (!isPrintableChar(str.charAt(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isPrintableChar(char ch) {
|
||||
return ch >= ' ' && ch <= '~';
|
||||
}
|
||||
|
||||
private StringUtils() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.internal;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/*>>>
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
*/
|
||||
|
||||
/** General internal utility methods. */
|
||||
public final class Utils {
|
||||
|
||||
private Utils() {}
|
||||
|
||||
/**
|
||||
* Throws an {@link IllegalArgumentException} if the argument is false. This method is similar to
|
||||
* {@code Preconditions.checkArgument(boolean, Object)} from Guava.
|
||||
*
|
||||
* @param isValid whether the argument check passed.
|
||||
* @param errorMessage the message to use for the exception. Will be converted to a string using
|
||||
* {@link String#valueOf(Object)}.
|
||||
*/
|
||||
public static void checkArgument(
|
||||
boolean isValid, @javax.annotation.Nullable Object errorMessage) {
|
||||
if (!isValid) {
|
||||
throw new IllegalArgumentException(String.valueOf(errorMessage));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an {@link IllegalArgumentException} if the argument is false. This method is similar to
|
||||
* {@code Preconditions.checkArgument(boolean, Object)} from Guava.
|
||||
*
|
||||
* @param expression a boolean expression
|
||||
* @param errorMessageTemplate a template for the exception message should the check fail. The
|
||||
* message is formed by replacing each {@code %s} placeholder in the template with an
|
||||
* argument. These are matched by position - the first {@code %s} gets {@code
|
||||
* errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted message in
|
||||
* square braces. Unmatched placeholders will be left as-is.
|
||||
* @param errorMessageArgs the arguments to be substituted into the message template. Arguments
|
||||
* are converted to strings using {@link String#valueOf(Object)}.
|
||||
* @throws IllegalArgumentException if {@code expression} is false
|
||||
* @throws NullPointerException if the check fails and either {@code errorMessageTemplate} or
|
||||
* {@code errorMessageArgs} is null (don't let this happen)
|
||||
*/
|
||||
public static void checkArgument(
|
||||
boolean expression,
|
||||
String errorMessageTemplate,
|
||||
@javax.annotation.Nullable Object... errorMessageArgs) {
|
||||
if (!expression) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, errorMessageArgs));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an {@link IllegalStateException} if the argument is false. This method is similar to
|
||||
* {@code Preconditions.checkState(boolean, Object)} from Guava.
|
||||
*
|
||||
* @param isValid whether the state check passed.
|
||||
* @param errorMessage the message to use for the exception. Will be converted to a string using
|
||||
* {@link String#valueOf(Object)}.
|
||||
*/
|
||||
public static void checkState(boolean isValid, @javax.annotation.Nullable Object errorMessage) {
|
||||
if (!isValid) {
|
||||
throw new IllegalStateException(String.valueOf(errorMessage));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an index in an array or other container. This method throws an {@link
|
||||
* IllegalArgumentException} if the size is negative and throws an {@link
|
||||
* IndexOutOfBoundsException} if the index is negative or greater than or equal to the size. This
|
||||
* method is similar to {@code Preconditions.checkElementIndex(int, int)} from Guava.
|
||||
*
|
||||
* @param index the index to validate.
|
||||
* @param size the size of the array or container.
|
||||
*/
|
||||
public static void checkIndex(int index, int size) {
|
||||
if (size < 0) {
|
||||
throw new IllegalArgumentException("Negative size: " + size);
|
||||
}
|
||||
if (index < 0 || index >= size) {
|
||||
throw new IndexOutOfBoundsException("Index out of bounds: size=" + size + ", index=" + index);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a {@link NullPointerException} if the argument is null. This method is similar to {@code
|
||||
* Preconditions.checkNotNull(Object, Object)} from Guava.
|
||||
*
|
||||
* @param arg the argument to check for null.
|
||||
* @param errorMessage the message to use for the exception. Will be converted to a string using
|
||||
* {@link String#valueOf(Object)}.
|
||||
* @return the argument, if it passes the null check.
|
||||
*/
|
||||
public static <T /*>>> extends @NonNull Object*/> T checkNotNull(
|
||||
T arg, @javax.annotation.Nullable Object errorMessage) {
|
||||
if (arg == null) {
|
||||
throw new NullPointerException(String.valueOf(errorMessage));
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a {@link NullPointerException} if any of the list elements is null.
|
||||
*
|
||||
* @param list the argument list to check for null.
|
||||
* @param errorMessage the message to use for the exception. Will be converted to a string using
|
||||
* {@link String#valueOf(Object)}.
|
||||
*/
|
||||
public static <T /*>>> extends @NonNull Object*/> void checkListElementNotNull(
|
||||
List<T> list, @javax.annotation.Nullable Object errorMessage) {
|
||||
for (T element : list) {
|
||||
if (element == null) {
|
||||
throw new NullPointerException(String.valueOf(errorMessage));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two Objects for equality. This functionality is provided by {@code
|
||||
* Objects.equal(Object, Object)} in Java 7.
|
||||
*/
|
||||
public static boolean equalsObjects(
|
||||
@javax.annotation.Nullable Object x, @javax.annotation.Nullable Object y) {
|
||||
return x == null ? y == null : x.equals(y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes each {@code %s} in {@code template} with an argument. These are matched by
|
||||
* position: the first {@code %s} gets {@code args[0]}, etc. If there are more arguments than
|
||||
* placeholders, the unmatched arguments will be appended to the end of the formatted message in
|
||||
* square braces.
|
||||
*
|
||||
* <p>Copied from {@code Preconditions.format(String, Object...)} from Guava
|
||||
*
|
||||
* @param template a non-null string containing 0 or more {@code %s} placeholders.
|
||||
* @param args the arguments to be substituted into the message template. Arguments are converted
|
||||
* to strings using {@link String#valueOf(Object)}. Arguments can be null.
|
||||
*/
|
||||
// Note that this is somewhat-improperly used from Verify.java as well.
|
||||
private static String format(String template, @javax.annotation.Nullable Object... args) {
|
||||
// If no arguments return the template.
|
||||
if (args == null) {
|
||||
return template;
|
||||
}
|
||||
|
||||
// start substituting the arguments into the '%s' placeholders
|
||||
StringBuilder builder = new StringBuilder(template.length() + 16 * args.length);
|
||||
int templateStart = 0;
|
||||
int i = 0;
|
||||
while (i < args.length) {
|
||||
int placeholderStart = template.indexOf("%s", templateStart);
|
||||
if (placeholderStart == -1) {
|
||||
break;
|
||||
}
|
||||
builder.append(template, templateStart, placeholderStart);
|
||||
builder.append(args[i++]);
|
||||
templateStart = placeholderStart + 2;
|
||||
}
|
||||
builder.append(template, templateStart, template.length());
|
||||
|
||||
// if we run out of placeholders, append the extra args in square braces
|
||||
if (i < args.length) {
|
||||
builder.append(" [");
|
||||
builder.append(args[i++]);
|
||||
while (i < args.length) {
|
||||
builder.append(", ");
|
||||
builder.append(args[i++]);
|
||||
}
|
||||
builder.append(']');
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.internal;
|
||||
|
||||
import openconsensus.common.Clock;
|
||||
import openconsensus.common.Timestamp;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/** A {@link Clock} that always returns 0. */
|
||||
@Immutable
|
||||
public final class ZeroTimeClock extends Clock {
|
||||
private static final ZeroTimeClock INSTANCE = new ZeroTimeClock();
|
||||
private static final Timestamp ZERO_TIMESTAMP = Timestamp.create(0, 0);
|
||||
|
||||
private ZeroTimeClock() {}
|
||||
|
||||
/**
|
||||
* Returns a {@code ZeroTimeClock}.
|
||||
*
|
||||
* @return a {@code ZeroTimeClock}.
|
||||
*/
|
||||
public static ZeroTimeClock getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Timestamp now() {
|
||||
return ZERO_TIMESTAMP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long nowNanos() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Interfaces and implementations that are internal to OpenCensus.
|
||||
*
|
||||
* <p>All the content under this package and its subpackages are considered annotated with {@link
|
||||
* openconsensus.common.Internal}.
|
||||
*/
|
||||
@Internal
|
||||
package openconsensus.internal;
|
||||
|
||||
import openconsensus.common.Internal;
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.metrics;
|
||||
|
||||
import openconsensus.common.ToDoubleFunction;
|
||||
import openconsensus.internal.Utils;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
/*>>>
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
*/
|
||||
|
||||
/**
|
||||
* Derived Double Gauge metric, to report instantaneous measurement of a double value. Gauges can go
|
||||
* both up and down. The gauges values can be negative.
|
||||
*
|
||||
* <p>Example: Create a Gauge with an object and a callback function.
|
||||
*
|
||||
* <pre>{@code
|
||||
* class YourClass {
|
||||
*
|
||||
* private static final MetricRegistry metricRegistry = Metrics.getMetricRegistry();
|
||||
*
|
||||
* List<LabelKey> labelKeys = Arrays.asList(LabelKey.create("Name", "desc"));
|
||||
* List<LabelValue> labelValues = Arrays.asList(LabelValue.create("Inbound"));
|
||||
*
|
||||
* DerivedDoubleGauge gauge = metricRegistry.addDerivedDoubleGauge(
|
||||
* "queue_size", "Pending jobs in a queue", "1", labelKeys);
|
||||
*
|
||||
* QueueManager queueManager = new QueueManager();
|
||||
* gauge.createTimeSeries(labelValues, queueManager,
|
||||
* new ToDoubleFunction<QueueManager>() {
|
||||
* {@literal @}Override
|
||||
* public double applyAsDouble(QueueManager queue) {
|
||||
* return queue.size();
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* void doWork() {
|
||||
* // Your code here.
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ThreadSafe
|
||||
public abstract class DerivedDoubleGauge {
|
||||
/**
|
||||
* Creates a {@code TimeSeries}. The value of a single point in the TimeSeries is observed from a
|
||||
* callback function. This function is invoked whenever metrics are collected, meaning the
|
||||
* reported value is up-to-date. It keeps a {@link WeakReference} to the object and it is the
|
||||
* user's responsibility to manage the lifetime of the object.
|
||||
*
|
||||
* @param labelValues the list of label values.
|
||||
* @param obj the state object from which the function derives a measurement.
|
||||
* @param function the function to be called.
|
||||
* @param <T> the type of the object upon which the function derives a measurement.
|
||||
* @throws NullPointerException if {@code labelValues} is null OR any element of {@code
|
||||
* labelValues} is null OR {@code function} is null.
|
||||
* @throws IllegalArgumentException if different time series with the same labels already exists
|
||||
* OR if number of {@code labelValues}s are not equal to the label keys.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract <T> void createTimeSeries(
|
||||
List<LabelValue> labelValues,
|
||||
/*@Nullable*/ T obj,
|
||||
ToDoubleFunction</*@Nullable*/ T> function);
|
||||
|
||||
/**
|
||||
* Removes the {@code TimeSeries} from the gauge metric, if it is present.
|
||||
*
|
||||
* @param labelValues the list of label values.
|
||||
* @throws NullPointerException if {@code labelValues} is null.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract void removeTimeSeries(List<LabelValue> labelValues);
|
||||
|
||||
/**
|
||||
* Removes all {@code TimeSeries} from the gauge metric.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract void clear();
|
||||
|
||||
/**
|
||||
* Returns the no-op implementation of the {@code DerivedDoubleGauge}.
|
||||
*
|
||||
* @return the no-op implementation of the {@code DerivedDoubleGauge}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
static DerivedDoubleGauge newNoopDerivedDoubleGauge(
|
||||
String name, String description, String unit, List<LabelKey> labelKeys) {
|
||||
return NoopDerivedDoubleGauge.create(name, description, unit, labelKeys);
|
||||
}
|
||||
|
||||
/** No-op implementations of DerivedDoubleGauge class. */
|
||||
private static final class NoopDerivedDoubleGauge extends DerivedDoubleGauge {
|
||||
private final int labelKeysSize;
|
||||
|
||||
static NoopDerivedDoubleGauge create(
|
||||
String name, String description, String unit, List<LabelKey> labelKeys) {
|
||||
return new NoopDerivedDoubleGauge(name, description, unit, labelKeys);
|
||||
}
|
||||
|
||||
/** Creates a new {@code NoopDerivedDoubleGauge}. */
|
||||
NoopDerivedDoubleGauge(String name, String description, String unit, List<LabelKey> labelKeys) {
|
||||
Utils.checkNotNull(name, "name");
|
||||
Utils.checkNotNull(description, "description");
|
||||
Utils.checkNotNull(unit, "unit");
|
||||
Utils.checkListElementNotNull(Utils.checkNotNull(labelKeys, "labelKeys"), "labelKey");
|
||||
labelKeysSize = labelKeys.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void createTimeSeries(
|
||||
List<LabelValue> labelValues,
|
||||
/*@Nullable*/ T obj,
|
||||
ToDoubleFunction</*@Nullable*/ T> function) {
|
||||
Utils.checkListElementNotNull(Utils.checkNotNull(labelValues, "labelValues"), "labelValue");
|
||||
Utils.checkArgument(
|
||||
labelKeysSize == labelValues.size(), "Label Keys and Label Values don't have same size.");
|
||||
Utils.checkNotNull(function, "function");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTimeSeries(List<LabelValue> labelValues) {
|
||||
Utils.checkNotNull(labelValues, "labelValues");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.metrics;
|
||||
|
||||
import openconsensus.common.ToLongFunction;
|
||||
import openconsensus.internal.Utils;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
/*>>>
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
*/
|
||||
|
||||
/**
|
||||
* Derived Long Gauge metric, to report instantaneous measurement of an int64 value. Gauges can go
|
||||
* both up and down. The gauges values can be negative.
|
||||
*
|
||||
* <p>Example: Create a Gauge with an object and a callback function.
|
||||
*
|
||||
* <pre>{@code
|
||||
* class YourClass {
|
||||
*
|
||||
* private static final MetricRegistry metricRegistry = Metrics.getMetricRegistry();
|
||||
*
|
||||
* List<LabelKey> labelKeys = Arrays.asList(LabelKey.create("Name", "desc"));
|
||||
* List<LabelValue> labelValues = Arrays.asList(LabelValue.create("Inbound"));
|
||||
*
|
||||
* DerivedLongGauge gauge = metricRegistry.addDerivedLongGauge(
|
||||
* "queue_size", "Pending jobs in a queue", "1", labelKeys);
|
||||
*
|
||||
* QueueManager queueManager = new QueueManager();
|
||||
* gauge.createTimeSeries(labelValues, queueManager,
|
||||
* new ToLongFunction<QueueManager>() {
|
||||
* {@literal @}Override
|
||||
* public long applyAsLong(QueueManager queue) {
|
||||
* return queue.size();
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* void doWork() {
|
||||
* // Your code here.
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ThreadSafe
|
||||
public abstract class DerivedLongGauge {
|
||||
/**
|
||||
* Creates a {@code TimeSeries}. The value of a single point in the TimeSeries is observed from a
|
||||
* callback function. This function is invoked whenever metrics are collected, meaning the
|
||||
* reported value is up-to-date. It keeps a {@link WeakReference} to the object and it is the
|
||||
* user's responsibility to manage the lifetime of the object.
|
||||
*
|
||||
* @param labelValues the list of label values.
|
||||
* @param obj the state object from which the function derives a measurement.
|
||||
* @param function the function to be called.
|
||||
* @param <T> the type of the object upon which the function derives a measurement.
|
||||
* @throws NullPointerException if {@code labelValues} is null OR any element of {@code
|
||||
* labelValues} is null OR {@code function} is null.
|
||||
* @throws IllegalArgumentException if different time series with the same labels already exists
|
||||
* OR if number of {@code labelValues}s are not equal to the label keys.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract <T> void createTimeSeries(
|
||||
List<LabelValue> labelValues, /*@Nullable*/ T obj, ToLongFunction</*@Nullable*/ T> function);
|
||||
|
||||
/**
|
||||
* Removes the {@code TimeSeries} from the gauge metric, if it is present.
|
||||
*
|
||||
* @param labelValues the list of label values.
|
||||
* @throws NullPointerException if {@code labelValues} is null.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract void removeTimeSeries(List<LabelValue> labelValues);
|
||||
|
||||
/**
|
||||
* Removes all {@code TimeSeries} from the gauge metric.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract void clear();
|
||||
|
||||
/**
|
||||
* Returns the no-op implementation of the {@code DerivedLongGauge}.
|
||||
*
|
||||
* @return the no-op implementation of the {@code DerivedLongGauge}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
static DerivedLongGauge newNoopDerivedLongGauge(
|
||||
String name, String description, String unit, List<LabelKey> labelKeys) {
|
||||
return NoopDerivedLongGauge.create(name, description, unit, labelKeys);
|
||||
}
|
||||
|
||||
/** No-op implementations of DerivedLongGauge class. */
|
||||
private static final class NoopDerivedLongGauge extends DerivedLongGauge {
|
||||
private final int labelKeysSize;
|
||||
|
||||
static NoopDerivedLongGauge create(
|
||||
String name, String description, String unit, List<LabelKey> labelKeys) {
|
||||
return new NoopDerivedLongGauge(name, description, unit, labelKeys);
|
||||
}
|
||||
|
||||
/** Creates a new {@code NoopDerivedLongGauge}. */
|
||||
NoopDerivedLongGauge(String name, String description, String unit, List<LabelKey> labelKeys) {
|
||||
Utils.checkNotNull(name, "name");
|
||||
Utils.checkNotNull(description, "description");
|
||||
Utils.checkNotNull(unit, "unit");
|
||||
Utils.checkListElementNotNull(Utils.checkNotNull(labelKeys, "labelKeys"), "labelKey");
|
||||
labelKeysSize = labelKeys.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void createTimeSeries(
|
||||
List<LabelValue> labelValues,
|
||||
/*@Nullable*/ T obj,
|
||||
ToLongFunction</*@Nullable*/ T> function) {
|
||||
Utils.checkListElementNotNull(Utils.checkNotNull(labelValues, "labelValues"), "labelValue");
|
||||
Utils.checkArgument(
|
||||
labelKeysSize == labelValues.size(), "Label Keys and Label Values don't have same size.");
|
||||
Utils.checkNotNull(function, "function");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTimeSeries(List<LabelValue> labelValues) {
|
||||
Utils.checkNotNull(labelValues, "labelValues");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.metrics;
|
||||
|
||||
import openconsensus.internal.Utils;
|
||||
import java.util.List;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
/**
|
||||
* Double Gauge metric, to report instantaneous measurement of a double value. Gauges can go both up
|
||||
* and down. The gauges values can be negative.
|
||||
*
|
||||
* <p>Example 1: Create a Gauge with default labels.
|
||||
*
|
||||
* <pre>{@code
|
||||
* class YourClass {
|
||||
*
|
||||
* private static final MetricRegistry metricRegistry = Metrics.getMetricRegistry();
|
||||
*
|
||||
* List<LabelKey> labelKeys = Arrays.asList(LabelKey.create("Name", "desc"));
|
||||
*
|
||||
* DoubleGauge gauge = metricRegistry.addDoubleGauge("queue_size",
|
||||
* "Pending jobs", "1", labelKeys);
|
||||
*
|
||||
* // It is recommended to keep a reference of a point for manual operations.
|
||||
* DoublePoint defaultPoint = gauge.getDefaultTimeSeries();
|
||||
*
|
||||
* void doWork() {
|
||||
* // Your code here.
|
||||
* defaultPoint.add(10);
|
||||
* }
|
||||
*
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p>Example 2: You can also use labels(keys and values) to track different types of metric.
|
||||
*
|
||||
* <pre>{@code
|
||||
* class YourClass {
|
||||
*
|
||||
* private static final MetricRegistry metricRegistry = Metrics.getMetricRegistry();
|
||||
*
|
||||
* List<LabelKey> labelKeys = Arrays.asList(LabelKey.create("Name", "desc"));
|
||||
* List<LabelValue> labelValues = Arrays.asList(LabelValue.create("Inbound"));
|
||||
*
|
||||
* DoubleGauge gauge = metricRegistry.addDoubleGauge("queue_size",
|
||||
* "Pending jobs", "1", labelKeys);
|
||||
*
|
||||
* // It is recommended to keep a reference of a point for manual operations.
|
||||
* DoublePoint inboundPoint = gauge.getOrCreateTimeSeries(labelValues);
|
||||
*
|
||||
* void doSomeWork() {
|
||||
* // Your code here.
|
||||
* inboundPoint.set(15);
|
||||
* }
|
||||
*
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ThreadSafe
|
||||
public abstract class DoubleGauge {
|
||||
|
||||
/**
|
||||
* Creates a {@code TimeSeries} and returns a {@code DoublePoint} if the specified {@code
|
||||
* labelValues} is not already associated with this gauge, else returns an existing {@code
|
||||
* DoublePoint}.
|
||||
*
|
||||
* <p>It is recommended to keep a reference to the DoublePoint instead of always calling this
|
||||
* method for manual operations.
|
||||
*
|
||||
* @param labelValues the list of label values. The number of label values must be the same to
|
||||
* that of the label keys passed to {@link MetricRegistry#addDoubleGauge}.
|
||||
* @return a {@code DoublePoint} the value of single gauge.
|
||||
* @throws NullPointerException if {@code labelValues} is null OR any element of {@code
|
||||
* labelValues} is null.
|
||||
* @throws IllegalArgumentException if number of {@code labelValues}s are not equal to the label
|
||||
* keys.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract DoublePoint getOrCreateTimeSeries(List<LabelValue> labelValues);
|
||||
|
||||
/**
|
||||
* Returns a {@code DoublePoint} for a gauge with all labels not set, or default labels.
|
||||
*
|
||||
* @return a {@code DoublePoint} for a gauge with all labels not set, or default labels.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract DoublePoint getDefaultTimeSeries();
|
||||
|
||||
/**
|
||||
* Removes the {@code TimeSeries} from the gauge metric, if it is present. i.e. references to
|
||||
* previous {@code DoublePoint} objects are invalid (not part of the metric).
|
||||
*
|
||||
* @param labelValues the list of label values.
|
||||
* @throws NullPointerException if {@code labelValues} is null or any element of {@code
|
||||
* labelValues} is null.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract void removeTimeSeries(List<LabelValue> labelValues);
|
||||
|
||||
/**
|
||||
* Removes all {@code TimeSeries} from the gauge metric. i.e. references to all previous {@code
|
||||
* DoublePoint} objects are invalid (not part of the metric).
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract void clear();
|
||||
|
||||
/**
|
||||
* Returns the no-op implementation of the {@code DoubleGauge}.
|
||||
*
|
||||
* @return the no-op implementation of the {@code DoubleGauge}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
static DoubleGauge newNoopDoubleGauge(
|
||||
String name, String description, String unit, List<LabelKey> labelKeys) {
|
||||
return NoopDoubleGauge.create(name, description, unit, labelKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of a single point in the Gauge.TimeSeries.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract static class DoublePoint {
|
||||
|
||||
/**
|
||||
* Adds the given value to the current value. The values can be negative.
|
||||
*
|
||||
* @param amt the value to add
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract void add(double amt);
|
||||
|
||||
/**
|
||||
* Sets the given value.
|
||||
*
|
||||
* @param val the new value.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract void set(double val);
|
||||
}
|
||||
|
||||
/** No-op implementations of DoubleGauge class. */
|
||||
private static final class NoopDoubleGauge extends DoubleGauge {
|
||||
private final int labelKeysSize;
|
||||
|
||||
static NoopDoubleGauge create(
|
||||
String name, String description, String unit, List<LabelKey> labelKeys) {
|
||||
return new NoopDoubleGauge(name, description, unit, labelKeys);
|
||||
}
|
||||
|
||||
/** Creates a new {@code NoopDoublePoint}. */
|
||||
NoopDoubleGauge(String name, String description, String unit, List<LabelKey> labelKeys) {
|
||||
Utils.checkNotNull(name, "name");
|
||||
Utils.checkNotNull(description, "description");
|
||||
Utils.checkNotNull(unit, "unit");
|
||||
Utils.checkListElementNotNull(Utils.checkNotNull(labelKeys, "labelKeys"), "labelKey");
|
||||
labelKeysSize = labelKeys.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NoopDoublePoint getOrCreateTimeSeries(List<LabelValue> labelValues) {
|
||||
Utils.checkListElementNotNull(Utils.checkNotNull(labelValues, "labelValues"), "labelValue");
|
||||
Utils.checkArgument(
|
||||
labelKeysSize == labelValues.size(), "Label Keys and Label Values don't have same size.");
|
||||
return NoopDoublePoint.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NoopDoublePoint getDefaultTimeSeries() {
|
||||
return NoopDoublePoint.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTimeSeries(List<LabelValue> labelValues) {
|
||||
Utils.checkNotNull(labelValues, "labelValues");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {}
|
||||
|
||||
/** No-op implementations of DoublePoint class. */
|
||||
private static final class NoopDoublePoint extends DoublePoint {
|
||||
private static final NoopDoublePoint INSTANCE = new NoopDoublePoint();
|
||||
|
||||
private NoopDoublePoint() {}
|
||||
|
||||
@Override
|
||||
public void add(double amt) {}
|
||||
|
||||
@Override
|
||||
public void set(double val) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.metrics;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.common.ExperimentalApi;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* The key of a {@code Label} associated with a {@code MetricDescriptor}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract class LabelKey {
|
||||
|
||||
LabelKey() {}
|
||||
|
||||
/**
|
||||
* Creates a {@link LabelKey}.
|
||||
*
|
||||
* @param key the key of a {@code Label}.
|
||||
* @param description a human-readable description of what this label key represents.
|
||||
* @return a {@code LabelKey}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static LabelKey create(String key, String description) {
|
||||
return new AutoValue_LabelKey(key, description);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key of this {@link LabelKey}.
|
||||
*
|
||||
* @return the key.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract String getKey();
|
||||
|
||||
/**
|
||||
* Returns the description of this {@link LabelKey}.
|
||||
*
|
||||
* @return the description.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract String getDescription();
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.metrics;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.common.ExperimentalApi;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* The value of a {@code Label} associated with a {@code TimeSeries}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract class LabelValue {
|
||||
|
||||
LabelValue() {}
|
||||
|
||||
/**
|
||||
* Creates a {@link LabelValue}.
|
||||
*
|
||||
* @param value the value of a {@code Label}. {@code null} value indicates an unset {@code
|
||||
* LabelValue}.
|
||||
* @return a {@code LabelValue}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static LabelValue create(@Nullable String value) {
|
||||
return new AutoValue_LabelValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this {@link LabelValue}. Returns {@code null} if the value is unset and
|
||||
* supposed to be ignored.
|
||||
*
|
||||
* @return the value.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Nullable
|
||||
public abstract String getValue();
|
||||
}
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.metrics;
|
||||
|
||||
import openconsensus.internal.Utils;
|
||||
import java.util.List;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
/**
|
||||
* Long Gauge metric, to report instantaneous measurement of an int64 value. Gauges can go both up
|
||||
* and down. The gauges values can be negative.
|
||||
*
|
||||
* <p>Example 1: Create a Gauge with default labels.
|
||||
*
|
||||
* <pre>{@code
|
||||
* class YourClass {
|
||||
*
|
||||
* private static final MetricRegistry metricRegistry = Metrics.getMetricRegistry();
|
||||
*
|
||||
* List<LabelKey> labelKeys = Arrays.asList(LabelKey.create("Name", "desc"));
|
||||
*
|
||||
* LongGauge gauge = metricRegistry.addLongGauge("queue_size", "Pending jobs", "1", labelKeys);
|
||||
*
|
||||
* // It is recommended to keep a reference of a point for manual operations.
|
||||
* LongPoint defaultPoint = gauge.getDefaultTimeSeries();
|
||||
*
|
||||
* void doWork() {
|
||||
* // Your code here.
|
||||
* defaultPoint.add(10);
|
||||
* }
|
||||
*
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p>Example 2: You can also use labels(keys and values) to track different types of metric.
|
||||
*
|
||||
* <pre>{@code
|
||||
* class YourClass {
|
||||
*
|
||||
* private static final MetricRegistry metricRegistry = Metrics.getMetricRegistry();
|
||||
*
|
||||
* List<LabelKey> labelKeys = Arrays.asList(LabelKey.create("Name", "desc"));
|
||||
* List<LabelValue> labelValues = Arrays.asList(LabelValue.create("Inbound"));
|
||||
*
|
||||
* LongGauge gauge = metricRegistry.addLongGauge("queue_size", "Pending jobs", "1", labelKeys);
|
||||
*
|
||||
* // It is recommended to keep a reference of a point for manual operations.
|
||||
* LongPoint inboundPoint = gauge.getOrCreateTimeSeries(labelValues);
|
||||
*
|
||||
* void doSomeWork() {
|
||||
* // Your code here.
|
||||
* inboundPoint.set(15);
|
||||
* }
|
||||
*
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ThreadSafe
|
||||
public abstract class LongGauge {
|
||||
|
||||
/**
|
||||
* Creates a {@code TimeSeries} and returns a {@code LongPoint} if the specified {@code
|
||||
* labelValues} is not already associated with this gauge, else returns an existing {@code
|
||||
* LongPoint}.
|
||||
*
|
||||
* <p>It is recommended to keep a reference to the LongPoint instead of always calling this method
|
||||
* for manual operations.
|
||||
*
|
||||
* @param labelValues the list of label values. The number of label values must be the same to
|
||||
* that of the label keys passed to {@link MetricRegistry#addLongGauge}.
|
||||
* @return a {@code LongPoint} the value of single gauge.
|
||||
* @throws NullPointerException if {@code labelValues} is null OR any element of {@code
|
||||
* labelValues} is null.
|
||||
* @throws IllegalArgumentException if number of {@code labelValues}s are not equal to the label
|
||||
* keys passed to {@link MetricRegistry#addLongGauge}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract LongPoint getOrCreateTimeSeries(List<LabelValue> labelValues);
|
||||
|
||||
/**
|
||||
* Returns a {@code LongPoint} for a gauge with all labels not set, or default labels.
|
||||
*
|
||||
* @return a {@code LongPoint} for a gauge with all labels not set, or default labels.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract LongPoint getDefaultTimeSeries();
|
||||
|
||||
/**
|
||||
* Removes the {@code TimeSeries} from the gauge metric, if it is present. i.e. references to
|
||||
* previous {@code LongPoint} objects are invalid (not part of the metric).
|
||||
*
|
||||
* @param labelValues the list of label values.
|
||||
* @throws NullPointerException if {@code labelValues} is null.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract void removeTimeSeries(List<LabelValue> labelValues);
|
||||
|
||||
/**
|
||||
* Removes all {@code TimeSeries} from the gauge metric. i.e. references to all previous {@code
|
||||
* LongPoint} objects are invalid (not part of the metric).
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract void clear();
|
||||
|
||||
/**
|
||||
* Returns the no-op implementation of the {@code LongGauge}.
|
||||
*
|
||||
* @return the no-op implementation of the {@code LongGauge}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
static LongGauge newNoopLongGauge(
|
||||
String name, String description, String unit, List<LabelKey> labelKeys) {
|
||||
return NoopLongGauge.create(name, description, unit, labelKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of a single point in the Gauge.TimeSeries.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract static class LongPoint {
|
||||
|
||||
/**
|
||||
* Adds the given value to the current value. The values can be negative.
|
||||
*
|
||||
* @param amt the value to add
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract void add(long amt);
|
||||
|
||||
/**
|
||||
* Sets the given value.
|
||||
*
|
||||
* @param val the new value.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract void set(long val);
|
||||
}
|
||||
|
||||
/** No-op implementations of LongGauge class. */
|
||||
private static final class NoopLongGauge extends LongGauge {
|
||||
private final int labelKeysSize;
|
||||
|
||||
static NoopLongGauge create(
|
||||
String name, String description, String unit, List<LabelKey> labelKeys) {
|
||||
return new NoopLongGauge(name, description, unit, labelKeys);
|
||||
}
|
||||
|
||||
/** Creates a new {@code NoopLongPoint}. */
|
||||
NoopLongGauge(String name, String description, String unit, List<LabelKey> labelKeys) {
|
||||
labelKeysSize = labelKeys.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NoopLongPoint getOrCreateTimeSeries(List<LabelValue> labelValues) {
|
||||
Utils.checkListElementNotNull(Utils.checkNotNull(labelValues, "labelValues"), "labelValue");
|
||||
Utils.checkArgument(
|
||||
labelKeysSize == labelValues.size(), "Label Keys and Label Values don't have same size.");
|
||||
return NoopLongPoint.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NoopLongPoint getDefaultTimeSeries() {
|
||||
return NoopLongPoint.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTimeSeries(List<LabelValue> labelValues) {
|
||||
Utils.checkNotNull(labelValues, "labelValues");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {}
|
||||
|
||||
/** No-op implementations of LongPoint class. */
|
||||
private static final class NoopLongPoint extends LongPoint {
|
||||
private static final NoopLongPoint INSTANCE = new NoopLongPoint();
|
||||
|
||||
private NoopLongPoint() {}
|
||||
|
||||
@Override
|
||||
public void add(long amt) {}
|
||||
|
||||
@Override
|
||||
public void set(long val) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.metrics;
|
||||
|
||||
import openconsensus.common.ExperimentalApi;
|
||||
import openconsensus.common.ToDoubleFunction;
|
||||
import openconsensus.common.ToLongFunction;
|
||||
import openconsensus.internal.Utils;
|
||||
import java.util.List;
|
||||
import openconsensus.metrics.export.MetricProducer;
|
||||
import openconsensus.metrics.export.MetricProducerManager;
|
||||
|
||||
/**
|
||||
* Creates and manages your application's set of metrics. The default implementation of this creates
|
||||
* a {@link MetricProducer} and registers it to the global {@link
|
||||
* MetricProducerManager}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
public abstract class MetricRegistry {
|
||||
/**
|
||||
* Builds a new long gauge to be added to the registry. This is more convenient form when you want
|
||||
* to manually increase and decrease values as per your service requirements.
|
||||
*
|
||||
* @param name the name of the metric.
|
||||
* @param description the description of the metric.
|
||||
* @param unit the unit of the metric.
|
||||
* @param labelKeys the list of the label keys.
|
||||
* @return a {@code LongGauge}.
|
||||
* @throws NullPointerException if {@code labelKeys} is null OR any element of {@code labelKeys}
|
||||
* is null OR {@code name}, {@code description}, {@code unit} is null.
|
||||
* @throws IllegalArgumentException if different metric with the same name already registered.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
public abstract LongGauge addLongGauge(
|
||||
String name, String description, String unit, List<LabelKey> labelKeys);
|
||||
|
||||
/**
|
||||
* Builds a new double gauge to be added to the registry. This is more convenient form when you
|
||||
* want to manually increase and decrease values as per your service requirements.
|
||||
*
|
||||
* @param name the name of the metric.
|
||||
* @param description the description of the metric.
|
||||
* @param unit the unit of the metric.
|
||||
* @param labelKeys the list of the label keys.
|
||||
* @return a {@code DoubleGauge}.
|
||||
* @throws NullPointerException if {@code labelKeys} is null OR any element of {@code labelKeys}
|
||||
* is null OR {@code name}, {@code description}, {@code unit} is null.
|
||||
* @throws IllegalArgumentException if different metric with the same name already registered.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
public abstract DoubleGauge addDoubleGauge(
|
||||
String name, String description, String unit, List<LabelKey> labelKeys);
|
||||
|
||||
/**
|
||||
* Builds a new derived long gauge to be added to the registry. This is more convenient form when
|
||||
* you want to define a gauge by executing a {@link ToLongFunction} on an object.
|
||||
*
|
||||
* @param name the name of the metric.
|
||||
* @param description the description of the metric.
|
||||
* @param unit the unit of the metric.
|
||||
* @param labelKeys the list of the label keys.
|
||||
* @return a {@code DerivedLongGauge}.
|
||||
* @throws NullPointerException if {@code labelKeys} is null OR any element of {@code labelKeys}
|
||||
* is null OR {@code name}, {@code description}, {@code unit} is null.
|
||||
* @throws IllegalArgumentException if different metric with the same name already registered.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
public abstract DerivedLongGauge addDerivedLongGauge(
|
||||
String name, String description, String unit, List<LabelKey> labelKeys);
|
||||
|
||||
/**
|
||||
* Builds a new derived double gauge to be added to the registry. This is more convenient form
|
||||
* when you want to define a gauge by executing a {@link ToDoubleFunction} on an object.
|
||||
*
|
||||
* @param name the name of the metric.
|
||||
* @param description the description of the metric.
|
||||
* @param unit the unit of the metric.
|
||||
* @param labelKeys the list of the label keys.
|
||||
* @return a {@code DerivedDoubleGauge}.
|
||||
* @throws NullPointerException if {@code labelKeys} is null OR any element of {@code labelKeys}
|
||||
* is null OR {@code name}, {@code description}, {@code unit} is null.
|
||||
* @throws IllegalArgumentException if different metric with the same name already registered.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
public abstract DerivedDoubleGauge addDerivedDoubleGauge(
|
||||
String name, String description, String unit, List<LabelKey> labelKeys);
|
||||
|
||||
static MetricRegistry newNoopMetricRegistry() {
|
||||
return new NoopMetricRegistry();
|
||||
}
|
||||
|
||||
private static final class NoopMetricRegistry extends MetricRegistry {
|
||||
|
||||
@Override
|
||||
public LongGauge addLongGauge(
|
||||
String name, String description, String unit, List<LabelKey> labelKeys) {
|
||||
Utils.checkListElementNotNull(Utils.checkNotNull(labelKeys, "labelKeys"), "labelKey");
|
||||
return LongGauge.newNoopLongGauge(
|
||||
Utils.checkNotNull(name, "name"),
|
||||
Utils.checkNotNull(description, "description"),
|
||||
Utils.checkNotNull(unit, "unit"),
|
||||
labelKeys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DoubleGauge addDoubleGauge(
|
||||
String name, String description, String unit, List<LabelKey> labelKeys) {
|
||||
Utils.checkListElementNotNull(Utils.checkNotNull(labelKeys, "labelKeys"), "labelKey");
|
||||
return DoubleGauge.newNoopDoubleGauge(
|
||||
Utils.checkNotNull(name, "name"),
|
||||
Utils.checkNotNull(description, "description"),
|
||||
Utils.checkNotNull(unit, "unit"),
|
||||
labelKeys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DerivedLongGauge addDerivedLongGauge(
|
||||
String name, String description, String unit, List<LabelKey> labelKeys) {
|
||||
Utils.checkListElementNotNull(Utils.checkNotNull(labelKeys, "labelKeys"), "labelKey");
|
||||
return DerivedLongGauge.newNoopDerivedLongGauge(
|
||||
Utils.checkNotNull(name, "name"),
|
||||
Utils.checkNotNull(description, "description"),
|
||||
Utils.checkNotNull(unit, "unit"),
|
||||
labelKeys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DerivedDoubleGauge addDerivedDoubleGauge(
|
||||
String name, String description, String unit, List<LabelKey> labelKeys) {
|
||||
Utils.checkListElementNotNull(Utils.checkNotNull(labelKeys, "labelKeys"), "labelKey");
|
||||
return DerivedDoubleGauge.newNoopDerivedDoubleGauge(
|
||||
Utils.checkNotNull(name, "name"),
|
||||
Utils.checkNotNull(description, "description"),
|
||||
Utils.checkNotNull(unit, "unit"),
|
||||
labelKeys);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.metrics;
|
||||
|
||||
import openconsensus.common.ExperimentalApi;
|
||||
import openconsensus.internal.DefaultVisibilityForTesting;
|
||||
import openconsensus.internal.Provider;
|
||||
import openconsensus.metrics.export.ExportComponent;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.annotation.Nullable;
|
||||
import openconsensus.metrics.export.MetricProducerManager;
|
||||
|
||||
/**
|
||||
* Class for accessing the default {@link MetricsComponent}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
public final class Metrics {
|
||||
private static final Logger logger = Logger.getLogger(Metrics.class.getName());
|
||||
private static final MetricsComponent metricsComponent =
|
||||
loadMetricsComponent(MetricsComponent.class.getClassLoader());
|
||||
|
||||
/**
|
||||
* Returns the global {@link ExportComponent}.
|
||||
*
|
||||
* @return the global {@code ExportComponent}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static ExportComponent getExportComponent() {
|
||||
return metricsComponent.getExportComponent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the global {@link MetricRegistry}.
|
||||
*
|
||||
* <p>This {@code MetricRegistry} is already added to the global {@link
|
||||
* MetricProducerManager}.
|
||||
*
|
||||
* @return the global {@code MetricRegistry}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static MetricRegistry getMetricRegistry() {
|
||||
return metricsComponent.getMetricRegistry();
|
||||
}
|
||||
|
||||
// Any provider that may be used for MetricsComponent can be added here.
|
||||
@DefaultVisibilityForTesting
|
||||
static MetricsComponent loadMetricsComponent(@Nullable ClassLoader classLoader) {
|
||||
try {
|
||||
// Call Class.forName with literal string name of the class to help shading tools.
|
||||
return Provider.createInstance(
|
||||
Class.forName(
|
||||
"io.opencensus.impl.metrics.MetricsComponentImpl", /*initialize=*/ true, classLoader),
|
||||
MetricsComponent.class);
|
||||
} catch (ClassNotFoundException e) {
|
||||
logger.log(
|
||||
Level.FINE,
|
||||
"Couldn't load full implementation for MetricsComponent, now trying to load lite "
|
||||
+ "implementation.",
|
||||
e);
|
||||
}
|
||||
try {
|
||||
// Call Class.forName with literal string name of the class to help shading tools.
|
||||
return Provider.createInstance(
|
||||
Class.forName(
|
||||
"io.opencensus.impllite.metrics.MetricsComponentImplLite",
|
||||
/*initialize=*/ true,
|
||||
classLoader),
|
||||
MetricsComponent.class);
|
||||
} catch (ClassNotFoundException e) {
|
||||
logger.log(
|
||||
Level.FINE,
|
||||
"Couldn't load lite implementation for MetricsComponent, now using default "
|
||||
+ "implementation for MetricsComponent.",
|
||||
e);
|
||||
}
|
||||
return MetricsComponent.newNoopMetricsComponent();
|
||||
}
|
||||
|
||||
private Metrics() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.metrics;
|
||||
|
||||
import openconsensus.common.ExperimentalApi;
|
||||
import openconsensus.metrics.export.ExportComponent;
|
||||
|
||||
/**
|
||||
* Class that holds the implementation instance for {@link ExportComponent}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
public abstract class MetricsComponent {
|
||||
|
||||
/**
|
||||
* Returns the {@link ExportComponent} with the provided implementation. If no implementation is
|
||||
* provided then no-op implementations will be used.
|
||||
*
|
||||
* @return the {@link ExportComponent} implementation.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract ExportComponent getExportComponent();
|
||||
|
||||
/**
|
||||
* Returns the {@link MetricRegistry} with the provided implementation.
|
||||
*
|
||||
* @return the {@link MetricRegistry} implementation.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract MetricRegistry getMetricRegistry();
|
||||
|
||||
/**
|
||||
* Returns an instance that contains no-op implementations for all the instances.
|
||||
*
|
||||
* @return an instance that contains no-op implementations for all the instances.
|
||||
*/
|
||||
static MetricsComponent newNoopMetricsComponent() {
|
||||
return new NoopMetricsComponent();
|
||||
}
|
||||
|
||||
private static final class NoopMetricsComponent extends MetricsComponent {
|
||||
private static final ExportComponent EXPORT_COMPONENT =
|
||||
ExportComponent.newNoopExportComponent();
|
||||
private static final MetricRegistry METRIC_REGISTRY = MetricRegistry.newNoopMetricRegistry();
|
||||
|
||||
@Override
|
||||
public ExportComponent getExportComponent() {
|
||||
return EXPORT_COMPONENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetricRegistry getMetricRegistry() {
|
||||
return METRIC_REGISTRY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.metrics.data;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* The value of {@link Exemplar} attachment.
|
||||
*
|
||||
* <p>In Stats API we only provide one subclass {@link AttachmentValueString}. No other subclasses
|
||||
* are added because we don't want to introduce dependencies on other libraries, for example Tracing
|
||||
* APIs.
|
||||
*
|
||||
* <p>Other packages are free to extend this class to hold specific information. As an example, see
|
||||
* {@code io.opencensus.contrib.exemplar.util.AttachmentValueSpanContext}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract class AttachmentValue {
|
||||
|
||||
/**
|
||||
* Returns the string attachment value.
|
||||
*
|
||||
* @return the string attachment value.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract String getValue();
|
||||
|
||||
/**
|
||||
* String {@link AttachmentValue}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@AutoValue
|
||||
@Immutable
|
||||
public abstract static class AttachmentValueString extends AttachmentValue {
|
||||
|
||||
AttachmentValueString() {}
|
||||
|
||||
/**
|
||||
* Creates an {@link AttachmentValueString}.
|
||||
*
|
||||
* @param value the string value.
|
||||
* @return an {@code AttachmentValueString}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static AttachmentValueString create(String value) {
|
||||
return new AutoValue_AttachmentValue_AttachmentValueString(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.metrics.data;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.common.Timestamp;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/*>>>
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
*/
|
||||
|
||||
/**
|
||||
* An example point that may be used to annotate aggregated distribution values, associated with a
|
||||
* histogram bucket.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract class Exemplar {
|
||||
|
||||
Exemplar() {}
|
||||
|
||||
/**
|
||||
* Returns value of the {@link Exemplar} point.
|
||||
*
|
||||
* @return value of the {@code Exemplar} point.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract double getValue();
|
||||
|
||||
/**
|
||||
* Returns the time that this {@link Exemplar}'s value was recorded.
|
||||
*
|
||||
* @return the time that this {@code Exemplar}'s value was recorded.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Timestamp getTimestamp();
|
||||
|
||||
/**
|
||||
* Returns the contextual information about the example value.
|
||||
*
|
||||
* @return the contextual information about the example value.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Map<String, AttachmentValue> getAttachments();
|
||||
|
||||
/**
|
||||
* Creates an {@link Exemplar}.
|
||||
*
|
||||
* @param value value of the {@link Exemplar} point.
|
||||
* @param timestamp the time that this {@code Exemplar}'s value was recorded.
|
||||
* @param attachments the contextual information about the example value.
|
||||
* @return an {@code Exemplar}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Exemplar create(
|
||||
double value, Timestamp timestamp, Map<String, AttachmentValue> attachments) {
|
||||
checkNotNull(attachments, "attachments");
|
||||
Map<String, AttachmentValue> attachmentsCopy =
|
||||
Collections.unmodifiableMap(new HashMap<String, AttachmentValue>(attachments));
|
||||
for (Entry<String, AttachmentValue> entry : attachmentsCopy.entrySet()) {
|
||||
checkNotNull(entry.getKey(), "key of attachments");
|
||||
checkNotNull(entry.getValue(), "value of attachments");
|
||||
}
|
||||
return new AutoValue_Exemplar(value, timestamp, attachmentsCopy);
|
||||
}
|
||||
|
||||
// TODO(songy23): shade the internal Utils jar and remove this duplicated method.
|
||||
private static <T /*>>> extends @NonNull Object*/> T checkNotNull(
|
||||
T arg, @javax.annotation.Nullable Object errorMessage) {
|
||||
if (arg == null) {
|
||||
throw new NullPointerException(String.valueOf(errorMessage));
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This package describes common data models in Metrics that are shared across multiple packages.
|
||||
*
|
||||
* <p>WARNING: Currently all the public classes under this package are marked as {@link
|
||||
* openconsensus.common.ExperimentalApi}. The classes and APIs under {@link io.opencensus.metrics}
|
||||
* are likely to get backwards-incompatible updates in the future. DO NOT USE except for
|
||||
* experimental purposes.
|
||||
*/
|
||||
@ExperimentalApi
|
||||
package openconsensus.metrics.data;
|
||||
|
||||
import openconsensus.common.ExperimentalApi;
|
||||
|
|
@ -0,0 +1,285 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.metrics.export;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.common.ExperimentalApi;
|
||||
import openconsensus.common.Function;
|
||||
import openconsensus.internal.Utils;
|
||||
import openconsensus.metrics.data.Exemplar;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import openconsensus.common.Functions;
|
||||
|
||||
/**
|
||||
* {@link Distribution} contains summary statistics for a population of values. It optionally
|
||||
* contains a histogram representing the distribution of those values across a set of buckets.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
@AutoValue
|
||||
@Immutable
|
||||
public abstract class Distribution {
|
||||
|
||||
Distribution() {}
|
||||
|
||||
/**
|
||||
* Creates a {@link Distribution}.
|
||||
*
|
||||
* @param count the count of the population values.
|
||||
* @param sum the sum of the population values.
|
||||
* @param sumOfSquaredDeviations the sum of squared deviations of the population values.
|
||||
* @param bucketOptions the bucket options used to create a histogram for the distribution.
|
||||
* @param buckets {@link Bucket}s of a histogram.
|
||||
* @return a {@code Distribution}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Distribution create(
|
||||
long count,
|
||||
double sum,
|
||||
double sumOfSquaredDeviations,
|
||||
BucketOptions bucketOptions,
|
||||
List<Bucket> buckets) {
|
||||
Utils.checkArgument(count >= 0, "count should be non-negative.");
|
||||
Utils.checkArgument(
|
||||
sumOfSquaredDeviations >= 0, "sum of squared deviations should be non-negative.");
|
||||
if (count == 0) {
|
||||
Utils.checkArgument(sum == 0, "sum should be 0 if count is 0.");
|
||||
Utils.checkArgument(
|
||||
sumOfSquaredDeviations == 0, "sum of squared deviations should be 0 if count is 0.");
|
||||
}
|
||||
Utils.checkNotNull(bucketOptions, "bucketOptions");
|
||||
List<Bucket> bucketsCopy =
|
||||
Collections.unmodifiableList(new ArrayList<Bucket>(Utils.checkNotNull(buckets, "buckets")));
|
||||
Utils.checkListElementNotNull(bucketsCopy, "bucket");
|
||||
return new AutoValue_Distribution(
|
||||
count, sum, sumOfSquaredDeviations, bucketOptions, bucketsCopy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the aggregated count.
|
||||
*
|
||||
* @return the aggregated count.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract long getCount();
|
||||
|
||||
/**
|
||||
* Returns the aggregated sum.
|
||||
*
|
||||
* @return the aggregated sum.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract double getSum();
|
||||
|
||||
/**
|
||||
* Returns the aggregated sum of squared deviations.
|
||||
*
|
||||
* <p>The sum of squared deviations from the mean of the values in the population. For values x_i
|
||||
* this is:
|
||||
*
|
||||
* <p>Sum[i=1..n]((x_i - mean)^2)
|
||||
*
|
||||
* <p>If count is zero then this field must be zero.
|
||||
*
|
||||
* @return the aggregated sum of squared deviations.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract double getSumOfSquaredDeviations();
|
||||
|
||||
/**
|
||||
* Returns bucket options used to create a histogram for the distribution.
|
||||
*
|
||||
* @return the {@code BucketOptions} associated with the {@code Distribution}, or {@code null} if
|
||||
* there isn't one.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Nullable
|
||||
public abstract BucketOptions getBucketOptions();
|
||||
|
||||
/**
|
||||
* Returns the aggregated histogram {@link Bucket}s.
|
||||
*
|
||||
* @return the aggregated histogram buckets.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract List<Bucket> getBuckets();
|
||||
|
||||
/**
|
||||
* The bucket options used to create a histogram for the distribution.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
public abstract static class BucketOptions {
|
||||
|
||||
private BucketOptions() {}
|
||||
|
||||
/**
|
||||
* Returns a {@link ExplicitOptions}.
|
||||
*
|
||||
* <p>The bucket boundaries for that histogram are described by bucket_bounds. This defines
|
||||
* size(bucket_bounds) + 1 (= N) buckets. The boundaries for bucket index i are:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@code [0, bucket_bounds[i]) for i == 0}
|
||||
* <li>{@code [bucket_bounds[i-1], bucket_bounds[i]) for 0 < i < N-1}
|
||||
* <li>{@code [bucket_bounds[i-1], +infinity) for i == N-1}
|
||||
* </ul>
|
||||
*
|
||||
* <p>If bucket_bounds has no elements (zero size), then there is no histogram associated with
|
||||
* the Distribution. If bucket_bounds has only one element, there are no finite buckets, and
|
||||
* that single element is the common boundary of the overflow and underflow buckets. The values
|
||||
* must be monotonically increasing.
|
||||
*
|
||||
* @param bucketBoundaries the bucket boundaries of a distribution (given explicitly). The
|
||||
* values must be strictly increasing and should be positive values.
|
||||
* @return a {@code ExplicitOptions} {@code BucketOptions}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static BucketOptions explicitOptions(List<Double> bucketBoundaries) {
|
||||
return ExplicitOptions.create(bucketBoundaries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given match function to the underlying BucketOptions.
|
||||
*
|
||||
* @param explicitFunction the function that should be applied if the BucketOptions has type
|
||||
* {@code ExplicitOptions}.
|
||||
* @param defaultFunction the function that should be applied if the BucketOptions has a type
|
||||
* that was added after this {@code match} method was added to the API. See {@link
|
||||
* Functions} for some common functions for handling unknown types.
|
||||
* @return the result of the function applied to the underlying BucketOptions.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract <T> T match(
|
||||
Function<? super ExplicitOptions, T> explicitFunction,
|
||||
Function<? super BucketOptions, T> defaultFunction);
|
||||
|
||||
/** A Bucket with explicit bounds {@link BucketOptions}. */
|
||||
@AutoValue
|
||||
@Immutable
|
||||
public abstract static class ExplicitOptions extends BucketOptions {
|
||||
|
||||
ExplicitOptions() {}
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super ExplicitOptions, T> explicitFunction,
|
||||
Function<? super BucketOptions, T> defaultFunction) {
|
||||
return explicitFunction.apply(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link ExplicitOptions}.
|
||||
*
|
||||
* @param bucketBoundaries the bucket boundaries of a distribution (given explicitly). The
|
||||
* values must be strictly increasing and should be positive.
|
||||
* @return a {@code ExplicitOptions}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
private static ExplicitOptions create(List<Double> bucketBoundaries) {
|
||||
Utils.checkNotNull(bucketBoundaries, "bucketBoundaries");
|
||||
List<Double> bucketBoundariesCopy =
|
||||
Collections.unmodifiableList(new ArrayList<Double>(bucketBoundaries));
|
||||
checkBucketBoundsAreSorted(bucketBoundariesCopy);
|
||||
return new AutoValue_Distribution_BucketOptions_ExplicitOptions(bucketBoundariesCopy);
|
||||
}
|
||||
|
||||
private static void checkBucketBoundsAreSorted(List<Double> bucketBoundaries) {
|
||||
if (bucketBoundaries.size() >= 1) {
|
||||
double previous = Utils.checkNotNull(bucketBoundaries.get(0), "bucketBoundary");
|
||||
Utils.checkArgument(previous > 0, "bucket boundary should be > 0");
|
||||
for (int i = 1; i < bucketBoundaries.size(); i++) {
|
||||
double next = Utils.checkNotNull(bucketBoundaries.get(i), "bucketBoundary");
|
||||
Utils.checkArgument(previous < next, "bucket boundaries not sorted.");
|
||||
previous = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bucket boundaries of this distribution.
|
||||
*
|
||||
* @return the bucket boundaries of this distribution.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract List<Double> getBucketBoundaries();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The histogram bucket of the population values.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@AutoValue
|
||||
@Immutable
|
||||
public abstract static class Bucket {
|
||||
|
||||
Bucket() {}
|
||||
|
||||
/**
|
||||
* Creates a {@link Bucket}.
|
||||
*
|
||||
* @param count the number of values in each bucket of the histogram.
|
||||
* @return a {@code Bucket}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Bucket create(long count) {
|
||||
Utils.checkArgument(count >= 0, "bucket count should be non-negative.");
|
||||
return new AutoValue_Distribution_Bucket(count, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Bucket} with an {@link Exemplar}.
|
||||
*
|
||||
* @param count the number of values in each bucket of the histogram.
|
||||
* @param exemplar the {@code Exemplar} of this {@code Bucket}.
|
||||
* @return a {@code Bucket}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Bucket create(long count, Exemplar exemplar) {
|
||||
Utils.checkArgument(count >= 0, "bucket count should be non-negative.");
|
||||
Utils.checkNotNull(exemplar, "exemplar");
|
||||
return new AutoValue_Distribution_Bucket(count, exemplar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of values in each bucket of the histogram.
|
||||
*
|
||||
* @return the number of values in each bucket of the histogram.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract long getCount();
|
||||
|
||||
/**
|
||||
* Returns the {@link Exemplar} associated with the {@link Bucket}, or {@code null} if there
|
||||
* isn't one.
|
||||
*
|
||||
* @return the {@code Exemplar} associated with the {@code Bucket}, or {@code null} if there
|
||||
* isn't one.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Nullable
|
||||
public abstract Exemplar getExemplar();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.metrics.export;
|
||||
|
||||
import openconsensus.common.ExperimentalApi;
|
||||
|
||||
/**
|
||||
* Class that holds the implementation instance for {@link MetricProducerManager}.
|
||||
*
|
||||
* <p>Unless otherwise noted all methods (on component) results are cacheable.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
public abstract class ExportComponent {
|
||||
/**
|
||||
* Returns the no-op implementation of the {@code ExportComponent}.
|
||||
*
|
||||
* @return the no-op implementation of the {@code ExportComponent}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static ExportComponent newNoopExportComponent() {
|
||||
return new NoopExportComponent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the global {@link MetricProducerManager} which can be used to register handlers to
|
||||
* export all the recorded metrics.
|
||||
*
|
||||
* @return the implementation of the {@code MetricExporter} or no-op if no implementation linked
|
||||
* in the binary.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract MetricProducerManager getMetricProducerManager();
|
||||
|
||||
private static final class NoopExportComponent extends ExportComponent {
|
||||
|
||||
private static final MetricProducerManager METRIC_PRODUCER_MANAGER =
|
||||
MetricProducerManager.newNoopMetricProducerManager();
|
||||
|
||||
@Override
|
||||
public MetricProducerManager getMetricProducerManager() {
|
||||
return METRIC_PRODUCER_MANAGER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.metrics.export;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.common.ExperimentalApi;
|
||||
import openconsensus.internal.Utils;
|
||||
import openconsensus.metrics.export.Value.ValueDistribution;
|
||||
import openconsensus.metrics.export.Value.ValueDouble;
|
||||
import openconsensus.metrics.export.Value.ValueLong;
|
||||
import openconsensus.metrics.export.Value.ValueSummary;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* A {@link Metric} with one or more {@link TimeSeries}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract class Metric {
|
||||
|
||||
Metric() {}
|
||||
|
||||
/**
|
||||
* Creates a {@link Metric}.
|
||||
*
|
||||
* @param metricDescriptor the {@link MetricDescriptor}.
|
||||
* @param timeSeriesList the {@link TimeSeries} list for this metric.
|
||||
* @return a {@code Metric}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Metric create(MetricDescriptor metricDescriptor, List<TimeSeries> timeSeriesList) {
|
||||
Utils.checkListElementNotNull(
|
||||
Utils.checkNotNull(timeSeriesList, "timeSeriesList"), "timeSeries");
|
||||
return createInternal(
|
||||
metricDescriptor, Collections.unmodifiableList(new ArrayList<TimeSeries>(timeSeriesList)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Metric}.
|
||||
*
|
||||
* @param metricDescriptor the {@link MetricDescriptor}.
|
||||
* @param timeSeries the single {@link TimeSeries} for this metric.
|
||||
* @return a {@code Metric}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Metric createWithOneTimeSeries(
|
||||
MetricDescriptor metricDescriptor, TimeSeries timeSeries) {
|
||||
return createInternal(
|
||||
metricDescriptor, Collections.singletonList(Utils.checkNotNull(timeSeries, "timeSeries")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Metric}.
|
||||
*
|
||||
* @param metricDescriptor the {@link MetricDescriptor}.
|
||||
* @param timeSeriesList the {@link TimeSeries} list for this metric.
|
||||
* @return a {@code Metric}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
private static Metric createInternal(
|
||||
MetricDescriptor metricDescriptor, List<TimeSeries> timeSeriesList) {
|
||||
Utils.checkNotNull(metricDescriptor, "metricDescriptor");
|
||||
checkTypeMatch(metricDescriptor.getType(), timeSeriesList);
|
||||
return new AutoValue_Metric(metricDescriptor, timeSeriesList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link MetricDescriptor} of this metric.
|
||||
*
|
||||
* @return the {@code MetricDescriptor} of this metric.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract MetricDescriptor getMetricDescriptor();
|
||||
|
||||
/**
|
||||
* Returns the {@link TimeSeries} list for this metric.
|
||||
*
|
||||
* <p>The type of the {@link TimeSeries#getPoints()} must match {@link MetricDescriptor.Type}.
|
||||
*
|
||||
* @return the {@code TimeSeriesList} for this metric.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract List<TimeSeries> getTimeSeriesList();
|
||||
|
||||
private static void checkTypeMatch(MetricDescriptor.Type type, List<TimeSeries> timeSeriesList) {
|
||||
for (TimeSeries timeSeries : timeSeriesList) {
|
||||
for (Point point : timeSeries.getPoints()) {
|
||||
Value value = point.getValue();
|
||||
String valueClassName = "";
|
||||
if (value.getClass().getSuperclass() != null) { // work around nullness check
|
||||
// AutoValue classes should always have a super class.
|
||||
valueClassName = value.getClass().getSuperclass().getSimpleName();
|
||||
}
|
||||
switch (type) {
|
||||
case GAUGE_INT64:
|
||||
case CUMULATIVE_INT64:
|
||||
Utils.checkArgument(
|
||||
value instanceof ValueLong, "Type mismatch: %s, %s.", type, valueClassName);
|
||||
break;
|
||||
case CUMULATIVE_DOUBLE:
|
||||
case GAUGE_DOUBLE:
|
||||
Utils.checkArgument(
|
||||
value instanceof ValueDouble, "Type mismatch: %s, %s.", type, valueClassName);
|
||||
break;
|
||||
case GAUGE_DISTRIBUTION:
|
||||
case CUMULATIVE_DISTRIBUTION:
|
||||
Utils.checkArgument(
|
||||
value instanceof ValueDistribution, "Type mismatch: %s, %s.", type, valueClassName);
|
||||
break;
|
||||
case SUMMARY:
|
||||
Utils.checkArgument(
|
||||
value instanceof ValueSummary, "Type mismatch: %s, %s.", type, valueClassName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.metrics.export;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.common.ExperimentalApi;
|
||||
import openconsensus.internal.Utils;
|
||||
import openconsensus.metrics.LabelKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* {@link MetricDescriptor} defines a {@code Metric} type and its schema.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract class MetricDescriptor {
|
||||
|
||||
MetricDescriptor() {}
|
||||
|
||||
/**
|
||||
* Creates a {@link MetricDescriptor}.
|
||||
*
|
||||
* @param name name of {@code MetricDescriptor}.
|
||||
* @param description description of {@code MetricDescriptor}.
|
||||
* @param unit the metric unit.
|
||||
* @param type type of {@code MetricDescriptor}.
|
||||
* @param labelKeys the label keys associated with the {@code MetricDescriptor}.
|
||||
* @return a {@code MetricDescriptor}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static MetricDescriptor create(
|
||||
String name, String description, String unit, Type type, List<LabelKey> labelKeys) {
|
||||
Utils.checkListElementNotNull(Utils.checkNotNull(labelKeys, "labelKeys"), "labelKey");
|
||||
return new AutoValue_MetricDescriptor(
|
||||
name,
|
||||
description,
|
||||
unit,
|
||||
type,
|
||||
Collections.unmodifiableList(new ArrayList<LabelKey>(labelKeys)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the metric descriptor name.
|
||||
*
|
||||
* @return the metric descriptor name.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract String getName();
|
||||
|
||||
/**
|
||||
* Returns the description of this metric descriptor.
|
||||
*
|
||||
* @return the description of this metric descriptor.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract String getDescription();
|
||||
|
||||
/**
|
||||
* Returns the unit of this metric descriptor.
|
||||
*
|
||||
* @return the unit of this metric descriptor.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract String getUnit();
|
||||
|
||||
/**
|
||||
* Returns the type of this metric descriptor.
|
||||
*
|
||||
* @return the type of this metric descriptor.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Type getType();
|
||||
|
||||
/**
|
||||
* Returns the label keys associated with this metric descriptor.
|
||||
*
|
||||
* @return the label keys associated with this metric descriptor.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract List<LabelKey> getLabelKeys();
|
||||
|
||||
/**
|
||||
* The kind of metric. It describes how the data is reported.
|
||||
*
|
||||
* <p>A gauge is an instantaneous measurement of a value.
|
||||
*
|
||||
* <p>A cumulative measurement is a value accumulated over a time interval. In a time series,
|
||||
* cumulative measurements should have the same start time and increasing end times, until an
|
||||
* event resets the cumulative value to zero and sets a new start time for the following points.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public enum Type {
|
||||
|
||||
/**
|
||||
* An instantaneous measurement of an int64 value.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
GAUGE_INT64,
|
||||
|
||||
/**
|
||||
* An instantaneous measurement of a double value.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
GAUGE_DOUBLE,
|
||||
|
||||
/**
|
||||
* An instantaneous measurement of a distribution value. The count and sum can go both up and
|
||||
* down. Used in scenarios like a snapshot of time the current items in a queue have spent
|
||||
* there.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
GAUGE_DISTRIBUTION,
|
||||
|
||||
/**
|
||||
* An cumulative measurement of an int64 value.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
CUMULATIVE_INT64,
|
||||
|
||||
/**
|
||||
* An cumulative measurement of a double value.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
CUMULATIVE_DOUBLE,
|
||||
|
||||
/**
|
||||
* An cumulative measurement of a distribution value. The count and sum can only go up, if
|
||||
* resets then the start_time should also be reset.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
CUMULATIVE_DISTRIBUTION,
|
||||
|
||||
/**
|
||||
* Some frameworks implemented DISTRIBUTION as a summary of observations (usually things like
|
||||
* request durations and response sizes). While it also provides a total count of observations
|
||||
* and a sum of all observed values, it calculates configurable quantiles over a sliding time
|
||||
* window.
|
||||
*
|
||||
* <p>This is not recommended, since it cannot be aggregated.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
SUMMARY,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.metrics.export;
|
||||
|
||||
import openconsensus.common.ExperimentalApi;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A {@link Metric} producer that can be registered for exporting using {@link
|
||||
* MetricProducerManager}.
|
||||
*
|
||||
* <p>All implementation MUST be thread-safe.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
public abstract class MetricProducer {
|
||||
|
||||
/**
|
||||
* Returns a collection of produced {@link Metric}s to be exported.
|
||||
*
|
||||
* @return a collection of produced {@link Metric}s to be exported.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Collection<Metric> getMetrics();
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.metrics.export;
|
||||
|
||||
import openconsensus.common.ExperimentalApi;
|
||||
import openconsensus.internal.Utils;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
/**
|
||||
* Keeps a set of {@link MetricProducer} that is used by exporters to determine the metrics that
|
||||
* need to be exported.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
@ThreadSafe
|
||||
public abstract class MetricProducerManager {
|
||||
|
||||
/**
|
||||
* Adds the {@link MetricProducer} to the manager if it is not already present.
|
||||
*
|
||||
* @param metricProducer the {@code MetricProducer} to be added to the manager.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract void add(MetricProducer metricProducer);
|
||||
|
||||
/**
|
||||
* Removes the {@link MetricProducer} to the manager if it is present.
|
||||
*
|
||||
* @param metricProducer the {@code MetricProducer} to be removed from the manager.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract void remove(MetricProducer metricProducer);
|
||||
|
||||
/**
|
||||
* Returns all registered {@link MetricProducer}s that should be exported.
|
||||
*
|
||||
* <p>This method should be used by any metrics exporter that automatically exports data for
|
||||
* {@code MetricProducer} registered with the {@code MetricProducerManager}.
|
||||
*
|
||||
* @return all registered {@code MetricProducer}s that should be exported.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Set<MetricProducer> getAllMetricProducer();
|
||||
|
||||
/**
|
||||
* Returns a no-op implementation for {@link MetricProducerManager}.
|
||||
*
|
||||
* @return a no-op implementation for {@code MetricProducerManager}.
|
||||
*/
|
||||
static MetricProducerManager newNoopMetricProducerManager() {
|
||||
return new NoopMetricProducerManager();
|
||||
}
|
||||
|
||||
private static final class NoopMetricProducerManager extends MetricProducerManager {
|
||||
|
||||
@Override
|
||||
public void add(MetricProducer metricProducer) {
|
||||
Utils.checkNotNull(metricProducer, "metricProducer");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(MetricProducer metricProducer) {
|
||||
Utils.checkNotNull(metricProducer, "metricProducer");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<MetricProducer> getAllMetricProducer() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.metrics.export;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.common.ExperimentalApi;
|
||||
import openconsensus.common.Timestamp;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* A timestamped measurement of a {@code TimeSeries}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
@AutoValue
|
||||
@Immutable
|
||||
public abstract class Point {
|
||||
|
||||
Point() {}
|
||||
|
||||
/**
|
||||
* Creates a {@link Point}.
|
||||
*
|
||||
* @param value the {@link Value} of this {@link Point}.
|
||||
* @param timestamp the {@link Timestamp} when this {@link Point} was recorded.
|
||||
* @return a {@code Point}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Point create(Value value, Timestamp timestamp) {
|
||||
return new AutoValue_Point(value, timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Value}.
|
||||
*
|
||||
* @return the {@code Value}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Value getValue();
|
||||
|
||||
/**
|
||||
* Returns the {@link Timestamp} when this {@link Point} was recorded.
|
||||
*
|
||||
* @return the {@code Timestamp}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Timestamp getTimestamp();
|
||||
}
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.metrics.export;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.common.ExperimentalApi;
|
||||
import openconsensus.internal.Utils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* Implementation of the {@link Distribution} as a summary of observations.
|
||||
*
|
||||
* <p>This is not recommended, since it cannot be aggregated.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
@AutoValue
|
||||
@Immutable
|
||||
public abstract class Summary {
|
||||
Summary() {}
|
||||
|
||||
/**
|
||||
* Creates a {@link Summary}.
|
||||
*
|
||||
* @param count the count of the population values.
|
||||
* @param sum the sum of the population values.
|
||||
* @param snapshot bucket boundaries of a histogram.
|
||||
* @return a {@code Summary} with the given values.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Summary create(@Nullable Long count, @Nullable Double sum, Snapshot snapshot) {
|
||||
checkCountAndSum(count, sum);
|
||||
Utils.checkNotNull(snapshot, "snapshot");
|
||||
return new AutoValue_Summary(count, sum, snapshot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the aggregated count. If not available returns {@code null}.
|
||||
*
|
||||
* @return the aggregated count.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Nullable
|
||||
public abstract Long getCount();
|
||||
|
||||
/**
|
||||
* Returns the aggregated sum. If not available returns {@code null}.
|
||||
*
|
||||
* @return the aggregated sum.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Nullable
|
||||
public abstract Double getSum();
|
||||
|
||||
/**
|
||||
* Returns the {@link Snapshot}.
|
||||
*
|
||||
* @return the {@code Snapshot}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Snapshot getSnapshot();
|
||||
|
||||
/**
|
||||
* Represents the summary observation of the recorded events over a sliding time window.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract static class Snapshot {
|
||||
/**
|
||||
* Returns the number of values in this {@code Snapshot}. If not available returns {@code null}.
|
||||
*
|
||||
* @return the number of values in this {@code Snapshot}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Nullable
|
||||
public abstract Long getCount();
|
||||
|
||||
/**
|
||||
* Returns the sum of values in this {@code Snapshot}. If not available returns {@code null}.
|
||||
*
|
||||
* @return the sum of values in this {@code Snapshot}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Nullable
|
||||
public abstract Double getSum();
|
||||
|
||||
/**
|
||||
* Returns the list of {@code ValueAtPercentile}s in this {@code Snapshot}.
|
||||
*
|
||||
* @return the list of {@code ValueAtPercentile}s in this {@code Snapshot}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract List<ValueAtPercentile> getValueAtPercentiles();
|
||||
|
||||
/**
|
||||
* Creates a {@link Snapshot}.
|
||||
*
|
||||
* @param count the number of values in this {@code Snapshot}.
|
||||
* @param sum the number of values in this {@code Snapshot}.
|
||||
* @param valueAtPercentiles the list of {@code ValueAtPercentile}.
|
||||
* @return a {@code Snapshot} with the given values.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Snapshot create(
|
||||
@Nullable Long count, @Nullable Double sum, List<ValueAtPercentile> valueAtPercentiles) {
|
||||
checkCountAndSum(count, sum);
|
||||
Utils.checkListElementNotNull(
|
||||
Utils.checkNotNull(valueAtPercentiles, "valueAtPercentiles"), "valueAtPercentile");
|
||||
return new AutoValue_Summary_Snapshot(
|
||||
count,
|
||||
sum,
|
||||
Collections.unmodifiableList(new ArrayList<ValueAtPercentile>(valueAtPercentiles)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the value at a given percentile of a distribution.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract static class ValueAtPercentile {
|
||||
/**
|
||||
* Returns the percentile in this {@code ValueAtPercentile}.
|
||||
*
|
||||
* <p>Must be in the interval (0.0, 100.0].
|
||||
*
|
||||
* @return the percentile in this {@code ValueAtPercentile}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract double getPercentile();
|
||||
|
||||
/**
|
||||
* Returns the value in this {@code ValueAtPercentile}.
|
||||
*
|
||||
* @return the value in this {@code ValueAtPercentile}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract double getValue();
|
||||
|
||||
/**
|
||||
* Creates a {@link ValueAtPercentile}.
|
||||
*
|
||||
* @param percentile the percentile in this {@code ValueAtPercentile}.
|
||||
* @param value the value in this {@code ValueAtPercentile}.
|
||||
* @return a {@code ValueAtPercentile} with the given values.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static ValueAtPercentile create(double percentile, double value) {
|
||||
Utils.checkArgument(
|
||||
0 < percentile && percentile <= 100.0,
|
||||
"percentile must be in the interval (0.0, 100.0]");
|
||||
Utils.checkArgument(value >= 0, "value must be non-negative");
|
||||
return new AutoValue_Summary_Snapshot_ValueAtPercentile(percentile, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkCountAndSum(@Nullable Long count, @Nullable Double sum) {
|
||||
Utils.checkArgument(count == null || count >= 0, "count must be non-negative.");
|
||||
Utils.checkArgument(sum == null || sum >= 0, "sum must be non-negative.");
|
||||
if (count != null && count == 0) {
|
||||
Utils.checkArgument(sum == null || sum == 0, "sum must be 0 if count is 0.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.metrics.export;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.common.ExperimentalApi;
|
||||
import openconsensus.common.Timestamp;
|
||||
import openconsensus.internal.Utils;
|
||||
import openconsensus.metrics.LabelKey;
|
||||
import openconsensus.metrics.LabelValue;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* A collection of data points that describes the time-varying values of a {@code Metric}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract class TimeSeries {
|
||||
|
||||
TimeSeries() {}
|
||||
|
||||
/**
|
||||
* Creates a {@link TimeSeries}.
|
||||
*
|
||||
* @param labelValues the {@code LabelValue}s that uniquely identify this {@code TimeSeries}.
|
||||
* @param points the data {@code Point}s of this {@code TimeSeries}.
|
||||
* @param startTimestamp the start {@code Timestamp} of this {@code TimeSeries}. Must be non-null
|
||||
* for cumulative {@code Point}s.
|
||||
* @return a {@code TimeSeries}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static TimeSeries create(
|
||||
List<LabelValue> labelValues, List<Point> points, @Nullable Timestamp startTimestamp) {
|
||||
Utils.checkListElementNotNull(Utils.checkNotNull(points, "points"), "point");
|
||||
return createInternal(
|
||||
labelValues, Collections.unmodifiableList(new ArrayList<Point>(points)), startTimestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link TimeSeries} with empty(or no) points.
|
||||
*
|
||||
* @param labelValues the {@code LabelValue}s that uniquely identify this {@code TimeSeries}.
|
||||
* @return a {@code TimeSeries}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static TimeSeries create(List<LabelValue> labelValues) {
|
||||
return createInternal(labelValues, Collections.<Point>emptyList(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link TimeSeries}.
|
||||
*
|
||||
* @param labelValues the {@code LabelValue}s that uniquely identify this {@code TimeSeries}.
|
||||
* @param point the single data {@code Point} of this {@code TimeSeries}.
|
||||
* @param startTimestamp the start {@code Timestamp} of this {@code TimeSeries}. Must be non-null
|
||||
* for cumulative {@code Point}s.
|
||||
* @return a {@code TimeSeries}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static TimeSeries createWithOnePoint(
|
||||
List<LabelValue> labelValues, Point point, @Nullable Timestamp startTimestamp) {
|
||||
Utils.checkNotNull(point, "point");
|
||||
return createInternal(labelValues, Collections.singletonList(point), startTimestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@code Point} of the {@link TimeSeries}.
|
||||
*
|
||||
* @param point the single data {@code Point} of this {@code TimeSeries}.
|
||||
* @return a {@code TimeSeries}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public TimeSeries setPoint(Point point) {
|
||||
Utils.checkNotNull(point, "point");
|
||||
return new AutoValue_TimeSeries(getLabelValues(), Collections.singletonList(point), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link TimeSeries}.
|
||||
*
|
||||
* @param labelValues the {@code LabelValue}s that uniquely identify this {@code TimeSeries}.
|
||||
* @param points the data {@code Point}s of this {@code TimeSeries}.
|
||||
* @param startTimestamp the start {@code Timestamp} of this {@code TimeSeries}. Must be non-null
|
||||
* for cumulative {@code Point}s.
|
||||
* @return a {@code TimeSeries}.
|
||||
*/
|
||||
private static TimeSeries createInternal(
|
||||
List<LabelValue> labelValues, List<Point> points, @Nullable Timestamp startTimestamp) {
|
||||
// Fail fast on null lists to prevent NullPointerException when copying the lists.
|
||||
Utils.checkListElementNotNull(Utils.checkNotNull(labelValues, "labelValues"), "labelValue");
|
||||
return new AutoValue_TimeSeries(
|
||||
Collections.unmodifiableList(new ArrayList<LabelValue>(labelValues)),
|
||||
points,
|
||||
startTimestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of {@link LabelValue}s that uniquely identify this {@link TimeSeries}.
|
||||
*
|
||||
* <p>Apply to all {@link Point}s.
|
||||
*
|
||||
* <p>The order of {@link LabelValue}s must match that of {@link LabelKey}s in the {@code
|
||||
* MetricDescriptor}.
|
||||
*
|
||||
* @return the {@code LabelValue}s.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract List<LabelValue> getLabelValues();
|
||||
|
||||
/**
|
||||
* Returns the data {@link Point}s of this {@link TimeSeries}.
|
||||
*
|
||||
* @return the data {@code Point}s.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract List<Point> getPoints();
|
||||
|
||||
/**
|
||||
* Returns the start {@link Timestamp} of this {@link TimeSeries} if the {@link Point}s are
|
||||
* cumulative, or {@code null} if the {@link Point}s are gauge.
|
||||
*
|
||||
* @return the start {@code Timestamp} or {@code null}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Nullable
|
||||
public abstract Timestamp getStartTimestamp();
|
||||
}
|
||||
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.metrics.export;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.common.ExperimentalApi;
|
||||
import openconsensus.common.Function;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* The actual point value for a {@link Point}.
|
||||
*
|
||||
* <p>Currently there are three types of {@link Value}:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@code double}
|
||||
* <li>{@code long}
|
||||
* <li>{@link Distribution}
|
||||
* </ul>
|
||||
*
|
||||
* <p>Each {@link Point} contains exactly one of the three {@link Value} types.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
@Immutable
|
||||
public abstract class Value {
|
||||
|
||||
Value() {}
|
||||
|
||||
/**
|
||||
* Returns a double {@link Value}.
|
||||
*
|
||||
* @param value value in double.
|
||||
* @return a double {@code Value}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Value doubleValue(double value) {
|
||||
return ValueDouble.create(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a long {@link Value}.
|
||||
*
|
||||
* @param value value in long.
|
||||
* @return a long {@code Value}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Value longValue(long value) {
|
||||
return ValueLong.create(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Distribution} {@link Value}.
|
||||
*
|
||||
* @param value value in {@link Distribution}.
|
||||
* @return a {@code Distribution} {@code Value}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Value distributionValue(Distribution value) {
|
||||
return ValueDistribution.create(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Summary} {@link Value}.
|
||||
*
|
||||
* @param value value in {@link Summary}.
|
||||
* @return a {@code Summary} {@code Value}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Value summaryValue(Summary value) {
|
||||
return ValueSummary.create(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given match function to the underlying data type.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract <T> T match(
|
||||
Function<? super Double, T> doubleFunction,
|
||||
Function<? super Long, T> longFunction,
|
||||
Function<? super Distribution, T> distributionFunction,
|
||||
Function<? super Summary, T> summaryFunction,
|
||||
Function<? super Value, T> defaultFunction);
|
||||
|
||||
/** A 64-bit double-precision floating-point {@link Value}. */
|
||||
@AutoValue
|
||||
@Immutable
|
||||
abstract static class ValueDouble extends Value {
|
||||
|
||||
ValueDouble() {}
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super Double, T> doubleFunction,
|
||||
Function<? super Long, T> longFunction,
|
||||
Function<? super Distribution, T> distributionFunction,
|
||||
Function<? super Summary, T> summaryFunction,
|
||||
Function<? super Value, T> defaultFunction) {
|
||||
return doubleFunction.apply(getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link ValueDouble}.
|
||||
*
|
||||
* @param value the value in double.
|
||||
* @return a {@code ValueDouble}.
|
||||
*/
|
||||
static ValueDouble create(double value) {
|
||||
return new AutoValue_Value_ValueDouble(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the double value.
|
||||
*
|
||||
* @return the double value.
|
||||
*/
|
||||
abstract double getValue();
|
||||
}
|
||||
|
||||
/** A 64-bit integer {@link Value}. */
|
||||
@AutoValue
|
||||
@Immutable
|
||||
abstract static class ValueLong extends Value {
|
||||
|
||||
ValueLong() {}
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super Double, T> doubleFunction,
|
||||
Function<? super Long, T> longFunction,
|
||||
Function<? super Distribution, T> distributionFunction,
|
||||
Function<? super Summary, T> summaryFunction,
|
||||
Function<? super Value, T> defaultFunction) {
|
||||
return longFunction.apply(getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link ValueLong}.
|
||||
*
|
||||
* @param value the value in long.
|
||||
* @return a {@code ValueLong}.
|
||||
*/
|
||||
static ValueLong create(long value) {
|
||||
return new AutoValue_Value_ValueLong(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the long value.
|
||||
*
|
||||
* @return the long value.
|
||||
*/
|
||||
abstract long getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ValueDistribution} contains summary statistics for a population of values. It optionally
|
||||
* contains a histogram representing the distribution of those values across a set of buckets.
|
||||
*/
|
||||
@AutoValue
|
||||
@Immutable
|
||||
abstract static class ValueDistribution extends Value {
|
||||
|
||||
ValueDistribution() {}
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super Double, T> doubleFunction,
|
||||
Function<? super Long, T> longFunction,
|
||||
Function<? super Distribution, T> distributionFunction,
|
||||
Function<? super Summary, T> summaryFunction,
|
||||
Function<? super Value, T> defaultFunction) {
|
||||
return distributionFunction.apply(getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link ValueDistribution}.
|
||||
*
|
||||
* @param value the {@link Distribution} value.
|
||||
* @return a {@code ValueDistribution}.
|
||||
*/
|
||||
static ValueDistribution create(Distribution value) {
|
||||
return new AutoValue_Value_ValueDistribution(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Distribution} value.
|
||||
*
|
||||
* @return the {@code Distribution} value.
|
||||
*/
|
||||
abstract Distribution getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ValueSummary} contains a snapshot representing values calculated over an arbitrary time
|
||||
* window.
|
||||
*/
|
||||
@AutoValue
|
||||
@Immutable
|
||||
abstract static class ValueSummary extends Value {
|
||||
|
||||
ValueSummary() {}
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super Double, T> doubleFunction,
|
||||
Function<? super Long, T> longFunction,
|
||||
Function<? super Distribution, T> distributionFunction,
|
||||
Function<? super Summary, T> summaryFunction,
|
||||
Function<? super Value, T> defaultFunction) {
|
||||
return summaryFunction.apply(getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link ValueSummary}.
|
||||
*
|
||||
* @param value the {@link Summary} value.
|
||||
* @return a {@code ValueSummary}.
|
||||
*/
|
||||
static ValueSummary create(Summary value) {
|
||||
return new AutoValue_Value_ValueSummary(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Summary} value.
|
||||
*
|
||||
* @return the {@code Summary} value.
|
||||
*/
|
||||
abstract Summary getValue();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This package describes the Metrics data model. Metrics are a data model for what stats exporters
|
||||
* take as input. This data model may eventually become the wire format for metrics.
|
||||
*
|
||||
* <p>WARNING: Currently all the public classes under this package are marked as {@link
|
||||
* openconsensus.common.ExperimentalApi}. The classes and APIs under {@link io.opencensus.metrics}
|
||||
* are likely to get backwards-incompatible updates in the future. DO NOT USE except for
|
||||
* experimental purposes.
|
||||
*
|
||||
* <p>Please see
|
||||
* https://github.com/census-instrumentation/opencensus-specs/blob/master/stats/Metrics.md and
|
||||
* https://github.com/census-instrumentation/opencensus-proto/blob/master/opencensus/proto/stats/metrics/metrics.proto
|
||||
* for more details.
|
||||
*/
|
||||
@ExperimentalApi
|
||||
package openconsensus.metrics;
|
||||
|
||||
import openconsensus.common.ExperimentalApi;
|
||||
|
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.resource;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.common.ExperimentalApi;
|
||||
import openconsensus.internal.DefaultVisibilityForTesting;
|
||||
import openconsensus.internal.StringUtils;
|
||||
import openconsensus.internal.Utils;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/*>>>
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
*/
|
||||
|
||||
/**
|
||||
* {@link Resource} represents a resource, which capture identifying information about the entities
|
||||
* for which signals (stats or traces) are reported. It further provides a framework for detection
|
||||
* of resource information from the environment and progressive population as signals propagate from
|
||||
* the core instrumentation library to a backend's exporter.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
@ExperimentalApi
|
||||
public abstract class Resource {
|
||||
@DefaultVisibilityForTesting
|
||||
static final int MAX_LENGTH = 255;
|
||||
private static final String OC_RESOURCE_TYPE_ENV = "OC_RESOURCE_TYPE";
|
||||
private static final String OC_RESOURCE_LABELS_ENV = "OC_RESOURCE_LABELS";
|
||||
private static final String LABEL_LIST_SPLITTER = ",";
|
||||
private static final String LABEL_KEY_VALUE_SPLITTER = "=";
|
||||
private static final String ERROR_MESSAGE_INVALID_CHARS =
|
||||
" should be a ASCII string with a length greater than 0 and not exceed "
|
||||
+ MAX_LENGTH
|
||||
+ " characters.";
|
||||
private static final String ERROR_MESSAGE_INVALID_VALUE =
|
||||
" should be a ASCII string with a length not exceed " + MAX_LENGTH + " characters.";
|
||||
|
||||
@javax.annotation.Nullable
|
||||
private static final String ENV_TYPE = parseResourceType(System.getenv(OC_RESOURCE_TYPE_ENV));
|
||||
|
||||
private static final Map<String, String> ENV_LABEL_MAP =
|
||||
parseResourceLabels(System.getenv(OC_RESOURCE_LABELS_ENV));
|
||||
|
||||
Resource() {}
|
||||
|
||||
/**
|
||||
* Returns the type identifier for the resource.
|
||||
*
|
||||
* @return the type identifier for the resource.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@javax.annotation.Nullable
|
||||
public abstract String getType();
|
||||
|
||||
/**
|
||||
* Returns a map of labels that describe the resource.
|
||||
*
|
||||
* @return a map of labels.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Map<String, String> getLabels();
|
||||
|
||||
/**
|
||||
* Returns a {@link Resource}. This resource information is loaded from the OC_RESOURCE_TYPE and
|
||||
* OC_RESOURCE_LABELS environment variables.
|
||||
*
|
||||
* @return a {@code Resource}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Resource createFromEnvironmentVariables() {
|
||||
return createInternal(ENV_TYPE, ENV_LABEL_MAP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Resource}.
|
||||
*
|
||||
* @param type the type identifier for the resource.
|
||||
* @param labels a map of labels that describe the resource.
|
||||
* @return a {@code Resource}.
|
||||
* @throws NullPointerException if {@code labels} is null.
|
||||
* @throws IllegalArgumentException if type or label key or label value is not a valid printable
|
||||
* ASCII string or exceed {@link #MAX_LENGTH} characters.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Resource create(
|
||||
@javax.annotation.Nullable String type, Map<String, String> labels) {
|
||||
return createInternal(
|
||||
type,
|
||||
Collections.unmodifiableMap(
|
||||
new LinkedHashMap<String, String>(Utils.checkNotNull(labels, "labels"))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Resource} that runs all input resources sequentially and merges their results.
|
||||
* In case a type of label key is already set, the first set value takes precedence.
|
||||
*
|
||||
* @param resources a list of resources.
|
||||
* @return a {@code Resource}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@javax.annotation.Nullable
|
||||
public static Resource mergeResources(List<Resource> resources) {
|
||||
Resource currentResource = null;
|
||||
for (Resource resource : resources) {
|
||||
currentResource = merge(currentResource, resource);
|
||||
}
|
||||
return currentResource;
|
||||
}
|
||||
|
||||
private static Resource createInternal(
|
||||
@javax.annotation.Nullable String type, Map<String, String> labels) {
|
||||
return new AutoValue_Resource(type, labels);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a resource type from the OC_RESOURCE_TYPE environment variable.
|
||||
*
|
||||
* <p>OC_RESOURCE_TYPE: A string that describes the type of the resource prefixed by a domain
|
||||
* namespace, e.g. “kubernetes.io/container”.
|
||||
*/
|
||||
@javax.annotation.Nullable
|
||||
static String parseResourceType(@javax.annotation.Nullable String rawEnvType) {
|
||||
if (rawEnvType != null && !rawEnvType.isEmpty()) {
|
||||
Utils.checkArgument(isValidAndNotEmpty(rawEnvType), "Type" + ERROR_MESSAGE_INVALID_CHARS);
|
||||
return rawEnvType.trim();
|
||||
}
|
||||
return rawEnvType;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a label map from the OC_RESOURCE_LABELS environment variable.
|
||||
*
|
||||
* <p>OC_RESOURCE_LABELS: A comma-separated list of labels describing the source in more detail,
|
||||
* e.g. “key1=val1,key2=val2”. Domain names and paths are accepted as label keys. Values may be
|
||||
* quoted or unquoted in general. If a value contains whitespaces, =, or " characters, it must
|
||||
* always be quoted.
|
||||
*/
|
||||
static Map<String, String> parseResourceLabels(@javax.annotation.Nullable String rawEnvLabels) {
|
||||
if (rawEnvLabels == null) {
|
||||
return Collections.<String, String>emptyMap();
|
||||
} else {
|
||||
Map<String, String> labels = new HashMap<String, String>();
|
||||
String[] rawLabels = rawEnvLabels.split(LABEL_LIST_SPLITTER, -1);
|
||||
for (String rawLabel : rawLabels) {
|
||||
String[] keyValuePair = rawLabel.split(LABEL_KEY_VALUE_SPLITTER, -1);
|
||||
if (keyValuePair.length != 2) {
|
||||
continue;
|
||||
}
|
||||
String key = keyValuePair[0].trim();
|
||||
String value = keyValuePair[1].trim().replaceAll("^\"|\"$", "");
|
||||
Utils.checkArgument(isValidAndNotEmpty(key), "Label key" + ERROR_MESSAGE_INVALID_CHARS);
|
||||
Utils.checkArgument(isValid(value), "Label value" + ERROR_MESSAGE_INVALID_VALUE);
|
||||
labels.put(key, value);
|
||||
}
|
||||
return Collections.unmodifiableMap(labels);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new, merged {@link Resource} by merging two resources. In case of a collision, first
|
||||
* resource takes precedence.
|
||||
*/
|
||||
@javax.annotation.Nullable
|
||||
private static Resource merge(
|
||||
@javax.annotation.Nullable Resource resource,
|
||||
@javax.annotation.Nullable Resource otherResource) {
|
||||
if (otherResource == null) {
|
||||
return resource;
|
||||
}
|
||||
if (resource == null) {
|
||||
return otherResource;
|
||||
}
|
||||
|
||||
String mergedType = resource.getType() != null ? resource.getType() : otherResource.getType();
|
||||
Map<String, String> mergedLabelMap =
|
||||
new LinkedHashMap<String, String>(otherResource.getLabels());
|
||||
|
||||
// Labels from resource overwrite labels from otherResource.
|
||||
for (Entry<String, String> entry : resource.getLabels().entrySet()) {
|
||||
mergedLabelMap.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return createInternal(mergedType, Collections.unmodifiableMap(mergedLabelMap));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given {@code String} is a valid printable ASCII string with a length not
|
||||
* exceed {@link #MAX_LENGTH} characters.
|
||||
*
|
||||
* @param name the name to be validated.
|
||||
* @return whether the name is valid.
|
||||
*/
|
||||
private static boolean isValid(String name) {
|
||||
return name.length() <= MAX_LENGTH && StringUtils.isPrintableString(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given {@code String} is a valid printable ASCII string with a length
|
||||
* greater than 0 and not exceed {@link #MAX_LENGTH} characters.
|
||||
*
|
||||
* @param name the name to be validated.
|
||||
* @return whether the name is valid.
|
||||
*/
|
||||
private static boolean isValidAndNotEmpty(String name) {
|
||||
return !name.isEmpty() && isValid(name);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* API for resource information population.
|
||||
*
|
||||
* <p>The resource library primarily defines a type "Resource" that captures information about the
|
||||
* entity for which stats or traces are recorded. For example, metrics exposed by a Kubernetes
|
||||
* container can be linked to a resource that specifies the cluster, namespace, pod, and container
|
||||
* name.
|
||||
*
|
||||
* <p>Two environment variables are used to populate resource information:
|
||||
*
|
||||
* <ul>
|
||||
* <li>OC_RESOURCE_TYPE: A string that describes the type of the resource prefixed by a domain
|
||||
* namespace. Leading and trailing whitespaces are trimmed. e.g. “kubernetes.io/container”.
|
||||
* <li>OC_RESOURCE_LABELS: A comma-separated list of labels describing the source in more detail,
|
||||
* e.g. “key1=val1,key2=val2”. The allowed character set is appropriately constrained.
|
||||
* </ul>
|
||||
*
|
||||
* <p>Type, label keys, and label values MUST contain only printable ASCII (codes between 32 and
|
||||
* 126, inclusive) and less than 256 characters. Type and label keys MUST have a length greater than
|
||||
* zero. They SHOULD start with a domain name and separate hierarchies with / characters, e.g.
|
||||
* k8s.io/namespace/name.
|
||||
*
|
||||
* <p>WARNING: Currently all the public classes under this package are marked as {@link
|
||||
* openconsensus.common.ExperimentalApi}. DO NOT USE except for experimental purposes.
|
||||
*
|
||||
* <p>Please see
|
||||
* https://github.com/census-instrumentation/opencensus-specs/blob/master/resource/Resource.md for
|
||||
* more details.
|
||||
*/
|
||||
@ExperimentalApi
|
||||
package openconsensus.resource;
|
||||
|
||||
import openconsensus.common.ExperimentalApi;
|
||||
|
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.stats;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.common.Function;
|
||||
import openconsensus.internal.Utils;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* {@link Aggregation} is the process of combining a certain set of {@code MeasureValue}s for a
|
||||
* given {@code Measure} into an {@link AggregationData}.
|
||||
*
|
||||
* <p>{@link Aggregation} currently supports 4 types of basic aggregation:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Sum
|
||||
* <li>Count
|
||||
* <li>Distribution
|
||||
* <li>LastValue
|
||||
* </ul>
|
||||
*
|
||||
* <p>When creating a {@link View}, one {@link Aggregation} needs to be specified as how to
|
||||
* aggregate {@code MeasureValue}s.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
public abstract class Aggregation {
|
||||
|
||||
private Aggregation() {}
|
||||
|
||||
/**
|
||||
* Applies the given match function to the underlying data type.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract <T> T match(
|
||||
Function<? super Sum, T> p0,
|
||||
Function<? super Count, T> p1,
|
||||
Function<? super Distribution, T> p2,
|
||||
Function<? super LastValue, T> p3,
|
||||
Function<? super Aggregation, T> defaultFunction);
|
||||
|
||||
/**
|
||||
* Calculate sum on aggregated {@code MeasureValue}s.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract static class Sum extends Aggregation {
|
||||
|
||||
Sum() {}
|
||||
|
||||
private static final Sum INSTANCE = new AutoValue_Aggregation_Sum();
|
||||
|
||||
/**
|
||||
* Construct a {@code Sum}.
|
||||
*
|
||||
* @return a new {@code Sum}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Sum create() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super Sum, T> p0,
|
||||
Function<? super Count, T> p1,
|
||||
Function<? super Distribution, T> p2,
|
||||
Function<? super LastValue, T> p3,
|
||||
Function<? super Aggregation, T> defaultFunction) {
|
||||
return p0.apply(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate count on aggregated {@code MeasureValue}s.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract static class Count extends Aggregation {
|
||||
|
||||
Count() {}
|
||||
|
||||
private static final Count INSTANCE = new AutoValue_Aggregation_Count();
|
||||
|
||||
/**
|
||||
* Construct a {@code Count}.
|
||||
*
|
||||
* @return a new {@code Count}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Count create() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super Sum, T> p0,
|
||||
Function<? super Count, T> p1,
|
||||
Function<? super Distribution, T> p2,
|
||||
Function<? super LastValue, T> p3,
|
||||
Function<? super Aggregation, T> defaultFunction) {
|
||||
return p1.apply(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate mean on aggregated {@code MeasureValue}s.
|
||||
*
|
||||
* @since 0.1.0
|
||||
* @deprecated since 0.13, use {@link Distribution} instead.
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
@Deprecated
|
||||
@AutoValue.CopyAnnotations
|
||||
public abstract static class Mean extends Aggregation {
|
||||
|
||||
Mean() {}
|
||||
|
||||
private static final Mean INSTANCE = new AutoValue_Aggregation_Mean();
|
||||
|
||||
/**
|
||||
* Construct a {@code Mean}.
|
||||
*
|
||||
* @return a new {@code Mean}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Mean create() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super Sum, T> p0,
|
||||
Function<? super Count, T> p1,
|
||||
Function<? super Distribution, T> p2,
|
||||
Function<? super LastValue, T> p3,
|
||||
Function<? super Aggregation, T> defaultFunction) {
|
||||
return defaultFunction.apply(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate distribution stats on aggregated {@code MeasureValue}s. Distribution includes mean,
|
||||
* count, histogram, min, max and sum of squared deviations.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract static class Distribution extends Aggregation {
|
||||
|
||||
Distribution() {}
|
||||
|
||||
/**
|
||||
* Construct a {@code Distribution}.
|
||||
*
|
||||
* @return a new {@code Distribution}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Distribution create(BucketBoundaries bucketBoundaries) {
|
||||
Utils.checkNotNull(bucketBoundaries, "bucketBoundaries");
|
||||
return new AutoValue_Aggregation_Distribution(bucketBoundaries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code Distribution}'s bucket boundaries.
|
||||
*
|
||||
* @return the {@code Distribution}'s bucket boundaries.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract BucketBoundaries getBucketBoundaries();
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super Sum, T> p0,
|
||||
Function<? super Count, T> p1,
|
||||
Function<? super Distribution, T> p2,
|
||||
Function<? super LastValue, T> p3,
|
||||
Function<? super Aggregation, T> defaultFunction) {
|
||||
return p2.apply(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the last value of aggregated {@code MeasureValue}s.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract static class LastValue extends Aggregation {
|
||||
|
||||
LastValue() {}
|
||||
|
||||
private static final LastValue INSTANCE = new AutoValue_Aggregation_LastValue();
|
||||
|
||||
/**
|
||||
* Construct a {@code LastValue}.
|
||||
*
|
||||
* @return a new {@code LastValue}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static LastValue create() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super Sum, T> p0,
|
||||
Function<? super Count, T> p1,
|
||||
Function<? super Distribution, T> p2,
|
||||
Function<? super LastValue, T> p3,
|
||||
Function<? super Aggregation, T> defaultFunction) {
|
||||
return p3.apply(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,532 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.stats;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.common.Function;
|
||||
import openconsensus.internal.Utils;
|
||||
import openconsensus.metrics.data.Exemplar;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* {@link AggregationData} is the result of applying a given {@link Aggregation} to a set of {@code
|
||||
* MeasureValue}s.
|
||||
*
|
||||
* <p>{@link AggregationData} currently supports 6 types of basic aggregation values:
|
||||
*
|
||||
* <ul>
|
||||
* <li>SumDataDouble
|
||||
* <li>SumDataLong
|
||||
* <li>CountData
|
||||
* <li>DistributionData
|
||||
* <li>LastValueDataDouble
|
||||
* <li>LastValueDataLong
|
||||
* </ul>
|
||||
*
|
||||
* <p>{@link ViewData} will contain one {@link AggregationData}, corresponding to its {@link
|
||||
* Aggregation} definition in {@link View}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
public abstract class AggregationData {
|
||||
|
||||
private AggregationData() {}
|
||||
|
||||
/**
|
||||
* Applies the given match function to the underlying data type.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract <T> T match(
|
||||
Function<? super SumDataDouble, T> p0,
|
||||
Function<? super SumDataLong, T> p1,
|
||||
Function<? super CountData, T> p2,
|
||||
Function<? super DistributionData, T> p3,
|
||||
Function<? super LastValueDataDouble, T> p4,
|
||||
Function<? super LastValueDataLong, T> p5,
|
||||
Function<? super AggregationData, T> defaultFunction);
|
||||
|
||||
/**
|
||||
* The sum value of aggregated {@code MeasureValueDouble}s.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract static class SumDataDouble extends AggregationData {
|
||||
|
||||
SumDataDouble() {}
|
||||
|
||||
/**
|
||||
* Creates a {@code SumDataDouble}.
|
||||
*
|
||||
* @param sum the aggregated sum.
|
||||
* @return a {@code SumDataDouble}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static SumDataDouble create(double sum) {
|
||||
return new AutoValue_AggregationData_SumDataDouble(sum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the aggregated sum.
|
||||
*
|
||||
* @return the aggregated sum.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract double getSum();
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super SumDataDouble, T> p0,
|
||||
Function<? super SumDataLong, T> p1,
|
||||
Function<? super CountData, T> p2,
|
||||
Function<? super DistributionData, T> p3,
|
||||
Function<? super LastValueDataDouble, T> p4,
|
||||
Function<? super LastValueDataLong, T> p5,
|
||||
Function<? super AggregationData, T> defaultFunction) {
|
||||
return p0.apply(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The sum value of aggregated {@code MeasureValueLong}s.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract static class SumDataLong extends AggregationData {
|
||||
|
||||
SumDataLong() {}
|
||||
|
||||
/**
|
||||
* Creates a {@code SumDataLong}.
|
||||
*
|
||||
* @param sum the aggregated sum.
|
||||
* @return a {@code SumDataLong}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static SumDataLong create(long sum) {
|
||||
return new AutoValue_AggregationData_SumDataLong(sum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the aggregated sum.
|
||||
*
|
||||
* @return the aggregated sum.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract long getSum();
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super SumDataDouble, T> p0,
|
||||
Function<? super SumDataLong, T> p1,
|
||||
Function<? super CountData, T> p2,
|
||||
Function<? super DistributionData, T> p3,
|
||||
Function<? super LastValueDataDouble, T> p4,
|
||||
Function<? super LastValueDataLong, T> p5,
|
||||
Function<? super AggregationData, T> defaultFunction) {
|
||||
return p1.apply(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The count value of aggregated {@code MeasureValue}s.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract static class CountData extends AggregationData {
|
||||
|
||||
CountData() {}
|
||||
|
||||
/**
|
||||
* Creates a {@code CountData}.
|
||||
*
|
||||
* @param count the aggregated count.
|
||||
* @return a {@code CountData}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static CountData create(long count) {
|
||||
return new AutoValue_AggregationData_CountData(count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the aggregated count.
|
||||
*
|
||||
* @return the aggregated count.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract long getCount();
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super SumDataDouble, T> p0,
|
||||
Function<? super SumDataLong, T> p1,
|
||||
Function<? super CountData, T> p2,
|
||||
Function<? super DistributionData, T> p3,
|
||||
Function<? super LastValueDataDouble, T> p4,
|
||||
Function<? super LastValueDataLong, T> p5,
|
||||
Function<? super AggregationData, T> defaultFunction) {
|
||||
return p2.apply(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The mean value of aggregated {@code MeasureValue}s.
|
||||
*
|
||||
* @since 0.1.0
|
||||
* @deprecated since 0.13, use {@link DistributionData} instead.
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
@Deprecated
|
||||
@AutoValue.CopyAnnotations
|
||||
public abstract static class MeanData extends AggregationData {
|
||||
|
||||
MeanData() {}
|
||||
|
||||
/**
|
||||
* Creates a {@code MeanData}.
|
||||
*
|
||||
* @param mean the aggregated mean.
|
||||
* @param count the aggregated count.
|
||||
* @return a {@code MeanData}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static MeanData create(double mean, long count) {
|
||||
return new AutoValue_AggregationData_MeanData(mean, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the aggregated mean.
|
||||
*
|
||||
* @return the aggregated mean.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract double getMean();
|
||||
|
||||
/**
|
||||
* Returns the aggregated count.
|
||||
*
|
||||
* @return the aggregated count.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract long getCount();
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super SumDataDouble, T> p0,
|
||||
Function<? super SumDataLong, T> p1,
|
||||
Function<? super CountData, T> p2,
|
||||
Function<? super DistributionData, T> p3,
|
||||
Function<? super LastValueDataDouble, T> p4,
|
||||
Function<? super LastValueDataLong, T> p5,
|
||||
Function<? super AggregationData, T> defaultFunction) {
|
||||
return defaultFunction.apply(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The distribution stats of aggregated {@code MeasureValue}s. Distribution stats include mean,
|
||||
* count, histogram, min, max and sum of squared deviations.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract static class DistributionData extends AggregationData {
|
||||
|
||||
DistributionData() {}
|
||||
|
||||
/**
|
||||
* Creates a {@code DistributionData}.
|
||||
*
|
||||
* @param mean mean value.
|
||||
* @param count count value.
|
||||
* @param min min value.
|
||||
* @param max max value.
|
||||
* @param sumOfSquaredDeviations sum of squared deviations.
|
||||
* @param bucketCounts histogram bucket counts.
|
||||
* @param exemplars the exemplars associated with histogram buckets.
|
||||
* @return a {@code DistributionData}.
|
||||
* @since 0.1.0
|
||||
* @deprecated since 0.17. Use {@link #create(double, long, double, List, List)}
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("InconsistentOverloads")
|
||||
public static DistributionData create(
|
||||
double mean,
|
||||
long count,
|
||||
double min,
|
||||
double max,
|
||||
double sumOfSquaredDeviations,
|
||||
List<Long> bucketCounts,
|
||||
List<Exemplar> exemplars) {
|
||||
return create(mean, count, sumOfSquaredDeviations, bucketCounts, exemplars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code DistributionData}.
|
||||
*
|
||||
* @param mean mean value.
|
||||
* @param count count value.
|
||||
* @param sumOfSquaredDeviations sum of squared deviations.
|
||||
* @param bucketCounts histogram bucket counts.
|
||||
* @param exemplars the exemplars associated with histogram buckets.
|
||||
* @return a {@code DistributionData}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static DistributionData create(
|
||||
double mean,
|
||||
long count,
|
||||
double sumOfSquaredDeviations,
|
||||
List<Long> bucketCounts,
|
||||
List<Exemplar> exemplars) {
|
||||
List<Long> bucketCountsCopy =
|
||||
Collections.unmodifiableList(
|
||||
new ArrayList<Long>(Utils.checkNotNull(bucketCounts, "bucketCounts")));
|
||||
for (Long bucketCount : bucketCountsCopy) {
|
||||
Utils.checkNotNull(bucketCount, "bucketCount");
|
||||
}
|
||||
|
||||
Utils.checkNotNull(exemplars, "exemplars");
|
||||
for (Exemplar exemplar : exemplars) {
|
||||
Utils.checkNotNull(exemplar, "exemplar");
|
||||
}
|
||||
|
||||
return new AutoValue_AggregationData_DistributionData(
|
||||
mean,
|
||||
count,
|
||||
sumOfSquaredDeviations,
|
||||
bucketCountsCopy,
|
||||
Collections.<Exemplar>unmodifiableList(new ArrayList<Exemplar>(exemplars)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code DistributionData}.
|
||||
*
|
||||
* @param mean mean value.
|
||||
* @param count count value.
|
||||
* @param min min value.
|
||||
* @param max max value.
|
||||
* @param sumOfSquaredDeviations sum of squared deviations.
|
||||
* @param bucketCounts histogram bucket counts.
|
||||
* @return a {@code DistributionData}.
|
||||
* @since 0.1.0
|
||||
* @deprecated since 0.17. Use {@link #create(double, long, double, List)}.
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("InconsistentOverloads")
|
||||
public static DistributionData create(
|
||||
double mean,
|
||||
long count,
|
||||
double min,
|
||||
double max,
|
||||
double sumOfSquaredDeviations,
|
||||
List<Long> bucketCounts) {
|
||||
return create(
|
||||
mean, count, sumOfSquaredDeviations, bucketCounts, Collections.<Exemplar>emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code DistributionData}.
|
||||
*
|
||||
* @param mean mean value.
|
||||
* @param count count value.
|
||||
* @param sumOfSquaredDeviations sum of squared deviations.
|
||||
* @param bucketCounts histogram bucket counts.
|
||||
* @return a {@code DistributionData}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static DistributionData create(
|
||||
double mean, long count, double sumOfSquaredDeviations, List<Long> bucketCounts) {
|
||||
return create(
|
||||
mean, count, sumOfSquaredDeviations, bucketCounts, Collections.<Exemplar>emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the aggregated mean.
|
||||
*
|
||||
* @return the aggregated mean.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract double getMean();
|
||||
|
||||
/**
|
||||
* Returns the aggregated count.
|
||||
*
|
||||
* @return the aggregated count.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract long getCount();
|
||||
|
||||
/**
|
||||
* Returns the minimum of the population values.
|
||||
*
|
||||
* @return the minimum of the population values.
|
||||
* @since 0.1.0
|
||||
* @deprecated since 0.17. Returns {@code 0}.
|
||||
*/
|
||||
@Deprecated
|
||||
public double getMin() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum of the population values.
|
||||
*
|
||||
* @return the maximum of the population values.
|
||||
* @since 0.1.0
|
||||
* @deprecated since 0.17. Returns {@code 0}.
|
||||
*/
|
||||
@Deprecated
|
||||
public double getMax() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the aggregated sum of squared deviations.
|
||||
*
|
||||
* @return the aggregated sum of squared deviations.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract double getSumOfSquaredDeviations();
|
||||
|
||||
/**
|
||||
* Returns the aggregated bucket counts. The returned list is immutable, trying to update it
|
||||
* will throw an {@code UnsupportedOperationException}.
|
||||
*
|
||||
* @return the aggregated bucket counts.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract List<Long> getBucketCounts();
|
||||
|
||||
/**
|
||||
* Returns the {@link Exemplar}s associated with histogram buckets.
|
||||
*
|
||||
* @return the {@code Exemplar}s associated with histogram buckets.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract List<Exemplar> getExemplars();
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super SumDataDouble, T> p0,
|
||||
Function<? super SumDataLong, T> p1,
|
||||
Function<? super CountData, T> p2,
|
||||
Function<? super DistributionData, T> p3,
|
||||
Function<? super LastValueDataDouble, T> p4,
|
||||
Function<? super LastValueDataLong, T> p5,
|
||||
Function<? super AggregationData, T> defaultFunction) {
|
||||
return p3.apply(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The last value of aggregated {@code MeasureValueDouble}s.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract static class LastValueDataDouble extends AggregationData {
|
||||
|
||||
LastValueDataDouble() {}
|
||||
|
||||
/**
|
||||
* Creates a {@code LastValueDataDouble}.
|
||||
*
|
||||
* @param lastValue the last value.
|
||||
* @return a {@code LastValueDataDouble}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static LastValueDataDouble create(double lastValue) {
|
||||
return new AutoValue_AggregationData_LastValueDataDouble(lastValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last value.
|
||||
*
|
||||
* @return the last value.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract double getLastValue();
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super SumDataDouble, T> p0,
|
||||
Function<? super SumDataLong, T> p1,
|
||||
Function<? super CountData, T> p2,
|
||||
Function<? super DistributionData, T> p3,
|
||||
Function<? super LastValueDataDouble, T> p4,
|
||||
Function<? super LastValueDataLong, T> p5,
|
||||
Function<? super AggregationData, T> defaultFunction) {
|
||||
return p4.apply(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The last value of aggregated {@code MeasureValueLong}s.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract static class LastValueDataLong extends AggregationData {
|
||||
|
||||
LastValueDataLong() {}
|
||||
|
||||
/**
|
||||
* Creates a {@code LastValueDataLong}.
|
||||
*
|
||||
* @param lastValue the last value.
|
||||
* @return a {@code LastValueDataLong}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static LastValueDataLong create(long lastValue) {
|
||||
return new AutoValue_AggregationData_LastValueDataLong(lastValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last value.
|
||||
*
|
||||
* @return the last value.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract long getLastValue();
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super SumDataDouble, T> p0,
|
||||
Function<? super SumDataLong, T> p1,
|
||||
Function<? super CountData, T> p2,
|
||||
Function<? super DistributionData, T> p3,
|
||||
Function<? super LastValueDataDouble, T> p4,
|
||||
Function<? super LastValueDataLong, T> p5,
|
||||
Function<? super AggregationData, T> defaultFunction) {
|
||||
return p5.apply(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.stats;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.internal.Utils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* The bucket boundaries for a histogram.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract class BucketBoundaries {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(BucketBoundaries.class.getName());
|
||||
|
||||
/**
|
||||
* Returns a {@code BucketBoundaries} with the given buckets.
|
||||
*
|
||||
* @param bucketBoundaries the boundaries for the buckets in the underlying histogram.
|
||||
* @return a new {@code BucketBoundaries} with the specified boundaries.
|
||||
* @throws NullPointerException if {@code bucketBoundaries} is null.
|
||||
* @throws IllegalArgumentException if {@code bucketBoundaries} is not sorted.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static final BucketBoundaries create(List<Double> bucketBoundaries) {
|
||||
Utils.checkNotNull(bucketBoundaries, "bucketBoundaries");
|
||||
List<Double> bucketBoundariesCopy = new ArrayList<Double>(bucketBoundaries); // Deep copy.
|
||||
// Check if sorted.
|
||||
if (bucketBoundariesCopy.size() > 1) {
|
||||
double previous = bucketBoundariesCopy.get(0);
|
||||
for (int i = 1; i < bucketBoundariesCopy.size(); i++) {
|
||||
double next = bucketBoundariesCopy.get(i);
|
||||
Utils.checkArgument(previous < next, "Bucket boundaries not sorted.");
|
||||
previous = next;
|
||||
}
|
||||
}
|
||||
return new AutoValue_BucketBoundaries(
|
||||
Collections.unmodifiableList(dropNegativeBucketBounds(bucketBoundariesCopy)));
|
||||
}
|
||||
|
||||
private static List<Double> dropNegativeBucketBounds(List<Double> bucketBoundaries) {
|
||||
// Negative values (BucketBounds) are currently not supported by any of the backends
|
||||
// that OC supports.
|
||||
int negativeBucketBounds = 0;
|
||||
int zeroBucketBounds = 0;
|
||||
for (Double value : bucketBoundaries) {
|
||||
if (value <= 0) {
|
||||
if (value == 0) {
|
||||
zeroBucketBounds++;
|
||||
} else {
|
||||
negativeBucketBounds++;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (negativeBucketBounds > 0) {
|
||||
logger.log(
|
||||
Level.WARNING,
|
||||
"Dropping "
|
||||
+ negativeBucketBounds
|
||||
+ " negative bucket boundaries, the values must be strictly > 0.");
|
||||
}
|
||||
return bucketBoundaries.subList(
|
||||
negativeBucketBounds + zeroBucketBounds, bucketBoundaries.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of histogram bucket boundaries.
|
||||
*
|
||||
* @return a list of histogram bucket boundaries.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract List<Double> getBoundaries();
|
||||
}
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.stats;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.common.Function;
|
||||
import openconsensus.internal.DefaultVisibilityForTesting;
|
||||
import openconsensus.internal.StringUtils;
|
||||
import openconsensus.internal.Utils;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* The definition of the {@link Measurement} that is taken by OpenCensus library.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
public abstract class Measure {
|
||||
@DefaultVisibilityForTesting static final int NAME_MAX_LENGTH = 255;
|
||||
private static final String ERROR_MESSAGE_INVALID_NAME =
|
||||
"Name should be a ASCII string with a length no greater than "
|
||||
+ NAME_MAX_LENGTH
|
||||
+ " characters.";
|
||||
|
||||
/**
|
||||
* Applies the given match function to the underlying data type.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract <T> T match(
|
||||
Function<? super MeasureDouble, T> p0,
|
||||
Function<? super MeasureLong, T> p1,
|
||||
Function<? super Measure, T> defaultFunction);
|
||||
|
||||
/**
|
||||
* Name of measure, as a {@code String}. Should be a ASCII string with a length no greater than
|
||||
* 255 characters.
|
||||
*
|
||||
* <p>Suggested format for name: {@code <web_host>/<path>}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract String getName();
|
||||
|
||||
/**
|
||||
* Detailed description of the measure, used in documentation.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract String getDescription();
|
||||
|
||||
/**
|
||||
* The units in which {@link Measure} values are measured.
|
||||
*
|
||||
* <p>The suggested grammar for a unit is as follows:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Expression = Component { "." Component } {"/" Component };
|
||||
* <li>Component = [ PREFIX ] UNIT [ Annotation ] | Annotation | "1";
|
||||
* <li>Annotation = "{" NAME "}" ;
|
||||
* </ul>
|
||||
*
|
||||
* <p>For example, string “MBy{transmitted}/ms” stands for megabytes per milliseconds, and the
|
||||
* annotation transmitted inside {} is just a comment of the unit.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
// TODO(songya): determine whether we want to check the grammar on string unit.
|
||||
public abstract String getUnit();
|
||||
|
||||
// Prevents this class from being subclassed anywhere else.
|
||||
private Measure() {}
|
||||
|
||||
/**
|
||||
* {@link Measure} with {@code Double} typed values.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract static class MeasureDouble extends Measure {
|
||||
|
||||
MeasureDouble() {}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link MeasureDouble}.
|
||||
*
|
||||
* @param name name of {@code Measure}. Suggested format: {@code <web_host>/<path>}.
|
||||
* @param description description of {@code Measure}.
|
||||
* @param unit unit of {@code Measure}.
|
||||
* @return a {@code MeasureDouble}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static MeasureDouble create(String name, String description, String unit) {
|
||||
Utils.checkArgument(
|
||||
StringUtils.isPrintableString(name) && name.length() <= NAME_MAX_LENGTH,
|
||||
ERROR_MESSAGE_INVALID_NAME);
|
||||
return new AutoValue_Measure_MeasureDouble(name, description, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T match(
|
||||
Function<? super MeasureDouble, T> p0,
|
||||
Function<? super MeasureLong, T> p1,
|
||||
Function<? super Measure, T> defaultFunction) {
|
||||
return p0.apply(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract String getName();
|
||||
|
||||
@Override
|
||||
public abstract String getDescription();
|
||||
|
||||
@Override
|
||||
public abstract String getUnit();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Measure} with {@code Long} typed values.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract static class MeasureLong extends Measure {
|
||||
|
||||
MeasureLong() {}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link MeasureLong}.
|
||||
*
|
||||
* @param name name of {@code Measure}. Suggested format: {@code <web_host>/<path>}.
|
||||
* @param description description of {@code Measure}.
|
||||
* @param unit unit of {@code Measure}.
|
||||
* @return a {@code MeasureLong}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static MeasureLong create(String name, String description, String unit) {
|
||||
Utils.checkArgument(
|
||||
StringUtils.isPrintableString(name) && name.length() <= NAME_MAX_LENGTH,
|
||||
ERROR_MESSAGE_INVALID_NAME);
|
||||
return new AutoValue_Measure_MeasureLong(name, description, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T match(
|
||||
Function<? super MeasureDouble, T> p0,
|
||||
Function<? super MeasureLong, T> p1,
|
||||
Function<? super Measure, T> defaultFunction) {
|
||||
return p1.apply(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract String getName();
|
||||
|
||||
@Override
|
||||
public abstract String getDescription();
|
||||
|
||||
@Override
|
||||
public abstract String getUnit();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.stats;
|
||||
|
||||
import openconsensus.internal.Utils;
|
||||
import openconsensus.metrics.data.AttachmentValue;
|
||||
import openconsensus.metrics.data.AttachmentValue.AttachmentValueString;
|
||||
import openconsensus.stats.Measure.MeasureDouble;
|
||||
import openconsensus.stats.Measure.MeasureLong;
|
||||
import openconsensus.tags.TagContext;
|
||||
import javax.annotation.concurrent.NotThreadSafe;
|
||||
|
||||
/**
|
||||
* A map from {@link Measure}s to measured values to be recorded at the same time.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@NotThreadSafe
|
||||
public abstract class MeasureMap {
|
||||
|
||||
/**
|
||||
* Associates the {@link MeasureDouble} with the given value. Subsequent updates to the same
|
||||
* {@link MeasureDouble} will overwrite the previous value.
|
||||
*
|
||||
* @param measure the {@link MeasureDouble}
|
||||
* @param value the value to be associated with {@code measure}
|
||||
* @return this
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract MeasureMap put(MeasureDouble measure, double value);
|
||||
|
||||
/**
|
||||
* Associates the {@link MeasureLong} with the given value. Subsequent updates to the same {@link
|
||||
* MeasureLong} will overwrite the previous value.
|
||||
*
|
||||
* @param measure the {@link MeasureLong}
|
||||
* @param value the value to be associated with {@code measure}
|
||||
* @return this
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract MeasureMap put(MeasureLong measure, long value);
|
||||
|
||||
/**
|
||||
* Associate the contextual information of an {@code Exemplar} to this {@link MeasureMap}.
|
||||
* Contextual information is represented as {@code String} key-value pairs.
|
||||
*
|
||||
* <p>If this method is called multiple times with the same key, only the last value will be kept.
|
||||
*
|
||||
* @param key the key of contextual information of an {@code Exemplar}.
|
||||
* @param value the string representation of contextual information of an {@code Exemplar}.
|
||||
* @return this
|
||||
* @since 0.1.0
|
||||
* @deprecated in favor of {@link #putAttachment(String, AttachmentValue)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public MeasureMap putAttachment(String key, String value) {
|
||||
return putAttachment(key, AttachmentValueString.create(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate the contextual information of an {@code Exemplar} to this {@link MeasureMap}.
|
||||
* Contextual information is represented as a {@code String} key and an {@link AttachmentValue}.
|
||||
*
|
||||
* <p>If this method is called multiple times with the same key, only the last value will be kept.
|
||||
*
|
||||
* @param key the key of contextual information of an {@code Exemplar}.
|
||||
* @param value the value of contextual information of an {@code Exemplar}.
|
||||
* @return this
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public MeasureMap putAttachment(String key, AttachmentValue value) {
|
||||
// Provides a default no-op implementation to avoid breaking other existing sub-classes.
|
||||
Utils.checkNotNull(key, "key");
|
||||
Utils.checkNotNull(value, "value");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Records all of the measures at the same time, with the current {@link TagContext}.
|
||||
*
|
||||
* <p>This method records all of the stats in the {@code MeasureMap} every time it is called.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract void record();
|
||||
|
||||
/**
|
||||
* Records all of the measures at the same time, with an explicit {@link TagContext}.
|
||||
*
|
||||
* <p>This method records all of the stats in the {@code MeasureMap} every time it is called.
|
||||
*
|
||||
* @param tags the tags associated with the measurements.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract void record(TagContext tags);
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.stats;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.common.Function;
|
||||
import openconsensus.stats.Measure.MeasureDouble;
|
||||
import openconsensus.stats.Measure.MeasureLong;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* Immutable representation of a Measurement.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
public abstract class Measurement {
|
||||
|
||||
/**
|
||||
* Applies the given match function to the underlying data type.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract <T> T match(
|
||||
Function<? super MeasurementDouble, T> p0,
|
||||
Function<? super MeasurementLong, T> p1,
|
||||
Function<? super Measurement, T> defaultFunction);
|
||||
|
||||
/**
|
||||
* Extracts the measured {@link Measure}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Measure getMeasure();
|
||||
|
||||
// Prevents this class from being subclassed anywhere else.
|
||||
private Measurement() {}
|
||||
|
||||
/**
|
||||
* {@code Double} typed {@link Measurement}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract static class MeasurementDouble extends Measurement {
|
||||
MeasurementDouble() {}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link MeasurementDouble}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static MeasurementDouble create(MeasureDouble measure, double value) {
|
||||
return new AutoValue_Measurement_MeasurementDouble(measure, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract MeasureDouble getMeasure();
|
||||
|
||||
/**
|
||||
* Returns the value for the measure.
|
||||
*
|
||||
* @return the value for the measure.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract double getValue();
|
||||
|
||||
@Override
|
||||
public <T> T match(
|
||||
Function<? super MeasurementDouble, T> p0,
|
||||
Function<? super MeasurementLong, T> p1,
|
||||
Function<? super Measurement, T> defaultFunction) {
|
||||
return p0.apply(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code Long} typed {@link Measurement}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract static class MeasurementLong extends Measurement {
|
||||
MeasurementLong() {}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link MeasurementLong}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static MeasurementLong create(MeasureLong measure, long value) {
|
||||
return new AutoValue_Measurement_MeasurementLong(measure, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract MeasureLong getMeasure();
|
||||
|
||||
/**
|
||||
* Returns the value for the measure.
|
||||
*
|
||||
* @return the value for the measure.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract long getValue();
|
||||
|
||||
@Override
|
||||
public <T> T match(
|
||||
Function<? super MeasurementDouble, T> p0,
|
||||
Function<? super MeasurementLong, T> p1,
|
||||
Function<? super Measurement, T> defaultFunction) {
|
||||
return p1.apply(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.stats;
|
||||
|
||||
import openconsensus.common.Functions;
|
||||
import openconsensus.common.Timestamp;
|
||||
import openconsensus.internal.Utils;
|
||||
import openconsensus.stats.Measure.MeasureDouble;
|
||||
import openconsensus.stats.Measure.MeasureLong;
|
||||
import openconsensus.tags.TagContext;
|
||||
import openconsensus.tags.TagValue;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.annotation.concurrent.GuardedBy;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
/*>>>
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
*/
|
||||
|
||||
/** No-op implementations of stats classes. */
|
||||
final class NoopStats {
|
||||
|
||||
private NoopStats() {}
|
||||
|
||||
/**
|
||||
* Returns a {@code StatsComponent} that has a no-op implementation for {@link StatsRecorder}.
|
||||
*
|
||||
* @return a {@code StatsComponent} that has a no-op implementation for {@code StatsRecorder}.
|
||||
*/
|
||||
static StatsComponent newNoopStatsComponent() {
|
||||
return new NoopStatsComponent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code StatsRecorder} that does not record any data.
|
||||
*
|
||||
* @return a {@code StatsRecorder} that does not record any data.
|
||||
*/
|
||||
static StatsRecorder getNoopStatsRecorder() {
|
||||
return NoopStatsRecorder.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code MeasureMap} that ignores all calls to {@link MeasureMap#put}.
|
||||
*
|
||||
* @return a {@code MeasureMap} that ignores all calls to {@code MeasureMap#put}.
|
||||
*/
|
||||
static MeasureMap newNoopMeasureMap() {
|
||||
return new NoopMeasureMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code ViewManager} that maintains a map of views, but always returns empty {@link
|
||||
* ViewData}s.
|
||||
*
|
||||
* @return a {@code ViewManager} that maintains a map of views, but always returns empty {@code
|
||||
* ViewData}s.
|
||||
*/
|
||||
static ViewManager newNoopViewManager() {
|
||||
return new NoopViewManager();
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
private static final class NoopStatsComponent extends StatsComponent {
|
||||
private final ViewManager viewManager = newNoopViewManager();
|
||||
private volatile boolean isRead;
|
||||
|
||||
@Override
|
||||
public ViewManager getViewManager() {
|
||||
return viewManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsRecorder getStatsRecorder() {
|
||||
return getNoopStatsRecorder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsCollectionState getState() {
|
||||
isRead = true;
|
||||
return StatsCollectionState.DISABLED;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void setState(StatsCollectionState state) {
|
||||
Utils.checkNotNull(state, "state");
|
||||
Utils.checkState(!isRead, "State was already read, cannot set state.");
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
private static final class NoopStatsRecorder extends StatsRecorder {
|
||||
static final StatsRecorder INSTANCE = new NoopStatsRecorder();
|
||||
|
||||
@Override
|
||||
public MeasureMap newMeasureMap() {
|
||||
return newNoopMeasureMap();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class NoopMeasureMap extends MeasureMap {
|
||||
private static final Logger logger = Logger.getLogger(NoopMeasureMap.class.getName());
|
||||
private boolean hasUnsupportedValues;
|
||||
|
||||
@Override
|
||||
public MeasureMap put(MeasureDouble measure, double value) {
|
||||
if (value < 0) {
|
||||
hasUnsupportedValues = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MeasureMap put(MeasureLong measure, long value) {
|
||||
if (value < 0) {
|
||||
hasUnsupportedValues = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void record() {}
|
||||
|
||||
@Override
|
||||
public void record(TagContext tags) {
|
||||
Utils.checkNotNull(tags, "tags");
|
||||
|
||||
if (hasUnsupportedValues) {
|
||||
// drop all the recorded values
|
||||
logger.log(Level.WARNING, "Dropping values, value to record must be non-negative.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
private static final class NoopViewManager extends ViewManager {
|
||||
private static final Timestamp ZERO_TIMESTAMP = Timestamp.create(0, 0);
|
||||
|
||||
@GuardedBy("registeredViews")
|
||||
private final Map<View.Name, View> registeredViews = new HashMap<View.Name, View>();
|
||||
|
||||
// Cached set of exported views. It must be set to null whenever a view is registered or
|
||||
// unregistered.
|
||||
@javax.annotation.Nullable private volatile Set<View> exportedViews;
|
||||
|
||||
@Override
|
||||
public void registerView(View newView) {
|
||||
Utils.checkNotNull(newView, "newView");
|
||||
synchronized (registeredViews) {
|
||||
exportedViews = null;
|
||||
View existing = registeredViews.get(newView.getName());
|
||||
Utils.checkArgument(
|
||||
existing == null || newView.equals(existing),
|
||||
"A different view with the same name already exists.");
|
||||
if (existing == null) {
|
||||
registeredViews.put(newView.getName(), newView);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@javax.annotation.Nullable
|
||||
@SuppressWarnings("deprecation")
|
||||
public ViewData getView(View.Name name) {
|
||||
Utils.checkNotNull(name, "name");
|
||||
synchronized (registeredViews) {
|
||||
View view = registeredViews.get(name);
|
||||
if (view == null) {
|
||||
return null;
|
||||
} else {
|
||||
return ViewData.create(
|
||||
view,
|
||||
Collections.<List</*@Nullable*/ TagValue>, AggregationData>emptyMap(),
|
||||
view.getWindow()
|
||||
.match(
|
||||
Functions.<ViewData.AggregationWindowData>returnConstant(
|
||||
ViewData.AggregationWindowData.CumulativeData.create(
|
||||
ZERO_TIMESTAMP, ZERO_TIMESTAMP)),
|
||||
Functions.<ViewData.AggregationWindowData>returnConstant(
|
||||
ViewData.AggregationWindowData.IntervalData.create(ZERO_TIMESTAMP)),
|
||||
Functions.<ViewData.AggregationWindowData>throwAssertionError()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<View> getAllExportedViews() {
|
||||
Set<View> views = exportedViews;
|
||||
if (views == null) {
|
||||
synchronized (registeredViews) {
|
||||
exportedViews = views = filterExportedViews(registeredViews.values());
|
||||
}
|
||||
}
|
||||
return views;
|
||||
}
|
||||
|
||||
// Returns the subset of the given views that should be exported
|
||||
@SuppressWarnings("deprecation")
|
||||
private static Set<View> filterExportedViews(Collection<View> allViews) {
|
||||
Set<View> views = new HashSet<View>();
|
||||
for (View view : allViews) {
|
||||
if (view.getWindow() instanceof View.AggregationWindow.Interval) {
|
||||
continue;
|
||||
}
|
||||
views.add(view);
|
||||
}
|
||||
return Collections.unmodifiableSet(views);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.stats;
|
||||
|
||||
import openconsensus.internal.DefaultVisibilityForTesting;
|
||||
import openconsensus.internal.Provider;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Class for accessing the default {@link StatsComponent}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public final class Stats {
|
||||
private static final Logger logger = Logger.getLogger(Stats.class.getName());
|
||||
|
||||
private static final StatsComponent statsComponent =
|
||||
loadStatsComponent(StatsComponent.class.getClassLoader());
|
||||
|
||||
/**
|
||||
* Returns the default {@link StatsRecorder}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static StatsRecorder getStatsRecorder() {
|
||||
return statsComponent.getStatsRecorder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default {@link ViewManager}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static ViewManager getViewManager() {
|
||||
return statsComponent.getViewManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current {@code StatsCollectionState}.
|
||||
*
|
||||
* <p>When no implementation is available, {@code getState} always returns {@link
|
||||
* StatsCollectionState#DISABLED}.
|
||||
*
|
||||
* <p>Once {@link #getState()} is called, subsequent calls to {@link
|
||||
* #setState(StatsCollectionState)} will throw an {@code IllegalStateException}.
|
||||
*
|
||||
* @return the current {@code StatsCollectionState}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static StatsCollectionState getState() {
|
||||
return statsComponent.getState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current {@code StatsCollectionState}.
|
||||
*
|
||||
* <p>When no implementation is available, {@code setState} does not change the state.
|
||||
*
|
||||
* <p>If state is set to {@link StatsCollectionState#DISABLED}, all stats that are previously
|
||||
* recorded will be cleared.
|
||||
*
|
||||
* @param state the new {@code StatsCollectionState}.
|
||||
* @throws IllegalStateException if {@link #getState()} was previously called.
|
||||
* @deprecated This method is deprecated because other libraries could cache the result of {@link
|
||||
* #getState()}, use a stale value, and behave incorrectly. It is only safe to call early in
|
||||
* initialization. This method throws {@link IllegalStateException} after {@code getState()}
|
||||
* has been called, in order to limit changes to the result of {@code getState()}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Deprecated
|
||||
public static void setState(StatsCollectionState state) {
|
||||
statsComponent.setState(state);
|
||||
}
|
||||
|
||||
// Any provider that may be used for StatsComponent can be added here.
|
||||
@DefaultVisibilityForTesting
|
||||
static StatsComponent loadStatsComponent(@Nullable ClassLoader classLoader) {
|
||||
try {
|
||||
// Call Class.forName with literal string name of the class to help shading tools.
|
||||
return Provider.createInstance(
|
||||
Class.forName(
|
||||
"io.opencensus.impl.stats.StatsComponentImpl", /*initialize=*/ true, classLoader),
|
||||
StatsComponent.class);
|
||||
} catch (ClassNotFoundException e) {
|
||||
logger.log(
|
||||
Level.FINE,
|
||||
"Couldn't load full implementation for StatsComponent, now trying to load lite "
|
||||
+ "implementation.",
|
||||
e);
|
||||
}
|
||||
try {
|
||||
// Call Class.forName with literal string name of the class to help shading tools.
|
||||
return Provider.createInstance(
|
||||
Class.forName(
|
||||
"io.opencensus.impllite.stats.StatsComponentImplLite",
|
||||
/*initialize=*/ true,
|
||||
classLoader),
|
||||
StatsComponent.class);
|
||||
} catch (ClassNotFoundException e) {
|
||||
logger.log(
|
||||
Level.FINE,
|
||||
"Couldn't load lite implementation for StatsComponent, now using "
|
||||
+ "default implementation for StatsComponent.",
|
||||
e);
|
||||
}
|
||||
return NoopStats.newNoopStatsComponent();
|
||||
}
|
||||
|
||||
private Stats() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.stats;
|
||||
|
||||
/**
|
||||
* State of the {@link StatsComponent}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public enum StatsCollectionState {
|
||||
|
||||
/**
|
||||
* State that fully enables stats collection.
|
||||
*
|
||||
* <p>The {@link StatsComponent} collects stats for registered views.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
ENABLED,
|
||||
|
||||
/**
|
||||
* State that disables stats collection.
|
||||
*
|
||||
* <p>The {@link StatsComponent} does not need to collect stats for registered views and may
|
||||
* return empty {@link ViewData}s from {@link ViewManager#getView(View.Name)}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
DISABLED
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.stats;
|
||||
|
||||
/**
|
||||
* Class that holds the implementations for {@link ViewManager} and {@link StatsRecorder}.
|
||||
*
|
||||
* <p>All objects returned by methods on {@code StatsComponent} are cacheable.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract class StatsComponent {
|
||||
|
||||
/**
|
||||
* Returns the default {@link ViewManager}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract ViewManager getViewManager();
|
||||
|
||||
/**
|
||||
* Returns the default {@link StatsRecorder}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract StatsRecorder getStatsRecorder();
|
||||
|
||||
/**
|
||||
* Returns the current {@code StatsCollectionState}.
|
||||
*
|
||||
* <p>When no implementation is available, {@code getState} always returns {@link
|
||||
* StatsCollectionState#DISABLED}.
|
||||
*
|
||||
* <p>Once {@link #getState()} is called, subsequent calls to {@link
|
||||
* #setState(StatsCollectionState)} will throw an {@code IllegalStateException}.
|
||||
*
|
||||
* @return the current {@code StatsCollectionState}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract StatsCollectionState getState();
|
||||
|
||||
/**
|
||||
* Sets the current {@code StatsCollectionState}.
|
||||
*
|
||||
* <p>When no implementation is available, {@code setState} does not change the state.
|
||||
*
|
||||
* <p>If state is set to {@link StatsCollectionState#DISABLED}, all stats that are previously
|
||||
* recorded will be cleared.
|
||||
*
|
||||
* @param state the new {@code StatsCollectionState}.
|
||||
* @throws IllegalStateException if {@link #getState()} was previously called.
|
||||
* @deprecated This method is deprecated because other libraries could cache the result of {@link
|
||||
* #getState()}, use a stale value, and behave incorrectly. It is only safe to call early in
|
||||
* initialization. This method throws {@link IllegalStateException} after {@code getState()}
|
||||
* has been called, in order to limit changes to the result of {@code getState()}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract void setState(StatsCollectionState state);
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.stats;
|
||||
|
||||
/**
|
||||
* Provides methods to record stats against tags.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract class StatsRecorder {
|
||||
// TODO(sebright): Should we provide convenience methods for only recording one measure?
|
||||
|
||||
/**
|
||||
* Returns an object for recording multiple measurements.
|
||||
*
|
||||
* @return an object for recording multiple measurements.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract MeasureMap newMeasureMap();
|
||||
}
|
||||
|
|
@ -0,0 +1,306 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.stats;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.common.Duration;
|
||||
import openconsensus.common.Function;
|
||||
import openconsensus.internal.DefaultVisibilityForTesting;
|
||||
import openconsensus.internal.StringUtils;
|
||||
import openconsensus.internal.Utils;
|
||||
import openconsensus.tags.TagKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* A View specifies an aggregation and a set of tag keys. The aggregation will be broken down by the
|
||||
* unique set of matching tag values for each measure.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
@AutoValue.CopyAnnotations
|
||||
@SuppressWarnings("deprecation")
|
||||
public abstract class View {
|
||||
|
||||
@DefaultVisibilityForTesting static final int NAME_MAX_LENGTH = 255;
|
||||
|
||||
private static final Comparator<TagKey> TAG_KEY_COMPARATOR =
|
||||
new Comparator<TagKey>() {
|
||||
@Override
|
||||
public int compare(TagKey key1, TagKey key2) {
|
||||
return key1.getName().compareToIgnoreCase(key2.getName());
|
||||
}
|
||||
};
|
||||
|
||||
View() {}
|
||||
|
||||
/**
|
||||
* Name of view. Must be unique.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Name getName();
|
||||
|
||||
/**
|
||||
* More detailed description, for documentation purposes.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract String getDescription();
|
||||
|
||||
/**
|
||||
* Measure type of this view.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Measure getMeasure();
|
||||
|
||||
/**
|
||||
* The {@link Aggregation} associated with this {@link View}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Aggregation getAggregation();
|
||||
|
||||
/**
|
||||
* Columns (a.k.a Tag Keys) to match with the associated {@link Measure}.
|
||||
*
|
||||
* <p>{@link Measure} will be recorded in a "greedy" way. That is, every view aggregates every
|
||||
* measure. This is similar to doing a GROUPBY on view’s columns. Columns must be unique.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract List<TagKey> getColumns();
|
||||
|
||||
/**
|
||||
* Returns the time {@link AggregationWindow} for this {@code View}.
|
||||
*
|
||||
* @return the time {@link AggregationWindow}.
|
||||
* @since 0.1.0
|
||||
* @deprecated since 0.13. In the future all {@link View}s will be cumulative.
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract AggregationWindow getWindow();
|
||||
|
||||
/**
|
||||
* Constructs a new {@link View}.
|
||||
*
|
||||
* @param name the {@link Name} of view. Must be unique.
|
||||
* @param description the description of view.
|
||||
* @param measure the {@link Measure} to be aggregated by this view.
|
||||
* @param aggregation the basic {@link Aggregation} that this view will support.
|
||||
* @param columns the {@link TagKey}s that this view will aggregate on. Columns should not contain
|
||||
* duplicates.
|
||||
* @param window the {@link AggregationWindow} of view.
|
||||
* @return a new {@link View}.
|
||||
* @since 0.1.0
|
||||
* @deprecated in favor of {@link #create(Name, String, Measure, Aggregation, List)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static View create(
|
||||
Name name,
|
||||
String description,
|
||||
Measure measure,
|
||||
Aggregation aggregation,
|
||||
List<TagKey> columns,
|
||||
AggregationWindow window) {
|
||||
Utils.checkArgument(
|
||||
new HashSet<TagKey>(columns).size() == columns.size(), "Columns have duplicate.");
|
||||
|
||||
List<TagKey> tagKeys = new ArrayList<TagKey>(columns);
|
||||
Collections.sort(tagKeys, TAG_KEY_COMPARATOR);
|
||||
return new AutoValue_View(
|
||||
name, description, measure, aggregation, Collections.unmodifiableList(tagKeys), window);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link View}.
|
||||
*
|
||||
* @param name the {@link Name} of view. Must be unique.
|
||||
* @param description the description of view.
|
||||
* @param measure the {@link Measure} to be aggregated by this view.
|
||||
* @param aggregation the basic {@link Aggregation} that this view will support.
|
||||
* @param columns the {@link TagKey}s that this view will aggregate on. Columns should not contain
|
||||
* duplicates.
|
||||
* @return a new {@link View}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static View create(
|
||||
Name name,
|
||||
String description,
|
||||
Measure measure,
|
||||
Aggregation aggregation,
|
||||
List<TagKey> columns) {
|
||||
Utils.checkArgument(
|
||||
new HashSet<TagKey>(columns).size() == columns.size(), "Columns have duplicate.");
|
||||
return create(
|
||||
name, description, measure, aggregation, columns, AggregationWindow.Cumulative.create());
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of a {@code View}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
// This type should be used as the key when associating data with Views.
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract static class Name {
|
||||
|
||||
Name() {}
|
||||
|
||||
/**
|
||||
* Returns the name as a {@code String}.
|
||||
*
|
||||
* @return the name as a {@code String}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract String asString();
|
||||
|
||||
/**
|
||||
* Creates a {@code View.Name} from a {@code String}. Should be a ASCII string with a length no
|
||||
* greater than 255 characters.
|
||||
*
|
||||
* <p>Suggested format for name: {@code <web_host>/<path>}.
|
||||
*
|
||||
* @param name the name {@code String}.
|
||||
* @return a {@code View.Name} with the given name {@code String}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Name create(String name) {
|
||||
Utils.checkArgument(
|
||||
StringUtils.isPrintableString(name) && name.length() <= NAME_MAX_LENGTH,
|
||||
"Name should be a ASCII string with a length no greater than 255 characters.");
|
||||
return new AutoValue_View_Name(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The time window for a {@code View}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
* @deprecated since 0.13. In the future all {@link View}s will be cumulative.
|
||||
*/
|
||||
@Deprecated
|
||||
@Immutable
|
||||
public abstract static class AggregationWindow {
|
||||
|
||||
private AggregationWindow() {}
|
||||
|
||||
/**
|
||||
* Applies the given match function to the underlying data type.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract <T> T match(
|
||||
Function<? super Cumulative, T> p0,
|
||||
Function<? super Interval, T> p1,
|
||||
Function<? super AggregationWindow, T> defaultFunction);
|
||||
|
||||
/**
|
||||
* Cumulative (infinite interval) time {@code AggregationWindow}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
* @deprecated since 0.13. In the future all {@link View}s will be cumulative.
|
||||
*/
|
||||
@Deprecated
|
||||
@Immutable
|
||||
@AutoValue
|
||||
@AutoValue.CopyAnnotations
|
||||
public abstract static class Cumulative extends AggregationWindow {
|
||||
|
||||
private static final Cumulative CUMULATIVE =
|
||||
new AutoValue_View_AggregationWindow_Cumulative();
|
||||
|
||||
Cumulative() {}
|
||||
|
||||
/**
|
||||
* Constructs a cumulative {@code AggregationWindow} that does not have an explicit {@code
|
||||
* Duration}. Instead, cumulative {@code AggregationWindow} always has an interval of infinite
|
||||
* {@code Duration}.
|
||||
*
|
||||
* @return a cumulative {@code AggregationWindow}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Cumulative create() {
|
||||
return CUMULATIVE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super Cumulative, T> p0,
|
||||
Function<? super Interval, T> p1,
|
||||
Function<? super AggregationWindow, T> defaultFunction) {
|
||||
return p0.apply(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interval (finite interval) time {@code AggregationWindow}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
* @deprecated since 0.13. In the future all {@link View}s will be cumulative.
|
||||
*/
|
||||
@Deprecated
|
||||
@Immutable
|
||||
@AutoValue
|
||||
@AutoValue.CopyAnnotations
|
||||
public abstract static class Interval extends AggregationWindow {
|
||||
|
||||
private static final Duration ZERO = Duration.create(0, 0);
|
||||
|
||||
Interval() {}
|
||||
|
||||
/**
|
||||
* Returns the {@code Duration} associated with this {@code Interval}.
|
||||
*
|
||||
* @return a {@code Duration}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Duration getDuration();
|
||||
|
||||
/**
|
||||
* Constructs an interval {@code AggregationWindow} that has a finite explicit {@code
|
||||
* Duration}.
|
||||
*
|
||||
* <p>The {@code Duration} should be able to round to milliseconds. Currently interval window
|
||||
* cannot have smaller {@code Duration} such as microseconds or nanoseconds.
|
||||
*
|
||||
* @return an interval {@code AggregationWindow}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Interval create(Duration duration) {
|
||||
Utils.checkArgument(duration.compareTo(ZERO) > 0, "Duration must be positive");
|
||||
return new AutoValue_View_AggregationWindow_Interval(duration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super Cumulative, T> p0,
|
||||
Function<? super Interval, T> p1,
|
||||
Function<? super AggregationWindow, T> defaultFunction) {
|
||||
return p1.apply(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,461 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.stats;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.common.Duration;
|
||||
import openconsensus.common.Function;
|
||||
import openconsensus.common.Functions;
|
||||
import openconsensus.common.Timestamp;
|
||||
import openconsensus.stats.Aggregation.Count;
|
||||
import openconsensus.stats.Aggregation.Distribution;
|
||||
import openconsensus.stats.Aggregation.LastValue;
|
||||
import openconsensus.stats.Aggregation.Sum;
|
||||
import openconsensus.stats.AggregationData.CountData;
|
||||
import openconsensus.stats.AggregationData.DistributionData;
|
||||
import openconsensus.stats.AggregationData.LastValueDataDouble;
|
||||
import openconsensus.stats.AggregationData.LastValueDataLong;
|
||||
import openconsensus.stats.AggregationData.SumDataDouble;
|
||||
import openconsensus.stats.AggregationData.SumDataLong;
|
||||
import openconsensus.stats.Measure.MeasureDouble;
|
||||
import openconsensus.stats.Measure.MeasureLong;
|
||||
import openconsensus.tags.TagValue;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/*>>>
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
*/
|
||||
|
||||
/**
|
||||
* The aggregated data for a particular {@link View}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
@AutoValue.CopyAnnotations
|
||||
@SuppressWarnings("deprecation")
|
||||
public abstract class ViewData {
|
||||
|
||||
// Prevents this class from being subclassed anywhere else.
|
||||
ViewData() {}
|
||||
|
||||
/**
|
||||
* The {@link View} associated with this {@link ViewData}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract View getView();
|
||||
|
||||
/**
|
||||
* The {@link AggregationData} grouped by combination of tag values, associated with this {@link
|
||||
* ViewData}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Map<List</*@Nullable*/ TagValue>, AggregationData> getAggregationMap();
|
||||
|
||||
/**
|
||||
* Returns the {@link AggregationWindowData} associated with this {@link ViewData}.
|
||||
*
|
||||
* <p>{@link AggregationWindowData} is deprecated since 0.13, please avoid using this method. Use
|
||||
* {@link #getStart()} and {@link #getEnd()} instead.
|
||||
*
|
||||
* @return the {@code AggregationWindowData}.
|
||||
* @since 0.1.0
|
||||
* @deprecated in favor of {@link #getStart()} and {@link #getEnd()}.
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract AggregationWindowData getWindowData();
|
||||
|
||||
/**
|
||||
* Returns the start {@code Timestamp} for a {@link ViewData}.
|
||||
*
|
||||
* @return the start {@code Timestamp}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Timestamp getStart();
|
||||
|
||||
/**
|
||||
* Returns the end {@code Timestamp} for a {@link ViewData}.
|
||||
*
|
||||
* @return the end {@code Timestamp}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Timestamp getEnd();
|
||||
|
||||
/**
|
||||
* Constructs a new {@link ViewData}.
|
||||
*
|
||||
* @param view the {@link View} associated with this {@link ViewData}.
|
||||
* @param map the mapping from {@link TagValue} list to {@link AggregationData}.
|
||||
* @param windowData the {@link AggregationWindowData}.
|
||||
* @return a {@code ViewData}.
|
||||
* @throws IllegalArgumentException if the types of {@code Aggregation} and {@code
|
||||
* AggregationData} don't match, or the types of {@code Window} and {@code WindowData} don't
|
||||
* match.
|
||||
* @since 0.1.0
|
||||
* @deprecated in favor of {@link #create(View, Map, Timestamp, Timestamp)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static ViewData create(
|
||||
final View view,
|
||||
Map<? extends List</*@Nullable*/ TagValue>, ? extends AggregationData> map,
|
||||
final AggregationWindowData windowData) {
|
||||
checkWindow(view.getWindow(), windowData);
|
||||
final Map<List</*@Nullable*/ TagValue>, AggregationData> deepCopy =
|
||||
new HashMap<List</*@Nullable*/ TagValue>, AggregationData>();
|
||||
for (Entry<? extends List</*@Nullable*/ TagValue>, ? extends AggregationData> entry :
|
||||
map.entrySet()) {
|
||||
checkAggregation(view.getAggregation(), entry.getValue(), view.getMeasure());
|
||||
deepCopy.put(
|
||||
Collections.unmodifiableList(new ArrayList</*@Nullable*/ TagValue>(entry.getKey())),
|
||||
entry.getValue());
|
||||
}
|
||||
return windowData.match(
|
||||
new Function<ViewData.AggregationWindowData.CumulativeData, ViewData>() {
|
||||
@Override
|
||||
public ViewData apply(ViewData.AggregationWindowData.CumulativeData arg) {
|
||||
return createInternal(
|
||||
view, Collections.unmodifiableMap(deepCopy), arg, arg.getStart(), arg.getEnd());
|
||||
}
|
||||
},
|
||||
new Function<ViewData.AggregationWindowData.IntervalData, ViewData>() {
|
||||
@Override
|
||||
public ViewData apply(ViewData.AggregationWindowData.IntervalData arg) {
|
||||
Duration duration = ((View.AggregationWindow.Interval) view.getWindow()).getDuration();
|
||||
return createInternal(
|
||||
view,
|
||||
Collections.unmodifiableMap(deepCopy),
|
||||
arg,
|
||||
arg.getEnd()
|
||||
.addDuration(Duration.create(-duration.getSeconds(), -duration.getNanos())),
|
||||
arg.getEnd());
|
||||
}
|
||||
},
|
||||
Functions.<ViewData>throwAssertionError());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link ViewData}.
|
||||
*
|
||||
* @param view the {@link View} associated with this {@link ViewData}.
|
||||
* @param map the mapping from {@link TagValue} list to {@link AggregationData}.
|
||||
* @param start the start {@link Timestamp} for this {@link ViewData}.
|
||||
* @param end the end {@link Timestamp} for this {@link ViewData}.
|
||||
* @return a {@code ViewData}.
|
||||
* @throws IllegalArgumentException if the types of {@code Aggregation} and {@code
|
||||
* AggregationData} don't match.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static ViewData create(
|
||||
View view,
|
||||
Map<? extends List</*@Nullable*/ TagValue>, ? extends AggregationData> map,
|
||||
Timestamp start,
|
||||
Timestamp end) {
|
||||
Map<List</*@Nullable*/ TagValue>, AggregationData> deepCopy =
|
||||
new HashMap<List</*@Nullable*/ TagValue>, AggregationData>();
|
||||
for (Entry<? extends List</*@Nullable*/ TagValue>, ? extends AggregationData> entry :
|
||||
map.entrySet()) {
|
||||
checkAggregation(view.getAggregation(), entry.getValue(), view.getMeasure());
|
||||
deepCopy.put(
|
||||
Collections.unmodifiableList(new ArrayList</*@Nullable*/ TagValue>(entry.getKey())),
|
||||
entry.getValue());
|
||||
}
|
||||
return createInternal(
|
||||
view,
|
||||
Collections.unmodifiableMap(deepCopy),
|
||||
AggregationWindowData.CumulativeData.create(start, end),
|
||||
start,
|
||||
end);
|
||||
}
|
||||
|
||||
// Suppresses a nullness warning about calls to the AutoValue_ViewData constructor. The generated
|
||||
// constructor does not have the @Nullable annotation on TagValue.
|
||||
private static ViewData createInternal(
|
||||
View view,
|
||||
Map<List</*@Nullable*/ TagValue>, AggregationData> aggregationMap,
|
||||
AggregationWindowData window,
|
||||
Timestamp start,
|
||||
Timestamp end) {
|
||||
@SuppressWarnings("nullness")
|
||||
Map<List<TagValue>, AggregationData> map = aggregationMap;
|
||||
return new AutoValue_ViewData(view, map, window, start, end);
|
||||
}
|
||||
|
||||
private static void checkWindow(
|
||||
View.AggregationWindow window, final AggregationWindowData windowData) {
|
||||
window.match(
|
||||
new Function<View.AggregationWindow.Cumulative, Void>() {
|
||||
@Override
|
||||
public Void apply(View.AggregationWindow.Cumulative arg) {
|
||||
throwIfWindowMismatch(
|
||||
windowData instanceof AggregationWindowData.CumulativeData, arg, windowData);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
new Function<View.AggregationWindow.Interval, Void>() {
|
||||
@Override
|
||||
public Void apply(View.AggregationWindow.Interval arg) {
|
||||
throwIfWindowMismatch(
|
||||
windowData instanceof AggregationWindowData.IntervalData, arg, windowData);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
Functions.</*@Nullable*/ Void>throwAssertionError());
|
||||
}
|
||||
|
||||
private static void throwIfWindowMismatch(
|
||||
boolean isValid, View.AggregationWindow window, AggregationWindowData windowData) {
|
||||
if (!isValid) {
|
||||
throw new IllegalArgumentException(createErrorMessageForWindow(window, windowData));
|
||||
}
|
||||
}
|
||||
|
||||
private static String createErrorMessageForWindow(
|
||||
View.AggregationWindow window, AggregationWindowData windowData) {
|
||||
return "AggregationWindow and AggregationWindowData types mismatch. "
|
||||
+ "AggregationWindow: "
|
||||
+ window.getClass().getSimpleName()
|
||||
+ " AggregationWindowData: "
|
||||
+ windowData.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
private static void checkAggregation(
|
||||
final Aggregation aggregation, final AggregationData aggregationData, final Measure measure) {
|
||||
aggregation.match(
|
||||
new Function<Sum, Void>() {
|
||||
@Override
|
||||
public Void apply(Sum arg) {
|
||||
measure.match(
|
||||
new Function<MeasureDouble, Void>() {
|
||||
@Override
|
||||
public Void apply(MeasureDouble arg) {
|
||||
throwIfAggregationMismatch(
|
||||
aggregationData instanceof SumDataDouble, aggregation, aggregationData);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
new Function<MeasureLong, Void>() {
|
||||
@Override
|
||||
public Void apply(MeasureLong arg) {
|
||||
throwIfAggregationMismatch(
|
||||
aggregationData instanceof SumDataLong, aggregation, aggregationData);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
Functions.</*@Nullable*/ Void>throwAssertionError());
|
||||
return null;
|
||||
}
|
||||
},
|
||||
new Function<Count, Void>() {
|
||||
@Override
|
||||
public Void apply(Count arg) {
|
||||
throwIfAggregationMismatch(
|
||||
aggregationData instanceof CountData, aggregation, aggregationData);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
new Function<Distribution, Void>() {
|
||||
@Override
|
||||
public Void apply(Distribution arg) {
|
||||
throwIfAggregationMismatch(
|
||||
aggregationData instanceof DistributionData, aggregation, aggregationData);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
new Function<LastValue, Void>() {
|
||||
@Override
|
||||
public Void apply(LastValue arg) {
|
||||
measure.match(
|
||||
new Function<MeasureDouble, Void>() {
|
||||
@Override
|
||||
public Void apply(MeasureDouble arg) {
|
||||
throwIfAggregationMismatch(
|
||||
aggregationData instanceof LastValueDataDouble,
|
||||
aggregation,
|
||||
aggregationData);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
new Function<MeasureLong, Void>() {
|
||||
@Override
|
||||
public Void apply(MeasureLong arg) {
|
||||
throwIfAggregationMismatch(
|
||||
aggregationData instanceof LastValueDataLong, aggregation, aggregationData);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
Functions.</*@Nullable*/ Void>throwAssertionError());
|
||||
return null;
|
||||
}
|
||||
},
|
||||
new Function<Aggregation, Void>() {
|
||||
@Override
|
||||
public Void apply(Aggregation arg) {
|
||||
// TODO(songya): remove this once Mean aggregation is completely removed. Before that
|
||||
// we need to continue supporting Mean, since it could still be used by users and some
|
||||
// deprecated RPC views.
|
||||
if (arg instanceof Aggregation.Mean) {
|
||||
throwIfAggregationMismatch(
|
||||
aggregationData instanceof AggregationData.MeanData,
|
||||
aggregation,
|
||||
aggregationData);
|
||||
return null;
|
||||
}
|
||||
throw new AssertionError();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void throwIfAggregationMismatch(
|
||||
boolean isValid, Aggregation aggregation, AggregationData aggregationData) {
|
||||
if (!isValid) {
|
||||
throw new IllegalArgumentException(
|
||||
createErrorMessageForAggregation(aggregation, aggregationData));
|
||||
}
|
||||
}
|
||||
|
||||
private static String createErrorMessageForAggregation(
|
||||
Aggregation aggregation, AggregationData aggregationData) {
|
||||
return "Aggregation and AggregationData types mismatch. "
|
||||
+ "Aggregation: "
|
||||
+ aggregation.getClass().getSimpleName()
|
||||
+ " AggregationData: "
|
||||
+ aggregationData.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@code AggregationWindowData} for a {@link ViewData}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
* @deprecated since 0.13, please use start and end {@link Timestamp} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@Immutable
|
||||
public abstract static class AggregationWindowData {
|
||||
|
||||
private AggregationWindowData() {}
|
||||
|
||||
/**
|
||||
* Applies the given match function to the underlying data type.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract <T> T match(
|
||||
Function<? super CumulativeData, T> p0,
|
||||
Function<? super IntervalData, T> p1,
|
||||
Function<? super AggregationWindowData, T> defaultFunction);
|
||||
|
||||
/**
|
||||
* Cumulative {@code AggregationWindowData}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
* @deprecated since 0.13, please use start and end {@link Timestamp} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@Immutable
|
||||
@AutoValue
|
||||
@AutoValue.CopyAnnotations
|
||||
public abstract static class CumulativeData extends AggregationWindowData {
|
||||
|
||||
CumulativeData() {}
|
||||
|
||||
/**
|
||||
* Returns the start {@code Timestamp} for a {@link CumulativeData}.
|
||||
*
|
||||
* @return the start {@code Timestamp}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Timestamp getStart();
|
||||
|
||||
/**
|
||||
* Returns the end {@code Timestamp} for a {@link CumulativeData}.
|
||||
*
|
||||
* @return the end {@code Timestamp}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Timestamp getEnd();
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super CumulativeData, T> p0,
|
||||
Function<? super IntervalData, T> p1,
|
||||
Function<? super AggregationWindowData, T> defaultFunction) {
|
||||
return p0.apply(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link CumulativeData}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static CumulativeData create(Timestamp start, Timestamp end) {
|
||||
if (start.compareTo(end) > 0) {
|
||||
throw new IllegalArgumentException("Start time is later than end time.");
|
||||
}
|
||||
return new AutoValue_ViewData_AggregationWindowData_CumulativeData(start, end);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interval {@code AggregationWindowData}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
* @deprecated since 0.13, please use start and end {@link Timestamp} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@Immutable
|
||||
@AutoValue
|
||||
@AutoValue.CopyAnnotations
|
||||
public abstract static class IntervalData extends AggregationWindowData {
|
||||
|
||||
IntervalData() {}
|
||||
|
||||
/**
|
||||
* Returns the end {@code Timestamp} for an {@link IntervalData}.
|
||||
*
|
||||
* @return the end {@code Timestamp}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Timestamp getEnd();
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super CumulativeData, T> p0,
|
||||
Function<? super IntervalData, T> p1,
|
||||
Function<? super AggregationWindowData, T> defaultFunction) {
|
||||
return p1.apply(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link IntervalData}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static IntervalData create(Timestamp end) {
|
||||
return new AutoValue_ViewData_AggregationWindowData_IntervalData(end);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.stats;
|
||||
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Provides facilities to register {@link View}s for collecting stats and retrieving stats data as a
|
||||
* {@link ViewData}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract class ViewManager {
|
||||
/**
|
||||
* Pull model for stats. Registers a {@link View} that will collect data to be accessed via {@link
|
||||
* #getView(View.Name)}.
|
||||
*
|
||||
* @param view the {@code View} to be registered.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract void registerView(View view);
|
||||
|
||||
/**
|
||||
* Returns the current stats data, {@link ViewData}, associated with the given view name.
|
||||
*
|
||||
* <p>Returns {@code null} if the {@code View} is not registered.
|
||||
*
|
||||
* @param view the name of {@code View} for the current stats.
|
||||
* @return {@code ViewData} for the {@code View}, or {@code null} if the {@code View} is not
|
||||
* registered.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Nullable
|
||||
public abstract ViewData getView(View.Name view);
|
||||
|
||||
/**
|
||||
* Returns all registered views that should be exported.
|
||||
*
|
||||
* <p>This method should be used by any stats exporter that automatically exports data for views
|
||||
* registered with the {@link ViewManager}.
|
||||
*
|
||||
* @return all registered views that should be exported.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Set<View> getAllExportedViews();
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/** API for stats recording. */
|
||||
// TODO: Add more details.
|
||||
// TODO: Add code examples.
|
||||
package openconsensus.stats;
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.tags;
|
||||
|
||||
import java.util.Iterator;
|
||||
import openconsensus.common.Internal;
|
||||
|
||||
/**
|
||||
* Internal tagging utilities.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Internal
|
||||
public final class InternalUtils {
|
||||
private InternalUtils() {}
|
||||
|
||||
/**
|
||||
* Internal tag accessor.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Iterator<Tag> getTags(TagContext tags) {
|
||||
return tags.getIterator();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.tags;
|
||||
|
||||
import openconsensus.common.Scope;
|
||||
import openconsensus.internal.NoopScope;
|
||||
import openconsensus.internal.Utils;
|
||||
import openconsensus.tags.propagation.TagContextBinarySerializer;
|
||||
import openconsensus.tags.propagation.TagPropagationComponent;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
/** No-op implementations of tagging classes. */
|
||||
final class NoopTags {
|
||||
|
||||
private NoopTags() {}
|
||||
|
||||
/**
|
||||
* Returns a {@code TagsComponent} that has a no-op implementation for {@link Tagger}.
|
||||
*
|
||||
* @return a {@code TagsComponent} that has a no-op implementation for {@code Tagger}.
|
||||
*/
|
||||
static TagsComponent newNoopTagsComponent() {
|
||||
return new NoopTagsComponent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Tagger} that only produces {@link TagContext}s with no tags.
|
||||
*
|
||||
* @return a {@code Tagger} that only produces {@code TagContext}s with no tags.
|
||||
*/
|
||||
static Tagger getNoopTagger() {
|
||||
return NoopTagger.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code TagContextBuilder} that ignores all calls to {@link TagContextBuilder#put}.
|
||||
*
|
||||
* @return a {@code TagContextBuilder} that ignores all calls to {@link TagContextBuilder#put}.
|
||||
*/
|
||||
static TagContextBuilder getNoopTagContextBuilder() {
|
||||
return NoopTagContextBuilder.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code TagContext} that does not contain any tags.
|
||||
*
|
||||
* @return a {@code TagContext} that does not contain any tags.
|
||||
*/
|
||||
static TagContext getNoopTagContext() {
|
||||
return NoopTagContext.INSTANCE;
|
||||
}
|
||||
|
||||
/** Returns a {@code TagPropagationComponent} that contains no-op serializers. */
|
||||
static TagPropagationComponent getNoopTagPropagationComponent() {
|
||||
return NoopTagPropagationComponent.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code TagContextBinarySerializer} that serializes all {@code TagContext}s to zero
|
||||
* bytes and deserializes all inputs to empty {@code TagContext}s.
|
||||
*/
|
||||
static TagContextBinarySerializer getNoopTagContextBinarySerializer() {
|
||||
return NoopTagContextBinarySerializer.INSTANCE;
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
private static final class NoopTagsComponent extends TagsComponent {
|
||||
private volatile boolean isRead;
|
||||
|
||||
@Override
|
||||
public Tagger getTagger() {
|
||||
return getNoopTagger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagPropagationComponent getTagPropagationComponent() {
|
||||
return getNoopTagPropagationComponent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaggingState getState() {
|
||||
isRead = true;
|
||||
return TaggingState.DISABLED;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void setState(TaggingState state) {
|
||||
Utils.checkNotNull(state, "state");
|
||||
Utils.checkState(!isRead, "State was already read, cannot set state.");
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
private static final class NoopTagger extends Tagger {
|
||||
static final Tagger INSTANCE = new NoopTagger();
|
||||
|
||||
@Override
|
||||
public TagContext empty() {
|
||||
return getNoopTagContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagContext getCurrentTagContext() {
|
||||
return getNoopTagContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagContextBuilder emptyBuilder() {
|
||||
return getNoopTagContextBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagContextBuilder toBuilder(TagContext tags) {
|
||||
Utils.checkNotNull(tags, "tags");
|
||||
return getNoopTagContextBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagContextBuilder currentBuilder() {
|
||||
return getNoopTagContextBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Scope withTagContext(TagContext tags) {
|
||||
Utils.checkNotNull(tags, "tags");
|
||||
return NoopScope.getInstance();
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
private static final class NoopTagContextBuilder extends TagContextBuilder {
|
||||
static final TagContextBuilder INSTANCE = new NoopTagContextBuilder();
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public TagContextBuilder put(TagKey key, TagValue value) {
|
||||
Utils.checkNotNull(key, "key");
|
||||
Utils.checkNotNull(value, "value");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagContextBuilder put(TagKey key, TagValue value, TagMetadata tagMetadata) {
|
||||
Utils.checkNotNull(key, "key");
|
||||
Utils.checkNotNull(value, "value");
|
||||
Utils.checkNotNull(tagMetadata, "tagMetadata");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagContextBuilder remove(TagKey key) {
|
||||
Utils.checkNotNull(key, "key");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagContext build() {
|
||||
return getNoopTagContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Scope buildScoped() {
|
||||
return NoopScope.getInstance();
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
private static final class NoopTagContext extends TagContext {
|
||||
static final TagContext INSTANCE = new NoopTagContext();
|
||||
|
||||
// TODO(sebright): Is there any way to let the user know that their tags were ignored?
|
||||
@Override
|
||||
protected Iterator<Tag> getIterator() {
|
||||
return Collections.<Tag>emptySet().iterator();
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
private static final class NoopTagPropagationComponent extends TagPropagationComponent {
|
||||
static final TagPropagationComponent INSTANCE = new NoopTagPropagationComponent();
|
||||
|
||||
@Override
|
||||
public TagContextBinarySerializer getBinarySerializer() {
|
||||
return getNoopTagContextBinarySerializer();
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
private static final class NoopTagContextBinarySerializer extends TagContextBinarySerializer {
|
||||
static final TagContextBinarySerializer INSTANCE = new NoopTagContextBinarySerializer();
|
||||
static final byte[] EMPTY_BYTE_ARRAY = {};
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray(TagContext tags) {
|
||||
Utils.checkNotNull(tags, "tags");
|
||||
return EMPTY_BYTE_ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagContext fromByteArray(byte[] bytes) {
|
||||
Utils.checkNotNull(bytes, "bytes");
|
||||
return getNoopTagContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.tags;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.tags.TagMetadata.TagTtl;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* {@link TagKey} paired with a {@link TagValue}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract class Tag {
|
||||
|
||||
private static final TagMetadata METADATA_UNLIMITED_PROPAGATION =
|
||||
TagMetadata.create(TagTtl.UNLIMITED_PROPAGATION);
|
||||
|
||||
Tag() {}
|
||||
|
||||
/**
|
||||
* Creates a {@code Tag} from the given key and value.
|
||||
*
|
||||
* <p>For backwards-compatibility this method still produces propagating {@link Tag}s.
|
||||
*
|
||||
* <p>This is equivalent to calling {@code create(key, value,
|
||||
* TagMetadata.create(TagTtl.UNLIMITED_PROPAGATION))}.
|
||||
*
|
||||
* @param key the tag key.
|
||||
* @param value the tag value.
|
||||
* @return a {@code Tag} with the given key and value.
|
||||
* @since 0.1.0
|
||||
* @deprecated in favor of {@link #create(TagKey, TagValue, TagMetadata)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static Tag create(TagKey key, TagValue value) {
|
||||
return create(key, value, METADATA_UNLIMITED_PROPAGATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code Tag} from the given key, value and metadata.
|
||||
*
|
||||
* @param key the tag key.
|
||||
* @param value the tag value.
|
||||
* @param tagMetadata the tag metadata.
|
||||
* @return a {@code Tag}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Tag create(TagKey key, TagValue value, TagMetadata tagMetadata) {
|
||||
return new AutoValue_Tag(key, value, tagMetadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tag's key.
|
||||
*
|
||||
* @return the tag's key.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract TagKey getKey();
|
||||
|
||||
/**
|
||||
* Returns the tag's value.
|
||||
*
|
||||
* @return the tag's value.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract TagValue getValue();
|
||||
|
||||
/**
|
||||
* Returns the {@link TagMetadata} associated with this {@link Tag}.
|
||||
*
|
||||
* @return the {@code TagMetadata}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract TagMetadata getTagMetadata();
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.tags;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* A map from {@link TagKey} to {@link TagValue} that can be used to label anything that is
|
||||
* associated with a specific operation.
|
||||
*
|
||||
* <p>For example, {@code TagContext}s can be used to label stats, log messages, or debugging
|
||||
* information.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
public abstract class TagContext {
|
||||
|
||||
/**
|
||||
* Returns an iterator over the tags in this {@code TagContext}.
|
||||
*
|
||||
* @return an iterator over the tags in this {@code TagContext}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
// This method is protected to prevent client code from accessing the tags of any TagContext. We
|
||||
// don't currently support efficient access to tags. However, every TagContext subclass needs to
|
||||
// provide access to its tags to the stats and tagging implementations by implementing this
|
||||
// method. If we decide to support access to tags in the future, we can add a public iterator()
|
||||
// method and implement it for all subclasses by calling getIterator().
|
||||
//
|
||||
// The stats and tagging implementations can access any TagContext's tags through
|
||||
// InternalUtils.getTags, which calls this method.
|
||||
protected abstract Iterator<Tag> getIterator();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TagContext";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true iff the other object is an instance of {@code TagContext} and contains the same
|
||||
* key-value pairs. Implementations are free to override this method to provide better
|
||||
* performance.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(@Nullable Object other) {
|
||||
if (!(other instanceof TagContext)) {
|
||||
return false;
|
||||
}
|
||||
TagContext otherTags = (TagContext) other;
|
||||
Iterator<Tag> iter1 = getIterator();
|
||||
Iterator<Tag> iter2 = otherTags.getIterator();
|
||||
HashMap<Tag, Integer> tags = new HashMap<Tag, Integer>();
|
||||
while (iter1 != null && iter1.hasNext()) {
|
||||
Tag tag = iter1.next();
|
||||
if (tags.containsKey(tag)) {
|
||||
tags.put(tag, tags.get(tag) + 1);
|
||||
} else {
|
||||
tags.put(tag, 1);
|
||||
}
|
||||
}
|
||||
while (iter2 != null && iter2.hasNext()) {
|
||||
Tag tag = iter2.next();
|
||||
if (!tags.containsKey(tag)) {
|
||||
return false;
|
||||
}
|
||||
int count = tags.get(tag);
|
||||
if (count > 1) {
|
||||
tags.put(tag, count - 1);
|
||||
} else {
|
||||
tags.remove(tag);
|
||||
}
|
||||
}
|
||||
return tags.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
int hashCode = 0;
|
||||
Iterator<Tag> i = getIterator();
|
||||
if (i == null) {
|
||||
return hashCode;
|
||||
}
|
||||
while (i.hasNext()) {
|
||||
Tag tag = i.next();
|
||||
if (tag != null) {
|
||||
hashCode += tag.hashCode();
|
||||
}
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.tags;
|
||||
|
||||
import openconsensus.common.Scope;
|
||||
|
||||
/**
|
||||
* Builder for the {@link TagContext} class.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract class TagContextBuilder {
|
||||
|
||||
/**
|
||||
* Adds the key/value pair regardless of whether the key is present.
|
||||
*
|
||||
* <p>For backwards-compatibility this method still produces propagating {@link Tag}s.
|
||||
*
|
||||
* <p>Equivalent to calling {@code put(key, value,
|
||||
* TagMetadata.create(TagTtl.UNLIMITED_PROPAGATION))}.
|
||||
*
|
||||
* @param key the {@code TagKey} which will be set.
|
||||
* @param value the {@code TagValue} to set for the given key.
|
||||
* @return this
|
||||
* @since 0.1.0
|
||||
* @deprecated in favor of {@link #put(TagKey, TagValue, TagMetadata)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract TagContextBuilder put(TagKey key, TagValue value);
|
||||
|
||||
/**
|
||||
* Adds the key/value pair and metadata regardless of whether the key is present.
|
||||
*
|
||||
* @param key the {@code TagKey} which will be set.
|
||||
* @param value the {@code TagValue} to set for the given key.
|
||||
* @param tagMetadata the {@code TagMetadata} associated with this {@link Tag}.
|
||||
* @return this
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract TagContextBuilder put(TagKey key, TagValue value, TagMetadata tagMetadata);
|
||||
|
||||
/**
|
||||
* Removes the key if it exists.
|
||||
*
|
||||
* @param key the {@code TagKey} which will be removed.
|
||||
* @return this
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract TagContextBuilder remove(TagKey key);
|
||||
|
||||
/**
|
||||
* Creates a {@code TagContext} from this builder.
|
||||
*
|
||||
* @return a {@code TagContext} with the same tags as this builder.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract TagContext build();
|
||||
|
||||
/**
|
||||
* Enters the scope of code where the {@link TagContext} created from this builder is in the
|
||||
* current context and returns an object that represents that scope. The scope is exited when the
|
||||
* returned object is closed.
|
||||
*
|
||||
* @return an object that defines a scope where the {@code TagContext} created from this builder
|
||||
* is set to the current context.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Scope buildScoped();
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.tags;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.internal.StringUtils;
|
||||
import openconsensus.internal.Utils;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* A key to a value stored in a {@link TagContext}.
|
||||
*
|
||||
* <p>Each {@code TagKey} has a {@code String} name. Names have a maximum length of {@link
|
||||
* #MAX_LENGTH} and contain only printable ASCII characters.
|
||||
*
|
||||
* <p>{@code TagKey}s are designed to be used as constants. Declaring each key as a constant
|
||||
* prevents key names from being validated multiple times.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract class TagKey {
|
||||
/**
|
||||
* The maximum length for a tag key name. The value is {@value #MAX_LENGTH}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static final int MAX_LENGTH = 255;
|
||||
|
||||
TagKey() {}
|
||||
|
||||
/**
|
||||
* Constructs a {@code TagKey} with the given name.
|
||||
*
|
||||
* <p>The name must meet the following requirements:
|
||||
*
|
||||
* <ol>
|
||||
* <li>It cannot be longer than {@link #MAX_LENGTH}.
|
||||
* <li>It can only contain printable ASCII characters.
|
||||
* </ol>
|
||||
*
|
||||
* @param name the name of the key.
|
||||
* @return a {@code TagKey} with the given name.
|
||||
* @throws IllegalArgumentException if the name is not valid.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static TagKey create(String name) {
|
||||
Utils.checkArgument(isValid(name), "Invalid TagKey name: %s", name);
|
||||
return new AutoValue_TagKey(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the key.
|
||||
*
|
||||
* @return the name of the key.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract String getName();
|
||||
|
||||
/**
|
||||
* Determines whether the given {@code String} is a valid tag key.
|
||||
*
|
||||
* @param name the tag key name to be validated.
|
||||
* @return whether the name is valid.
|
||||
*/
|
||||
private static boolean isValid(String name) {
|
||||
return !name.isEmpty() && name.length() <= MAX_LENGTH && StringUtils.isPrintableString(name);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.tags;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* {@link TagMetadata} contains properties associated with a {@link Tag}.
|
||||
*
|
||||
* <p>For now only the property {@link TagTtl} is defined. In future, additional properties may be
|
||||
* added to address specific situations.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract class TagMetadata {
|
||||
|
||||
TagMetadata() {}
|
||||
|
||||
/**
|
||||
* Creates a {@link TagMetadata} with the given {@link TagTtl}.
|
||||
*
|
||||
* @param tagTtl TTL of a {@code Tag}.
|
||||
* @return a {@code TagMetadata}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static TagMetadata create(TagTtl tagTtl) {
|
||||
return new AutoValue_TagMetadata(tagTtl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link TagTtl} of this {@link TagMetadata}.
|
||||
*
|
||||
* @return the {@code TagTtl}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract TagTtl getTagTtl();
|
||||
|
||||
/**
|
||||
* {@link TagTtl} is an integer that represents number of hops a tag can propagate.
|
||||
*
|
||||
* <p>Anytime a sender serializes a tag, sends it over the wire and receiver deserializes the tag
|
||||
* then the tag is considered to have travelled one hop.
|
||||
*
|
||||
* <p>There could be one or more proxy(ies) between sender and receiver. Proxies are treated as
|
||||
* transparent entities and they are not counted as hops.
|
||||
*
|
||||
* <p>For now, only special values of {@link TagTtl} are supported.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public enum TagTtl {
|
||||
|
||||
/**
|
||||
* A {@link Tag} with {@link TagTtl#NO_PROPAGATION} is considered to have local scope and is
|
||||
* used within the process where it's created.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
NO_PROPAGATION(0),
|
||||
|
||||
/**
|
||||
* A {@link Tag} with {@link TagTtl#UNLIMITED_PROPAGATION} can propagate unlimited hops.
|
||||
*
|
||||
* <p>However, it is still subject to outgoing and incoming (on remote side) filter criteria.
|
||||
*
|
||||
* <p>{@link TagTtl#UNLIMITED_PROPAGATION} is typical used to track a request, which may be
|
||||
* processed across multiple entities.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
UNLIMITED_PROPAGATION(-1);
|
||||
|
||||
private final int hops;
|
||||
|
||||
private TagTtl(int hops) {
|
||||
this.hops = hops;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.tags;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.internal.StringUtils;
|
||||
import openconsensus.internal.Utils;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* A validated tag value.
|
||||
*
|
||||
* <p>Validation ensures that the {@code String} has a maximum length of {@link #MAX_LENGTH} and
|
||||
* contains only printable ASCII characters.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract class TagValue {
|
||||
/**
|
||||
* The maximum length for a tag value. The value is {@value #MAX_LENGTH}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static final int MAX_LENGTH = 255;
|
||||
|
||||
TagValue() {}
|
||||
|
||||
/**
|
||||
* Constructs a {@code TagValue} from the given string. The string must meet the following
|
||||
* requirements:
|
||||
*
|
||||
* <ol>
|
||||
* <li>It cannot be longer than {@link #MAX_LENGTH}.
|
||||
* <li>It can only contain printable ASCII characters.
|
||||
* </ol>
|
||||
*
|
||||
* @param value the tag value.
|
||||
* @throws IllegalArgumentException if the {@code String} is not valid.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static TagValue create(String value) {
|
||||
Utils.checkArgument(isValid(value), "Invalid TagValue: %s", value);
|
||||
return new AutoValue_TagValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tag value as a {@code String}.
|
||||
*
|
||||
* @return the tag value as a {@code String}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract String asString();
|
||||
|
||||
/**
|
||||
* Determines whether the given {@code String} is a valid tag value.
|
||||
*
|
||||
* @param value the tag value to be validated.
|
||||
* @return whether the value is valid.
|
||||
*/
|
||||
private static boolean isValid(String value) {
|
||||
return value.length() <= MAX_LENGTH && StringUtils.isPrintableString(value);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.tags;
|
||||
|
||||
import openconsensus.common.Scope;
|
||||
|
||||
/**
|
||||
* Object for creating new {@link TagContext}s and {@code TagContext}s based on the current context.
|
||||
*
|
||||
* <p>This class returns {@link TagContextBuilder builders} that can be used to create the
|
||||
* implementation-dependent {@link TagContext}s.
|
||||
*
|
||||
* <p>Implementations may have different constraints and are free to convert tag contexts to their
|
||||
* own subtypes. This means callers cannot assume the {@link #getCurrentTagContext() current
|
||||
* context} is the same instance as the one {@link #withTagContext(TagContext) placed into scope}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract class Tagger {
|
||||
|
||||
/**
|
||||
* Returns an empty {@code TagContext}.
|
||||
*
|
||||
* @return an empty {@code TagContext}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract TagContext empty();
|
||||
|
||||
/**
|
||||
* Returns the current {@code TagContext}.
|
||||
*
|
||||
* @return the current {@code TagContext}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract TagContext getCurrentTagContext();
|
||||
|
||||
/**
|
||||
* Returns a new empty {@code Builder}.
|
||||
*
|
||||
* @return a new empty {@code Builder}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract TagContextBuilder emptyBuilder();
|
||||
|
||||
/**
|
||||
* Returns a builder based on this {@code TagContext}.
|
||||
*
|
||||
* @return a builder based on this {@code TagContext}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract TagContextBuilder toBuilder(TagContext tags);
|
||||
|
||||
/**
|
||||
* Returns a new builder created from the current {@code TagContext}.
|
||||
*
|
||||
* @return a new builder created from the current {@code TagContext}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract TagContextBuilder currentBuilder();
|
||||
|
||||
/**
|
||||
* Enters the scope of code where the given {@code TagContext} is in the current context
|
||||
* (replacing the previous {@code TagContext}) and returns an object that represents that scope.
|
||||
* The scope is exited when the returned object is closed.
|
||||
*
|
||||
* @param tags the {@code TagContext} to be set to the current context.
|
||||
* @return an object that defines a scope where the given {@code TagContext} is set to the current
|
||||
* context.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Scope withTagContext(TagContext tags);
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.tags;
|
||||
|
||||
/**
|
||||
* State of the {@link TagsComponent}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public enum TaggingState {
|
||||
// TODO(sebright): Should we add a state that propagates the tags, but doesn't allow
|
||||
// modifications?
|
||||
|
||||
/**
|
||||
* State that fully enables tagging.
|
||||
*
|
||||
* <p>The {@link TagsComponent} can add tags to {@link TagContext}s, propagate {@code TagContext}s
|
||||
* in the current context, and serialize {@code TagContext}s.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
ENABLED,
|
||||
|
||||
/**
|
||||
* State that disables tagging.
|
||||
*
|
||||
* <p>The {@link TagsComponent} may not add tags to {@link TagContext}s, propagate {@code
|
||||
* TagContext}s in the current context, or serialize {@code TagContext}s.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
// TODO(sebright): Document how this interacts with stats collection.
|
||||
DISABLED
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.tags;
|
||||
|
||||
import openconsensus.internal.DefaultVisibilityForTesting;
|
||||
import openconsensus.internal.Provider;
|
||||
import openconsensus.tags.propagation.TagPropagationComponent;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Class for accessing the default {@link TagsComponent}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public final class Tags {
|
||||
private static final Logger logger = Logger.getLogger(Tags.class.getName());
|
||||
|
||||
private static final TagsComponent tagsComponent =
|
||||
loadTagsComponent(TagsComponent.class.getClassLoader());
|
||||
|
||||
private Tags() {}
|
||||
|
||||
/**
|
||||
* Returns the default {@code Tagger}.
|
||||
*
|
||||
* @return the default {@code Tagger}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Tagger getTagger() {
|
||||
return tagsComponent.getTagger();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default {@code TagPropagationComponent}.
|
||||
*
|
||||
* @return the default {@code TagPropagationComponent}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static TagPropagationComponent getTagPropagationComponent() {
|
||||
return tagsComponent.getTagPropagationComponent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current {@code TaggingState}.
|
||||
*
|
||||
* <p>When no implementation is available, {@code getState} always returns {@link
|
||||
* TaggingState#DISABLED}.
|
||||
*
|
||||
* <p>Once {@link #getState()} is called, subsequent calls to {@link #setState(TaggingState)} will
|
||||
* throw an {@code IllegalStateException}.
|
||||
*
|
||||
* @return the current {@code TaggingState}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static TaggingState getState() {
|
||||
return tagsComponent.getState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current {@code TaggingState}.
|
||||
*
|
||||
* <p>When no implementation is available, {@code setState} does not change the state.
|
||||
*
|
||||
* @param state the new {@code TaggingState}.
|
||||
* @throws IllegalStateException if {@link #getState()} was previously called.
|
||||
* @deprecated This method is deprecated because other libraries could cache the result of {@link
|
||||
* #getState()}, use a stale value, and behave incorrectly. It is only safe to call early in
|
||||
* initialization. This method throws {@link IllegalStateException} after {@link #getState()}
|
||||
* has been called, in order to limit changes to the result of {@code getState()}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Deprecated
|
||||
public static void setState(TaggingState state) {
|
||||
tagsComponent.setState(state);
|
||||
}
|
||||
|
||||
// Any provider that may be used for TagsComponent can be added here.
|
||||
@DefaultVisibilityForTesting
|
||||
static TagsComponent loadTagsComponent(@Nullable ClassLoader classLoader) {
|
||||
try {
|
||||
// Call Class.forName with literal string name of the class to help shading tools.
|
||||
return Provider.createInstance(
|
||||
Class.forName(
|
||||
"io.opencensus.impl.tags.TagsComponentImpl", /*initialize=*/ true, classLoader),
|
||||
TagsComponent.class);
|
||||
} catch (ClassNotFoundException e) {
|
||||
logger.log(
|
||||
Level.FINE,
|
||||
"Couldn't load full implementation for TagsComponent, now trying to load lite "
|
||||
+ "implementation.",
|
||||
e);
|
||||
}
|
||||
try {
|
||||
// Call Class.forName with literal string name of the class to help shading tools.
|
||||
return Provider.createInstance(
|
||||
Class.forName(
|
||||
"io.opencensus.impllite.tags.TagsComponentImplLite",
|
||||
/*initialize=*/ true,
|
||||
classLoader),
|
||||
TagsComponent.class);
|
||||
} catch (ClassNotFoundException e) {
|
||||
logger.log(
|
||||
Level.FINE,
|
||||
"Couldn't load lite implementation for TagsComponent, now using "
|
||||
+ "default implementation for TagsComponent.",
|
||||
e);
|
||||
}
|
||||
return NoopTags.newNoopTagsComponent();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.tags;
|
||||
|
||||
import openconsensus.tags.propagation.TagPropagationComponent;
|
||||
|
||||
/**
|
||||
* Class that holds the implementation for {@link Tagger} and {@link TagPropagationComponent}.
|
||||
*
|
||||
* <p>All objects returned by methods on {@code TagsComponent} are cacheable.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract class TagsComponent {
|
||||
|
||||
/**
|
||||
* Returns the {@link Tagger} for this implementation.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Tagger getTagger();
|
||||
|
||||
/**
|
||||
* Returns the {@link TagPropagationComponent} for this implementation.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract TagPropagationComponent getTagPropagationComponent();
|
||||
|
||||
/**
|
||||
* Returns the current {@code TaggingState}.
|
||||
*
|
||||
* <p>When no implementation is available, {@code getState} always returns {@link
|
||||
* TaggingState#DISABLED}.
|
||||
*
|
||||
* <p>Once {@link #getState()} is called, subsequent calls to {@link #setState(TaggingState)} will
|
||||
* throw an {@code IllegalStateException}.
|
||||
*
|
||||
* @return the current {@code TaggingState}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract TaggingState getState();
|
||||
|
||||
/**
|
||||
* Sets the current {@code TaggingState}.
|
||||
*
|
||||
* <p>When no implementation is available, {@code setState} does not change the state.
|
||||
*
|
||||
* @param state the new {@code TaggingState}.
|
||||
* @throws IllegalStateException if {@link #getState()} was previously called.
|
||||
* @deprecated This method is deprecated because other libraries could cache the result of {@link
|
||||
* #getState()}, use a stale value, and behave incorrectly. It is only safe to call early in
|
||||
* initialization. This method throws {@link IllegalStateException} after {@code getState()}
|
||||
* has been called, in order to limit changes to the result of {@code getState()}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract void setState(TaggingState state);
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* API for associating tags with scoped operations.
|
||||
*
|
||||
* <p>This package manages a set of tags in the {@code io.grpc.Context}. The tags can be used to
|
||||
* label anything that is associated with a specific operation. For example, the {@code
|
||||
* io.opencensus.stats} package labels all stats with the current tags.
|
||||
*
|
||||
* <p>{@link openconsensus.tags.Tag Tags} are key-value pairs. The {@link openconsensus.tags.TagKey
|
||||
* keys} and {@link openconsensus.tags.TagValue values} are wrapped {@code String}s. They are stored
|
||||
* as a map in a {@link openconsensus.tags.TagContext}.
|
||||
*
|
||||
* <p>Note that tags are independent of the tracing data that is propagated in the {@code
|
||||
* io.grpc.Context}, such as trace ID.
|
||||
*/
|
||||
// TODO(sebright): Add code examples.
|
||||
package openconsensus.tags;
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.tags.propagation;
|
||||
|
||||
import openconsensus.tags.Tag;
|
||||
import openconsensus.tags.TagContext;
|
||||
import openconsensus.tags.TagMetadata;
|
||||
import openconsensus.tags.TagMetadata.TagTtl;
|
||||
|
||||
/**
|
||||
* Object for serializing and deserializing {@link TagContext}s with the binary format.
|
||||
*
|
||||
* <p>See <a
|
||||
* href="https://github.com/census-instrumentation/opencensus-specs/blob/master/encodings/BinaryEncoding.md#tag-context">opencensus-specs</a>
|
||||
* for the specification of the cross-language binary serialization format.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract class TagContextBinarySerializer {
|
||||
|
||||
/**
|
||||
* Serializes the {@code TagContext} into the on-the-wire representation.
|
||||
*
|
||||
* <p>This method should be the inverse of {@link #fromByteArray}.
|
||||
*
|
||||
* <p>{@link Tag}s that have a {@link TagMetadata} with {@link TagTtl#NO_PROPAGATION} will not be
|
||||
* serialized.
|
||||
*
|
||||
* @param tags the {@code TagContext} to serialize.
|
||||
* @return the on-the-wire representation of a {@code TagContext}.
|
||||
* @throws TagContextSerializationException if the result would be larger than the maximum allowed
|
||||
* serialized size.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract byte[] toByteArray(TagContext tags) throws TagContextSerializationException;
|
||||
|
||||
/**
|
||||
* Creates a {@code TagContext} from the given on-the-wire encoded representation.
|
||||
*
|
||||
* <p>This method should be the inverse of {@link #toByteArray}.
|
||||
*
|
||||
* @param bytes on-the-wire representation of a {@code TagContext}.
|
||||
* @return a {@code TagContext} deserialized from {@code bytes}.
|
||||
* @throws TagContextDeserializationException if there is a parse error, the input contains
|
||||
* invalid tags, or the input is larger than the maximum allowed serialized size.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract TagContext fromByteArray(byte[] bytes) throws TagContextDeserializationException;
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.tags.propagation;
|
||||
|
||||
import openconsensus.tags.TagContext;
|
||||
|
||||
/**
|
||||
* Exception thrown when a {@link TagContext} cannot be parsed.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public final class TagContextDeserializationException extends Exception {
|
||||
private static final long serialVersionUID = 0L;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code TagContextParseException} with the given message.
|
||||
*
|
||||
* @param message a message describing the error.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public TagContextDeserializationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code TagContextParseException} with the given message and cause.
|
||||
*
|
||||
* @param message a message describing the error.
|
||||
* @param cause the cause of the error.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public TagContextDeserializationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.tags.propagation;
|
||||
|
||||
import openconsensus.tags.TagContext;
|
||||
|
||||
/**
|
||||
* Exception thrown when a {@link TagContext} cannot be serialized.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public final class TagContextSerializationException extends Exception {
|
||||
private static final long serialVersionUID = 0L;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code TagContextSerializationException} with the given message.
|
||||
*
|
||||
* @param message a message describing the error.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public TagContextSerializationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code TagContextSerializationException} with the given message and cause.
|
||||
*
|
||||
* @param message a message describing the error.
|
||||
* @param cause the cause of the error.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public TagContextSerializationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.tags.propagation;
|
||||
|
||||
import openconsensus.tags.TagContext;
|
||||
|
||||
/**
|
||||
* Object containing all supported {@link TagContext} propagation formats.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
// TODO(sebright): Add an HTTP serializer.
|
||||
public abstract class TagPropagationComponent {
|
||||
|
||||
/**
|
||||
* Returns the {@link TagContextBinarySerializer} for this implementation.
|
||||
*
|
||||
* @return the {@code TagContextBinarySerializer} for this implementation.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract TagContextBinarySerializer getBinarySerializer();
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.tags.unsafe;
|
||||
|
||||
import io.grpc.Context;
|
||||
import openconsensus.tags.Tag;
|
||||
import openconsensus.tags.TagContext;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* Utility methods for accessing the {@link TagContext} contained in the {@link io.grpc.Context}.
|
||||
*
|
||||
* <p>Most code should interact with the current context via the public APIs in {@link
|
||||
* TagContext} and avoid accessing {@link #TAG_CONTEXT_KEY} directly.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public final class ContextUtils {
|
||||
private static final TagContext EMPTY_TAG_CONTEXT = new EmptyTagContext();
|
||||
|
||||
private ContextUtils() {}
|
||||
|
||||
/**
|
||||
* The {@link io.grpc.Context.Key} used to interact with the {@code TagContext} contained in the
|
||||
* {@link io.grpc.Context}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static final Context.Key<TagContext> TAG_CONTEXT_KEY =
|
||||
Context.keyWithDefault("opencensus-tag-context-key", EMPTY_TAG_CONTEXT);
|
||||
|
||||
@Immutable
|
||||
private static final class EmptyTagContext extends TagContext {
|
||||
|
||||
@Override
|
||||
protected Iterator<Tag> getIterator() {
|
||||
return Collections.<Tag>emptySet().iterator();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.trace;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.internal.Utils;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* A text annotation with a set of attributes.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract class Annotation {
|
||||
private static final Map<String, AttributeValue> EMPTY_ATTRIBUTES =
|
||||
Collections.unmodifiableMap(Collections.<String, AttributeValue>emptyMap());
|
||||
|
||||
/**
|
||||
* Returns a new {@code Annotation} with the given description.
|
||||
*
|
||||
* @param description the text description of the {@code Annotation}.
|
||||
* @return a new {@code Annotation} with the given description.
|
||||
* @throws NullPointerException if {@code description} is {@code null}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Annotation fromDescription(String description) {
|
||||
return new AutoValue_Annotation(description, EMPTY_ATTRIBUTES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@code Annotation} with the given description and set of attributes.
|
||||
*
|
||||
* @param description the text description of the {@code Annotation}.
|
||||
* @param attributes the attributes of the {@code Annotation}.
|
||||
* @return a new {@code Annotation} with the given description and set of attributes.
|
||||
* @throws NullPointerException if {@code description} or {@code attributes} are {@code null}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Annotation fromDescriptionAndAttributes(
|
||||
String description, Map<String, AttributeValue> attributes) {
|
||||
return new AutoValue_Annotation(
|
||||
description,
|
||||
Collections.unmodifiableMap(
|
||||
new HashMap<String, AttributeValue>(Utils.checkNotNull(attributes, "attributes"))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the description of the {@code Annotation}.
|
||||
*
|
||||
* @return the description of the {@code Annotation}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract String getDescription();
|
||||
|
||||
/**
|
||||
* Return the attributes of the {@code Annotation}.
|
||||
*
|
||||
* @return the attributes of the {@code Annotation}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Map<String, AttributeValue> getAttributes();
|
||||
|
||||
Annotation() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.trace;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.common.Function;
|
||||
import openconsensus.common.Functions;
|
||||
import openconsensus.internal.Utils;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* A class that represents all the possible values for an attribute. An attribute can have 3 types
|
||||
* of values: {@code String}, {@code Boolean} or {@code Long}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
public abstract class AttributeValue {
|
||||
/**
|
||||
* Returns an {@code AttributeValue} with a string value.
|
||||
*
|
||||
* @param stringValue The new value.
|
||||
* @return an {@code AttributeValue} with a string value.
|
||||
* @throws NullPointerException if {@code stringValue} is {@code null}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static AttributeValue stringAttributeValue(String stringValue) {
|
||||
return AttributeValueString.create(stringValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@code AttributeValue} with a boolean value.
|
||||
*
|
||||
* @param booleanValue The new value.
|
||||
* @return an {@code AttributeValue} with a boolean value.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static AttributeValue booleanAttributeValue(boolean booleanValue) {
|
||||
return AttributeValueBoolean.create(booleanValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@code AttributeValue} with a long value.
|
||||
*
|
||||
* @param longValue The new value.
|
||||
* @return an {@code AttributeValue} with a long value.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static AttributeValue longAttributeValue(long longValue) {
|
||||
return AttributeValueLong.create(longValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@code AttributeValue} with a double value.
|
||||
*
|
||||
* @param doubleValue The new value.
|
||||
* @return an {@code AttributeValue} with a double value.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static AttributeValue doubleAttributeValue(double doubleValue) {
|
||||
return AttributeValueDouble.create(doubleValue);
|
||||
}
|
||||
|
||||
AttributeValue() {}
|
||||
|
||||
/**
|
||||
* Applies a function to the underlying value. The function that is called depends on the value's
|
||||
* type, which can be {@code String}, {@code Long}, or {@code Boolean}.
|
||||
*
|
||||
* @param stringFunction the function that should be applied if the value has type {@code String}.
|
||||
* @param longFunction the function that should be applied if the value has type {@code Long}.
|
||||
* @param booleanFunction the function that should be applied if the value has type {@code
|
||||
* Boolean}.
|
||||
* @param defaultFunction the function that should be applied if the value has a type that was
|
||||
* added after this {@code match} method was added to the API. See {@link
|
||||
* Functions} for some common functions for handling unknown types.
|
||||
* @return the result of the function applied to the underlying value.
|
||||
* @since 0.1.0
|
||||
* @deprecated in favor of {@link #match(Function, Function, Function, Function, Function)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract <T> T match(
|
||||
Function<? super String, T> stringFunction,
|
||||
Function<? super Boolean, T> booleanFunction,
|
||||
Function<? super Long, T> longFunction,
|
||||
Function<Object, T> defaultFunction);
|
||||
|
||||
/**
|
||||
* Applies a function to the underlying value. The function that is called depends on the value's
|
||||
* type, which can be {@code String}, {@code Long}, or {@code Boolean}.
|
||||
*
|
||||
* @param stringFunction the function that should be applied if the value has type {@code String}.
|
||||
* @param longFunction the function that should be applied if the value has type {@code Long}.
|
||||
* @param booleanFunction the function that should be applied if the value has type {@code
|
||||
* Boolean}.
|
||||
* @param doubleFunction the function that should be applied if the value has type {@code Double}.
|
||||
* @param defaultFunction the function that should be applied if the value has a type that was
|
||||
* added after this {@code match} method was added to the API. See {@link
|
||||
* Functions} for some common functions for handling unknown types.
|
||||
* @return the result of the function applied to the underlying value.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@SuppressWarnings("InconsistentOverloads")
|
||||
public abstract <T> T match(
|
||||
Function<? super String, T> stringFunction,
|
||||
Function<? super Boolean, T> booleanFunction,
|
||||
Function<? super Long, T> longFunction,
|
||||
Function<? super Double, T> doubleFunction,
|
||||
Function<Object, T> defaultFunction);
|
||||
|
||||
@Immutable
|
||||
@AutoValue
|
||||
abstract static class AttributeValueString extends AttributeValue {
|
||||
|
||||
AttributeValueString() {}
|
||||
|
||||
static AttributeValue create(String stringValue) {
|
||||
return new AutoValue_AttributeValue_AttributeValueString(
|
||||
Utils.checkNotNull(stringValue, "stringValue"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super String, T> stringFunction,
|
||||
Function<? super Boolean, T> booleanFunction,
|
||||
Function<? super Long, T> longFunction,
|
||||
Function<Object, T> defaultFunction) {
|
||||
return stringFunction.apply(getStringValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super String, T> stringFunction,
|
||||
Function<? super Boolean, T> booleanFunction,
|
||||
Function<? super Long, T> longFunction,
|
||||
Function<? super Double, T> doubleFunction,
|
||||
Function<Object, T> defaultFunction) {
|
||||
return stringFunction.apply(getStringValue());
|
||||
}
|
||||
|
||||
abstract String getStringValue();
|
||||
}
|
||||
|
||||
@Immutable
|
||||
@AutoValue
|
||||
abstract static class AttributeValueBoolean extends AttributeValue {
|
||||
|
||||
AttributeValueBoolean() {}
|
||||
|
||||
static AttributeValue create(Boolean booleanValue) {
|
||||
return new AutoValue_AttributeValue_AttributeValueBoolean(
|
||||
Utils.checkNotNull(booleanValue, "booleanValue"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super String, T> stringFunction,
|
||||
Function<? super Boolean, T> booleanFunction,
|
||||
Function<? super Long, T> longFunction,
|
||||
Function<Object, T> defaultFunction) {
|
||||
return booleanFunction.apply(getBooleanValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super String, T> stringFunction,
|
||||
Function<? super Boolean, T> booleanFunction,
|
||||
Function<? super Long, T> longFunction,
|
||||
Function<? super Double, T> doubleFunction,
|
||||
Function<Object, T> defaultFunction) {
|
||||
return booleanFunction.apply(getBooleanValue());
|
||||
}
|
||||
|
||||
abstract Boolean getBooleanValue();
|
||||
}
|
||||
|
||||
@Immutable
|
||||
@AutoValue
|
||||
abstract static class AttributeValueLong extends AttributeValue {
|
||||
|
||||
AttributeValueLong() {}
|
||||
|
||||
static AttributeValue create(Long longValue) {
|
||||
return new AutoValue_AttributeValue_AttributeValueLong(
|
||||
Utils.checkNotNull(longValue, "longValue"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super String, T> stringFunction,
|
||||
Function<? super Boolean, T> booleanFunction,
|
||||
Function<? super Long, T> longFunction,
|
||||
Function<Object, T> defaultFunction) {
|
||||
return longFunction.apply(getLongValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super String, T> stringFunction,
|
||||
Function<? super Boolean, T> booleanFunction,
|
||||
Function<? super Long, T> longFunction,
|
||||
Function<? super Double, T> doubleFunction,
|
||||
Function<Object, T> defaultFunction) {
|
||||
return longFunction.apply(getLongValue());
|
||||
}
|
||||
|
||||
abstract Long getLongValue();
|
||||
}
|
||||
|
||||
@Immutable
|
||||
@AutoValue
|
||||
abstract static class AttributeValueDouble extends AttributeValue {
|
||||
|
||||
AttributeValueDouble() {}
|
||||
|
||||
static AttributeValue create(Double doubleValue) {
|
||||
return new AutoValue_AttributeValue_AttributeValueDouble(
|
||||
Utils.checkNotNull(doubleValue, "doubleValue"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super String, T> stringFunction,
|
||||
Function<? super Boolean, T> booleanFunction,
|
||||
Function<? super Long, T> longFunction,
|
||||
Function<Object, T> defaultFunction) {
|
||||
return defaultFunction.apply(getDoubleValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T match(
|
||||
Function<? super String, T> stringFunction,
|
||||
Function<? super Boolean, T> booleanFunction,
|
||||
Function<? super Long, T> longFunction,
|
||||
Function<? super Double, T> doubleFunction,
|
||||
Function<Object, T> defaultFunction) {
|
||||
return doubleFunction.apply(getDoubleValue());
|
||||
}
|
||||
|
||||
abstract Double getDoubleValue();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.trace;
|
||||
|
||||
/**
|
||||
* Superclass for {@link MessageEvent} and {@link NetworkEvent} to resolve API backward
|
||||
* compatibility issue.
|
||||
*
|
||||
* <p>{@code SpanData.create} can't be overloaded with parameter types that differ only in the type
|
||||
* of the TimedEvent, because the signatures are the same after generic type erasure. {@code
|
||||
* BaseMessageEvent} allows the same method to accept both {@code TimedEvents<NetworkEvent>} and
|
||||
* {@code TimedEvents<MessageEvent>}.
|
||||
*
|
||||
* <p>This class should only be extended by {@code NetworkEvent} and {@code MessageEvent}.
|
||||
*
|
||||
* @deprecated This class is for internal use only.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class BaseMessageEvent {
|
||||
// package protected to avoid users to extend it.
|
||||
BaseMessageEvent() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.trace;
|
||||
|
||||
import openconsensus.internal.Utils;
|
||||
import java.util.Arrays;
|
||||
|
||||
final class BigendianEncoding {
|
||||
static final int LONG_BYTES = Long.SIZE / Byte.SIZE;
|
||||
static final int BYTE_BASE16 = 2;
|
||||
static final int LONG_BASE16 = BYTE_BASE16 * LONG_BYTES;
|
||||
private static final String ALPHABET = "0123456789abcdef";
|
||||
private static final int ASCII_CHARACTERS = 128;
|
||||
private static final char[] ENCODING = buildEncodingArray();
|
||||
private static final byte[] DECODING = buildDecodingArray();
|
||||
|
||||
private static char[] buildEncodingArray() {
|
||||
char[] encoding = new char[512];
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
encoding[i] = ALPHABET.charAt(i >>> 4);
|
||||
encoding[i | 0x100] = ALPHABET.charAt(i & 0xF);
|
||||
}
|
||||
return encoding;
|
||||
}
|
||||
|
||||
private static byte[] buildDecodingArray() {
|
||||
byte[] decoding = new byte[ASCII_CHARACTERS];
|
||||
Arrays.fill(decoding, (byte) -1);
|
||||
for (int i = 0; i < ALPHABET.length(); i++) {
|
||||
char c = ALPHABET.charAt(i);
|
||||
decoding[c] = (byte) i;
|
||||
}
|
||||
return decoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code long} value whose big-endian representation is stored in the first 8 bytes
|
||||
* of {@code bytes} starting from the {@code offset}.
|
||||
*
|
||||
* @param bytes the byte array representation of the {@code long}.
|
||||
* @param offset the starting offset in the byte array.
|
||||
* @return the {@code long} value whose big-endian representation is given.
|
||||
* @throws IllegalArgumentException if {@code bytes} has fewer than 8 elements.
|
||||
*/
|
||||
static long longFromByteArray(byte[] bytes, int offset) {
|
||||
Utils.checkArgument(bytes.length >= offset + LONG_BYTES, "array too small");
|
||||
return (bytes[offset] & 0xFFL) << 56
|
||||
| (bytes[offset + 1] & 0xFFL) << 48
|
||||
| (bytes[offset + 2] & 0xFFL) << 40
|
||||
| (bytes[offset + 3] & 0xFFL) << 32
|
||||
| (bytes[offset + 4] & 0xFFL) << 24
|
||||
| (bytes[offset + 5] & 0xFFL) << 16
|
||||
| (bytes[offset + 6] & 0xFFL) << 8
|
||||
| (bytes[offset + 7] & 0xFFL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the big-endian representation of {@code value} in the {@code dest} starting from the
|
||||
* {@code destOffset}.
|
||||
*
|
||||
* @param value the value to be converted.
|
||||
* @param dest the destination byte array.
|
||||
* @param destOffset the starting offset in the destination byte array.
|
||||
*/
|
||||
static void longToByteArray(long value, byte[] dest, int destOffset) {
|
||||
Utils.checkArgument(dest.length >= destOffset + LONG_BYTES, "array too small");
|
||||
dest[destOffset + 7] = (byte) (value & 0xFFL);
|
||||
dest[destOffset + 6] = (byte) (value >> 8 & 0xFFL);
|
||||
dest[destOffset + 5] = (byte) (value >> 16 & 0xFFL);
|
||||
dest[destOffset + 4] = (byte) (value >> 24 & 0xFFL);
|
||||
dest[destOffset + 3] = (byte) (value >> 32 & 0xFFL);
|
||||
dest[destOffset + 2] = (byte) (value >> 40 & 0xFFL);
|
||||
dest[destOffset + 1] = (byte) (value >> 48 & 0xFFL);
|
||||
dest[destOffset] = (byte) (value >> 56 & 0xFFL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code long} value whose base16 representation is stored in the first 16 chars of
|
||||
* {@code chars} starting from the {@code offset}.
|
||||
*
|
||||
* @param chars the base16 representation of the {@code long}.
|
||||
* @param offset the starting offset in the {@code CharSequence}.
|
||||
*/
|
||||
static long longFromBase16String(CharSequence chars, int offset) {
|
||||
Utils.checkArgument(chars.length() >= offset + LONG_BASE16, "chars too small");
|
||||
return (decodeByte(chars.charAt(offset), chars.charAt(offset + 1)) & 0xFFL) << 56
|
||||
| (decodeByte(chars.charAt(offset + 2), chars.charAt(offset + 3)) & 0xFFL) << 48
|
||||
| (decodeByte(chars.charAt(offset + 4), chars.charAt(offset + 5)) & 0xFFL) << 40
|
||||
| (decodeByte(chars.charAt(offset + 6), chars.charAt(offset + 7)) & 0xFFL) << 32
|
||||
| (decodeByte(chars.charAt(offset + 8), chars.charAt(offset + 9)) & 0xFFL) << 24
|
||||
| (decodeByte(chars.charAt(offset + 10), chars.charAt(offset + 11)) & 0xFFL) << 16
|
||||
| (decodeByte(chars.charAt(offset + 12), chars.charAt(offset + 13)) & 0xFFL) << 8
|
||||
| (decodeByte(chars.charAt(offset + 14), chars.charAt(offset + 15)) & 0xFFL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the base16 encoding of the specified {@code value} to the {@code dest}.
|
||||
*
|
||||
* @param value the value to be converted.
|
||||
* @param dest the destination char array.
|
||||
* @param destOffset the starting offset in the destination char array.
|
||||
*/
|
||||
static void longToBase16String(long value, char[] dest, int destOffset) {
|
||||
byteToBase16((byte) (value >> 56 & 0xFFL), dest, destOffset);
|
||||
byteToBase16((byte) (value >> 48 & 0xFFL), dest, destOffset + BYTE_BASE16);
|
||||
byteToBase16((byte) (value >> 40 & 0xFFL), dest, destOffset + 2 * BYTE_BASE16);
|
||||
byteToBase16((byte) (value >> 32 & 0xFFL), dest, destOffset + 3 * BYTE_BASE16);
|
||||
byteToBase16((byte) (value >> 24 & 0xFFL), dest, destOffset + 4 * BYTE_BASE16);
|
||||
byteToBase16((byte) (value >> 16 & 0xFFL), dest, destOffset + 5 * BYTE_BASE16);
|
||||
byteToBase16((byte) (value >> 8 & 0xFFL), dest, destOffset + 6 * BYTE_BASE16);
|
||||
byteToBase16((byte) (value & 0xFFL), dest, destOffset + 7 * BYTE_BASE16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the specified byte, and returns the encoded {@code String}.
|
||||
*
|
||||
* @param value the value to be converted.
|
||||
* @param dest the destination char array.
|
||||
* @param destOffset the starting offset in the destination char array.
|
||||
*/
|
||||
static void byteToBase16String(byte value, char[] dest, int destOffset) {
|
||||
byteToBase16(value, dest, destOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the specified two character sequence, and returns the resulting {@code byte}.
|
||||
*
|
||||
* @param chars the character sequence to be decoded.
|
||||
* @param offset the starting offset in the {@code CharSequence}.
|
||||
* @return the resulting {@code byte}
|
||||
* @throws IllegalArgumentException if the input is not a valid encoded string according to this
|
||||
* encoding.
|
||||
*/
|
||||
static byte byteFromBase16String(CharSequence chars, int offset) {
|
||||
Utils.checkArgument(chars.length() >= offset + 2, "chars too small");
|
||||
return decodeByte(chars.charAt(offset), chars.charAt(offset + 1));
|
||||
}
|
||||
|
||||
private static byte decodeByte(char hi, char lo) {
|
||||
Utils.checkArgument(lo < ASCII_CHARACTERS && DECODING[lo] != -1, "invalid character " + lo);
|
||||
Utils.checkArgument(hi < ASCII_CHARACTERS && DECODING[hi] != -1, "invalid character " + hi);
|
||||
int decoded = DECODING[hi] << 4 | DECODING[lo];
|
||||
return (byte) decoded;
|
||||
}
|
||||
|
||||
private static void byteToBase16(byte value, char[] dest, int destOffset) {
|
||||
int b = value & 0xFF;
|
||||
dest[destOffset] = ENCODING[b];
|
||||
dest[destOffset + 1] = ENCODING[b | 0x100];
|
||||
}
|
||||
|
||||
private BigendianEncoding() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.trace;
|
||||
|
||||
import openconsensus.internal.Utils;
|
||||
import java.util.Map;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* The {@code BlankSpan} is a singleton class, which is the default {@link Span} that is used when
|
||||
* no {@code Span} implementation is available. All operations are no-op.
|
||||
*
|
||||
* <p>Used also to stop tracing, see {@link Tracer#withSpan}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
public final class BlankSpan extends Span {
|
||||
/**
|
||||
* Singleton instance of this class.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static final BlankSpan INSTANCE = new BlankSpan();
|
||||
|
||||
private BlankSpan() {
|
||||
super(SpanContext.INVALID, null);
|
||||
}
|
||||
|
||||
/** No-op implementation of the {@link Span#putAttribute(String, AttributeValue)} method. */
|
||||
@Override
|
||||
public void putAttribute(String key, AttributeValue value) {
|
||||
Utils.checkNotNull(key, "key");
|
||||
Utils.checkNotNull(value, "value");
|
||||
}
|
||||
|
||||
/** No-op implementation of the {@link Span#putAttributes(Map)} method. */
|
||||
@Override
|
||||
public void putAttributes(Map<String, AttributeValue> attributes) {
|
||||
Utils.checkNotNull(attributes, "attributes");
|
||||
}
|
||||
|
||||
/** No-op implementation of the {@link Span#addAnnotation(String, Map)} method. */
|
||||
@Override
|
||||
public void addAnnotation(String description, Map<String, AttributeValue> attributes) {
|
||||
Utils.checkNotNull(description, "description");
|
||||
Utils.checkNotNull(attributes, "attributes");
|
||||
}
|
||||
|
||||
/** No-op implementation of the {@link Span#addAnnotation(Annotation)} method. */
|
||||
@Override
|
||||
public void addAnnotation(Annotation annotation) {
|
||||
Utils.checkNotNull(annotation, "annotation");
|
||||
}
|
||||
|
||||
/** No-op implementation of the {@link Span#addNetworkEvent(NetworkEvent)} method. */
|
||||
@Override
|
||||
@Deprecated
|
||||
public void addNetworkEvent(NetworkEvent networkEvent) {}
|
||||
|
||||
/** No-op implementation of the {@link Span#addMessageEvent(MessageEvent)} method. */
|
||||
@Override
|
||||
public void addMessageEvent(MessageEvent messageEvent) {
|
||||
Utils.checkNotNull(messageEvent, "messageEvent");
|
||||
}
|
||||
|
||||
/** No-op implementation of the {@link Span#addLink(Link)} method. */
|
||||
@Override
|
||||
public void addLink(Link link) {
|
||||
Utils.checkNotNull(link, "link");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatus(Status status) {
|
||||
Utils.checkNotNull(status, "status");
|
||||
}
|
||||
|
||||
/** No-op implementation of the {@link Span#end(EndSpanOptions)} method. */
|
||||
@Override
|
||||
public void end(EndSpanOptions options) {
|
||||
Utils.checkNotNull(options, "options");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BlankSpan";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.trace;
|
||||
|
||||
import io.grpc.Context;
|
||||
import openconsensus.common.Scope;
|
||||
import openconsensus.trace.unsafe.ContextUtils;
|
||||
import java.util.concurrent.Callable;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Util methods/functionality to interact with the {@link Span} in the {@link io.grpc.Context}. */
|
||||
final class CurrentSpanUtils {
|
||||
// No instance of this class.
|
||||
private CurrentSpanUtils() {}
|
||||
|
||||
/**
|
||||
* Returns The {@link Span} from the current context.
|
||||
*
|
||||
* @return The {@code Span} from the current context.
|
||||
*/
|
||||
@Nullable
|
||||
static Span getCurrentSpan() {
|
||||
return ContextUtils.CONTEXT_SPAN_KEY.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enters the scope of code where the given {@link Span} is in the current context, and returns an
|
||||
* object that represents that scope. The scope is exited when the returned object is closed.
|
||||
*
|
||||
* <p>Supports try-with-resource idiom.
|
||||
*
|
||||
* @param span The {@code Span} to be set to the current context.
|
||||
* @param endSpan if {@code true} the returned {@code Scope} will close the {@code Span}.
|
||||
* @return An object that defines a scope where the given {@code Span} is set to the current
|
||||
* context.
|
||||
*/
|
||||
static Scope withSpan(Span span, boolean endSpan) {
|
||||
return new ScopeInSpan(span, endSpan);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a {@link Runnable} so that it executes with the {@code span} as the current {@code Span}.
|
||||
*
|
||||
* @param span the {@code Span} to be set as current.
|
||||
* @param endSpan if {@code true} the returned {@code Runnable} will close the {@code Span}.
|
||||
* @param runnable the {@code Runnable} to run in the {@code Span}.
|
||||
* @return the wrapped {@code Runnable}.
|
||||
*/
|
||||
static Runnable withSpan(Span span, boolean endSpan, Runnable runnable) {
|
||||
return new RunnableInSpan(span, runnable, endSpan);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a {@link Callable} so that it executes with the {@code span} as the current {@code Span}.
|
||||
*
|
||||
* @param span the {@code Span} to be set as current.
|
||||
* @param endSpan if {@code true} the returned {@code Runnable} will close the {@code Span}.
|
||||
* @param callable the {@code Callable} to run in the {@code Span}.
|
||||
* @return the wrapped {@code Callable}.
|
||||
*/
|
||||
static <C> Callable<C> withSpan(Span span, boolean endSpan, Callable<C> callable) {
|
||||
return new CallableInSpan<C>(span, callable, endSpan);
|
||||
}
|
||||
|
||||
// Defines an arbitrary scope of code as a traceable operation. Supports try-with-resources idiom.
|
||||
private static final class ScopeInSpan implements Scope {
|
||||
private final Context origContext;
|
||||
private final Span span;
|
||||
private final boolean endSpan;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link ScopeInSpan}.
|
||||
*
|
||||
* @param span is the {@code Span} to be added to the current {@code io.grpc.Context}.
|
||||
*/
|
||||
private ScopeInSpan(Span span, boolean endSpan) {
|
||||
this.span = span;
|
||||
this.endSpan = endSpan;
|
||||
origContext = Context.current().withValue(ContextUtils.CONTEXT_SPAN_KEY, span).attach();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
Context.current().detach(origContext);
|
||||
if (endSpan) {
|
||||
span.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class RunnableInSpan implements Runnable {
|
||||
// TODO(bdrutu): Investigate if the extra private visibility increases the generated bytecode.
|
||||
private final Span span;
|
||||
private final Runnable runnable;
|
||||
private final boolean endSpan;
|
||||
|
||||
private RunnableInSpan(Span span, Runnable runnable, boolean endSpan) {
|
||||
this.span = span;
|
||||
this.runnable = runnable;
|
||||
this.endSpan = endSpan;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Context origContext =
|
||||
Context.current().withValue(ContextUtils.CONTEXT_SPAN_KEY, span).attach();
|
||||
try {
|
||||
runnable.run();
|
||||
} catch (Throwable t) {
|
||||
setErrorStatus(span, t);
|
||||
if (t instanceof RuntimeException) {
|
||||
throw (RuntimeException) t;
|
||||
} else if (t instanceof Error) {
|
||||
throw (Error) t;
|
||||
}
|
||||
throw new RuntimeException("unexpected", t);
|
||||
} finally {
|
||||
Context.current().detach(origContext);
|
||||
if (endSpan) {
|
||||
span.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class CallableInSpan<V> implements Callable<V> {
|
||||
private final Span span;
|
||||
private final Callable<V> callable;
|
||||
private final boolean endSpan;
|
||||
|
||||
private CallableInSpan(Span span, Callable<V> callable, boolean endSpan) {
|
||||
this.span = span;
|
||||
this.callable = callable;
|
||||
this.endSpan = endSpan;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V call() throws Exception {
|
||||
Context origContext =
|
||||
Context.current().withValue(ContextUtils.CONTEXT_SPAN_KEY, span).attach();
|
||||
try {
|
||||
return callable.call();
|
||||
} catch (Exception e) {
|
||||
setErrorStatus(span, e);
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
setErrorStatus(span, t);
|
||||
if (t instanceof Error) {
|
||||
throw (Error) t;
|
||||
}
|
||||
throw new RuntimeException("unexpected", t);
|
||||
} finally {
|
||||
Context.current().detach(origContext);
|
||||
if (endSpan) {
|
||||
span.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setErrorStatus(Span span, Throwable t) {
|
||||
span.setStatus(
|
||||
Status.UNKNOWN.withDescription(
|
||||
t.getMessage() == null ? t.getClass().getSimpleName() : t.getMessage()));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.trace;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.common.ExperimentalApi;
|
||||
import java.util.Collection;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import openconsensus.trace.export.SampledSpanStore;
|
||||
|
||||
/**
|
||||
* A class that enables overriding the default values used when ending a {@link Span}. Allows
|
||||
* overriding the {@link Status status}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract class EndSpanOptions {
|
||||
/**
|
||||
* The default {@code EndSpanOptions}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static final EndSpanOptions DEFAULT = builder().build();
|
||||
|
||||
/**
|
||||
* Returns a new {@link Builder} with default options.
|
||||
*
|
||||
* @return a new {@code Builder} with default options.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new AutoValue_EndSpanOptions.Builder().setSampleToLocalSpanStore(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* If {@code true} this is equivalent with calling the {@link
|
||||
* SampledSpanStore#registerSpanNamesForCollection(Collection)} in
|
||||
* advance for this span name.
|
||||
*
|
||||
* @return {@code true} if the name of the {@code Span} should be registered to the {@code
|
||||
* SampledSpanStore}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
public abstract boolean getSampleToLocalSpanStore();
|
||||
|
||||
/**
|
||||
* Returns the status.
|
||||
*
|
||||
* <p>If {@code null} then the {@link Span} will record the {@link Status} set via {@link
|
||||
* Span#setStatus(Status)} or the default {@link Status#OK} if no status was set.
|
||||
*
|
||||
* @return the status.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Nullable
|
||||
public abstract Status getStatus();
|
||||
|
||||
/**
|
||||
* Builder class for {@link EndSpanOptions}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@AutoValue.Builder
|
||||
public abstract static class Builder {
|
||||
/**
|
||||
* Sets the status for the {@link Span}.
|
||||
*
|
||||
* <p>If set, this will override the status set via {@link Span#setStatus(Status)}.
|
||||
*
|
||||
* @param status the status.
|
||||
* @return this.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Builder setStatus(Status status);
|
||||
|
||||
/**
|
||||
* If set to {@code true} this is equivalent with calling the {@link
|
||||
* SampledSpanStore#registerSpanNamesForCollection(Collection)} in
|
||||
* advance for the given span name.
|
||||
*
|
||||
* <p>WARNING: setting this option to a randomly generated span name can OOM your process
|
||||
* because the library will save samples for each name.
|
||||
*
|
||||
* <p>It is strongly recommended to use the {@link
|
||||
* SampledSpanStore#registerSpanNamesForCollection(Collection)} API
|
||||
* instead.
|
||||
*
|
||||
* @return this.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@ExperimentalApi
|
||||
public abstract Builder setSampleToLocalSpanStore(boolean sampleToLocalSpanStore);
|
||||
|
||||
/**
|
||||
* Builds and returns a {@code EndSpanOptions} with the desired settings.
|
||||
*
|
||||
* @return a {@code EndSpanOptions} with the desired settings.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract EndSpanOptions build();
|
||||
|
||||
Builder() {}
|
||||
}
|
||||
|
||||
EndSpanOptions() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.trace;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* A link to a {@link Span} from a different trace.
|
||||
*
|
||||
* <p>It requires a {@link Type} which describes the relationship with the linked {@code Span} and
|
||||
* the identifiers of the linked {@code Span}.
|
||||
*
|
||||
* <p>Used (for example) in batching operations, where a single batch handler processes multiple
|
||||
* requests from different traces.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract class Link {
|
||||
private static final Map<String, AttributeValue> EMPTY_ATTRIBUTES = Collections.emptyMap();
|
||||
|
||||
/**
|
||||
* The relationship with the linked {@code Span} relative to the current {@code Span}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public enum Type {
|
||||
/**
|
||||
* When the linked {@code Span} is a child of the current {@code Span}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
CHILD_LINKED_SPAN,
|
||||
/**
|
||||
* When the linked {@code Span} is a parent of the current {@code Span}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
PARENT_LINKED_SPAN
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@code Link}.
|
||||
*
|
||||
* @param context the context of the linked {@code Span}.
|
||||
* @param type the type of the relationship with the linked {@code Span}.
|
||||
* @return a new {@code Link}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Link fromSpanContext(SpanContext context, Type type) {
|
||||
return new AutoValue_Link(context.getTraceId(), context.getSpanId(), type, EMPTY_ATTRIBUTES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@code Link}.
|
||||
*
|
||||
* @param context the context of the linked {@code Span}.
|
||||
* @param type the type of the relationship with the linked {@code Span}.
|
||||
* @param attributes the attributes of the {@code Link}.
|
||||
* @return a new {@code Link}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Link fromSpanContext(
|
||||
SpanContext context, Type type, Map<String, AttributeValue> attributes) {
|
||||
return new AutoValue_Link(
|
||||
context.getTraceId(),
|
||||
context.getSpanId(),
|
||||
type,
|
||||
Collections.unmodifiableMap(new HashMap<String, AttributeValue>(attributes)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code TraceId}.
|
||||
*
|
||||
* @return the {@code TraceId}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract TraceId getTraceId();
|
||||
|
||||
/**
|
||||
* Returns the {@code SpanId}.
|
||||
*
|
||||
* @return the {@code SpanId}
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract SpanId getSpanId();
|
||||
|
||||
/**
|
||||
* Returns the {@code Type}.
|
||||
*
|
||||
* @return the {@code Type}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Type getType();
|
||||
|
||||
/**
|
||||
* Returns the set of attributes.
|
||||
*
|
||||
* @return the set of attributes.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Map<String, AttributeValue> getAttributes();
|
||||
|
||||
Link() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.trace;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.internal.Utils;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* A class that represents a generic messaging event. This class can represent messaging happened in
|
||||
* any layer, especially higher application layer. Thus, it can be used when recording events in
|
||||
* pipeline works, in-process bidirectional streams and batch processing.
|
||||
*
|
||||
* <p>It requires a {@link Type type} and a message id that serves to uniquely identify each
|
||||
* message. It can optionally have information about the message size.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
@SuppressWarnings("deprecation")
|
||||
public abstract class MessageEvent extends BaseMessageEvent {
|
||||
/**
|
||||
* Available types for a {@code MessageEvent}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public enum Type {
|
||||
/**
|
||||
* When the message was sent.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
SENT,
|
||||
/**
|
||||
* When the message was received.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
RECEIVED,
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link Builder} with default values.
|
||||
*
|
||||
* @param type designates whether this is a send or receive message.
|
||||
* @param messageId serves to uniquely identify each message.
|
||||
* @return a new {@code Builder} with default values.
|
||||
* @throws NullPointerException if {@code type} is {@code null}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Builder builder(Type type, long messageId) {
|
||||
return new AutoValue_MessageEvent.Builder()
|
||||
.setType(Utils.checkNotNull(type, "type"))
|
||||
.setMessageId(messageId)
|
||||
// We need to set a value for the message size because the autovalue requires all
|
||||
// primitives to be initialized.
|
||||
.setUncompressedMessageSize(0)
|
||||
.setCompressedMessageSize(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the {@code MessageEvent}.
|
||||
*
|
||||
* @return the type of the {@code MessageEvent}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Type getType();
|
||||
|
||||
/**
|
||||
* Returns the message id argument that serves to uniquely identify each message.
|
||||
*
|
||||
* @return the message id of the {@code MessageEvent}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract long getMessageId();
|
||||
|
||||
/**
|
||||
* Returns the uncompressed size in bytes of the {@code MessageEvent}.
|
||||
*
|
||||
* @return the uncompressed size in bytes of the {@code MessageEvent}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract long getUncompressedMessageSize();
|
||||
|
||||
/**
|
||||
* Returns the compressed size in bytes of the {@code MessageEvent}.
|
||||
*
|
||||
* @return the compressed size in bytes of the {@code MessageEvent}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract long getCompressedMessageSize();
|
||||
|
||||
/**
|
||||
* Builder class for {@link MessageEvent}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@AutoValue.Builder
|
||||
public abstract static class Builder {
|
||||
// Package protected methods because these values are mandatory and set only in the
|
||||
// MessageEvent#builder() function.
|
||||
abstract Builder setType(Type type);
|
||||
|
||||
abstract Builder setMessageId(long messageId);
|
||||
|
||||
/**
|
||||
* Sets the uncompressed message size.
|
||||
*
|
||||
* @param uncompressedMessageSize represents the uncompressed size in bytes of this message.
|
||||
* @return this.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Builder setUncompressedMessageSize(long uncompressedMessageSize);
|
||||
|
||||
/**
|
||||
* Sets the compressed message size.
|
||||
*
|
||||
* @param compressedMessageSize represents the compressed size in bytes of this message.
|
||||
* @return this.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Builder setCompressedMessageSize(long compressedMessageSize);
|
||||
|
||||
/**
|
||||
* Builds and returns a {@code MessageEvent} with the desired values.
|
||||
*
|
||||
* @return a {@code MessageEvent} with the desired values.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract MessageEvent build();
|
||||
|
||||
Builder() {}
|
||||
}
|
||||
|
||||
MessageEvent() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.trace;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import openconsensus.common.Timestamp;
|
||||
import openconsensus.internal.Utils;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* A class that represents a network event. It requires a {@link Type type} and a message id that
|
||||
* serves to uniquely identify each network message. It can optionally can have information about
|
||||
* the kernel time and message size.
|
||||
*
|
||||
* @deprecated Use {@link MessageEvent}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
@AutoValue.CopyAnnotations
|
||||
@Deprecated
|
||||
public abstract class NetworkEvent extends BaseMessageEvent {
|
||||
/**
|
||||
* Available types for a {@code NetworkEvent}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public enum Type {
|
||||
/**
|
||||
* When the message was sent.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
SENT,
|
||||
/**
|
||||
* When the message was received.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
RECV,
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link Builder} with default values.
|
||||
*
|
||||
* @param type designates whether this is a network send or receive message.
|
||||
* @param messageId serves to uniquely identify each network message.
|
||||
* @return a new {@code Builder} with default values.
|
||||
* @throws NullPointerException if {@code type} is {@code null}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static Builder builder(Type type, long messageId) {
|
||||
return new AutoValue_NetworkEvent.Builder()
|
||||
.setType(Utils.checkNotNull(type, "type"))
|
||||
.setMessageId(messageId)
|
||||
// We need to set a value for the message size because the autovalue requires all
|
||||
// primitives to be initialized.
|
||||
.setUncompressedMessageSize(0)
|
||||
.setCompressedMessageSize(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the kernel timestamp associated with the {@code NetworkEvent} or {@code null} if not
|
||||
* set.
|
||||
*
|
||||
* @return the kernel timestamp associated with the {@code NetworkEvent} or {@code null} if not
|
||||
* set.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Nullable
|
||||
public abstract Timestamp getKernelTimestamp();
|
||||
|
||||
/**
|
||||
* Returns the type of the {@code NetworkEvent}.
|
||||
*
|
||||
* @return the type of the {@code NetworkEvent}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Type getType();
|
||||
|
||||
/**
|
||||
* Returns the message id argument that serves to uniquely identify each network message.
|
||||
*
|
||||
* @return the message id of the {@code NetworkEvent}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract long getMessageId();
|
||||
|
||||
/**
|
||||
* Returns the uncompressed size in bytes of the {@code NetworkEvent}.
|
||||
*
|
||||
* @return the uncompressed size in bytes of the {@code NetworkEvent}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract long getUncompressedMessageSize();
|
||||
|
||||
/**
|
||||
* Returns the compressed size in bytes of the {@code NetworkEvent}.
|
||||
*
|
||||
* @return the compressed size in bytes of the {@code NetworkEvent}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract long getCompressedMessageSize();
|
||||
|
||||
/**
|
||||
* Returns the uncompressed size in bytes of the {@code NetworkEvent}.
|
||||
*
|
||||
* @deprecated Use {@link #getUncompressedMessageSize}.
|
||||
* @return the uncompressed size in bytes of the {@code NetworkEvent}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Deprecated
|
||||
public long getMessageSize() {
|
||||
return getUncompressedMessageSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder class for {@link NetworkEvent}.
|
||||
*
|
||||
* @deprecated {@link NetworkEvent} is deprecated. Please use {@link MessageEvent} and its builder
|
||||
* {@link MessageEvent.Builder}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@AutoValue.Builder
|
||||
@Deprecated
|
||||
public abstract static class Builder {
|
||||
// Package protected methods because these values are mandatory and set only in the
|
||||
// NetworkEvent#builder() function.
|
||||
abstract Builder setType(Type type);
|
||||
|
||||
abstract Builder setMessageId(long messageId);
|
||||
|
||||
/**
|
||||
* Sets the kernel timestamp.
|
||||
*
|
||||
* @param kernelTimestamp The kernel timestamp of the event.
|
||||
* @return this.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Builder setKernelTimestamp(@Nullable Timestamp kernelTimestamp);
|
||||
|
||||
/**
|
||||
* Sets the uncompressed message size.
|
||||
*
|
||||
* @deprecated Use {@link #setUncompressedMessageSize}.
|
||||
* @param messageSize represents the uncompressed size in bytes of this message.
|
||||
* @return this.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Deprecated
|
||||
public Builder setMessageSize(long messageSize) {
|
||||
return setUncompressedMessageSize(messageSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the uncompressed message size.
|
||||
*
|
||||
* @param uncompressedMessageSize represents the uncompressed size in bytes of this message.
|
||||
* @return this.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Builder setUncompressedMessageSize(long uncompressedMessageSize);
|
||||
|
||||
/**
|
||||
* Sets the compressed message size.
|
||||
*
|
||||
* @param compressedMessageSize represents the compressed size in bytes of this message.
|
||||
* @return this.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Builder setCompressedMessageSize(long compressedMessageSize);
|
||||
|
||||
/**
|
||||
* Builds and returns a {@code NetworkEvent} with the desired values.
|
||||
*
|
||||
* @return a {@code NetworkEvent} with the desired values.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract NetworkEvent build();
|
||||
|
||||
Builder() {}
|
||||
}
|
||||
|
||||
NetworkEvent() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.trace;
|
||||
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Sampler is used to make decisions on {@link Span} sampling.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract class Sampler {
|
||||
/**
|
||||
* Called during {@link Span} creation to make a sampling decision.
|
||||
*
|
||||
* @param parentContext the parent span's {@link SpanContext}. {@code null} if this is a root
|
||||
* span.
|
||||
* @param hasRemoteParent {@code true} if the parent {@code Span} is remote. {@code null} if this
|
||||
* is a root span.
|
||||
* @param traceId the {@link TraceId} for the new {@code Span}. This will be identical to that in
|
||||
* the parentContext, unless this is a root span.
|
||||
* @param spanId the {@link SpanId} for the new {@code Span}.
|
||||
* @param name the name of the new {@code Span}.
|
||||
* @param parentLinks the parentLinks associated with the new {@code Span}.
|
||||
* @return {@code true} if the {@code Span} is sampled.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract boolean shouldSample(
|
||||
@Nullable SpanContext parentContext,
|
||||
@Nullable Boolean hasRemoteParent,
|
||||
TraceId traceId,
|
||||
SpanId spanId,
|
||||
String name,
|
||||
List<Span> parentLinks);
|
||||
|
||||
/**
|
||||
* Returns the description of this {@code Sampler}. This may be displayed on debug pages or in the
|
||||
* logs.
|
||||
*
|
||||
* <p>Example: "ProbabilitySampler{0.000100}"
|
||||
*
|
||||
* @return the description of this {@code Sampler}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract String getDescription();
|
||||
}
|
||||
|
|
@ -0,0 +1,288 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.trace;
|
||||
|
||||
import openconsensus.internal.Utils;
|
||||
import openconsensus.trace.internal.BaseMessageEventUtils;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An abstract class that represents a span. It has an associated {@link SpanContext} and a set of
|
||||
* {@link Options}.
|
||||
*
|
||||
* <p>Spans are created by the {@link SpanBuilder#startSpan} method.
|
||||
*
|
||||
* <p>{@code Span} <b>must</b> be ended by calling {@link #end()} or {@link #end(EndSpanOptions)}
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract class Span {
|
||||
private static final Map<String, AttributeValue> EMPTY_ATTRIBUTES = Collections.emptyMap();
|
||||
|
||||
// Contains the identifiers associated with this Span.
|
||||
private final SpanContext context;
|
||||
|
||||
// Contains the options associated with this Span. This object is immutable.
|
||||
private final Set<Options> options;
|
||||
|
||||
/**
|
||||
* {@code Span} options. These options are NOT propagated to child spans. These options determine
|
||||
* features such as whether a {@code Span} should record any annotations or events.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public enum Options {
|
||||
/**
|
||||
* This option is set if the Span is part of a sampled distributed trace OR {@link
|
||||
* SpanBuilder#setRecordEvents(boolean)} was called with true.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
RECORD_EVENTS;
|
||||
}
|
||||
|
||||
private static final Set<Options> DEFAULT_OPTIONS =
|
||||
Collections.unmodifiableSet(EnumSet.noneOf(Options.class));
|
||||
|
||||
/**
|
||||
* Creates a new {@code Span}.
|
||||
*
|
||||
* @param context the context associated with this {@code Span}.
|
||||
* @param options the options associated with this {@code Span}. If {@code null} then default
|
||||
* options will be set.
|
||||
* @throws NullPointerException if context is {@code null}.
|
||||
* @throws IllegalArgumentException if the {@code SpanContext} is sampled but no RECORD_EVENTS
|
||||
* options.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
protected Span(SpanContext context, @Nullable EnumSet<Options> options) {
|
||||
this.context = Utils.checkNotNull(context, "context");
|
||||
this.options =
|
||||
options == null
|
||||
? DEFAULT_OPTIONS
|
||||
: Collections.<Options>unmodifiableSet(EnumSet.copyOf(options));
|
||||
Utils.checkArgument(
|
||||
!context.getTraceOptions().isSampled() || this.options.contains(Options.RECORD_EVENTS),
|
||||
"Span is sampled, but does not have RECORD_EVENTS set.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an attribute to the {@code Span}. If the {@code Span} previously contained a mapping for
|
||||
* the key, the old value is replaced by the specified value.
|
||||
*
|
||||
* @param key the key for this attribute.
|
||||
* @param value the value for this attribute.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public void putAttribute(String key, AttributeValue value) {
|
||||
// Not final because for performance reasons we want to override this in the implementation.
|
||||
// Also a default implementation is needed to not break the compatibility (users may extend this
|
||||
// for testing).
|
||||
Utils.checkNotNull(key, "key");
|
||||
Utils.checkNotNull(value, "value");
|
||||
putAttributes(Collections.singletonMap(key, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a set of attributes to the {@code Span}. The effect of this call is equivalent to that of
|
||||
* calling {@link #putAttribute(String, AttributeValue)} once for each element in the specified
|
||||
* map.
|
||||
*
|
||||
* @param attributes the attributes that will be added and associated with the {@code Span}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public void putAttributes(Map<String, AttributeValue> attributes) {
|
||||
// Not final because we want to start overriding this method from the beginning, this will
|
||||
// allow us to remove the addAttributes faster. All implementations MUST override this method.
|
||||
Utils.checkNotNull(attributes, "attributes");
|
||||
addAttributes(attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a set of attributes to the {@code Span}. The effect of this call is equivalent to that of
|
||||
* calling {@link #putAttribute(String, AttributeValue)} once for each element in the specified
|
||||
* map.
|
||||
*
|
||||
* @deprecated Use {@link #putAttributes(Map)}
|
||||
* @param attributes the attributes that will be added and associated with the {@code Span}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Deprecated
|
||||
public void addAttributes(Map<String, AttributeValue> attributes) {
|
||||
putAttributes(attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an annotation to the {@code Span}.
|
||||
*
|
||||
* @param description the description of the annotation time event.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public final void addAnnotation(String description) {
|
||||
Utils.checkNotNull(description, "description");
|
||||
addAnnotation(description, EMPTY_ATTRIBUTES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an annotation to the {@code Span}.
|
||||
*
|
||||
* @param description the description of the annotation time event.
|
||||
* @param attributes the attributes that will be added; these are associated with this annotation,
|
||||
* not the {@code Span} as for {@link #putAttributes(Map)}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract void addAnnotation(String description, Map<String, AttributeValue> attributes);
|
||||
|
||||
/**
|
||||
* Adds an annotation to the {@code Span}.
|
||||
*
|
||||
* @param annotation the annotations to add.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract void addAnnotation(Annotation annotation);
|
||||
|
||||
/**
|
||||
* Adds a NetworkEvent to the {@code Span}.
|
||||
*
|
||||
* <p>This function is only intended to be used by RPC systems (either client or server), not by
|
||||
* higher level applications.
|
||||
*
|
||||
* @param networkEvent the network event to add.
|
||||
* @deprecated Use {@link #addMessageEvent}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Deprecated
|
||||
public void addNetworkEvent(NetworkEvent networkEvent) {
|
||||
addMessageEvent(BaseMessageEventUtils.asMessageEvent(networkEvent));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a MessageEvent to the {@code Span}.
|
||||
*
|
||||
* <p>This function can be used by higher level applications to record messaging event.
|
||||
*
|
||||
* <p>This method should always be overridden by users whose API versions are larger or equal to
|
||||
* {@code 0.12}.
|
||||
*
|
||||
* @param messageEvent the message to add.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public void addMessageEvent(MessageEvent messageEvent) {
|
||||
// Default implementation by invoking addNetworkEvent() so that any existing derived classes,
|
||||
// including implementation and the mocked ones, do not need to override this method explicitly.
|
||||
Utils.checkNotNull(messageEvent, "messageEvent");
|
||||
addNetworkEvent(BaseMessageEventUtils.asNetworkEvent(messageEvent));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link Link} to the {@code Span}.
|
||||
*
|
||||
* <p>Used (for example) in batching operations, where a single batch handler processes multiple
|
||||
* requests from different traces.
|
||||
*
|
||||
* @param link the link to add.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract void addLink(Link link);
|
||||
|
||||
/**
|
||||
* Sets the {@link Status} to the {@code Span}.
|
||||
*
|
||||
* <p>If used, this will override the default {@code Span} status. Default is {@link Status#OK}.
|
||||
*
|
||||
* <p>Only the value of the last call will be recorded, and implementations are free to ignore
|
||||
* previous calls. If the status is set via {@link EndSpanOptions.Builder#setStatus(Status)} that
|
||||
* will always be the last call.
|
||||
*
|
||||
* @param status the {@link Status} to set.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public void setStatus(Status status) {
|
||||
// Implemented as no-op for backwards compatibility (for example gRPC extends Span in tests).
|
||||
// Implementation must override this method.
|
||||
Utils.checkNotNull(status, "status");
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the end of {@code Span} execution with the given options.
|
||||
*
|
||||
* <p>Only the timing of the first end call for a given {@code Span} will be recorded, and
|
||||
* implementations are free to ignore all further calls.
|
||||
*
|
||||
* @param options the options to be used for the end of the {@code Span}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract void end(EndSpanOptions options);
|
||||
|
||||
/**
|
||||
* Marks the end of {@code Span} execution with the default options.
|
||||
*
|
||||
* <p>Only the timing of the first end call for a given {@code Span} will be recorded, and
|
||||
* implementations are free to ignore all further calls.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public final void end() {
|
||||
end(EndSpanOptions.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code SpanContext} associated with this {@code Span}.
|
||||
*
|
||||
* @return the {@code SpanContext} associated with this {@code Span}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public final SpanContext getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the options associated with this {@code Span}.
|
||||
*
|
||||
* @return the options associated with this {@code Span}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public final Set<Options> getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of span. Can be used to specify additional relationships between spans in addition to a
|
||||
* parent/child relationship.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public enum Kind {
|
||||
/**
|
||||
* Indicates that the span covers server-side handling of an RPC or other remote request.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
SERVER,
|
||||
|
||||
/**
|
||||
* Indicates that the span covers the client-side wrapper around an RPC or other remote request.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
CLIENT
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,356 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.trace;
|
||||
|
||||
import com.google.errorprone.annotations.MustBeClosed;
|
||||
import openconsensus.common.Scope;
|
||||
import openconsensus.internal.Utils;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* {@link SpanBuilder} is used to construct {@link Span} instances which define arbitrary scopes of
|
||||
* code that are sampled for distributed tracing as a single atomic unit.
|
||||
*
|
||||
* <p>This is a simple example where all the work is being done within a single scope and a single
|
||||
* thread and the Context is automatically propagated:
|
||||
*
|
||||
* <pre>{@code
|
||||
* class MyClass {
|
||||
* private static final Tracer tracer = Tracing.getTracer();
|
||||
* void doWork {
|
||||
* // Create a Span as a child of the current Span.
|
||||
* try (Scope ss = tracer.spanBuilder("MyChildSpan").startScopedSpan()) {
|
||||
* tracer.getCurrentSpan().addAnnotation("my annotation");
|
||||
* doSomeWork(); // Here the new span is in the current Context, so it can be used
|
||||
* // implicitly anywhere down the stack.
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p>There might be cases where you do not perform all the work inside one static scope and the
|
||||
* Context is automatically propagated:
|
||||
*
|
||||
* <pre>{@code
|
||||
* class MyRpcServerInterceptorListener implements RpcServerInterceptor.Listener {
|
||||
* private static final Tracer tracer = Tracing.getTracer();
|
||||
* private Span mySpan;
|
||||
*
|
||||
* public MyRpcInterceptor() {}
|
||||
*
|
||||
* public void onRequest(String rpcName, Metadata metadata) {
|
||||
* // Create a Span as a child of the remote Span.
|
||||
* mySpan = tracer.spanBuilderWithRemoteParent(
|
||||
* getTraceContextFromMetadata(metadata), rpcName).startSpan();
|
||||
* }
|
||||
*
|
||||
* public void onExecuteHandler(ServerCallHandler serverCallHandler) {
|
||||
* try (Scope ws = tracer.withSpan(mySpan)) {
|
||||
* tracer.getCurrentSpan().addAnnotation("Start rpc execution.");
|
||||
* serverCallHandler.run(); // Here the new span is in the current Context, so it can be
|
||||
* // used implicitly anywhere down the stack.
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // Called when the RPC is canceled and guaranteed onComplete will not be called.
|
||||
* public void onCancel() {
|
||||
* // IMPORTANT: DO NOT forget to ended the Span here as the work is done.
|
||||
* mySpan.end(EndSpanOptions.builder().setStatus(Status.CANCELLED));
|
||||
* }
|
||||
*
|
||||
* // Called when the RPC is done and guaranteed onCancel will not be called.
|
||||
* public void onComplete(RpcStatus rpcStatus) {
|
||||
* // IMPORTANT: DO NOT forget to ended the Span here as the work is done.
|
||||
* mySpan.end(EndSpanOptions.builder().setStatus(rpcStatusToCanonicalTraceStatus(status));
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p>This is a simple example where all the work is being done within a single scope and the
|
||||
* Context is manually propagated:
|
||||
*
|
||||
* <pre>{@code
|
||||
* class MyClass {
|
||||
* private static final Tracer tracer = Tracing.getTracer();
|
||||
* void DoWork(Span parent) {
|
||||
* Span childSpan = tracer.spanBuilderWithExplicitParent("MyChildSpan", parent).startSpan();
|
||||
* childSpan.addAnnotation("my annotation");
|
||||
* try {
|
||||
* doSomeWork(childSpan); // Manually propagate the new span down the stack.
|
||||
* } finally {
|
||||
* // To make sure we end the span even in case of an exception.
|
||||
* childSpan.end(); // Manually end the span.
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p>If your Java version is less than Java SE 7, see {@link SpanBuilder#startSpan} and {@link
|
||||
* SpanBuilder#startScopedSpan} for usage examples.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract class SpanBuilder {
|
||||
|
||||
/**
|
||||
* Sets the {@link Sampler} to use. If not set, the implementation will provide a default.
|
||||
*
|
||||
* @param sampler the {@code Sampler} to use when determining sampling for a {@code Span}.
|
||||
* @return this.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract SpanBuilder setSampler(Sampler sampler);
|
||||
|
||||
/**
|
||||
* Sets the {@code List} of parent links. Links are used to link {@link Span}s in different
|
||||
* traces. Used (for example) in batching operations, where a single batch handler processes
|
||||
* multiple requests from different traces.
|
||||
*
|
||||
* @param parentLinks new links to be added.
|
||||
* @return this.
|
||||
* @throws NullPointerException if {@code parentLinks} is {@code null}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract SpanBuilder setParentLinks(List<Span> parentLinks);
|
||||
|
||||
/**
|
||||
* Sets the option {@link Span.Options#RECORD_EVENTS} for the newly created {@code Span}. If not
|
||||
* called, the implementation will provide a default.
|
||||
*
|
||||
* @param recordEvents new value determining if this {@code Span} should have events recorded.
|
||||
* @return this.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract SpanBuilder setRecordEvents(boolean recordEvents);
|
||||
|
||||
/**
|
||||
* Sets the {@link Span.Kind} for the newly created {@code Span}. If not called, the
|
||||
* implementation will provide a default.
|
||||
*
|
||||
* @param spanKind the kind of the newly created {@code Span}.
|
||||
* @return this.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public SpanBuilder setSpanKind(@Nullable Span.Kind spanKind) {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new {@link Span}.
|
||||
*
|
||||
* <p>Users <b>must</b> manually call {@link Span#end()} or {@link Span#end(EndSpanOptions)} to
|
||||
* end this {@code Span}.
|
||||
*
|
||||
* <p>Does not install the newly created {@code Span} to the current Context.
|
||||
*
|
||||
* <p>Example of usage:
|
||||
*
|
||||
* <pre>{@code
|
||||
* class MyClass {
|
||||
* private static final Tracer tracer = Tracing.getTracer();
|
||||
* void DoWork(Span parent) {
|
||||
* Span childSpan = tracer.spanBuilderWithExplicitParent("MyChildSpan", parent).startSpan();
|
||||
* childSpan.addAnnotation("my annotation");
|
||||
* try {
|
||||
* doSomeWork(childSpan); // Manually propagate the new span down the stack.
|
||||
* } finally {
|
||||
* // To make sure we end the span even in case of an exception.
|
||||
* childSpan.end(); // Manually end the span.
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @return the newly created {@code Span}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract Span startSpan();
|
||||
|
||||
/**
|
||||
* Starts a new span and sets it as the {@link Tracer#getCurrentSpan current span}.
|
||||
*
|
||||
* <p>Enters the scope of code where the newly created {@code Span} is in the current Context, and
|
||||
* returns an object that represents that scope. When the returned object is closed, the scope is
|
||||
* exited, the previous Context is restored, and the newly created {@code Span} is ended using
|
||||
* {@link Span#end}.
|
||||
*
|
||||
* <p>Supports try-with-resource idiom.
|
||||
*
|
||||
* <p>Example of usage:
|
||||
*
|
||||
* <pre>{@code
|
||||
* class MyClass {
|
||||
* private static final Tracer tracer = Tracing.getTracer();
|
||||
* void doWork {
|
||||
* // Create a Span as a child of the current Span.
|
||||
* try (Scope ss = tracer.spanBuilder("MyChildSpan").startScopedSpan()) {
|
||||
* tracer.getCurrentSpan().addAnnotation("my annotation");
|
||||
* doSomeWork(); // Here the new span is in the current Context, so it can be used
|
||||
* // implicitly anywhere down the stack. Anytime in this closure the span
|
||||
* // can be accessed via tracer.getCurrentSpan().
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p>Prior to Java SE 7, you can use a finally block to ensure that a resource is closed (the
|
||||
* {@code Span} is ended and removed from the Context) regardless of whether the try statement
|
||||
* completes normally or abruptly.
|
||||
*
|
||||
* <p>Example of usage prior to Java SE7:
|
||||
*
|
||||
* <pre>{@code
|
||||
* class MyClass {
|
||||
* private static Tracer tracer = Tracing.getTracer();
|
||||
* void doWork {
|
||||
* // Create a Span as a child of the current Span.
|
||||
* Scope ss = tracer.spanBuilder("MyChildSpan").startScopedSpan();
|
||||
* try {
|
||||
* tracer.getCurrentSpan().addAnnotation("my annotation");
|
||||
* doSomeWork(); // Here the new span is in the current Context, so it can be used
|
||||
* // implicitly anywhere down the stack. Anytime in this closure the span
|
||||
* // can be accessed via tracer.getCurrentSpan().
|
||||
* } finally {
|
||||
* ss.close();
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p>WARNING: The try-with-resources feature to auto-close spans as described above can sound
|
||||
* very tempting due to its convenience, but it comes with an important and easy-to-miss
|
||||
* trade-off: the span will be closed before any {@code catch} or {@code finally} blocks get a
|
||||
* chance to execute. So if you need to catch any exceptions and log information about them (for
|
||||
* example), then you do not want to use the try-with-resources shortcut because that logging will
|
||||
* not be tagged with the span info of the span it logically falls under, and if you try to
|
||||
* retrieve {@code Tracer.getCurrentSpan()} then you'll either get the parent span if one exists
|
||||
* or {@code BlankSpan} if there was no parent span. This can be confusing and seem
|
||||
* counter-intuitive, but it's the way try-with-resources works.
|
||||
*
|
||||
* @return an object that defines a scope where the newly created {@code Span} will be set to the
|
||||
* current Context.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@MustBeClosed
|
||||
public final Scope startScopedSpan() {
|
||||
return CurrentSpanUtils.withSpan(startSpan(), /* endSpan= */ true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new span and runs the given {@code Runnable} with the newly created {@code Span} as
|
||||
* the current {@code Span}, and ends the {@code Span} after the {@code Runnable} is run.
|
||||
*
|
||||
* <p>Any error will end up as a {@link Status#UNKNOWN}.
|
||||
*
|
||||
* <pre><code>
|
||||
* tracer.spanBuilder("MyRunnableSpan").startSpanAndRun(myRunnable);
|
||||
* </code></pre>
|
||||
*
|
||||
* <p>It is equivalent with the following code:
|
||||
*
|
||||
* <pre><code>
|
||||
* Span span = tracer.spanBuilder("MyRunnableSpan").startSpan();
|
||||
* Runnable newRunnable = tracer.withSpan(span, myRunnable);
|
||||
* try {
|
||||
* newRunnable.run();
|
||||
* } finally {
|
||||
* span.end();
|
||||
* }
|
||||
* </code></pre>
|
||||
*
|
||||
* @param runnable the {@code Runnable} to run in the {@code Span}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public final void startSpanAndRun(final Runnable runnable) {
|
||||
final Span span = startSpan();
|
||||
CurrentSpanUtils.withSpan(span, /* endSpan= */ true, runnable).run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new span and calls the given {@code Callable} with the newly created {@code Span} as
|
||||
* the current {@code Span}, and ends the {@code Span} after the {@code Callable} is called.
|
||||
*
|
||||
* <p>Any error will end up as a {@link Status#UNKNOWN}.
|
||||
*
|
||||
* <pre><code>
|
||||
* MyResult myResult = tracer.spanBuilder("MyCallableSpan").startSpanAndCall(myCallable);
|
||||
* </code></pre>
|
||||
*
|
||||
* <p>It is equivalent with the following code:
|
||||
*
|
||||
* <pre><code>
|
||||
* Span span = tracer.spanBuilder("MyCallableSpan").startSpan();
|
||||
* {@code Callable<MyResult>} newCallable = tracer.withSpan(span, myCallable);
|
||||
* MyResult myResult = null;
|
||||
* try {
|
||||
* myResult = newCallable.call();
|
||||
* } finally {
|
||||
* span.end();
|
||||
* }
|
||||
* );
|
||||
* </code></pre>
|
||||
*
|
||||
* @param callable the {@code Callable} to run in the {@code Span}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public final <V> V startSpanAndCall(Callable<V> callable) throws Exception {
|
||||
final Span span = startSpan();
|
||||
return CurrentSpanUtils.withSpan(span, /* endSpan= */ true, callable).call();
|
||||
}
|
||||
|
||||
static final class NoopSpanBuilder extends SpanBuilder {
|
||||
static NoopSpanBuilder createWithParent(String spanName, @Nullable Span parent) {
|
||||
return new NoopSpanBuilder(spanName);
|
||||
}
|
||||
|
||||
static NoopSpanBuilder createWithRemoteParent(
|
||||
String spanName, @Nullable SpanContext remoteParentSpanContext) {
|
||||
return new NoopSpanBuilder(spanName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span startSpan() {
|
||||
return BlankSpan.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpanBuilder setSampler(@Nullable Sampler sampler) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpanBuilder setParentLinks(List<Span> parentLinks) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpanBuilder setRecordEvents(boolean recordEvents) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpanBuilder setSpanKind(@Nullable Span.Kind spanKind) {
|
||||
return this;
|
||||
}
|
||||
|
||||
private NoopSpanBuilder(String name) {
|
||||
Utils.checkNotNull(name, "name");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.trace;
|
||||
|
||||
import java.util.Arrays;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* A class that represents a span context. A span context contains the state that must propagate to
|
||||
* child {@link Span}s and across process boundaries. It contains the identifiers (a {@link TraceId
|
||||
* trace_id} and {@link SpanId span_id}) associated with the {@link Span} and a set of {@link
|
||||
* TraceOptions options}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
public final class SpanContext {
|
||||
private static final Tracestate TRACESTATE_DEFAULT = Tracestate.builder().build();
|
||||
private final TraceId traceId;
|
||||
private final SpanId spanId;
|
||||
private final TraceOptions traceOptions;
|
||||
private final Tracestate tracestate;
|
||||
|
||||
/**
|
||||
* The invalid {@code SpanContext}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static final SpanContext INVALID =
|
||||
new SpanContext(TraceId.INVALID, SpanId.INVALID, TraceOptions.DEFAULT, TRACESTATE_DEFAULT);
|
||||
|
||||
/**
|
||||
* Creates a new {@code SpanContext} with the given identifiers and options.
|
||||
*
|
||||
* @param traceId the trace identifier of the span context.
|
||||
* @param spanId the span identifier of the span context.
|
||||
* @param traceOptions the trace options for the span context.
|
||||
* @return a new {@code SpanContext} with the given identifiers and options.
|
||||
* @deprecated use {@link #create(TraceId, SpanId, TraceOptions, Tracestate)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static SpanContext create(TraceId traceId, SpanId spanId, TraceOptions traceOptions) {
|
||||
return create(traceId, spanId, traceOptions, TRACESTATE_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code SpanContext} with the given identifiers and options.
|
||||
*
|
||||
* @param traceId the trace identifier of the span context.
|
||||
* @param spanId the span identifier of the span context.
|
||||
* @param traceOptions the trace options for the span context.
|
||||
* @param tracestate the trace state for the span context.
|
||||
* @return a new {@code SpanContext} with the given identifiers and options.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static SpanContext create(
|
||||
TraceId traceId, SpanId spanId, TraceOptions traceOptions, Tracestate tracestate) {
|
||||
return new SpanContext(traceId, spanId, traceOptions, tracestate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the trace identifier associated with this {@code SpanContext}.
|
||||
*
|
||||
* @return the trace identifier associated with this {@code SpanContext}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public TraceId getTraceId() {
|
||||
return traceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the span identifier associated with this {@code SpanContext}.
|
||||
*
|
||||
* @return the span identifier associated with this {@code SpanContext}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public SpanId getSpanId() {
|
||||
return spanId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code TraceOptions} associated with this {@code SpanContext}.
|
||||
*
|
||||
* @return the {@code TraceOptions} associated with this {@code SpanContext}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public TraceOptions getTraceOptions() {
|
||||
return traceOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code Tracestate} associated with this {@code SpanContext}.
|
||||
*
|
||||
* @return the {@code Tracestate} associated with this {@code SpanContext}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public Tracestate getTracestate() {
|
||||
return tracestate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this {@code SpanContext} is valid.
|
||||
*
|
||||
* @return true if this {@code SpanContext} is valid.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public boolean isValid() {
|
||||
return traceId.isValid() && spanId.isValid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof SpanContext)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SpanContext that = (SpanContext) obj;
|
||||
return traceId.equals(that.traceId)
|
||||
&& spanId.equals(that.spanId)
|
||||
&& traceOptions.equals(that.traceOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(new Object[] {traceId, spanId, traceOptions});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SpanContext{traceId="
|
||||
+ traceId
|
||||
+ ", spanId="
|
||||
+ spanId
|
||||
+ ", traceOptions="
|
||||
+ traceOptions
|
||||
+ "}";
|
||||
}
|
||||
|
||||
private SpanContext(
|
||||
TraceId traceId, SpanId spanId, TraceOptions traceOptions, Tracestate tracestate) {
|
||||
this.traceId = traceId;
|
||||
this.spanId = spanId;
|
||||
this.traceOptions = traceOptions;
|
||||
this.tracestate = tracestate;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
* Copyright 2019, OpenConsensus Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package openconsensus.trace;
|
||||
|
||||
import openconsensus.internal.Utils;
|
||||
import java.util.Random;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* A class that represents a span identifier. A valid span identifier is an 8-byte array with at
|
||||
* least one non-zero byte.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Immutable
|
||||
public final class SpanId implements Comparable<SpanId> {
|
||||
/**
|
||||
* The size in bytes of the {@code SpanId}.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static final int SIZE = 8;
|
||||
|
||||
/**
|
||||
* The invalid {@code SpanId}. All bytes are 0.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static final SpanId INVALID = new SpanId(0);
|
||||
|
||||
private static final int BASE16_SIZE = 2 * SIZE;
|
||||
private static final long INVALID_ID = 0;
|
||||
|
||||
// The internal representation of the SpanId.
|
||||
private final long id;
|
||||
|
||||
private SpanId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code SpanId} built from a byte representation.
|
||||
*
|
||||
* @param src the representation of the {@code SpanId}.
|
||||
* @return a {@code SpanId} whose representation is given by the {@code src} parameter.
|
||||
* @throws NullPointerException if {@code src} is null.
|
||||
* @throws IllegalArgumentException if {@code src.length} is not {@link SpanId#SIZE}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static SpanId fromBytes(byte[] src) {
|
||||
Utils.checkNotNull(src, "src");
|
||||
// TODO: Remove this extra condition.
|
||||
Utils.checkArgument(src.length == SIZE, "Invalid size: expected %s, got %s", SIZE, src.length);
|
||||
return fromBytes(src, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code SpanId} whose representation is copied from the {@code src} beginning at the
|
||||
* {@code srcOffset} offset.
|
||||
*
|
||||
* @param src the buffer where the representation of the {@code SpanId} is copied.
|
||||
* @param srcOffset the offset in the buffer where the representation of the {@code SpanId}
|
||||
* begins.
|
||||
* @return a {@code SpanId} whose representation is copied from the buffer.
|
||||
* @throws NullPointerException if {@code src} is null.
|
||||
* @throws IndexOutOfBoundsException if {@code srcOffset+SpanId.SIZE} is greater than {@code
|
||||
* src.length}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static SpanId fromBytes(byte[] src, int srcOffset) {
|
||||
Utils.checkNotNull(src, "src");
|
||||
return new SpanId(BigendianEncoding.longFromByteArray(src, srcOffset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code SpanId} built from a lowercase base16 representation.
|
||||
*
|
||||
* @param src the lowercase base16 representation.
|
||||
* @return a {@code SpanId} built from a lowercase base16 representation.
|
||||
* @throws NullPointerException if {@code src} is null.
|
||||
* @throws IllegalArgumentException if {@code src.length} is not {@code 2 * SpanId.SIZE} OR if the
|
||||
* {@code str} has invalid characters.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static SpanId fromLowerBase16(CharSequence src) {
|
||||
Utils.checkNotNull(src, "src");
|
||||
// TODO: Remove this extra condition.
|
||||
Utils.checkArgument(
|
||||
src.length() == BASE16_SIZE,
|
||||
"Invalid size: expected %s, got %s",
|
||||
BASE16_SIZE,
|
||||
src.length());
|
||||
return fromLowerBase16(src, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code SpanId} built from a lowercase base16 representation.
|
||||
*
|
||||
* @param src the lowercase base16 representation.
|
||||
* @param srcOffset the offset in the buffer where the representation of the {@code SpanId}
|
||||
* begins.
|
||||
* @return a {@code SpanId} built from a lowercase base16 representation.
|
||||
* @throws NullPointerException if {@code src} is null.
|
||||
* @throws IllegalArgumentException if not enough characters in the {@code src} from the {@code
|
||||
* srcOffset}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static SpanId fromLowerBase16(CharSequence src, int srcOffset) {
|
||||
Utils.checkNotNull(src, "src");
|
||||
return new SpanId(BigendianEncoding.longFromBase16String(src, srcOffset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new random {@code SpanId}.
|
||||
*
|
||||
* @param random The random number generator.
|
||||
* @return a valid new {@code SpanId}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public static SpanId generateRandomId(Random random) {
|
||||
long id;
|
||||
do {
|
||||
id = random.nextLong();
|
||||
} while (id == INVALID_ID);
|
||||
return new SpanId(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the byte representation of the {@code SpanId}.
|
||||
*
|
||||
* @return the byte representation of the {@code SpanId}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public byte[] getBytes() {
|
||||
byte[] bytes = new byte[SIZE];
|
||||
BigendianEncoding.longToByteArray(id, bytes, 0);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the byte array representations of the {@code SpanId} into the {@code dest} beginning at
|
||||
* the {@code destOffset} offset.
|
||||
*
|
||||
* @param dest the destination buffer.
|
||||
* @param destOffset the starting offset in the destination buffer.
|
||||
* @throws NullPointerException if {@code dest} is null.
|
||||
* @throws IndexOutOfBoundsException if {@code destOffset+SpanId.SIZE} is greater than {@code
|
||||
* dest.length}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public void copyBytesTo(byte[] dest, int destOffset) {
|
||||
BigendianEncoding.longToByteArray(id, dest, destOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the lowercase base16 representations of the {@code SpanId} into the {@code dest}
|
||||
* beginning at the {@code destOffset} offset.
|
||||
*
|
||||
* @param dest the destination buffer.
|
||||
* @param destOffset the starting offset in the destination buffer.
|
||||
* @throws IndexOutOfBoundsException if {@code destOffset + 2 * SpanId.SIZE} is greater than
|
||||
* {@code dest.length}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public void copyLowerBase16To(char[] dest, int destOffset) {
|
||||
BigendianEncoding.longToBase16String(id, dest, destOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the span identifier is valid. A valid span identifier is an 8-byte array with
|
||||
* at least one non-zero byte.
|
||||
*
|
||||
* @return {@code true} if the span identifier is valid.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public boolean isValid() {
|
||||
return id != INVALID_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the lowercase base16 encoding of this {@code SpanId}.
|
||||
*
|
||||
* @return the lowercase base16 encoding of this {@code SpanId}.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public String toLowerBase16() {
|
||||
char[] chars = new char[BASE16_SIZE];
|
||||
copyLowerBase16To(chars, 0);
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof SpanId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SpanId that = (SpanId) obj;
|
||||
return id == that.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// Copied from Long.hashCode in java8.
|
||||
return (int) (id ^ (id >>> 32));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SpanId{spanId=" + toLowerBase16() + "}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(SpanId that) {
|
||||
// Copied from Long.compare in java8.
|
||||
return (id < that.id) ? -1 : ((id == that.id) ? 0 : 1);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue