Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 78 additions & 13 deletions all/src/test/java/io/opentelemetry/all/NullGuardsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.opentelemetry.api.common.KeyValue;
import io.opentelemetry.api.common.Value;
import io.opentelemetry.common.impl.ApiUsageLogger;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.internal.testing.slf4j.SuppressLogger;
import java.io.File;
Expand All @@ -27,7 +28,14 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.jar.JarEntry;
Expand Down Expand Up @@ -104,24 +112,81 @@ class NullGuardsTest {
* fallbacks in runtime-defaulted artifacts.
*/
private static final Map<String, GuardStyle> METHOD_STYLE_OVERRIDES =
Map.of(
overrideKey(GlobalOpenTelemetry.class, "set", void.class, OpenTelemetry.class),
GuardStyle.FAIL_FAST,
overrideKey(GlobalOpenTelemetry.class, "set", void.class, Supplier.class),
GuardStyle.FAIL_FAST,
overrideKey(
Map.ofEntries(
Map.entry(
overrideKey(GlobalOpenTelemetry.class, "set", void.class, OpenTelemetry.class),
GuardStyle.FAIL_FAST),
Map.entry(
overrideKey(GlobalOpenTelemetry.class, "set", void.class, Supplier.class),
GuardStyle.FAIL_FAST),
Map.entry(
overrideKey(
OpenTelemetry.class,
"propagating",
OpenTelemetry.class,
ContextPropagators.class),
GuardStyle.FAIL_FAST,
GuardStyle.FAIL_FAST),
// Context wrappers are setup-time adapters. Fail fast rather than defer an NPE until use
// or substitute a noop that could discard application work or return an invalid result.
Map.entry(
overrideKey(Context.class, "taskWrapping", Executor.class, Executor.class),
GuardStyle.FAIL_FAST),
Map.entry(
overrideKey(
Context.class, "taskWrapping", ExecutorService.class, ExecutorService.class),
GuardStyle.FAIL_FAST),
Map.entry(
overrideKey(
Context.class,
"taskWrapping",
ScheduledExecutorService.class,
ScheduledExecutorService.class),
GuardStyle.FAIL_FAST),
Map.entry(
overrideKey(Context.class, "wrap", Executor.class, Executor.class),
GuardStyle.FAIL_FAST),
Map.entry(
overrideKey(Context.class, "wrap", ExecutorService.class, ExecutorService.class),
GuardStyle.FAIL_FAST),
Map.entry(
overrideKey(
Context.class,
"wrap",
ScheduledExecutorService.class,
ScheduledExecutorService.class),
GuardStyle.FAIL_FAST),
Map.entry(
overrideKey(Context.class, "wrap", Runnable.class, Runnable.class),
GuardStyle.FAIL_FAST),
Map.entry(
overrideKey(Context.class, "wrap", Callable.class, Callable.class),
GuardStyle.FAIL_FAST),
Map.entry(
overrideKey(Context.class, "wrapFunction", Function.class, Function.class),
GuardStyle.FAIL_FAST),
Map.entry(
overrideKey(Context.class, "wrapFunction", BiFunction.class, BiFunction.class),
GuardStyle.FAIL_FAST),
Map.entry(
overrideKey(Context.class, "wrapConsumer", Consumer.class, Consumer.class),
GuardStyle.FAIL_FAST),
Map.entry(
overrideKey(Context.class, "wrapConsumer", BiConsumer.class, BiConsumer.class),
GuardStyle.FAIL_FAST),
Map.entry(
overrideKey(Context.class, "wrapSupplier", Supplier.class, Supplier.class),
GuardStyle.FAIL_FAST),
// Value.empty() cannot preserve these generic return types. We may reevaluate in future.
overrideKey(Value.class, "of", Value.class, String.class), GuardStyle.FAIL_FAST,
overrideKey(Value.class, "of", Value.class, byte[].class), GuardStyle.FAIL_FAST,
overrideKey(Value.class, "of", Value.class, Value[].class), GuardStyle.FAIL_FAST,
overrideKey(Value.class, "of", Value.class, List.class), GuardStyle.FAIL_FAST,
overrideKey(Value.class, "of", Value.class, KeyValue[].class), GuardStyle.FAIL_FAST,
overrideKey(Value.class, "of", Value.class, Map.class), GuardStyle.FAIL_FAST);
Map.entry(
overrideKey(Value.class, "of", Value.class, String.class), GuardStyle.FAIL_FAST),
Map.entry(
overrideKey(Value.class, "of", Value.class, byte[].class), GuardStyle.FAIL_FAST),
Map.entry(
overrideKey(Value.class, "of", Value.class, Value[].class), GuardStyle.FAIL_FAST),
Map.entry(overrideKey(Value.class, "of", Value.class, List.class), GuardStyle.FAIL_FAST),
Map.entry(
overrideKey(Value.class, "of", Value.class, KeyValue[].class), GuardStyle.FAIL_FAST),
Map.entry(overrideKey(Value.class, "of", Value.class, Map.class), GuardStyle.FAIL_FAST));

private static String overrideKey(
Class<?> owner, String name, Class<?> returnType, Class<?>... paramTypes) {
Expand Down
17 changes: 12 additions & 5 deletions api/all/src/main/java/io/opentelemetry/api/trace/SpanId.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,11 @@ public static String getInvalid() {
* @return {@code true} if the span identifier is valid.
*/
public static boolean isValid(CharSequence spanId) {
return spanId != null
&& spanId.length() == HEX_LENGTH
if (spanId == null) {
ApiUsageLogger.logNullParam(SpanId.class, "isValid", "spanId");
return false;
}
return spanId.length() == HEX_LENGTH
&& !INVALID.contentEquals(spanId)
&& OtelEncodingUtils.isValidBase16String(spanId);
}
Expand All @@ -72,9 +75,13 @@ public static boolean isValid(CharSequence spanId) {
* @return the lowercase hex (base16) representation of the {@code SpanId}.
*/
public static String fromBytes(byte[] spanIdBytes) {
if (spanIdBytes == null || spanIdBytes.length < BYTES_LENGTH) {
ApiUsageLogger.logUsageIssue(SpanId.class, "fromBytes", "spanIdBytes is null or too short");
return INVALID;
if (spanIdBytes == null) {
ApiUsageLogger.logNullParam(SpanId.class, "fromBytes", "spanIdBytes");
return getInvalid();
}
if (spanIdBytes.length < BYTES_LENGTH) {
ApiUsageLogger.logUsageIssue(SpanId.class, "fromBytes", "spanIdBytes is too short");
return getInvalid();
}
char[] result = TemporaryBuffers.chars(HEX_LENGTH);
OtelEncodingUtils.bytesToBase16(spanIdBytes, result, BYTES_LENGTH);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package io.opentelemetry.api.trace;

import io.opentelemetry.common.impl.ApiUsageLogger;
import javax.annotation.concurrent.Immutable;

/**
Expand Down Expand Up @@ -54,6 +55,10 @@ static TraceFlags getSampled() {
* @return the {@link TraceFlags} converted from the given lowercase hex (base16) representation.
*/
static TraceFlags fromHex(CharSequence src, int srcOffset) {
if (src == null) {
ApiUsageLogger.logNullParam(TraceFlags.class, "fromHex", "src");
return getDefault();
}
return ImmutableTraceFlags.fromHex(src, srcOffset);
}

Expand Down
15 changes: 11 additions & 4 deletions api/all/src/main/java/io/opentelemetry/api/trace/TraceId.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,11 @@ public static String getInvalid() {
* @return {@code true} if the {@code TraceId} is valid.
*/
public static boolean isValid(CharSequence traceId) {
return traceId != null
&& traceId.length() == HEX_LENGTH
if (traceId == null) {
ApiUsageLogger.logNullParam(TraceId.class, "isValid", "traceId");
return false;
}
return traceId.length() == HEX_LENGTH
&& !INVALID.contentEquals(traceId)
&& OtelEncodingUtils.isValidBase16String(traceId);
}
Expand All @@ -76,8 +79,12 @@ public static boolean isValid(CharSequence traceId) {
* @return the lowercase hex (base16) representation of the {@code TraceId}.
*/
public static String fromBytes(byte[] traceIdBytes) {
if (traceIdBytes == null || traceIdBytes.length < BYTES_LENGTH) {
ApiUsageLogger.logUsageIssue(TraceId.class, "fromBytes", "traceIdBytes is null or too short");
if (traceIdBytes == null) {
ApiUsageLogger.logNullParam(TraceId.class, "fromBytes", "traceIdBytes");
return INVALID;
}
if (traceIdBytes.length < BYTES_LENGTH) {
ApiUsageLogger.logUsageIssue(TraceId.class, "fromBytes", "traceIdBytes is too short");
return INVALID;
}
char[] result = TemporaryBuffers.chars(HEX_LENGTH);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package io.opentelemetry.api.trace;

import io.opentelemetry.common.impl.ApiUsageLogger;
import javax.annotation.concurrent.ThreadSafe;

/**
Expand Down Expand Up @@ -52,6 +53,11 @@ static TracerProvider noop() {
* @since 1.4.0
*/
default TracerBuilder tracerBuilder(String instrumentationScopeName) {
if (instrumentationScopeName == null) {
ApiUsageLogger.logNullParam(
TracerProvider.class, "tracerBuilder", "instrumentationScopeName");
return DefaultTracerBuilder.getInstance();
}
return DefaultTracerBuilder.getInstance();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import io.opentelemetry.api.trace.TraceFlags;
import io.opentelemetry.api.trace.TraceId;
import io.opentelemetry.api.trace.TraceState;
import io.opentelemetry.common.impl.ApiUsageLogger;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapGetter;
import io.opentelemetry.context.propagation.TextMapPropagator;
Expand Down Expand Up @@ -94,7 +95,12 @@ public Collection<String> fields() {

@Override
public <C> void inject(Context context, @Nullable C carrier, TextMapSetter<C> setter) {
if (context == null || setter == null) {
if (context == null) {
ApiUsageLogger.logNullParam(TextMapPropagator.class, "inject", "context");
return;
}
if (setter == null) {
ApiUsageLogger.logNullParam(TextMapPropagator.class, "inject", "setter");
return;
}

Expand Down Expand Up @@ -132,9 +138,11 @@ public <C> void inject(Context context, @Nullable C carrier, TextMapSetter<C> se
@Override
public <C> Context extract(Context context, @Nullable C carrier, TextMapGetter<C> getter) {
if (context == null) {
ApiUsageLogger.logNullParam(TextMapPropagator.class, "extract", "context");
return Context.root();
}
if (getter == null) {
ApiUsageLogger.logNullParam(TextMapPropagator.class, "extract", "getter");
return context;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

package io.opentelemetry.context;

import io.opentelemetry.common.impl.ApiUsageLogger;
import java.util.Arrays;
import javax.annotation.Nullable;

Expand Down Expand Up @@ -55,6 +56,10 @@ private ArrayBasedContext(Object[] entries) {
@Nullable
@SuppressWarnings("ReferenceEquality")
public <V> V get(ContextKey<V> key) {
if (key == null) {
ApiUsageLogger.logNullParam(Context.class, "get", "key");
return null;
}
for (int i = 0; i < entries.length; i += 2) {
if (entries[i] == key) {
@SuppressWarnings("unchecked")
Expand All @@ -68,6 +73,14 @@ public <V> V get(ContextKey<V> key) {
@Override
@SuppressWarnings("ReferenceEquality")
public <V> Context with(ContextKey<V> key, V value) {
if (key == null) {
ApiUsageLogger.logNullParam(Context.class, "with", "key");
return this;
}
if (value == null) {
ApiUsageLogger.logNullParam(Context.class, "with", "value");
// Continue to preserve the preexisting behavior of storing null values.
}
for (int i = 0; i < entries.length; i += 2) {
if (entries[i] == key) {
if (entries[i + 1] == value) {
Expand Down
Loading
Loading