Skip to content

Conversation

@kathiehuang
Copy link
Contributor

@kathiehuang kathiehuang commented Oct 1, 2025

What does this PR do?

  • Implements functionality in Azure Functions to handle proxy payloads - for now, specifically profile payloads
  • Starts a background task that runs a proxy flusher
  • Adds a profiling endpoint that receives profile proxy payloads and sends them through an mpsc channel where the proxy flusher receives it and forwards it to Datadog, handling retries and exponential backoffs
  • Works in Python, Node.js, and Java, but the Java and .NET Continuous Profilers in serverless are not currently supported by the Profiling team
  • Added datadog-fips to Cargo.toml to use its reqwest client builder method

Motivation

Profiling is not yet supported in Azure Functions.

Additional Notes

Tested across all hosting plans. This works for Python and Node.js.

  • For Node.js, profiling only has prebuilt binaries for Linux arm64/x64, Alpine Linux x64, macOS arm64/x64, and Windows x64. The default for Azure Apps in Terraform is Windows x32, so we had to go to the Configuration tab in the Azure portal and change Platform to 64 Bit to get profiling to work.

This worked in Java as well in testing, but the Java Continuous Profiler in serverless is not currently supported by the Profiling team.

The .NET Continuous Profiler in serverless is also not currently supported by the Profiling team - could not test because the .NET tracer shuts down the profiler if it detects it's in an Azure Function:

Describe how to test/QA your changes

To test this, follow the Serverless Compatibility Layer instructions to deploy function apps across runtimes and hosting plans with the built binary. Generate load on the function app and check Datadog to see profiles show up!

Follow up task: Talk with APM Serverless about changes in their tracer code that will need to be made. SVLS-7841

@kathiehuang kathiehuang changed the title [SVLS-7018] Support profiling in Azure Functions WIP [SVLS-7018] Support profiling in Azure Functions Oct 1, 2025
@kathiehuang kathiehuang force-pushed the kathie.huang/receive-profile-payload branch from c0abc20 to d9ea13b Compare October 15, 2025 18:58
@kathiehuang kathiehuang changed the title WIP [SVLS-7018] Support profiling in Azure Functions [SVLS-7018] Support profiling in Azure Functions Oct 16, 2025
@kathiehuang kathiehuang changed the title [SVLS-7018] Support profiling in Azure Functions [SVLS-7673] Support profiling in Azure Functions Oct 16, 2025
@kathiehuang kathiehuang marked this pull request as ready for review October 27, 2025 16:58
@kathiehuang kathiehuang marked this pull request as draft October 27, 2025 16:59
@kathiehuang
Copy link
Contributor Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +248 to +266
// Extract headers and body
let (parts, body) = request.into_parts();

let body_bytes = match body.collect().await {
Ok(collected) => collected.to_bytes(),
Err(e) => {
return log_and_create_http_response(
&format!("Error reading profiling request body: {e}"),
StatusCode::BAD_REQUEST,
);
}
};

// Create proxy request
let proxy_request = ProxyRequest {
headers: parts.headers,
body: body_bytes,
target_url: config.profiling_intake.url.to_string(),
};

Choose a reason for hiding this comment

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

P1 Badge Forward profiling query string to Datadog

The profiling proxy handler builds the outgoing request URL from the static profiling_intake endpoint and ignores parts.uri.query(). Profiling clients pass service, environment, and other metadata via the query string when posting to /profiling/v1/input; dropping these parameters means the flusher forwards payloads without required metadata, causing ingestion failures or misattribution. Append the incoming query parameters to ProxyRequest.target_url before sending to the proxy flusher.

Useful? React with 👍 / 👎.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@kathiehuang
Copy link
Contributor Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +240 to +257
/// Handles incoming proxy requests for profiling - can be abstracted into a generic proxy handler for other proxy requests in the future
async fn profiling_proxy_handler(
config: Arc<config::Config>,
request: hyper_migration::HttpRequest,
proxy_tx: Sender<ProxyRequest>,
) -> http::Result<hyper_migration::HttpResponse> {
debug!("Trace Agent | Received profiling request");

// Extract headers and body
let (parts, body) = request.into_parts();

let body_bytes = match body.collect().await {
Ok(collected) => collected.to_bytes(),
Err(e) => {
return log_and_create_http_response(
&format!("Error reading profiling request body: {e}"),
StatusCode::BAD_REQUEST,
);

Choose a reason for hiding this comment

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

P1 Badge Enforce profiling payload size before buffering

The new profiling proxy endpoint reads the entire request body into memory (body.collect().await) without validating the Content-Length. The trace and stats handlers call verify_request_content_length to reject payloads larger than Config::max_request_content_length before allocation, but the profiling handler omits this guard. A client can therefore POST an arbitrarily large profiling payload and the mini agent will buffer it in RAM before forwarding, allowing a single request to exhaust memory and crash the function. Consider applying the same content length check as the other endpoints before collecting the body.

Useful? React with 👍 / 👎.

Copy link
Contributor Author

@kathiehuang kathiehuang Oct 27, 2025

Choose a reason for hiding this comment

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

The lambda extension also doesn't validate the content-length, probably because profiling payloads are typically much larger and they're coming from the Datadog profiler

@kathiehuang kathiehuang marked this pull request as ready for review October 27, 2025 19:20
@kathiehuang kathiehuang changed the title [SVLS-7673] Support profiling in Azure Functions [SVLS-7018] Support profiling in Azure Functions Oct 27, 2025
@kathiehuang kathiehuang requested review from a team and duncanpharvey October 27, 2025 19:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants