Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
44 changes: 22 additions & 22 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions crates/datadog-agent-config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ license.workspace = true

[dependencies]
figment = { version = "0.10", default-features = false, features = ["yaml", "env"] }
libdd-trace-obfuscation = { git = "https://github.com/DataDog/libdatadog", rev = "48da0d82cb32b43d4cdece35b794c9bcbc275a03", default-features = false }
libdd-trace-utils = { git = "https://github.com/DataDog/libdatadog", rev = "48da0d82cb32b43d4cdece35b794c9bcbc275a03", default-features = false }
libdd-trace-obfuscation = { git = "https://github.com/DataDog/libdatadog", rev = "a820699426f28cbabb3a74d87c7309d030b52e7c", default-features = false }
libdd-trace-utils = { git = "https://github.com/DataDog/libdatadog", rev = "a820699426f28cbabb3a74d87c7309d030b52e7c", default-features = false }
log = { version = "0.4", default-features = false }
serde = { version = "1.0", default-features = false, features = ["derive"] }
serde-aux = { version = "4.7", default-features = false }
Expand Down
2 changes: 1 addition & 1 deletion crates/datadog-metrics-collector/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ description = "Collector to read, compute, and submit enhanced metrics in Server
[dependencies]
dogstatsd = { path = "../dogstatsd", default-features = true }
tracing = { version = "0.1", default-features = false }
libdd-common = { git = "https://github.com/DataDog/libdatadog", rev = "48da0d82cb32b43d4cdece35b794c9bcbc275a03", default-features = false }
libdd-common = { git = "https://github.com/DataDog/libdatadog", rev = "a820699426f28cbabb3a74d87c7309d030b52e7c", default-features = false }

