Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use MSBuild Logging APIs for Task output instead of StdOut #933

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Keep some of the previous API surface area to minimize breaks. Add do…
…cumentation comments to clarify intended usage of members.
  • Loading branch information
baronfel committed Mar 1, 2025
commit 649d0fc9ff5a29f533a0b8ed83333b31920c7e41
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@
using Microsoft.Extensions.Logging;
using Microsoft.Sbom.Api;
using Microsoft.Sbom.Api.Config;
using Microsoft.Sbom.Api.Config.Extensions;
using Microsoft.Sbom.Api.Converters;
using Microsoft.Sbom.Api.Convertors;
using Microsoft.Sbom.Api.Entities.Output;
@@ -45,11 +46,38 @@ namespace Microsoft.Sbom.Extensions.DependencyInjection;

public static class ServiceCollectionExtensions
{
public static IServiceCollection AddSbomTool(this IServiceCollection services)
/// <summary>
/// Initializes the services required to use the SBOM Tool using a default <see cref="InputConfiguration"/> and <see cref="LogEventLevel"/>.
/// </summary>
/// <param name="services">The services to which registrations are added.</param>
/// <param name="inputConfiguration">The default configuration to use, which will be registered as a singleton and will overwrite the currently-set <see cref="Configuration"/>.</param>
/// <param name="logLevel">The log verbosity level with which to use for the minimal logger used for internal services. These services require an <see cref="ILogger"/> but may themselves be used to <strong>initialize</strong> an <see cref="ILogger"/>, so need separate configuration.</param>
/// <remarks>The <see cref="InputConfiguration"/> is registered as a singleton in the container, and the <paramref name="logLevel"/> is used to create a default logger for internal utility classes, irrespective of any other <see cref="ILogger"/> registered in the container. This method does not register an instance of <see cref="ILogger"/>, however one is required for the system to function. Callers need to provide their own implementation.</remarks>
/// <returns></returns>
public static IServiceCollection AddSbomConfiguration(this IServiceCollection services, InputConfiguration inputConfiguration, LogEventLevel logLevel = LogEventLevel.Information)
{
ArgumentNullException.ThrowIfNull(inputConfiguration);
services
.AddSingleton(_ =>
{
inputConfiguration.ToConfiguration();
return inputConfiguration;
})
.AddSbomTool(logLevel);
return services;
}

/// <summary>
/// Initializes the services required to use the SBOM Tool using a default <see cref="LogEventLevel"/>.
/// </summary>
/// <param name="services">The services to which registrations are added.</param>
/// <param name="logLevel">The log verbosity level with which to use for the minimal logger used for internal services. These services require an <see cref="ILogger"/> but may themselves be used to <strong>initialize</strong> an <see cref="ILogger"/>, so need separate configuration.</param>
/// <remarks>This method does not register an instance of <see cref="ILogger"/>, however one is required for the system to function. Callers need to provide their own implementation.</remarks>
public static IServiceCollection AddSbomTool(this IServiceCollection services, LogEventLevel logLevel = LogEventLevel.Information)
{
services
.AddSingleton<IConfiguration, Configuration>()
.AddTransient(x => FileSystemUtilsProvider.CreateInstance(CreateDefaultLogger()))
.AddTransient(x => FileSystemUtilsProvider.CreateInstance(CreateLogger(logLevel)))
.AddTransient<IWorkflow<SbomParserBasedValidationWorkflow>, SbomParserBasedValidationWorkflow>()
.AddTransient<IWorkflow<SbomGenerationWorkflow>, SbomGenerationWorkflow>()
.AddTransient<IWorkflow<SbomRedactionWorkflow>, SbomRedactionWorkflow>()
@@ -162,6 +190,11 @@ public static IServiceCollection AddSbomTool(this IServiceCollection services)
return services;
}

/// <summary>
/// This method integrates Serilog into the <see cref="Microsoft.Extensions.Logging"/> infrastructure.
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection ConfigureLoggingProviders(this IServiceCollection services)
{
var providers = new LoggerProviderCollection();
@@ -182,7 +215,13 @@ public static IServiceCollection ConfigureLoggingProviders(this IServiceCollecti
return services;
}

public static ILogger CreateDefaultLogger(LogEventLevel logLevel = LogEventLevel.Information)
/// <summary>
/// Creates a logger with the specified <paramref name="logLevel"/> that writes to a file and optionally to stderr.
/// This logger converts all errors from ComponentDetection assemblies to warnings, and does not write tabular output to stdout/stderr, only the configured file.
/// </summary>
/// <param name="logLevel"></param>
/// <returns></returns>
public static ILogger CreateLogger(LogEventLevel logLevel = LogEventLevel.Information)
{
return new RemapComponentDetectionErrorsToWarningsLogger(
new LoggerConfiguration()
11 changes: 4 additions & 7 deletions src/Microsoft.Sbom.Targets/GenerateSbomTask.cs
Original file line number Diff line number Diff line change
@@ -9,7 +9,6 @@ namespace Microsoft.Sbom.Targets;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Sbom.Api.Manifest.ManifestConfigHandlers;
using Microsoft.Sbom.Api.Metadata;
using Microsoft.Sbom.Api.Providers;
@@ -58,9 +57,7 @@ public override bool Execute()
NoComponentGovernanceSummary = true
};

var taskHost = Host.CreateDefaultBuilder()
.ConfigureServices((host, services) =>
services
using var services = new ServiceCollection()
.AddSingleton<IConfiguration, Configuration>()
.AddSingleton(runtimeConfiguration)
.AddSingleton<Serilog.ILogger>(msbuildLogger)
@@ -85,10 +82,10 @@ public override bool Execute()
.AddSingleton<IManifestInterface, SPDX22.Validator>()
.AddSingleton<IManifestInterface, SPDX30.Validator>()
.AddSingleton<IManifestConfigHandler, SPDX22ManifestConfigHandler>()
.AddSingleton<IManifestConfigHandler, SPDX30ManifestConfigHandler>())
.Build();
.AddSingleton<IManifestConfigHandler, SPDX30ManifestConfigHandler>()
.BuildServiceProvider();

var generator = taskHost.Services.GetRequiredService<ISbomGenerator>();
var generator = services.GetRequiredService<ISbomGenerator>();

// Set other configurations. The GenerateSBOMAsync() already sanitizes and checks for
// a valid namespace URI and generates a random guid for NamespaceUriUniquePart if
2 changes: 1 addition & 1 deletion src/Microsoft.Sbom.Tool/Program.cs
Original file line number Diff line number Diff line change
@@ -79,7 +79,7 @@ await Host.CreateDefaultBuilder(args)
.AddSingleton(x =>
{
var level = x.GetService<Common.Config.InputConfiguration>()?.Verbosity?.Value ?? Serilog.Events.LogEventLevel.Information;
var defaultLogger = Extensions.DependencyInjection.ServiceCollectionExtensions.CreateDefaultLogger(level);
var defaultLogger = Extensions.DependencyInjection.ServiceCollectionExtensions.CreateLogger(level);
Serilog.Log.Logger = defaultLogger;
return defaultLogger;
})
Loading
Oops, something went wrong.