Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stabilize log any value #6591

Merged
merged 8 commits into from
Aug 30, 2024
Merged
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
25 changes: 25 additions & 0 deletions api/all/src/main/java/io/opentelemetry/api/common/KeyValue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.api.common;

/**
* Key-value pair of {@link String} key and {@link Value} value.
*
* @see Value#of(KeyValue...)
*/
public interface KeyValue {

/** Returns a {@link KeyValue} for the given {@code key} and {@code value}. */
static KeyValue of(String key, Value<?> value) {
return KeyValueImpl.create(key, value);
}

/** Returns the key. */
String getKey();

/** Returns the value. */
Value<?> getValue();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.api.common;

import com.google.auto.value.AutoValue;

@AutoValue
abstract class KeyValueImpl implements KeyValue {

KeyValueImpl() {}

static KeyValueImpl create(String key, Value<?> value) {
return new AutoValue_KeyValueImpl(key, value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.api.common;

import static java.util.stream.Collectors.joining;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;

final class KeyValueList implements Value<List<KeyValue>> {

private final List<KeyValue> value;

private KeyValueList(List<KeyValue> value) {
this.value = value;
}

static Value<List<KeyValue>> create(KeyValue... value) {
Objects.requireNonNull(value, "value must not be null");
List<KeyValue> list = new ArrayList<>(value.length);
list.addAll(Arrays.asList(value));
return new KeyValueList(Collections.unmodifiableList(list));
}

static Value<List<KeyValue>> createFromMap(Map<String, Value<?>> value) {
Objects.requireNonNull(value, "value must not be null");
KeyValue[] array =
value.entrySet().stream()
.map(entry -> KeyValue.of(entry.getKey(), entry.getValue()))
.toArray(KeyValue[]::new);
return create(array);
}

@Override
public ValueType getType() {
return ValueType.KEY_VALUE_LIST;
}

@Override
public List<KeyValue> getValue() {
return value;
}

@Override
public String asString() {
return value.stream()
.map(item -> item.getKey() + "=" + item.getValue().asString())
.collect(joining(", ", "[", "]"));
}

@Override
public String toString() {
return "KeyValueList{" + asString() + "}";
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;

Check warning on line 66 in api/all/src/main/java/io/opentelemetry/api/common/KeyValueList.java

View check run for this annotation

Codecov / codecov/patch

api/all/src/main/java/io/opentelemetry/api/common/KeyValueList.java#L66

Added line #L66 was not covered by tests
}
return (o instanceof Value) && Objects.equals(this.value, ((Value<?>) o).getValue());
}

@Override
public int hashCode() {
return value.hashCode();
}
}
117 changes: 117 additions & 0 deletions api/all/src/main/java/io/opentelemetry/api/common/Value.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.api.common;

import java.nio.ByteBuffer;
import java.util.List;
import java.util.Map;

/**
* Value mirrors the proto <a
* href="https://github.com/open-telemetry/opentelemetry-proto/blob/ac3242b03157295e4ee9e616af53b81517b06559/opentelemetry/proto/common/v1/common.proto#L28">AnyValue</a>
* message type, and is used to model any type.
*
* <p>It can be used to represent:
*
* <ul>
* <li>Primitive values via {@link #of(long)}, {@link #of(String)}, {@link #of(boolean)}, {@link
* #of(double)}.
* <li>String-keyed maps (i.e. associative arrays, dictionaries) via {@link #of(KeyValue...)},
* {@link #of(Map)}. Note, because map values are type {@link Value}, maps can be nested
* within other maps.
* <li>Arrays (heterogeneous or homogenous) via {@link #of(Value[])}. Note, because array values
* are type {@link Value}, arrays can contain primitives, complex types like maps or arrays,
* or any combination.
* <li>Raw bytes via {@link #of(byte[])}
* </ul>
*
* <p>Currently, Value is only used as an argument for {@link
* io.opentelemetry.api.logs.LogRecordBuilder#setBody(Value)}.
*
* @param <T> the type. See {@link #getValue()} for description of types.
*/
public interface Value<T> {

/** Returns an {@link Value} for the {@link String} value. */
static Value<String> of(String value) {
return ValueString.create(value);
}

/** Returns an {@link Value} for the {@code boolean} value. */
static Value<Boolean> of(boolean value) {
return ValueBoolean.create(value);
}

/** Returns an {@link Value} for the {@code long} value. */
static Value<Long> of(long value) {
return ValueLong.create(value);
}

/** Returns an {@link Value} for the {@code double} value. */
static Value<Double> of(double value) {
return ValueDouble.create(value);
}

/** Returns an {@link Value} for the {@code byte[]} value. */
static Value<ByteBuffer> of(byte[] value) {
return ValueBytes.create(value);
}

/** Returns an {@link Value} for the array of {@link Value} values. */
static Value<List<Value<?>>> of(Value<?>... value) {
return ValueArray.create(value);
}

/** Returns an {@link Value} for the list of {@link Value} values. */
static Value<List<Value<?>>> of(List<Value<?>> value) {
return ValueArray.create(value);
}

/**
* Returns an {@link Value} for the array of {@link KeyValue} values. {@link KeyValue#getKey()}
* values should not repeat - duplicates may be dropped.
*/
static Value<List<KeyValue>> of(KeyValue... value) {
return KeyValueList.create(value);
}

/** Returns an {@link Value} for the {@link Map} of key, {@link Value}. */
static Value<List<KeyValue>> of(Map<String, Value<?>> value) {
return KeyValueList.createFromMap(value);
}

/** Returns the type of this {@link Value}. Useful for building switch statements. */
ValueType getType();

/**
* Returns the value for this {@link Value}.
*
* <p>The return type varies by {@link #getType()} as described below:
*
* <ul>
* <li>{@link ValueType#STRING} returns {@link String}
* <li>{@link ValueType#BOOLEAN} returns {@code boolean}
* <li>{@link ValueType#LONG} returns {@code long}
* <li>{@link ValueType#DOUBLE} returns {@code double}
* <li>{@link ValueType#ARRAY} returns {@link List} of {@link Value}
* <li>{@link ValueType#KEY_VALUE_LIST} returns {@link List} of {@link KeyValue}
* <li>{@link ValueType#BYTES} returns read only {@link ByteBuffer}. See {@link
* ByteBuffer#asReadOnlyBuffer()}.
* </ul>
*/
T getValue();

/**
* Return a string encoding of this {@link Value}. This is intended to be a fallback serialized
* representation in case there is no suitable encoding that can utilize {@link #getType()} /
* {@link #getValue()} to serialize specific types.
*
* <p>WARNING: No guarantees are made about the encoding of this string response. It MAY change in
* a future minor release. If you need a reliable string encoding, write your own serializer.
*/
// TODO(jack-berg): Should this be a JSON encoding?
String asString();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.api.common;

import static java.util.stream.Collectors.joining;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

final class ValueArray implements Value<List<Value<?>>> {

private final List<Value<?>> value;

private ValueArray(List<Value<?>> value) {
this.value = value;
}

static Value<List<Value<?>>> create(Value<?>... value) {
Objects.requireNonNull(value, "value must not be null");
List<Value<?>> list = new ArrayList<>(value.length);
list.addAll(Arrays.asList(value));
return new ValueArray(Collections.unmodifiableList(list));
}

static Value<List<Value<?>>> create(List<Value<?>> value) {
return new ValueArray(Collections.unmodifiableList(value));
}

@Override
public ValueType getType() {
return ValueType.ARRAY;
}

@Override
public List<Value<?>> getValue() {
return value;
}

@Override
public String asString() {
return value.stream().map(Value::asString).collect(joining(", ", "[", "]"));
}

@Override
public String toString() {
return "ValueArray{" + asString() + "}";
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;

Check warning on line 58 in api/all/src/main/java/io/opentelemetry/api/common/ValueArray.java

View check run for this annotation

Codecov / codecov/patch

api/all/src/main/java/io/opentelemetry/api/common/ValueArray.java#L58

Added line #L58 was not covered by tests
}
return (o instanceof Value) && Objects.equals(this.value, ((Value<?>) o).getValue());
}

@Override
public int hashCode() {
return value.hashCode();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,25 @@
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.api.incubator.logs;
package io.opentelemetry.api.common;

import java.util.Objects;

final class AnyValueBoolean implements AnyValue<Boolean> {
final class ValueBoolean implements Value<Boolean> {

private final boolean value;

private AnyValueBoolean(boolean value) {
private ValueBoolean(boolean value) {
this.value = value;
}

static AnyValue<Boolean> create(boolean value) {
return new AnyValueBoolean(value);
static Value<Boolean> create(boolean value) {
return new ValueBoolean(value);
}

@Override
public AnyValueType getType() {
return AnyValueType.BOOLEAN;
public ValueType getType() {
return ValueType.BOOLEAN;
}

@Override
Expand All @@ -36,15 +36,15 @@ public String asString() {

@Override
public String toString() {
return "AnyValueBoolean{" + asString() + "}";
return "ValueBoolean{" + asString() + "}";
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
return (o instanceof AnyValue) && Objects.equals(this.value, ((AnyValue<?>) o).getValue());
return (o instanceof Value) && Objects.equals(this.value, ((Value<?>) o).getValue());
}

@Override
Expand Down
Loading
Loading