[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.61", features = ["Win32_System_JobObjects"], optional = true, default-features = false }
Expand Down
129 changes: 7 additions & 122 deletions crates/datadog-metrics-collector/src/azure_instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,51 +8,11 @@

use dogstatsd::aggregator::AggregatorHandle;
use dogstatsd::metric::{Metric, MetricValue, SortedTags};
use std::env;
use libdd_common::azure_app_services;
use tracing::{error, warn};

const INSTANCE_METRIC: &str = "azure.functions.enhanced.instance";

/// Resolves the instance ID from explicit values (used by tests).
///
/// Picks the env var that matches the Azure integration metric's `instance`
/// tag for the current hosting plan with fallback logic
/// if the preferred source is empty.
fn resolve_instance_id_from(
website_sku: Option<&str>,
container_name: Option<&str>,
website_pod_name: Option<&str>,
computer_name: Option<&str>,
) -> Option<String> {
fn non_empty(s: Option<&str>) -> Option<&str> {
s.filter(|v| !v.is_empty())
}

let sku_preferred = match website_sku {
Some("FlexConsumption") | Some("Dynamic") => {
non_empty(container_name).or(non_empty(website_pod_name))
}
Some(_) => non_empty(computer_name),
None => None,
};

sku_preferred
.or_else(|| non_empty(container_name))
.or_else(|| non_empty(website_pod_name))
.or_else(|| non_empty(computer_name))
.map(|s| s.to_lowercase())
}

/// Resolves the instance ID from environment variables.
fn resolve_instance_id() -> Option<String> {
resolve_instance_id_from(
env::var("WEBSITE_SKU").ok().as_deref(),
env::var("CONTAINER_NAME").ok().as_deref(),
env::var("WEBSITE_POD_NAME").ok().as_deref(),
env::var("COMPUTERNAME").ok().as_deref(),
)
}

pub struct InstanceMetricsCollector {
aggregator: AggregatorHandle,
tags: Option<SortedTags>,
Expand All @@ -61,8 +21,12 @@ pub struct InstanceMetricsCollector {
impl InstanceMetricsCollector {
/// Creates a new collector, returning `None` if no instance ID is found.
pub fn new(aggregator: AggregatorHandle, tags: Option<SortedTags>) -> Option<Self> {
let instance_id = resolve_instance_id();
let Some(instance_id) = instance_id else {
let instance_name = azure_app_services::AAS_METADATA_FUNCTION
.as_ref()
.map(|m| m.get_instance_name().to_lowercase())
.filter(|n| n != azure_app_services::UNKNOWN_VALUE);
Comment on lines +24 to +27

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve consumption instance resolution

In FlexConsumption/Dynamic Azure Functions where Azure also exposes COMPUTERNAME, this now takes the instance name from the pinned libdd-common metadata resolver, which prioritizes COMPUTERNAME before WEBSITE_POD_NAME/CONTAINER_NAME. The previous implementation deliberately used the container/pod values for those SKUs so the azure.functions.enhanced.instance tag matched the Azure integration's instance dimension; using COMPUTERNAME in that scenario causes the enhanced instance metric to be attributed under a different instance tag.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

In FlexConsumption/Dynamic Azure Functions, COMPUTERNAME is unset. My investigation to identify what env vars should be used for each hosting plan can be found here


Comment on lines +24 to +28

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

get_instance_name uses get_value_or_unknown! which returns either the stored instance_name string or unknown - never an empty string

let Some(instance_id) = instance_name else {
warn!("No instance ID found, instance metric will not be submitted");
return None;
Comment on lines 21 to 31

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I feel like unit tests would be redundant since we have tests for the instance name resolution in libdatadog but happy to add if we feel they're needed!

};
Expand Down Expand Up @@ -95,82 +59,3 @@ impl InstanceMetricsCollector {
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_flex_consumption_uses_container_name() {
let id = resolve_instance_id_from(
Some("FlexConsumption"),
Some("0--abc-DEF"),
Some("0--abc-DEF"),
None,
);
assert_eq!(id, Some("0--abc-def".to_string()));
}

#[test]
fn test_flex_consumption_falls_back_to_pod_name_if_container_missing() {
let id = resolve_instance_id_from(Some("FlexConsumption"), None, Some("pod-XYZ"), None);
assert_eq!(id, Some("pod-xyz".to_string()));
}

#[test]
fn test_consumption_uses_container_name() {
let id = resolve_instance_id_from(
Some("Dynamic"),
Some("ABCD1234-111122223333444455"),
None,
None,
);
assert_eq!(id, Some("abcd1234-111122223333444455".to_string()));
}

#[test]
fn test_elastic_premium_uses_computer_name() {
let id =
resolve_instance_id_from(Some("ElasticPremium"), None, None, Some("ep0fakewk0000A1"));
assert_eq!(id, Some("ep0fakewk0000a1".to_string()));
}

#[test]
fn test_dedicated_uses_computer_name() {
let id = resolve_instance_id_from(Some("PremiumV3"), None, None, Some("p3fakewk0000B2"));
assert_eq!(id, Some("p3fakewk0000b2".to_string()));
}

#[test]
fn test_empty_string_is_treated_as_missing() {
let id =
resolve_instance_id_from(Some("ElasticPremium"), Some(""), Some(""), Some("worker-1"));
assert_eq!(id, Some("worker-1".to_string()));
}

#[test]
fn test_unknown_sku_falls_back_to_search_order() {
let id = resolve_instance_id_from(Some("SomeNewSku"), Some("container-1"), None, None);
assert_eq!(id, Some("container-1".to_string()));
}

#[test]
fn test_missing_sku_falls_back_to_search_order() {
let id = resolve_instance_id_from(None, Some("container-1"), None, Some("worker-1"));
assert_eq!(id, Some("container-1".to_string()));
}

#[test]
fn test_no_env_vars_returns_none() {
let id = resolve_instance_id_from(None, None, None, None);
assert_eq!(id, None);
}

// On Windows Consumption we've observed CONTAINER_NAME and WEBSITE_POD_NAME
// unset but COMPUTERNAME set
#[test]
fn test_windows_consumption_falls_through_to_computer_name() {
let id = resolve_instance_id_from(Some("Dynamic"), None, None, Some("10-20-30-40"));
assert_eq!(id, Some("10-20-30-40".to_string()));
}
}
9 changes: 3 additions & 6 deletions crates/datadog-metrics-collector/src/azure_tags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ use libdd_common::{azure_app_services, tag::Tag};
use std::env;
use tracing::warn;

/// `libdd_common::azure_app_services` returns this value when the corresponding Azure metadata isn't populated.
const AAS_UNKNOWN_VALUE: &str = "unknown";

/// Builds the common tags for all enhanced metrics.
///
/// Sources:
Expand All @@ -30,15 +27,15 @@ pub fn build_enhanced_metrics_tags() -> Option<SortedTags> {
("subscription_id", aas_metadata.get_subscription_id()),
("name", aas_metadata.get_site_name()),
] {
if value != AAS_UNKNOWN_VALUE {
if value != azure_app_services::UNKNOWN_VALUE {
pairs.push((name, value.to_string()));
}
}
}

for (tag_name, env_var) in [
("region", "REGION_NAME"),
("plan_tier", "WEBSITE_SKU"),
("region", azure_app_services::REGION_NAME),
("plan_tier", azure_app_services::WEBSITE_SKU),
("service", "DD_SERVICE"),
("env", "DD_ENV"),
("version", "DD_VERSION"),
Expand Down
2 changes: 1 addition & 1 deletion crates/datadog-serverless-compat/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ windows-enhanced-metrics = ["datadog-metrics-collector/windows-enhanced-metrics"
datadog-logs-agent = { path = "../datadog-logs-agent" }
datadog-metrics-collector = { path = "../datadog-metrics-collector" }
datadog-trace-agent = { path = "../datadog-trace-agent" }
libdd-trace-utils = { git = "https://github.com/DataDog/libdatadog", rev = "48da0d82cb32b43d4cdece35b794c9bcbc275a03" }
libdd-trace-utils = { git = "https://github.com/DataDog/libdatadog", rev = "a820699426f28cbabb3a74d87c7309d030b52e7c" }
datadog-fips = { path = "../datadog-fips", default-features = false }
dogstatsd = { path = "../dogstatsd", default-features = true }
reqwest = { version = "0.12.4", default-features = false }
Expand Down
Loading
Loading