diff --git a/exporters/otlp/profiles/build.gradle.kts b/exporters/otlp/profiles/build.gradle.kts new file mode 100644 index 00000000000..8b22581662f --- /dev/null +++ b/exporters/otlp/profiles/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { + id("otel.java-conventions") + id("otel.publish-conventions") + + id("otel.animalsniffer-conventions") +} + +description = "OpenTelemetry - Profiles Exporter" +otelJava.moduleName.set("io.opentelemetry.exporter.otlp.profiles") + +dependencies { + api(project(":sdk:common")) +} diff --git a/exporters/otlp/profiles/gradle.properties b/exporters/otlp/profiles/gradle.properties new file mode 100644 index 00000000000..4476ae57e31 --- /dev/null +++ b/exporters/otlp/profiles/gradle.properties @@ -0,0 +1 @@ +otel.release=alpha diff --git a/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/AggregationTemporality.java b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/AggregationTemporality.java new file mode 100644 index 00000000000..4586a4652b1 --- /dev/null +++ b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/AggregationTemporality.java @@ -0,0 +1,39 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.otlp.profiles; + +/** + * Specifies the method of aggregating metric values. + * + *

TODO: This is intentionally not the same as metrics/AggregationTemporality. For profiles.proto + * 'v1experimental' version, this class is considered distinct from the pre-exiting + * AggregationTemporality in metrics.proto. As the profiles.proto stabilises, they may be refactored + * into a version in common.proto. Meanwhile the Java class structure reflects the .proto structure + * in making distinct entities. + * + *

refs for refactoring discussion: + * + * @see + * "https://github.com/open-telemetry/opentelemetry-proto/blob/v1.3.0/opentelemetry/proto/metrics/v1/metrics.proto#L261" + * @see + * "https://github.com/open-telemetry/opentelemetry-proto/blob/v1.3.0/opentelemetry/proto/profiles/v1experimental/pprofextended.proto#L147" + * @see "https://github.com/open-telemetry/opentelemetry-proto/issues/547" + * @see "https://github.com/open-telemetry/opentelemetry-proto/pull/534#discussion_r1552403726" + * @see "profiles.proto::AggregationTemporality" + */ +public enum AggregationTemporality { + + /** + * DELTA is an AggregationTemporality for a profiler which reports changes since last report time. + */ + DELTA, + + /** + * CUMULATIVE is an AggregationTemporality for a profiler which reports changes since a fixed + * start time. + */ + CUMULATIVE +} diff --git a/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/AttributeUnitData.java b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/AttributeUnitData.java new file mode 100644 index 00000000000..47f2403cbd4 --- /dev/null +++ b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/AttributeUnitData.java @@ -0,0 +1,23 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.otlp.profiles; + +import javax.annotation.concurrent.Immutable; + +/** + * Represents a mapping between Attribute Keys and Units. + * + * @see "pprofextended.proto::AttributeUnit" + */ +@Immutable +public interface AttributeUnitData { + + /** Index into string table. */ + long getAttributeKey(); + + /** Index into string table. */ + long getUnitIndex(); +} diff --git a/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/BuildIdKind.java b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/BuildIdKind.java new file mode 100644 index 00000000000..9852b623aed --- /dev/null +++ b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/BuildIdKind.java @@ -0,0 +1,20 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.otlp.profiles; + +/** + * Indicates the semantics of the build_id field. + * + * @see "pprofextended.proto::BuildIdKind" + */ +public enum BuildIdKind { + + /** Linker-generated build ID, stored in the ELF binary notes. */ + LINKER, + + /** Build ID based on the content hash of the binary. */ + BINARY_HASH; +} diff --git a/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/FunctionData.java b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/FunctionData.java new file mode 100644 index 00000000000..3f246ce4a02 --- /dev/null +++ b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/FunctionData.java @@ -0,0 +1,32 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.otlp.profiles; + +import javax.annotation.concurrent.Immutable; + +/** + * Describes a function. + * + * @see "pprofextended.proto::Function" + */ +@Immutable +public interface FunctionData { + + /** Name of the function, in human-readable form if available. Index into string table. */ + long getNameIndex(); + + /** + * Name of the function, as identified by the system. For instance, it can be a C++ mangled name. + * Index into string table. + */ + long getSystemNameIndex(); + + /** Source file containing the function. Index into string table. */ + long getFilenameIndex(); + + /** Line number in source file. */ + long getStartLine(); +} diff --git a/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/LabelData.java b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/LabelData.java new file mode 100644 index 00000000000..adc8787bae8 --- /dev/null +++ b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/LabelData.java @@ -0,0 +1,33 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.otlp.profiles; + +import javax.annotation.concurrent.Immutable; + +/** + * Provides additional context for a sample, such as thread ID or allocation size, with optional + * units. + * + * @see "pprofextended.proto::Label" + */ +@Immutable +public interface LabelData { + + /** Index into string table. */ + long getKeyIndex(); + + /** String value of the label data, if applicable. Index into string table */ + long getStrIndex(); + + /** Numeric value of the label data, if applicable. */ + long getNum(); + + /** + * Specifies the units of num, applicable only if num is present. Use arbitrary string (for + * example, "requests") as a custom count unit. + */ + long getNumUnitIndex(); +} diff --git a/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/LineData.java b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/LineData.java new file mode 100644 index 00000000000..b19e53cfa1e --- /dev/null +++ b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/LineData.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.otlp.profiles; + +import javax.annotation.concurrent.Immutable; + +/** + * Details a specific line in a source code, linked to a function. + * + * @see "pprofextended.proto::Line" + */ +@Immutable +public interface LineData { + + /** The index of the corresponding Function for this line. Index into function table. */ + long getFunctionIndex(); + + /** Line number in source code. */ + long getLine(); + + /** Column number in source code. */ + long getColumn(); +} diff --git a/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/LinkData.java b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/LinkData.java new file mode 100644 index 00000000000..dd76c9283b2 --- /dev/null +++ b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/LinkData.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.otlp.profiles; + +import javax.annotation.concurrent.Immutable; + +/** + * A connection from a profile Sample to a trace Span. + * + * @see "pprofextended.proto::Link" + */ +@Immutable +public interface LinkData { + + /** + * Returns a unique identifier of a trace that this linked span is part of as 32 character + * lowercase hex String. + */ + String getTraceId(); + + /** Returns a unique identifier for the linked span, as 16 character lowercase hex String. */ + String getSpanId(); +} diff --git a/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/LocationData.java b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/LocationData.java new file mode 100644 index 00000000000..d22ba65c55d --- /dev/null +++ b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/LocationData.java @@ -0,0 +1,45 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.otlp.profiles; + +import java.util.List; +import javax.annotation.concurrent.Immutable; + +/** + * Describes a function. + * + * @see "pprofextended.proto::Location" + */ +@Immutable +public interface LocationData { + + /** + * The index of the corresponding profile.Mapping for this location. It can be unset if the + * mapping is unknown or not applicable for this profile type. + */ + long getMappingIndex(); + + /** The instruction address for this location, if available. */ + long getAddress(); + + /** + * Multiple line indicates this location has inlined functions, where the last entry represents + * the caller into which the preceding entries were inlined. + */ + List getLines(); + + /** + * Provides an indication that multiple symbols map to this location's address, for example due to + * identical code folding by the linker. + */ + boolean isFolded(); + + /** Type of frame (e.g. kernel, native, python, hotspot, php). Index into string table. */ + int getTypeIndex(); + + /** References to attributes in Profile.attribute_table. */ + List getAttributes(); +} diff --git a/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/MappingData.java b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/MappingData.java new file mode 100644 index 00000000000..2b5e14a0c91 --- /dev/null +++ b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/MappingData.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.otlp.profiles; + +import java.util.List; +import javax.annotation.concurrent.Immutable; + +/** + * Describes the mapping of a binary in memory. + * + * @see "pprofextended.proto::Mapping" + */ +@Immutable +public interface MappingData { + + /** Address at which the binary (or DLL) is loaded into memory. */ + long getMemoryStart(); + + /** The limit of the address range occupied by this mapping. */ + long getMemoryLimit(); + + /** Offset in the binary that corresponds to the first mapped address. */ + long getFileOffset(); + + /** + * The object this entry is loaded from. This can be a filename on disk for the main binary and + * shared libraries, or virtual abstraction like "[vdso]". Index into the string table. + */ + long getFilenameIndex(); + + /** + * Uniquely identifies a particular program version with high probability. e.g., for binaries + * generated by GNU tools, the contents of the .note.gnu.build-id field. Index into the string + * table. + */ + long getBuildIdIndex(); + + /** Specifies the kind of build id. See BuildIdKind enum for more details */ + BuildIdKind getBuildIdKind(); + + /** References to attributes in Profile.attribute_table. */ + List getAttributeIndices(); + + boolean hasFunctions(); + + boolean hasFilenames(); + + boolean hasLineNumbers(); + + boolean hasInlineFrames(); +} diff --git a/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/ProfileContainerData.java b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/ProfileContainerData.java new file mode 100644 index 00000000000..f7e16f1ba0d --- /dev/null +++ b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/ProfileContainerData.java @@ -0,0 +1,92 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.otlp.profiles; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.internal.OtelEncodingUtils; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.resources.Resource; +import java.nio.ByteBuffer; +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +/** + * A ProfileContainer represents a single profile. It wraps pprof profile with OpenTelemetry + * specific metadata. + * + * @see "profiles.proto::ProfileContainer" + */ +@Immutable +public interface ProfileContainerData { + + /** Returns the resource of this profile. */ + Resource getResource(); + + /** Returns the instrumentation scope that generated this profile. */ + InstrumentationScopeInfo getInstrumentationScopeInfo(); + + /** + * Returns a globally unique identifier for a profile, as 32 character lowercase hex String. An ID + * with all zeroes is considered invalid. This field is required. + */ + String getProfileId(); + + /** + * Returns a globally unique identifier for a profile, as a 16 bytes array. An ID with all zeroes + * is considered invalid. This field is required. + */ + default byte[] getProfileIdBytes() { + return OtelEncodingUtils.bytesFromBase16(getProfileId(), 32); + } + + /** + * Returns the start time of the profile. Value is UNIX Epoch time in nanoseconds since 00:00:00 + * UTC on 1 January 1970. This field is semantically required and it is expected that end_time >= + * start_time. + */ + long getStartEpochNanos(); + + /** + * Returns the end time of the profile. Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC + * on 1 January 1970. This field is semantically required and it is expected that end_time >= + * start_time. + */ + long getEndEpochNanos(); + + /** + * Returns profile-wide attributes. Attribute keys MUST be unique (it is not allowed to have more + * than one attribute with the same key). + * + * @see + * "https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/common/README.md#attribute" + */ + Attributes getAttributes(); + + /** + * Returns the total number of attributes that were recorded on this profile container. + * + *

This number may be larger than the number of attributes that are attached to this profile + * container, if the total number recorded was greater than the configured maximum value. + */ + int getTotalAttributeCount(); + + /** + * Returns the format of the original payload. Common values are defined in semantic conventions. + * [required if original_payload is present] + */ + @Nullable + String getOriginalPayloadFormat(); + + /** + * Returns the original payload, in a profiler-native format e.g. JFR. Optional. Default behavior + * should be to not include the original payload. If the original payload is in pprof format, it + * SHOULD not be included in this field. + */ + ByteBuffer getOriginalPayload(); + + /** Returns an extended pprof profile. Required, even when originalPayload is also present. */ + ProfileData getProfile(); +} diff --git a/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/ProfileData.java b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/ProfileData.java new file mode 100644 index 00000000000..63b26401de9 --- /dev/null +++ b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/ProfileData.java @@ -0,0 +1,87 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.otlp.profiles; + +import io.opentelemetry.api.common.Attributes; +import java.util.List; +import javax.annotation.concurrent.Immutable; + +/** + * Represents a complete profile, including sample types, samples, mappings to binaries, locations, + * functions, string table, and additional metadata. + * + * @see "pprofextended.proto::Profile" + */ +@Immutable +public interface ProfileData { + + /** A description of the samples associated with each Sample.value. */ + List getSampleTypes(); + + /** The set of samples recorded in this profile. */ + List getSamples(); + + /** + * Mapping from address ranges to the image/binary/library mapped into that address range. + * mapping[0] will be the main binary. + */ + List getMappings(); + + /** Locations referenced by samples via location_indices. */ + List getLocations(); + + /** Array of locations referenced by samples. */ + List getLocationIndices(); + + /** Functions referenced by locations. */ + List getFunctions(); + + /** Lookup table for attributes. */ + Attributes getAttributes(); + + /** Represents a mapping between Attribute Keys and Units. */ + List getAttributeUnits(); + + /** Lookup table for links. */ + List getLinks(); + + /** + * A common table for strings referenced by various messages. string_table[0] must always be "". + */ + List getStringTable(); + + /** + * Frames with Function.function_name fully matching the following regexp will be dropped from the + * samples, along with their successors. Index into string table. + */ + long getDropFrames(); + + /** + * Frames with Function.function_name fully matching the following regexp will be kept, even if + * matching drop_frames pattern. Index into string table. + */ + long getKeepFrames(); + + /** Time of collection (UTC) represented as nanoseconds past the epoch. */ + long getTimeNanos(); + + /** Duration of the profile, if a duration makes sense. */ + long getDurationNanos(); + + /** + * The kind of events between sampled occurrences. e.g [ "cpu","cycles" ] or [ "heap","bytes" ] + */ + ValueTypeData getPeriodType(); + + /** The number of events between sampled occurrences. */ + long getPeriod(); + + /** Free-form text associated with the profile. Indices into string table. */ + List getComment(); + + /** Type of the preferred sample. Index into the string table. */ + long getDefaultSampleType(); +} diff --git a/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/SampleData.java b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/SampleData.java new file mode 100644 index 00000000000..f5671511421 --- /dev/null +++ b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/SampleData.java @@ -0,0 +1,55 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.otlp.profiles; + +import java.util.List; +import javax.annotation.concurrent.Immutable; + +/** + * Each Sample records values encountered in some program context. The program context is typically + * a stack trace, perhaps augmented with auxiliary information like the thread-id, some indicator of + * a higher level request being handled etc. + * + * @see "pprofextended.proto::Sample" + */ +@Immutable +public interface SampleData { + + /** + * locationsStartIndex along with locationsLength refers to a slice of locations in + * Profile.location. Supersedes locationIndices. + */ + long getLocationsStartIndex(); + + /** + * locationsLength along with locationsStartIndex refers to a slice of locations in + * Profile.location. locationIndices. + */ + long getLocationsLength(); + + /** + * reference to a 128bit id that uniquely identifies this stacktrace, globally. Index into the + * string table. + */ + int getStacktraceIdIndex(); + + /** + * The type and unit of each value is defined by the corresponding entry in Profile.sample_type. + */ + List getValues(); + + /** References to attributes in Profile.attribute_table. */ + List getAttributes(); + + /** Reference to link in Profile.link_table. */ + long getLink(); + + /** + * Timestamps associated with Sample represented in ms. These timestamps are expected to fall + * within the Profile's time range. + */ + List getTimestamps(); +} diff --git a/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/ValueTypeData.java b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/ValueTypeData.java new file mode 100644 index 00000000000..22c18787b32 --- /dev/null +++ b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/ValueTypeData.java @@ -0,0 +1,27 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.otlp.profiles; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +/** + * ValueType describes the type and units of a value, with an optional aggregation temporality. + * + * @see "pprofextended.proto::ValueType" + */ +@Immutable +public interface ValueTypeData { + + /** Index into string table. */ + long type(); + + /** Index into string table. */ + long unit(); + + @Nullable + AggregationTemporality aggregationTemporality(); +} diff --git a/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/package-info.java b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/package-info.java new file mode 100644 index 00000000000..ec0107701b5 --- /dev/null +++ b/exporters/otlp/profiles/src/main/java/io/opentelemetry/exporter/otlp/profiles/package-info.java @@ -0,0 +1,10 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +/** The data format to model profiles for export. */ +@ParametersAreNonnullByDefault +package io.opentelemetry.exporter.otlp.profiles; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/settings.gradle.kts b/settings.gradle.kts index a5d95eb9bf7..3fc709b740d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -39,6 +39,7 @@ include(":exporters:logging") include(":exporters:logging-otlp") include(":exporters:otlp:all") include(":exporters:otlp:common") +include(":exporters:otlp:profiles") include(":exporters:otlp:testing-internal") include(":exporters:prometheus") include(":exporters:zipkin")