async_profiler_agent/metadata/mod.rs
1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4//! This module includes ways to get metadata attached to profiling reports.
5
6use ordered_float::OrderedFloat;
7pub use std::time::Duration;
8
9/// An ordered float. Individual type to avoid public API dependencies.
10#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
11#[serde(transparent)]
12pub struct OrderedF64(OrderedFloat<f64>);
13
14impl OrderedF64 {
15 /// Create a new `OrderedF64`
16 ///
17 /// ```rust
18 /// # use async_profiler_agent::metadata::OrderedF64;
19 /// let _v = OrderedF64::new(0.0);
20 /// ```
21 pub const fn new(value: f64) -> Self {
22 Self(OrderedFloat(value))
23 }
24}
25
26impl From<f64> for OrderedF64 {
27 fn from(value: f64) -> Self {
28 Self(OrderedFloat(value))
29 }
30}
31
32impl From<OrderedF64> for f64 {
33 fn from(value: OrderedF64) -> Self {
34 value.0.0
35 }
36}
37
38/// Host Metadata, which describes a host that runs a profiling agent. The current set of supported agent metadata is
39/// AWS-specific. If you are not running on AWS, you can use [AgentMetadata::NoMetadata].
40#[derive(Debug, Clone, PartialEq, Eq)]
41#[non_exhaustive]
42pub enum AgentMetadata {
43 /// Metadata for an [EC2] instance running on AWS
44 ///
45 /// [EC2]: https://aws.amazon.com/ec2
46 #[cfg_attr(feature = "__unstable-fargate-cpu-count", non_exhaustive)]
47 Ec2AgentMetadata {
48 /// The AWS account id
49 aws_account_id: String,
50 /// The AWS region id
51 aws_region_id: String,
52 /// The EC2 instance id
53 ec2_instance_id: String,
54 },
55 /// Metadata for a [Fargate] task running on AWS.
56 ///
57 /// [Fargate]: https://aws.amazon.com/fargate
58 #[cfg_attr(feature = "__unstable-fargate-cpu-count", non_exhaustive)]
59 FargateAgentMetadata {
60 /// The AWS account id
61 aws_account_id: String,
62 /// The AWS region id
63 aws_region_id: String,
64 /// The ECS task ARN
65 ///
66 /// For example, `arn:aws:ecs:us-east-1:123456789012:task/profiler-metadata-cluster/5261e761e0e2a3d92da3f02c8e5bab1f`
67 ///
68 /// See the ECS documentation for more details
69 ecs_task_arn: String,
70 /// The ECS cluster ARN
71 ///
72 /// For example, `arn:aws:ecs:us-east-1:123456789012:cluster/profiler-metadata-cluster`
73 ///
74 /// See the ECS documentation for more details
75 ecs_cluster_arn: String,
76 /// The CPU limit for the Fargate cluster
77 ///
78 /// For example, `Some(0.25)`. This will be `None` if the CPU limit is not specified.
79 ///
80 /// See the ECS documentation for more details
81 #[cfg(feature = "__unstable-fargate-cpu-count")]
82 cpu_limit: Option<OrderedF64>,
83 /// The memory limit for the Fargate cluster (in megabytes)
84 ///
85 /// For example, `Some(2048)`. This will be `None` if the memory limit is not specified.
86 ///
87 /// See the ECS documentation for more details
88 #[cfg(feature = "__unstable-fargate-cpu-count")]
89 memory_limit: Option<u64>,
90 },
91 /// Metadata for a host that is neither an EC2 nor a Fargate
92 #[deprecated = "Use AgentMetadata::NoMetadata"]
93 Other,
94 /// A placeholder when a host has no metadata, or when a reporter does not
95 /// use metadata.
96 NoMetadata,
97}
98
99impl AgentMetadata {
100 /// Create a builder for EC2 agent metadata
101 ///
102 /// Normally, for real-world use, you would get the metadata using
103 /// autodetection via
104 #[cfg_attr(
105 feature = "aws-metadata-no-defaults",
106 doc = "[aws::load_agent_metadata],"
107 )]
108 #[cfg_attr(
109 feature = "aws-metadata-no-defaults",
110 doc = "`aws::load_agent_metadata`,"
111 )]
112 /// this function is intended for use in tests.
113 ///
114 /// ## Example
115 ///
116 /// ```rust
117 /// # use async_profiler_agent::metadata::AgentMetadata;
118 /// let metadata = AgentMetadata::ec2_agent_metadata(
119 /// "123456789012".to_string(),
120 /// "us-east-1".to_string(),
121 /// "i-1234567890abcdef0".to_string(),
122 /// ).build();
123 /// ```
124 pub fn ec2_agent_metadata(
125 aws_account_id: String,
126 aws_region_id: String,
127 ec2_instance_id: String,
128 ) -> Ec2AgentMetadataBuilder {
129 Ec2AgentMetadataBuilder {
130 aws_account_id,
131 aws_region_id,
132 ec2_instance_id,
133 }
134 }
135
136 /// Create a builder for Fargate agent metadata
137 ///
138 /// Normally, for real-world use, you would get the metadata using
139 /// autodetection via
140 #[cfg_attr(
141 feature = "aws-metadata-no-defaults",
142 doc = "[aws::load_agent_metadata],"
143 )]
144 #[cfg_attr(
145 feature = "aws-metadata-no-defaults",
146 doc = "`aws::load_agent_metadata`,"
147 )]
148 /// this function is intended for use in tests.
149 ///
150 /// ## Example
151 ///
152 /// ```rust
153 /// # use async_profiler_agent::metadata::AgentMetadata;
154 /// let metadata = AgentMetadata::fargate_agent_metadata(
155 /// "123456789012".to_string(),
156 /// "us-east-1".to_string(),
157 /// "arn:aws:ecs:us-east-1:123456789012:task/cluster/5261e761e0e2a3d92da3f02c8e5bab1f".to_string(),
158 /// "arn:aws:ecs:us-east-1:123456789012:cluster/profiler-metadata-cluster".to_string(),
159 /// )
160 /// .with_cpu_limit(0.25)
161 /// .with_memory_limit(2048)
162 /// .build();
163 /// ```
164 pub fn fargate_agent_metadata(
165 aws_account_id: String,
166 aws_region_id: String,
167 ecs_task_arn: String,
168 ecs_cluster_arn: String,
169 ) -> FargateAgentMetadataBuilder {
170 FargateAgentMetadataBuilder {
171 aws_account_id,
172 aws_region_id,
173 ecs_task_arn,
174 ecs_cluster_arn,
175 cpu_limit: None,
176 memory_limit: None,
177 }
178 }
179}
180
181/// Builder for EC2 agent metadata
182#[derive(Debug, Clone)]
183pub struct Ec2AgentMetadataBuilder {
184 aws_account_id: String,
185 aws_region_id: String,
186 ec2_instance_id: String,
187}
188
189impl Ec2AgentMetadataBuilder {
190 /// Build the AgentMetadata
191 pub fn build(self) -> AgentMetadata {
192 AgentMetadata::Ec2AgentMetadata {
193 aws_account_id: self.aws_account_id,
194 aws_region_id: self.aws_region_id,
195 ec2_instance_id: self.ec2_instance_id,
196 }
197 }
198}
199
200/// Builder for Fargate agent metadata
201#[derive(Debug, Clone)]
202pub struct FargateAgentMetadataBuilder {
203 aws_account_id: String,
204 aws_region_id: String,
205 ecs_task_arn: String,
206 ecs_cluster_arn: String,
207 cpu_limit: Option<f64>,
208 memory_limit: Option<u64>,
209}
210
211impl FargateAgentMetadataBuilder {
212 /// Set the CPU limit (in vCPUs)
213 pub fn with_cpu_limit(mut self, cpu_limit: f64) -> Self {
214 self.cpu_limit = Some(cpu_limit);
215 self
216 }
217
218 /// Set the memory limit (in megabytes)
219 pub fn with_memory_limit(mut self, memory_limit: u64) -> Self {
220 self.memory_limit = Some(memory_limit);
221 self
222 }
223
224 /// Build the AgentMetadata
225 pub fn build(self) -> AgentMetadata {
226 AgentMetadata::FargateAgentMetadata {
227 aws_account_id: self.aws_account_id,
228 aws_region_id: self.aws_region_id,
229 ecs_task_arn: self.ecs_task_arn,
230 ecs_cluster_arn: self.ecs_cluster_arn,
231 #[cfg(feature = "__unstable-fargate-cpu-count")]
232 cpu_limit: self.cpu_limit.map(Into::into),
233 #[cfg(feature = "__unstable-fargate-cpu-count")]
234 memory_limit: self.memory_limit,
235 }
236 }
237}
238
239/// Metadata associated with a specific individual profiling report
240#[derive(Debug, Clone, PartialEq, Eq)]
241pub struct ReportMetadata<'a> {
242 /// The host running the agent
243 pub instance: &'a AgentMetadata,
244 /// The start time of the profiling report, as a duration from the process start
245 pub start: Duration,
246 /// The end time of the profiling report, as a duration from the process start
247 pub end: Duration,
248 /// The desired reporting interval (on average, this should be
249 /// approximately the same as `self.end - self.start`).
250 pub reporting_interval: Duration,
251}
252
253#[cfg(feature = "aws-metadata-no-defaults")]
254pub mod aws;
255
256/// [private] dummy metadata to make testing easier
257#[cfg(test)]
258pub(crate) const DUMMY_METADATA: ReportMetadata<'static> = ReportMetadata {
259 instance: &AgentMetadata::NoMetadata,
260 start: Duration::from_secs(1),
261 end: Duration::from_secs(2),
262 reporting_interval: Duration::from_secs(1),
263};