Skip to content
This repository has been archived by the owner on Dec 6, 2024. It is now read-only.

Adds Profiling Signal #3

Merged
merged 25 commits into from
Jul 26, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
0c3571c
WIP: add profiling signal
felixge Jan 26, 2023
3decfa0
Merge remote-tracking branch 'felix/profiling-signal' into profiling
petethepig Jun 14, 2023
912021b
snapshot
petethepig Jun 14, 2023
72ddb55
snapshot
petethepig Jun 14, 2023
05ecb3c
empty profile proto
petethepig Jun 14, 2023
1ebf7eb
improved naming (profile_records came from log_records)
petethepig Jun 20, 2023
fb6e215
adds alternative variations of profiles proto
petethepig Jun 27, 2023
25dce2e
fix
petethepig Jun 27, 2023
e041293
Update CHANGELOG.md for 1.0.0 release (#493)
tigrannajaryan Jul 5, 2023
1695002
incorporating the feedback from the last meeting
petethepig Jul 5, 2023
7faab0e
copyright year fix
petethepig Jul 6, 2023
a87c236
uint64 -> uint32 for indices
petethepig Jul 6, 2023
980fc89
adds attributes to Location and Mapping
petethepig Jul 6, 2023
6b98f0c
move stacktraces to a separate message
petethepig Jul 7, 2023
efc572c
follow up to prev commit
petethepig Jul 7, 2023
8fe43e9
adds another alternative (arrays)
petethepig Jul 7, 2023
2487cf3
Fix EOF issue in metrics payload
ZaradarBH Jul 12, 2023
afcd2aa
Update metrics.json
ZaradarBH Jul 12, 2023
b016676
adds a decision log
petethepig Jul 18, 2023
1ced00e
[CI] Report link-check error when external URL used for local doc pag…
chalin Jul 19, 2023
199d94d
add markdown linting to makefile and github actions (reference: #464)
jaydeluca Jul 4, 2023
81a296f
fix linting errors from recent merge from main
jaydeluca Jul 13, 2023
8cd1e60
included recent suggestions
petethepig Jul 26, 2023
d3b7479
Merge branch 'main' into profiling
petethepig Jul 26, 2023
54bba7a
Merge remote-tracking branch 'profile/main' into profiling
petethepig Jul 26, 2023
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
79 changes: 79 additions & 0 deletions opentelemetry/proto/collector/profiles/v1/profiles_service.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright 2019, OpenTelemetry 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.

syntax = "proto3";

package opentelemetry.proto.collector.profiles.v1;

import "opentelemetry/proto/profiles/v1/profiles.proto";

option csharp_namespace = "OpenTelemetry.Proto.Collector.Profiles.V1";
option java_multiple_files = true;
option java_package = "io.opentelemetry.proto.collector.profiles.v1";
option java_outer_classname = "ProfilesServiceProto";
option go_package = "go.opentelemetry.io/proto/otlp/collector/profiles/v1";

// Service that can be used to push profiles between one Application instrumented with
// OpenTelemetry and a collector, or between a collector and a central collector (in this
// case spans are sent/received to/from multiple Applications).
service ProfilesService {
// For performance reasons, it is recommended to keep this RPC
// alive for the entire life of the application.
rpc Export(ExportProfilesServiceRequest) returns (ExportProfilesServiceResponse) {}
}

message ExportProfilesServiceRequest {
// An array of ResourceProfiles.
// For data coming from a single resource this array will typically contain one
// element. Intermediary nodes (such as OpenTelemetry Collector) that receive
// data from multiple origins typically batch the data before forwarding further and
// in that case this array will contain multiple elements.
repeated opentelemetry.proto.profiles.v1.ResourceProfiles resource_profiles = 1;
}

message ExportProfilesServiceResponse {
// The details of a partially successful export request.
//
// If the request is only partially accepted
// (i.e. when the server accepts only parts of the data and rejects the rest)
// the server MUST initialize the `partial_success` field and MUST
// set the `rejected_<signal>` with the number of items it rejected.
//
// Servers MAY also make use of the `partial_success` field to convey
// warnings/suggestions to senders even when the request was fully accepted.
// In such cases, the `rejected_<signal>` MUST have a value of `0` and
// the `error_message` MUST be non-empty.
//
// A `partial_success` message with an empty value (rejected_<signal> = 0 and
// `error_message` = "") is equivalent to it not being set/present. Senders
// SHOULD interpret it the same way as in the full success case.
ExportProfilesPartialSuccess partial_success = 1;
}

message ExportProfilesPartialSuccess {
// The number of rejected profiles.
//
// A `rejected_<signal>` field holding a `0` value indicates that the
// request was fully accepted.
int64 rejected_profiles = 1;

// A developer-facing human-readable message in English. It should be used
// either to explain why the server rejected parts of the data during a partial
// success or to convey warnings/suggestions during a full success. The message
// should offer guidance on how users can address such issues.
//
// error_message is an optional field. An error_message with an empty value
// is equivalent to it not being set.
string error_message = 2;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# This is an API configuration to generate an HTTP/JSON -> gRPC gateway for the
# OpenTelemetry service using github.com/grpc-ecosystem/grpc-gateway.
type: google.api.Service
config_version: 3
http:
rules:
- selector: opentelemetry.proto.collector.profiles.v1.ProfilesService.Export
post: /v1/profiles
body: "*"
169 changes: 169 additions & 0 deletions opentelemetry/proto/profiles/v1/alternatives/arrays/arrays.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
syntax = "proto3";

package opentelemetry.proto.profiles.v1.alternatives.arrays;

import "opentelemetry/proto/common/v1/common.proto";
import "opentelemetry/proto/resource/v1/resource.proto";

option go_package = "go.opentelemetry.io/proto/otlp/profiles/v1/arrays";


// A pointer from a profile to a trace span.
message Link {
// A unique identifier of a trace that this linked span is part of. The ID is a
// 16-byte array.
bytes trace_id = 1;
// A unique identifier for the linked span. The ID is an 8-byte array.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// A unique identifier for the linked span. The ID is an 8-byte array.
// A unique identifier for the linked span. The ID is an 16-byte array.

Similar to the trace_id a 16 byte array should be preferred over a 8-byte array for global uniqueness.

bytes span_id = 2;
}

// AttributeSet represents a set of attributes. It is referenced from Samples
// and not embedded because it is common for multiple samples to have the same
// set of attributes
message AttributeSet {
repeated opentelemetry.proto.common.v1.KeyValue attributes = 1;
uint32 dropped_attributes_count = 2;
}

message Stacktrace {
repeated uint32 location_indices = 1;
}

// message Sample {
// uint32 stacktrace_index = 1;
// repeated uint32 link_indices = 2;
// repeated uint32 attribute_set_indices = 3;
// repeated int64 values = 4;

// // optional
// fixed64 timestamp_unix_nano = 5;
// }

message SampleType {
// borrowed from metrics proto
enum AggregationTemporality {
AGGREGATION_TEMPORALITY_UNSPECIFIED = 0;
AGGREGATION_TEMPORALITY_DELTA = 1;
AGGREGATION_TEMPORALITY_CUMULATIVE = 2;
}

AggregationTemporality aggregation_temporality = 1;
uint64 sample_size = 2;

// CPU / memory /etc
uint32 type_index = 3; // Index into string table.
uint32 unit_index = 4; // Index into string table.
}

message ProfileType {
repeated uint32 stacktrace_indices = 10;
repeated uint32 link_indices = 11;
repeated uint32 attribute_set_indices = 12;
repeated int64 values = 13;
repeated uint64 timestamps = 14;
}

message Profile {
repeated SampleType sample_types = 1;
repeated Stacktrace stacktraces = 2;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: perhaps stack_traces? as two words

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe not. "stacktrace" is fine as a term, I actually like it more. As long as we are consistent in using it as one word :)

repeated Mapping mappings = 4;
repeated Location locations = 5;
repeated Function functions = 6;
repeated Link links = 7;
repeated AttributeSet attribute_sets = 8;

// 0-th element must be an empty string ("")
repeated string string_table = 9;

repeated ProfileType profile_types = 10;

// stacktrace_index
// link_indices
// attribute_set_indices
// values
// timestamp_unix_nano
}


// borrowed from pprof proto
message Mapping {
// Address at which the binary (or DLL) is loaded into memory.
uint64 memory_start = 1;
// The limit of the address range occupied by this mapping.
uint64 memory_limit = 2;
// Offset in the binary that corresponds to the first mapped address.
uint64 file_offset = 3;
// The object this entry is loaded from. This can be a filename on
// disk for the main binary and shared libraries, or virtual
// abstractions like "[vdso]".
uint32 filename_index = 4; // Index into string table

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add some

Suggested change
uint32 filename_index = 4; // Index into string table
File file = 4;

and later on :

message File {
uint32 filename_index = 1;  // Index into string table
  // A unique identifier of a file. The ID is a 16-byte array.
  bytes file_id = 2;
}

Filename are usually less unique. And to combine it, message Profile could be extended to hold a repeated File file_tabe, so that different locations can reference it.

// A string that uniquely identifies a particular program version
// with high probability. E.g., for binaries generated by GNU tools,
// it could be the contents of the .note.gnu.build-id field.
uint32 build_id_index = 5; // Index into string table

enum SymbolicInfo {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed in the last sync, it's unclear whether we want to start with tracking all these symbolization options from the start.

Aside, I also find "info" a bit too generic, so I'd name this enum SymbolFidelity if we decide to keep it.

And then in order to simplify it, I also mentioned in the sync that maybe we should start with just

enum SymbolFidelity {
   SYMBOL_FIDELITY_UNSPECIFIED = 0;
  SYMBOL_FIDELITY_FULL = 1;
}

But one downside of this is that given this choices, producers will likely start to put the FULL value when any symbolic info is present.

Given that, I wonder if we should start with a simple bool is_symbolized field and once we encounter a real need for carrying fidelity information, we add it then. Possibly by adding the separate SymbolFidelity enum field - I don't see much problem with having two fields where one is just a yes/no boolean and the other one "zooms" into the details.

SYMBOLIC_INFO_UNSPECIFIED = 0;
SYMBOLIC_INFO_FULL = 1;
SYMBOLIC_INFO_FUNCTIONS_ONLY = 2;
SYMBOLIC_INFO_NO_INLINE_FRAMES = 3;
}

SymbolicInfo symbolic_info = 6;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of SymbolicInfo we maybe should use repeated Label here. Similar to the original discussion open-telemetry#488 (comment)


// TODO(@petethepig): I wonder if we need something a little more specialized here
repeated uint32 attribute_set_indices = 7;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could potentially be better if inlined

}

// borrowed from pprof proto
// Describes function and line table debug information.
message Location {
// The id of the corresponding profile.Mapping for this location.
// It can be unset if the mapping is unknown or not applicable for
// this profile type.
uint32 mapping_index = 1;
// The instruction address for this location, if available. It
// should be within [Mapping.memory_start...Mapping.memory_limit]
// for the corresponding mapping. A non-leaf address may be in the
// middle of a call instruction. It is up to display tools to find
// the beginning of the instruction if necessary.
uint64 address = 2;
// Multiple line indicates this location has inlined functions,
// where the last entry represents the caller into which the
// preceding entries were inlined.
//
// E.g., if memcpy() is inlined into printf:
// line[0].function_name == "memcpy"
// line[1].function_name == "printf"
repeated Line line = 3;
// Provides an indication that multiple symbols map to this location's
// address, for example due to identical code folding by the linker. In that
// case the line information above represents one of the multiple
// symbols. This field must be recomputed when the symbolization state of the
// profile changes.
bool is_folded = 4;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This field is fairly exotic. I'd drop it for now.


// TODO(@petethepig): I wonder if we need something a little more specialized here
repeated uint32 attribute_set_indices = 5;
}

// borrowed from pprof proto
message Line {
// The id of the corresponding profile.Function for this line.
uint32 function_index = 1;
// Line number in source code.
uint32 line = 2;
}

// borrowed from pprof proto
message Function {
// Name of the function, in human-readable form if available.
uint32 name_index = 1; // Index into string table
// Name of the function, as identified by the system.
// For instance, it can be a C++ mangled name.
uint32 system_name_index = 2; // Index into string table
// Source file containing the function.
uint32 filename_index = 3; // Index into string table
// Line number in source file.
uint32 start_line = 4;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
syntax = "proto3";

package opentelemetry.proto.profiles.v1.alternatives.denormalized;

import "opentelemetry/proto/common/v1/common.proto";
import "opentelemetry/proto/resource/v1/resource.proto";

option go_package = "go.opentelemetry.io/proto/otlp/profiles/v1/alternatives/denormalized";


// A pointer from a profile to a trace span.
message Link {
// A unique identifier of a trace that this linked span is part of. The ID is a
// 16-byte array.
bytes trace_id = 1;
// A unique identifier for the linked span. The ID is an 8-byte array.
bytes span_id = 2;
}

message Stacktrace {
repeated Location locations = 1;
}

message Sample {
Stacktrace stacktrace = 1;
repeated Link links = 2;
repeated opentelemetry.proto.common.v1.KeyValue attributes = 3;
uint32 dropped_attributes_count = 4;

// this one is repeated because there can be multiple profile kinds in one profile. Typical example is memory profiles in go that contain:
// * alloc_objects
// * alloc_bytes
// * inuse_objects
// * inuse_bytes
repeated fixed64 values = 5;

// optional
fixed64 timestamp_unix_nano = 6;
}

// borrowed from metrics proto
enum AggregationTemporality {
AGGREGATION_TEMPORALITY_UNSPECIFIED = 0;
AGGREGATION_TEMPORALITY_DELTA = 1;
AGGREGATION_TEMPORALITY_CUMULATIVE = 2;
}

message SampleType {
AggregationTemporality aggregation_temporality = 1;
uint64 sample_size = 2;

// CPU / memory /etc
string type = 3;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For easier handling, maybe we could use an enum here?

Suggested change
string type = 3;
enum SamplingType {
SAMPLING_TYPE_UNSPECIFIED = 0;
SAMPLING_TYPE_CPU = 1;
[...]
}
[..]
SamplingType type = 3;

string unit = 4;
}

message Profile {
repeated SampleType sample_types = 1;
repeated Sample samples = 2;
}

// borrowed from pprof proto
message Mapping {
// Address at which the binary (or DLL) is loaded into memory.
uint64 memory_start = 1;
// The limit of the address range occupied by this mapping.
uint64 memory_limit = 2;
// Offset in the binary that corresponds to the first mapped address.
uint64 file_offset = 3;
// The object this entry is loaded from. This can be a filename on
// disk for the main binary and shared libraries, or virtual
// abstractions like "[vdso]".
string filename = 4;
// A string that uniquely identifies a particular program version
// with high probability. E.g., for binaries generated by GNU tools,
// it could be the contents of the .note.gnu.build-id field.
string build_id = 5;

// The following fields indicate the resolution of symbolic info.
bool has_functions = 6;
bool has_filenames = 7;
bool has_line_numbers = 8;
bool has_inline_frames = 9;
}

// borrowed from pprof proto
// Describes function and line table debug information.
message Location {
// profile.Mapping for this location.
// It can be unset if the mapping is unknown or not applicable for
// this profile type.
Mapping mapping = 1;

// The instruction address for this location, if available. It
// should be within [Mapping.memory_start...Mapping.memory_limit]
// for the corresponding mapping. A non-leaf address may be in the
// middle of a call instruction. It is up to display tools to find
// the beginning of the instruction if necessary.
uint64 address = 2;
// Multiple line indicates this location has inlined functions,
// where the last entry represents the caller into which the
// preceding entries were inlined.
//
// E.g., if memcpy() is inlined into printf:
// line[0].function_name == "memcpy"
// line[1].function_name == "printf"
repeated Line line = 3;
// Provides an indication that multiple symbols map to this location's
// address, for example due to identical code folding by the linker. In that
// case the line information above represents one of the multiple
// symbols. This field must be recomputed when the symbolization state of the
// profile changes.
bool is_folded = 4;
}

// borrowed from pprof proto
message Line {
// Function for this line.
Function function = 1;
// Line number in source code.
int64 line = 2;
}

// borrowed from pprof proto
message Function {
// Name of the function, in human-readable form if available.
string name = 1;
// Name of the function, as identified by the system.
// For instance, it can be a C++ mangled name.
string system_name = 2;
// Source file containing the function.
string filename = 3;
// Line number in source file.
uint32 start_line = 4;
}
Loading