Skip to content

Commit 4b9d3be

Browse files
committed
[profiling] Support Otel protobuf
1 parent 5ea1f98 commit 4b9d3be

File tree

19 files changed

+2403
-0
lines changed

19 files changed

+2403
-0
lines changed

Cargo.lock

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ members = [
1515
"datadog-live-debugger-ffi",
1616
"datadog-profiling",
1717
"datadog-profiling-ffi",
18+
"datadog-profiling-otel",
1819
"datadog-profiling-protobuf",
1920
"datadog-profiling-replayer",
2021
"datadog-remote-config",

datadog-profiling-otel/Cargo.toml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Copyright 2025-Present Datadog, Inc. https://www.datadoghq.com/
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
[package]
5+
name = "datadog-profiling-otel"
6+
rust-version.workspace = true
7+
edition.workspace = true
8+
version.workspace = true
9+
license.workspace = true
10+
11+
[lib]
12+
bench = false
13+
14+
[dependencies]
15+
prost = "0.13"
16+
prost-types = "0.13"
17+
18+
[build-dependencies]
19+
prost-build = "0.13"
20+
21+
[dev-dependencies]
22+
bolero = "0.13"

datadog-profiling-otel/README.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# datadog-profiling-otel
2+
3+
This module provides Rust bindings for the OpenTelemetry profiling protobuf definitions, generated using the `prost` library.
4+
5+
## Usage
6+
7+
### Basic Setup
8+
9+
Add this to your `Cargo.toml`:
10+
11+
```toml
12+
[dependencies]
13+
datadog-profiling-otel = "20.0.0"
14+
```
15+
16+
### Creating Profile Data
17+
18+
```rust
19+
use datadog_profiling_otel::*;
20+
21+
// Create a profiles dictionary
22+
let mut profiles_dict = ProfilesDictionary::default();
23+
profiles_dict.string_table.push("cpu".to_string());
24+
profiles_dict.string_table.push("nanoseconds".to_string());
25+
26+
// Create a sample type
27+
let sample_type = ValueType {
28+
type_strindex: 0, // "cpu"
29+
unit_strindex: 1, // "nanoseconds"
30+
aggregation_temporality: AggregationTemporality::Delta.into(),
31+
};
32+
33+
// Create a profile
34+
let mut profile = Profile::default();
35+
profile.sample_type = Some(sample_type);
36+
profile.time_nanos = std::time::SystemTime::now()
37+
.duration_since(std::time::UNIX_EPOCH)
38+
.unwrap()
39+
.as_nanos() as i64;
40+
41+
// Assemble the complete profiles data
42+
let mut profiles_data = ProfilesData::default();
43+
profiles_data.dictionary = Some(profiles_dict);
44+
45+
let mut scope_profiles = ScopeProfiles::default();
46+
scope_profiles.profiles.push(profile);
47+
48+
let mut resource_profiles = ResourceProfiles::default();
49+
resource_profiles.scope_profiles.push(scope_profiles);
50+
51+
profiles_data.resource_profiles.push(resource_profiles);
52+
```
53+
54+
### Running Examples
55+
56+
```bash
57+
# Run the basic usage example
58+
cargo run --example basic_usage
59+
60+
# Run tests
61+
cargo test
62+
63+
# Build
64+
cargo build
65+
```
66+
67+
## Module Structure
68+
69+
The generated code follows the OpenTelemetry protobuf structure:
70+
71+
- `ProfilesData`: Top-level container for all profile data
72+
- `ResourceProfiles`: Profiles grouped by resource
73+
- `ScopeProfiles`: Profiles grouped by instrumentation scope
74+
- `Profile`: Individual profile with samples and metadata
75+
- `ProfilesDictionary`: Shared data (strings, mappings, locations, etc.)
76+
- `Sample`: Individual measurements with stack traces
77+
- `Location`: Function locations in the call stack
78+
- `Function`: Function information
79+
- `Mapping`: Binary/library mapping information
80+
81+
## Dependencies
82+
83+
- `prost`: Protobuf implementation
84+
- `prost-types`: Additional protobuf types
85+
- `prost-build`: Build-time protobuf compilation
86+
87+
## License
88+
89+
Apache-2.0

datadog-profiling-otel/build.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright 2025-Present Datadog, Inc. https://www.datadoghq.com/
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
use std::env;
5+
use std::path::PathBuf;
6+
7+
fn main() {
8+
// Tell Cargo to rerun this build script if the proto files change
9+
println!("cargo:rerun-if-changed=profiles.proto");
10+
println!("cargo:rerun-if-changed=opentelemetry/proto/common/v1/common.proto");
11+
println!("cargo:rerun-if-changed=opentelemetry/proto/resource/v1/resource.proto");
12+
13+
// Create the output directory
14+
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
15+
16+
// Configure prost-build
17+
let mut config = prost_build::Config::new();
18+
config.out_dir(&out_dir);
19+
20+
// Compile the proto files - include all proto files so imports work correctly
21+
config
22+
.compile_protos(
23+
&[
24+
"opentelemetry/proto/common/v1/common.proto",
25+
"opentelemetry/proto/resource/v1/resource.proto",
26+
"profiles.proto",
27+
],
28+
&["."],
29+
)
30+
.expect("Failed to compile protobuf files");
31+
32+
// Generate the module file with correct structure
33+
let module_content = r#"
34+
// Copyright 2025-Present Datadog, Inc. https://www.datadoghq.com/
35+
// SPDX-License-Identifier: Apache-2.0
36+
37+
// This module is generated by prost-build from profiles.proto
38+
#[allow(clippy::all)]
39+
pub mod opentelemetry {
40+
pub mod proto {
41+
pub mod common {
42+
pub mod v1 {
43+
include!(concat!(env!("OUT_DIR"), "/opentelemetry.proto.common.v1.rs"));
44+
}
45+
}
46+
pub mod resource {
47+
pub mod v1 {
48+
include!(concat!(env!("OUT_DIR"), "/opentelemetry.proto.resource.v1.rs"));
49+
}
50+
}
51+
pub mod profiles {
52+
pub mod v1development {
53+
include!(concat!(env!("OUT_DIR"), "/opentelemetry.proto.profiles.v1development.rs"));
54+
}
55+
}
56+
}
57+
}
58+
59+
// Re-export commonly used types
60+
pub use opentelemetry::proto::profiles::v1development::*;
61+
pub use opentelemetry::proto::common::v1::*;
62+
pub use opentelemetry::proto::resource::v1::*;
63+
"#;
64+
65+
std::fs::write(out_dir.join("mod.rs"), module_content).expect("Failed to write module file");
66+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright 2025-Present Datadog, Inc. https://www.datadoghq.com/
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
// This example demonstrates how to use the generated protobuf code
5+
// from the OpenTelemetry profiles.proto file.
6+
7+
fn main() {
8+
use datadog_profiling_otel::*;
9+
10+
// Create a simple profile with some basic data
11+
let mut profiles_dict = ProfilesDictionary::default();
12+
13+
// Add some strings to the string table
14+
profiles_dict.string_table.push("cpu".to_string());
15+
profiles_dict.string_table.push("nanoseconds".to_string());
16+
profiles_dict.string_table.push("main".to_string());
17+
18+
// Create a sample type
19+
let sample_type = ValueType {
20+
type_strindex: 0, // "cpu"
21+
unit_strindex: 1, // "nanoseconds"
22+
aggregation_temporality: AggregationTemporality::Delta.into(),
23+
};
24+
25+
// Create a profile
26+
let profile = Profile {
27+
sample_type: Some(sample_type),
28+
time_nanos: std::time::SystemTime::now()
29+
.duration_since(std::time::UNIX_EPOCH)
30+
.unwrap()
31+
.as_nanos() as i64,
32+
..Default::default()
33+
};
34+
35+
// Create profiles data
36+
let mut profiles_data = ProfilesData {
37+
dictionary: Some(profiles_dict),
38+
..Default::default()
39+
};
40+
41+
let mut scope_profiles = ScopeProfiles::default();
42+
scope_profiles.profiles.push(profile);
43+
44+
let mut resource_profiles = ResourceProfiles::default();
45+
resource_profiles.scope_profiles.push(scope_profiles);
46+
47+
profiles_data.resource_profiles.push(resource_profiles);
48+
49+
println!("Successfully created OpenTelemetry profile data!");
50+
println!(
51+
"Profile contains {} resource profiles",
52+
profiles_data.resource_profiles.len()
53+
);
54+
println!(
55+
"Time: {}",
56+
profiles_data.resource_profiles[0].scope_profiles[0].profiles[0].time_nanos
57+
);
58+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2023, OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
syntax = "proto3";
16+
17+
package opentelemetry.proto.common.v1;
18+
19+
// KeyValue is a key-value pair that is used to store Span attributes, Link
20+
// attributes, etc.
21+
message KeyValue {
22+
string key = 1;
23+
oneof value {
24+
string string_value = 2;
25+
bool bool_value = 3;
26+
int64 int_value = 4;
27+
double double_value = 5;
28+
bytes bytes_value = 6;
29+
}
30+
}
31+
32+
// InstrumentationScope is a message representing the instrumentation scope information
33+
// such as the fully qualified name and version.
34+
message InstrumentationScope {
35+
// An empty instrumentation scope name means the name is unknown.
36+
string name = 1;
37+
string version = 2;
38+
repeated KeyValue attributes = 3;
39+
uint32 dropped_attributes_count = 4;
40+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2023, OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
syntax = "proto3";
16+
17+
package opentelemetry.proto.resource.v1;
18+
19+
import "opentelemetry/proto/common/v1/common.proto";
20+
21+
// Resource information.
22+
message Resource {
23+
// Set of attributes that describe the resource.
24+
repeated opentelemetry.proto.common.v1.KeyValue attributes = 1;
25+
26+
// dropped_attributes_count is the number of dropped attributes. If the value is 0,
27+
// then no attributes were dropped.
28+
uint32 dropped_attributes_count = 2;
29+
}

0 commit comments

Comments
 (0)