From f02dc0e0160a5c4fb393d5b3a963dc0e3f3c13ef Mon Sep 17 00:00:00 2001 From: michaeltlombardi <14190564+michaeltlombardi@users.noreply.github.com> Date: Wed, 8 Jul 2026 09:08:24 -0500 Subject: [PATCH 1/4] (GH-1061) Init telemetry crate This change adds the `dsc-lib-telemetry` crate to the project to provide OpenTelemetry support for DSC. This change also makes a minor update to the `Cargo.toml` file to standardize the order of the crates for each member group. This should ensure that the file doesn't change during a build unless required, minimizing the re-analysis that the IDE needs to do when you build the project. --- Cargo.lock | 4 + Cargo.toml | 114 ++++++++++---------- data.build.json | 126 +++++++++++++++++------ lib/dsc-lib-telemetry/.project.data.json | 5 + lib/dsc-lib-telemetry/Cargo.toml | 7 ++ lib/dsc-lib-telemetry/src/lib.rs | 12 +++ 6 files changed, 181 insertions(+), 87 deletions(-) create mode 100644 lib/dsc-lib-telemetry/.project.data.json create mode 100644 lib/dsc-lib-telemetry/Cargo.toml create mode 100644 lib/dsc-lib-telemetry/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index adb4bb00c..ec9e06385 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -908,6 +908,10 @@ dependencies = [ "nix", ] +[[package]] +name = "dsc-lib-telemetry" +version = "0.0.0" + [[package]] name = "dsc-resource-echo" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index c623cbf4d..65eccb184 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,29 +5,30 @@ resolver = "2" members = [ "dsc", "dsc-bicep-ext", - "lib/dsc-lib", - "lib/dsc-lib-jsonschema", + "grammars/tree-sitter-dscexpression", + "grammars/tree-sitter-ssh-server-config", "lib/dsc-lib-jsonschema-macros", - "resources/dscecho", + "lib/dsc-lib-jsonschema", "lib/dsc-lib-osinfo", - "resources/osinfo", "lib/dsc-lib-pal", - "resources/process", - "resources/registry", "lib/dsc-lib-registry", - "resources/runcommandonset", "lib/dsc-lib-security_context", + "lib/dsc-lib-telemetry", + "lib/dsc-lib", "resources/dism_dsc", + "resources/dscecho", + "resources/osinfo", + "resources/process", + "resources/registry", + "resources/runcommandonset", "resources/sshdconfig", - "resources/WindowsUpdate", - "resources/windows_service", "resources/windows_firewall", + "resources/windows_service", + "resources/WindowsUpdate", "tools/dsctest", "tools/test_group_resource", - "grammars/tree-sitter-dscexpression", - "grammars/tree-sitter-ssh-server-config", - "y2j", - "xtask" + "xtask", + "y2j" ] # This value is modified by the `Set-DefaultWorkspaceMember` helper. @@ -36,29 +37,30 @@ members = [ default-members = [ "dsc", "dsc-bicep-ext", - "lib/dsc-lib", - "lib/dsc-lib-jsonschema", + "grammars/tree-sitter-dscexpression", + "grammars/tree-sitter-ssh-server-config", "lib/dsc-lib-jsonschema-macros", - "resources/dscecho", + "lib/dsc-lib-jsonschema", "lib/dsc-lib-osinfo", - "resources/osinfo", "lib/dsc-lib-pal", - "resources/process", - "resources/registry", "lib/dsc-lib-registry", - "resources/runcommandonset", "lib/dsc-lib-security_context", + "lib/dsc-lib-telemetry", + "lib/dsc-lib", "resources/dism_dsc", + "resources/dscecho", + "resources/osinfo", + "resources/process", + "resources/registry", + "resources/runcommandonset", "resources/sshdconfig", - "resources/WindowsUpdate", - "resources/windows_service", "resources/windows_firewall", + "resources/windows_service", + "resources/WindowsUpdate", "tools/dsctest", "tools/test_group_resource", - "grammars/tree-sitter-dscexpression", - "grammars/tree-sitter-ssh-server-config", - "y2j", - "xtask" + "xtask", + "y2j" ] [workspace.metadata.groups] @@ -68,69 +70,72 @@ default-members = [ Windows = [ "dsc", "dsc-bicep-ext", - "lib/dsc-lib", - "lib/dsc-lib-jsonschema", + "grammars/tree-sitter-dscexpression", + "grammars/tree-sitter-ssh-server-config", "lib/dsc-lib-jsonschema-macros", - "resources/dscecho", + "lib/dsc-lib-jsonschema", "lib/dsc-lib-osinfo", - "resources/osinfo", "lib/dsc-lib-pal", + "lib/dsc-lib-registry", + "lib/dsc-lib-security_context", + "lib/dsc-lib-telemetry", + "lib/dsc-lib", + "resources/dism_dsc", + "resources/dscecho", + "resources/osinfo", "resources/process", "resources/registry", - "lib/dsc-lib-registry", "resources/runcommandonset", - "lib/dsc-lib-security_context", "resources/sshdconfig", - "resources/WindowsUpdate", - "resources/windows_service", "resources/windows_firewall", + "resources/windows_service", + "resources/WindowsUpdate", "tools/dsctest", "tools/test_group_resource", - "grammars/tree-sitter-dscexpression", - "grammars/tree-sitter-ssh-server-config", - "y2j", "xtask", - "resources/dism_dsc" + "y2j" ] macOS = [ "dsc", "dsc-bicep-ext", - "lib/dsc-lib", - "lib/dsc-lib-jsonschema", + "grammars/tree-sitter-dscexpression", + "grammars/tree-sitter-ssh-server-config", "lib/dsc-lib-jsonschema-macros", - "resources/dscecho", + "lib/dsc-lib-jsonschema", "lib/dsc-lib-osinfo", + "lib/dsc-lib-security_context", + "lib/dsc-lib-telemetry", + "lib/dsc-lib", + "resources/dscecho", "resources/osinfo", "resources/process", "resources/runcommandonset", - "lib/dsc-lib-security_context", "resources/sshdconfig", "tools/dsctest", "tools/test_group_resource", - "grammars/tree-sitter-dscexpression", - "grammars/tree-sitter-ssh-server-config", + "xtask", "y2j", - "xtask" ] Linux = [ "dsc", "dsc-bicep-ext", - "lib/dsc-lib", - "lib/dsc-lib-jsonschema", + "grammars/tree-sitter-dscexpression", + "grammars/tree-sitter-ssh-server-config", "lib/dsc-lib-jsonschema-macros", - "resources/dscecho", + "lib/dsc-lib-jsonschema", "lib/dsc-lib-osinfo", + "lib/dsc-lib-security_context", + "lib/dsc-lib-telemetry", + "lib/dsc-lib", + "resources/dscecho", "resources/osinfo", "resources/process", "resources/runcommandonset", - "lib/dsc-lib-security_context", "resources/sshdconfig", "tools/dsctest", "tools/test_group_resource", - "grammars/tree-sitter-dscexpression", - "grammars/tree-sitter-ssh-server-config", - "y2j", - "xtask" + "xtask", + "y2j" ] [profile.release] @@ -299,7 +304,8 @@ dsc-lib = { path = "lib/dsc-lib" } dsc-lib-jsonschema = { path = "lib/dsc-lib-jsonschema" } dsc-lib-jsonschema-macros = { path = "lib/dsc-lib-jsonschema-macros" } dsc-lib-osinfo = { path = "lib/dsc-lib-osinfo" } +dsc-lib-registry = { path = "lib/dsc-lib-registry" } dsc-lib-security_context = { path = "lib/dsc-lib-security_context" } +dsc-lib-telemetry = { path = "lib/dsc-lib-telemetry" } tree-sitter-dscexpression = { path = "grammars/tree-sitter-dscexpression" } -dsc-lib-registry = { path = "lib/dsc-lib-registry" } tree-sitter-ssh-server-config = { path = "grammars/tree-sitter-ssh-server-config" } diff --git a/data.build.json b/data.build.json index 9a6d58d03..14e692f71 100644 --- a/data.build.json +++ b/data.build.json @@ -120,6 +120,16 @@ ] }, "Projects": [ + { + "Name": "root", + "Kind": "Root", + "RelativePath": ".", + "CopyFiles": { + "All": [ + "NOTICE.txt" + ] + } + }, { "Name": "root", "Kind": "Root", @@ -139,12 +149,27 @@ "psDscAdapter/powershell.resource.ps1", "psDscAdapter/psDscAdapter.psd1", "psDscAdapter/psDscAdapter.psm1", - "powershell.dsc.resource.json" + "powershell.dsc.resource.json", + "PowerShell_adapter.dsc.resource.json" ], "Windows": [ "psDscAdapter/win_psDscAdapter.psd1", "psDscAdapter/win_psDscAdapter.psm1", - "windowspowershell.dsc.resource.json" + "windowspowershell.dsc.resource.json", + "WindowsPowerShell_adapter.dsc.resource.json" + ] + } + }, + { + "Name": "PSAdaptedTestClassResource", + "Kind": "Resource", + "RelativePath": "adapters/powershell/Tests", + "TestOnly": true, + "CopyFiles": { + "All": [ + "PSAdaptedTestClassResource.psd1", + "PSAdaptedTestClassResource.psm1", + "PSAdaptedTestClassResource.dsc.adaptedResource.json" ] } }, @@ -174,16 +199,6 @@ ] } }, - { - "Name": "dism_dsc", - "Kind": "Resource", - "IsRust": true, - "SupportedPlatformOS": "Windows", - "Binaries": ["dism_dsc"], - "CopyFiles": { - "Windows": ["optionalfeature.dsc.resource.json", "featureondemand.dsc.resource.json", "windows_feature.dsc.resource.json"] - } - }, { "Name": "dsc", "Kind": "CLI", @@ -277,6 +292,12 @@ "RelativePath": "lib/dsc-lib-osinfo", "IsRust": true }, + { + "Name": "dsc-lib-otel", + "Kind": "Library", + "RelativePath": "lib/dsc-lib-otel", + "IsRust": true + }, { "Name": "dsc-lib-pal", "Kind": "Library", @@ -321,11 +342,29 @@ ] } }, + { + "Name": "dism_dsc", + "Kind": "Resource", + "RelativePath": "resources/dism_dsc", + "SupportedPlatformOS": "Windows", + "IsRust": true, + "Binaries": [ + "dism_dsc" + ], + "CopyFiles": { + "Windows": [ + "optionalfeature.dsc.resource.json", + "featureondemand.dsc.resource.json", + "windows_feature.dsc.resource.json" + ] + } + }, { "Name": "dscecho", "Kind": "Resource", "RelativePath": "resources/dscecho", "IsRust": true, + "RustPackageName": "dsc-resource-echo", "Binaries": [ "dscecho" ], @@ -340,6 +379,7 @@ "Kind": "Resource", "RelativePath": "resources/osinfo", "IsRust": true, + "RustPackageName": "dsc-resource-osinfo", "Binaries": [ "osinfo" ], @@ -354,6 +394,7 @@ "Kind": "Resource", "RelativePath": "resources/process", "IsRust": true, + "RustPackageName": "dsc-resource-process", "Binaries": [ "process" ], @@ -395,6 +436,7 @@ "RelativePath": "resources/registry", "SupportedPlatformOS": "Windows", "IsRust": true, + "RustPackageName": "dsc-resource-registry", "Binaries": [ "registry" ], @@ -409,6 +451,7 @@ "Kind": "Resource", "RelativePath": "resources/runcommandonset", "IsRust": true, + "RustPackageName": "dsc-resource-run_command_on_set", "Binaries": [ "runcommandonset" ], @@ -423,12 +466,15 @@ "Kind": "Resource", "RelativePath": "resources/sshdconfig", "IsRust": true, + "RustPackageName": "dsc-resource-sshdconfig", "Binaries": [ "sshdconfig" ], "CopyFiles": { "All": [ - "sshd_config.dsc.resource.json" + "sshd_config.dsc.resource.json", + "sshd-subsystem.dsc.resource.json", + "sshd-subsystemList.dsc.resource.json" ], "Windows": [ "sshd-windows.dsc.resource.json" @@ -441,6 +487,7 @@ "RelativePath": "resources/WindowsUpdate", "SupportedPlatformOS": "Windows", "IsRust": true, + "RustPackageName": "dsc-resource-windows-update", "Binaries": [ "wu_dsc" ], @@ -451,18 +498,30 @@ } }, { - "Name": "windows_firewall", - "Kind": "Resource", - "IsRust": true, - "SupportedPlatformOS": "Windows", - "Binaries": [ - "windows_firewall" - ], - "CopyFiles": { - "Windows": [ - "windows_firewall.dsc.resource.json" - ] - } + "Name": "windows_firewall", + "Kind": "Resource", + "RelativePath": "resources/windows_firewall", + "SupportedPlatformOS": "Windows", + "IsRust": true, + "Binaries": [ + "windows_firewall" + ], + "CopyFiles": { + "Windows": [ + "windows_firewall.dsc.resource.json" + ] + } + }, + { + "Name": "windows_personalization", + "Kind": "Resource", + "RelativePath": "resources/windows_personalization", + "SupportedPlatformOS": "Windows", + "CopyFiles": { + "Windows": [ + "windows_personalization.dsc.adaptedResource.yaml" + ] + } }, { "Name": "windows_service", @@ -491,7 +550,8 @@ "CopyFiles": { "All": [ "adaptedTest.dsc.adaptedResource.json", - "dsctest.dsc.manifests.json" + "dsctest.dsc.manifests.json", + "deprecated/deprecated.dsc.manifests.json" ] } }, @@ -510,6 +570,13 @@ ] } }, + { + "Name": "xtask", + "Kind": "CLI", + "RelativePath": "xtask", + "IsRust": true, + "TestOnly": true + }, { "Name": "y2j", "Kind": "CLI", @@ -518,13 +585,6 @@ "Binaries": [ "y2j" ] - }, - { - "Name": "xtask", - "Kind": "CLI", - "RelativePath": "xtask", - "IsRust": true, - "TestOnly": true } ] } diff --git a/lib/dsc-lib-telemetry/.project.data.json b/lib/dsc-lib-telemetry/.project.data.json new file mode 100644 index 000000000..f3c43b68d --- /dev/null +++ b/lib/dsc-lib-telemetry/.project.data.json @@ -0,0 +1,5 @@ +{ + "Name": "dsc-lib-telemetry", + "Kind": "Library", + "IsRust": true +} diff --git a/lib/dsc-lib-telemetry/Cargo.toml b/lib/dsc-lib-telemetry/Cargo.toml new file mode 100644 index 000000000..cfc2298f4 --- /dev/null +++ b/lib/dsc-lib-telemetry/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "dsc-lib-telemetry" +version = "0.0.0" +edition = "2024" + +[lib] +doctest = false # Disable doc tests by default for compilation speed diff --git a/lib/dsc-lib-telemetry/src/lib.rs b/lib/dsc-lib-telemetry/src/lib.rs new file mode 100644 index 000000000..409e55b6f --- /dev/null +++ b/lib/dsc-lib-telemetry/src/lib.rs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +//! This library provides telemetry support for DSC. +//! +//! It includes functionality for OpenTelemetry tracing, metrics, and exporting telemetry data to various backends. +//! Other crates can take a dependency on this crate to leverage its OTel capabilities and keep a consistent +//! implementation and dependencies. +//! +//! This crate also supports basic tracing functionality for applications that do not require full OpenTelemetry +//! support. This functionality bundles the [`tracing`] crate and related crates to provide a simple way to emit trace +//! events to stderr in a human-readable format. From b760d708247996f439930d72bd0acac84b003075 Mon Sep 17 00:00:00 2001 From: Mikey Lombardi Date: Mon, 10 Aug 2026 13:02:45 -0500 Subject: [PATCH 2/4] (GH-1061) Encapsulate tracing initialization in telemetry crate Prior to this change, `dsc` initialized tracing directly. Other crates, like `registry`, follow similar steps to initialize tracing. This change extracts the tracing initialization logic into the telemetry crate in the `basic` module. This module defines a `BasicTracingOptions` struct that can create a default guard and initialize a subscriber. This change also re-exports the tracing crates from within the `basic` module to enable taking a single dependency. --- Cargo.lock | 7 ++ dsc/Cargo.toml | 1 + dsc/src/util.rs | 63 ++-------- lib/dsc-lib-telemetry/Cargo.toml | 6 + lib/dsc-lib-telemetry/src/basic.rs | 178 +++++++++++++++++++++++++++++ lib/dsc-lib-telemetry/src/lib.rs | 29 +++-- 6 files changed, 225 insertions(+), 59 deletions(-) create mode 100644 lib/dsc-lib-telemetry/src/basic.rs diff --git a/Cargo.lock b/Cargo.lock index ec9e06385..80f251607 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -749,6 +749,7 @@ dependencies = [ "crossterm", "ctrlc", "dsc-lib", + "dsc-lib-telemetry", "indicatif", "jsonschema", "path-absolutize", @@ -911,6 +912,12 @@ dependencies = [ [[package]] name = "dsc-lib-telemetry" version = "0.0.0" +dependencies = [ + "thiserror 2.0.19", + "tracing", + "tracing-indicatif", + "tracing-subscriber", +] [[package]] name = "dsc-resource-echo" diff --git a/dsc/Cargo.toml b/dsc/Cargo.toml index a6530d729..9aa836dfe 100644 --- a/dsc/Cargo.toml +++ b/dsc/Cargo.toml @@ -37,3 +37,4 @@ tracing-subscriber = { workspace = true } tracing-indicatif = { workspace = true } # workspace crate dependencies dsc-lib = { workspace = true } +dsc-lib-telemetry = { workspace = true } diff --git a/dsc/src/util.rs b/dsc/src/util.rs index 51eb4596a..a5035b1d2 100644 --- a/dsc/src/util.rs +++ b/dsc/src/util.rs @@ -46,6 +46,7 @@ use dsc_lib::{ parse_input_to_json, }, }; +use dsc_lib_telemetry::{StderrFormat, basic::{BasicTracingOptions}}; use path_absolutize::Absolutize; use rust_i18n::t; use schemars::{Schema, schema_for}; @@ -62,8 +63,6 @@ use syntect::{ util::{as_24_bit_terminal_escaped, LinesWithEndings} }; use tracing::{Level, debug, error, info, warn, trace}; -use tracing_subscriber::{filter::EnvFilter, layer::SubscriberExt, Layer}; -use tracing_indicatif::IndicatifLayer; pub const EXIT_SUCCESS: i32 = 0; pub const EXIT_INVALID_ARGS: i32 = 1; @@ -327,22 +326,10 @@ pub fn write_object(json: &str, format: Option<&OutputFormat>, include_separator #[allow(clippy::too_many_lines)] pub fn enable_tracing(trace_level_arg: Option<&TraceLevel>, trace_format_arg: Option<&TraceFormat>) { - let mut policy_is_used = false; let mut tracing_setting = TracingSetting::default(); - let default_filter = EnvFilter::try_from_default_env() - .or_else(|_| EnvFilter::try_new("warn")) - .unwrap_or_default() - .add_directive(Level::WARN.into()); - let default_indicatif_layer = IndicatifLayer::new(); - let default_layer = tracing_subscriber::fmt::Layer::default().with_writer(default_indicatif_layer.get_stderr_writer()); - let default_fmt = default_layer - .with_ansi(true) - .with_level(true) - .boxed(); - let default_subscriber = tracing_subscriber::Registry::default().with(default_fmt).with(default_filter).with(default_indicatif_layer); - let default_guard = tracing::subscriber::set_default(default_subscriber); + let default_guard = dsc_lib_telemetry::basic::BasicTracingOptions::init_default_guard(); // read setting/policy from files if let Ok(v) = get_setting("tracing") { @@ -399,44 +386,18 @@ pub fn enable_tracing(trace_level_arg: Option<&TraceLevel>, trace_format_arg: Op TraceLevel::Debug => Level::DEBUG, TraceLevel::Trace => Level::TRACE, }; - - // enable tracing - let filter = EnvFilter::try_from_default_env() - .or_else(|_| EnvFilter::try_new("warn")) - .unwrap_or_default() - .add_directive(tracing_level.into()); - let indicatif_layer = IndicatifLayer::new(); - let layer = tracing_subscriber::fmt::Layer::default().with_writer(indicatif_layer.get_stderr_writer()); - let with_source = tracing_level == Level::DEBUG || tracing_level == Level::TRACE; - let fmt = match tracing_setting.format { - TraceFormat::Default => { - layer - .with_ansi(true) - .with_level(true) - .with_target(with_source) - .with_line_number(with_source) - .boxed() - }, - TraceFormat::Plaintext => { - layer - .with_ansi(false) - .with_level(true) - .with_target(with_source) - .with_line_number(with_source) - .boxed() - }, - TraceFormat::Json | TraceFormat::PassThrough => { - layer - .with_ansi(false) - .with_level(true) - .with_target(with_source) - .with_line_number(with_source) - .json() - .boxed() - }, + // convert to 'dsc-lib-otel' crate type + let stderr_format = match tracing_setting.format { + TraceFormat::Default => StderrFormat::Default, + TraceFormat::Plaintext => StderrFormat::Plaintext, + TraceFormat::Json | TraceFormat::PassThrough => StderrFormat::Json, }; - let subscriber = tracing_subscriber::Registry::default().with(fmt).with(filter).with(indicatif_layer); + // enable tracing + let subscriber = BasicTracingOptions { + tracing_level, + stderr_format + }.init_subscriber(); drop(default_guard); if tracing::subscriber::set_global_default(subscriber).is_err() { diff --git a/lib/dsc-lib-telemetry/Cargo.toml b/lib/dsc-lib-telemetry/Cargo.toml index cfc2298f4..9d031a31d 100644 --- a/lib/dsc-lib-telemetry/Cargo.toml +++ b/lib/dsc-lib-telemetry/Cargo.toml @@ -5,3 +5,9 @@ edition = "2024" [lib] doctest = false # Disable doc tests by default for compilation speed + +[dependencies] +thiserror = { workspace = true } +tracing = { workspace = true } +tracing-indicatif = { workspace = true } +tracing-subscriber = { workspace = true } diff --git a/lib/dsc-lib-telemetry/src/basic.rs b/lib/dsc-lib-telemetry/src/basic.rs new file mode 100644 index 000000000..720c2ae4e --- /dev/null +++ b/lib/dsc-lib-telemetry/src/basic.rs @@ -0,0 +1,178 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +//! This module provides basic tracing functionality for applications that do not require full +//! OpenTelemetry support. +//! +//! It bundles the [`tracing`] crate and related crates to provide a simple way to emit trace +//! events to stderr in a human-readable format. +//! +//! This module simplifies the process of setting up a tracing subscriber with configurable options +//! for tracing level and stderr output format. It also provides a default guard for capturing +//! events emitted during application initialization, enabling developers to set up their own +//! subscriber later in the application lifecycle. + +// Re-export the tracing crates so that other crates can use them without +// having to add them as separate dependencies. +pub use tracing; +pub use tracing_indicatif; +pub use tracing_subscriber; + +use crate::StderrFormat; + +use tracing::{Level, subscriber::DefaultGuard}; +use tracing_indicatif::IndicatifLayer; +use tracing_subscriber::{ + EnvFilter, + Layer, + Registry, + fmt::Layer as FormatLayer, + layer::{Layered, SubscriberExt} +}; + +// Define type aliases for the boxed layer and the basic tracing subscriber to simplify their usage +// in the code. We don't provide documentation for these type aliases because that overrides the +// documentation for the underlying types, which is more useful to users of this crate. +pub type BoxedLayer = Box + Send + Sync>; +pub type BasicTracingSubscriber = Layered< + IndicatifLayer>>, + Layered> +>; + +/// Represents the options for basic tracing functionality in DSC. +/// +/// This struct allows users to configure the tracing level and the format of stderr output for +/// trace events. It's only used for the legacy basic tracing functionality, not for OpenTelemetry +/// tracing, logging, or metrics. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct BasicTracingOptions { + /// Indicates the minimum level of tracing events to be recorded. Events below this level are + /// filtered out and not emitted. The default level is [`Level::INFO`]. + pub tracing_level: Level, + /// Specifies the format of stderr output for trace events. The default format is + /// [`StderrFormat::Default`]. + pub stderr_format: StderrFormat, +} + +impl Default for BasicTracingOptions { + fn default() -> Self { + BasicTracingOptions { + tracing_level: Level::INFO, + stderr_format: StderrFormat::Default, + } + } +} + +impl BasicTracingOptions { + /// Returns a [`DefaultGuard`] that sets up a default tracing subscriber for capturing events + /// emitted during the initialization of the application. + /// + /// The default subscriber is configured with a filter that captures [`Level::WARN`] events and + /// higher, and it uses an [`IndicatifLayer`] for progress reporting. The subscriber is set as + /// the default, allowing it to capture events emitted during initialization. + /// + /// # Example + /// + /// The following example demonstrates how to use this method to setup a default guard that you + /// use during the initialization of your application before dropping it to use your own + /// subscriber. + /// + /// ```rust + /// # use dsc_lib_telemetry::basic::BasicTracingOptions; + /// let default_guard = BasicTracingOptions::init_default_guard(); + /// + /// // Perform initialization tasks that may emit tracing events here; + /// // For this example, we're just assigning values to the tracing level + /// // and stderr format. + /// let tracing_level = tracing::Level::INFO; + /// let stderr_format = dsc_lib_telemetry::StderrFormat::Default; + /// + /// // Initialize your own subscriber based on the desired tracing level + /// // and stderr format. + /// let subscriber = dsc_lib_telemetry::basic::BasicTracingOptions { + /// tracing_level, + /// stderr_format + /// }.init_subscriber(); + /// + /// // Drop the default guard to stop capturing events with the default + /// // subscriber and set your own subscriber as the global default. + /// drop(default_guard); + /// if tracing::subscriber::set_global_default(subscriber).is_err() { + /// eprintln!("Failed to set tracing subscriber as global default."); + /// } + /// ``` + pub fn init_default_guard() -> DefaultGuard { + let default_filter = EnvFilter::try_from_default_env() + .or_else(|_| EnvFilter::try_new("warn")) + .unwrap_or_default() + .add_directive(Level::WARN.into()); + let default_indicatif_layer = IndicatifLayer::new(); + let default_layer = FormatLayer::default() + .with_writer(default_indicatif_layer.get_stderr_writer()); + let default_fmt = default_layer + .with_ansi(true) + .with_level(true) + .boxed(); + let default_subscriber = tracing_subscriber::Registry::default() + .with(default_fmt) + .with(default_filter) + .with(default_indicatif_layer); + let default_guard = tracing::subscriber::set_default(default_subscriber); + + default_guard + } + + /// Initializes a tracing subscriber based on the provided [`BasicTracingOptions`]. + /// + /// This method sets up a tracing subscriber that captures events at the specified tracing level and formats stderr + /// output according to the specified format. The subscriber is configured with an `IndicatifLayer` for progress + /// reporting. + /// + /// # Example + /// + /// The following example demonstrates how to use this method to initialize a tracing + /// subscriber and set it as the global default subscriber. + /// + /// ```rust + /// # use dsc_lib_telemetry::basic::{BasicTracingOptions, StderrFormat}; + /// # use tracing::Level; + /// + /// let tracing_options = BasicTracingOptions { + /// tracing_level: Level::INFO, + /// stderr_format: StderrFormat::Json, + /// }; + /// let subscriber = tracing_options.init_subscriber(); + /// + /// if tracing::subscriber::set_global_default(subscriber).is_err() { + /// eprintln!("Failed to set tracing subscriber as global default."); + /// } + /// ``` + /// + /// # Returns + /// + /// [`BasicTracingSubscriber`] that can be set as the global default subscriber using + /// [`tracing::subscriber::set_global_default`]. + pub fn init_subscriber(&self) -> BasicTracingSubscriber { + let with_source = self.tracing_level == Level::DEBUG || self.tracing_level == Level::TRACE; + let filter = EnvFilter::try_from_default_env() + .or_else(|_| EnvFilter::try_new("warn")) + .unwrap_or_default() + .add_directive(self.tracing_level.into()); + let indicatif_layer = IndicatifLayer::new(); + let layer = FormatLayer::default() + .with_writer(indicatif_layer.get_stderr_writer()) + .with_level(true) + .with_target(with_source) + .with_line_number(with_source); + let format_layer = match self.stderr_format { + StderrFormat::Default => layer.with_ansi(true).boxed(), + StderrFormat::Plaintext => layer.with_ansi(false).boxed(), + StderrFormat::Json => layer.with_ansi(false).json().boxed(), + }; + + Registry::default() + .with(format_layer) + .with(filter) + .with(indicatif_layer) + } +} diff --git a/lib/dsc-lib-telemetry/src/lib.rs b/lib/dsc-lib-telemetry/src/lib.rs index 409e55b6f..128741e18 100644 --- a/lib/dsc-lib-telemetry/src/lib.rs +++ b/lib/dsc-lib-telemetry/src/lib.rs @@ -2,11 +2,24 @@ // Licensed under the MIT License. //! This library provides telemetry support for DSC. -//! -//! It includes functionality for OpenTelemetry tracing, metrics, and exporting telemetry data to various backends. -//! Other crates can take a dependency on this crate to leverage its OTel capabilities and keep a consistent -//! implementation and dependencies. -//! -//! This crate also supports basic tracing functionality for applications that do not require full OpenTelemetry -//! support. This functionality bundles the [`tracing`] crate and related crates to provide a simple way to emit trace -//! events to stderr in a human-readable format. +//! +//! It includes functionality for OpenTelemetry tracing, metrics, and exporting telemetry data to +//! various backends. Other crates can take a dependency on this crate to leverage its OTel +//! capabilities and keep a consistent implementation and dependencies. +//! +//! This crate also supports basic tracing functionality for applications that do not require full +//! OpenTelemetry support. This functionality bundles the [`tracing`] crate and related crates to +//! provide a simple way to emit trace events to stderr in a human-readable format. + +pub mod basic; + +/// Represents the different formats that can be used for stderr output in tracing. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum StderrFormat { + /// Emit trace events as human-readable text to stderr with ANSI color codes. + Default, + /// Emit trace events as human-readable text to stderr without ANSI color codes. + Plaintext, + /// Emit trace events as JSON to stderr. + Json, +} From 3b6b7c2b84a5aff5e4e26ee0e797903a3f744d09 Mon Sep 17 00:00:00 2001 From: Mikey Lombardi Date: Mon, 10 Aug 2026 16:31:04 -0500 Subject: [PATCH 3/4] (MAINT) Drop Erroneous modifications to build data --- data.build.json | 126 +++++++++++++----------------------------------- 1 file changed, 33 insertions(+), 93 deletions(-) diff --git a/data.build.json b/data.build.json index 14e692f71..9a6d58d03 100644 --- a/data.build.json +++ b/data.build.json @@ -120,16 +120,6 @@ ] }, "Projects": [ - { - "Name": "root", - "Kind": "Root", - "RelativePath": ".", - "CopyFiles": { - "All": [ - "NOTICE.txt" - ] - } - }, { "Name": "root", "Kind": "Root", @@ -149,27 +139,12 @@ "psDscAdapter/powershell.resource.ps1", "psDscAdapter/psDscAdapter.psd1", "psDscAdapter/psDscAdapter.psm1", - "powershell.dsc.resource.json", - "PowerShell_adapter.dsc.resource.json" + "powershell.dsc.resource.json" ], "Windows": [ "psDscAdapter/win_psDscAdapter.psd1", "psDscAdapter/win_psDscAdapter.psm1", - "windowspowershell.dsc.resource.json", - "WindowsPowerShell_adapter.dsc.resource.json" - ] - } - }, - { - "Name": "PSAdaptedTestClassResource", - "Kind": "Resource", - "RelativePath": "adapters/powershell/Tests", - "TestOnly": true, - "CopyFiles": { - "All": [ - "PSAdaptedTestClassResource.psd1", - "PSAdaptedTestClassResource.psm1", - "PSAdaptedTestClassResource.dsc.adaptedResource.json" + "windowspowershell.dsc.resource.json" ] } }, @@ -199,6 +174,16 @@ ] } }, + { + "Name": "dism_dsc", + "Kind": "Resource", + "IsRust": true, + "SupportedPlatformOS": "Windows", + "Binaries": ["dism_dsc"], + "CopyFiles": { + "Windows": ["optionalfeature.dsc.resource.json", "featureondemand.dsc.resource.json", "windows_feature.dsc.resource.json"] + } + }, { "Name": "dsc", "Kind": "CLI", @@ -292,12 +277,6 @@ "RelativePath": "lib/dsc-lib-osinfo", "IsRust": true }, - { - "Name": "dsc-lib-otel", - "Kind": "Library", - "RelativePath": "lib/dsc-lib-otel", - "IsRust": true - }, { "Name": "dsc-lib-pal", "Kind": "Library", @@ -342,29 +321,11 @@ ] } }, - { - "Name": "dism_dsc", - "Kind": "Resource", - "RelativePath": "resources/dism_dsc", - "SupportedPlatformOS": "Windows", - "IsRust": true, - "Binaries": [ - "dism_dsc" - ], - "CopyFiles": { - "Windows": [ - "optionalfeature.dsc.resource.json", - "featureondemand.dsc.resource.json", - "windows_feature.dsc.resource.json" - ] - } - }, { "Name": "dscecho", "Kind": "Resource", "RelativePath": "resources/dscecho", "IsRust": true, - "RustPackageName": "dsc-resource-echo", "Binaries": [ "dscecho" ], @@ -379,7 +340,6 @@ "Kind": "Resource", "RelativePath": "resources/osinfo", "IsRust": true, - "RustPackageName": "dsc-resource-osinfo", "Binaries": [ "osinfo" ], @@ -394,7 +354,6 @@ "Kind": "Resource", "RelativePath": "resources/process", "IsRust": true, - "RustPackageName": "dsc-resource-process", "Binaries": [ "process" ], @@ -436,7 +395,6 @@ "RelativePath": "resources/registry", "SupportedPlatformOS": "Windows", "IsRust": true, - "RustPackageName": "dsc-resource-registry", "Binaries": [ "registry" ], @@ -451,7 +409,6 @@ "Kind": "Resource", "RelativePath": "resources/runcommandonset", "IsRust": true, - "RustPackageName": "dsc-resource-run_command_on_set", "Binaries": [ "runcommandonset" ], @@ -466,15 +423,12 @@ "Kind": "Resource", "RelativePath": "resources/sshdconfig", "IsRust": true, - "RustPackageName": "dsc-resource-sshdconfig", "Binaries": [ "sshdconfig" ], "CopyFiles": { "All": [ - "sshd_config.dsc.resource.json", - "sshd-subsystem.dsc.resource.json", - "sshd-subsystemList.dsc.resource.json" + "sshd_config.dsc.resource.json" ], "Windows": [ "sshd-windows.dsc.resource.json" @@ -487,7 +441,6 @@ "RelativePath": "resources/WindowsUpdate", "SupportedPlatformOS": "Windows", "IsRust": true, - "RustPackageName": "dsc-resource-windows-update", "Binaries": [ "wu_dsc" ], @@ -498,30 +451,18 @@ } }, { - "Name": "windows_firewall", - "Kind": "Resource", - "RelativePath": "resources/windows_firewall", - "SupportedPlatformOS": "Windows", - "IsRust": true, - "Binaries": [ - "windows_firewall" - ], - "CopyFiles": { - "Windows": [ - "windows_firewall.dsc.resource.json" - ] - } - }, - { - "Name": "windows_personalization", - "Kind": "Resource", - "RelativePath": "resources/windows_personalization", - "SupportedPlatformOS": "Windows", - "CopyFiles": { - "Windows": [ - "windows_personalization.dsc.adaptedResource.yaml" - ] - } + "Name": "windows_firewall", + "Kind": "Resource", + "IsRust": true, + "SupportedPlatformOS": "Windows", + "Binaries": [ + "windows_firewall" + ], + "CopyFiles": { + "Windows": [ + "windows_firewall.dsc.resource.json" + ] + } }, { "Name": "windows_service", @@ -550,8 +491,7 @@ "CopyFiles": { "All": [ "adaptedTest.dsc.adaptedResource.json", - "dsctest.dsc.manifests.json", - "deprecated/deprecated.dsc.manifests.json" + "dsctest.dsc.manifests.json" ] } }, @@ -570,13 +510,6 @@ ] } }, - { - "Name": "xtask", - "Kind": "CLI", - "RelativePath": "xtask", - "IsRust": true, - "TestOnly": true - }, { "Name": "y2j", "Kind": "CLI", @@ -585,6 +518,13 @@ "Binaries": [ "y2j" ] + }, + { + "Name": "xtask", + "Kind": "CLI", + "RelativePath": "xtask", + "IsRust": true, + "TestOnly": true } ] } From 7d2695fc840e84ce94d55b85250045d6b8321a57 Mon Sep 17 00:00:00 2001 From: Mikey Lombardi Date: Mon, 10 Aug 2026 16:37:54 -0500 Subject: [PATCH 4/4] (MAINT) Address PR comments --- dsc/src/util.rs | 2 +- lib/dsc-lib-telemetry/src/basic.rs | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/dsc/src/util.rs b/dsc/src/util.rs index a5035b1d2..4b18fac6c 100644 --- a/dsc/src/util.rs +++ b/dsc/src/util.rs @@ -386,7 +386,7 @@ pub fn enable_tracing(trace_level_arg: Option<&TraceLevel>, trace_format_arg: Op TraceLevel::Debug => Level::DEBUG, TraceLevel::Trace => Level::TRACE, }; - // convert to 'dsc-lib-otel' crate type + // convert to 'dsc-lib-telemetry' crate type let stderr_format = match tracing_setting.format { TraceFormat::Default => StderrFormat::Default, TraceFormat::Plaintext => StderrFormat::Plaintext, diff --git a/lib/dsc-lib-telemetry/src/basic.rs b/lib/dsc-lib-telemetry/src/basic.rs index 720c2ae4e..c3a8d0b82 100644 --- a/lib/dsc-lib-telemetry/src/basic.rs +++ b/lib/dsc-lib-telemetry/src/basic.rs @@ -3,10 +3,10 @@ //! This module provides basic tracing functionality for applications that do not require full //! OpenTelemetry support. -//! +//! //! It bundles the [`tracing`] crate and related crates to provide a simple way to emit trace //! events to stderr in a human-readable format. -//! +//! //! This module simplifies the process of setting up a tracing subscriber with configurable options //! for tracing level and stderr output format. It also provides a default guard for capturing //! events emitted during application initialization, enabling developers to set up their own @@ -117,9 +117,8 @@ impl BasicTracingOptions { .with(default_fmt) .with(default_filter) .with(default_indicatif_layer); - let default_guard = tracing::subscriber::set_default(default_subscriber); - default_guard + tracing::subscriber::set_default(default_subscriber) } /// Initializes a tracing subscriber based on the provided [`BasicTracingOptions`]. @@ -134,7 +133,7 @@ impl BasicTracingOptions { /// subscriber and set it as the global default subscriber. /// /// ```rust - /// # use dsc_lib_telemetry::basic::{BasicTracingOptions, StderrFormat}; + /// # use dsc_lib_telemetry::{basic::BasicTracingOptions, StderrFormat}; /// # use tracing::Level; /// /// let tracing_options = BasicTracingOptions {