diff --git a/ReleaseHistory.md b/ReleaseHistory.md index fb7b47bb..3f6122aa 100644 --- a/ReleaseHistory.md +++ b/ReleaseHistory.md @@ -16,6 +16,7 @@ - NEW => new feature ## UNRELEASED +* BUG: Fork telemetry to log always to Console and AppInsights in the same time when Error occur. [1002](https://github.com/microsoft/binskim/pull/1002) ## **v4.3.0** * DEP: Update `msdia140.dll` from 14.36.32532.0 to 14.40.33810.0. This update fixes the `System.AccessViolationException: Attempted to read or write protected memory` exception that occurs when reading certain PDB files. [996](https://github.com/microsoft/binskim/pull/996) diff --git a/src/BinSkim.Driver/MultithreadedAnalyzeCommand.cs b/src/BinSkim.Driver/MultithreadedAnalyzeCommand.cs index 725bfeb9..99edb664 100644 --- a/src/BinSkim.Driver/MultithreadedAnalyzeCommand.cs +++ b/src/BinSkim.Driver/MultithreadedAnalyzeCommand.cs @@ -8,6 +8,8 @@ using System.Linq; using System.Reflection; +using CommandLine; + using Microsoft.CodeAnalysis.BinaryParsers; using Microsoft.CodeAnalysis.IL.Rules; using Microsoft.CodeAnalysis.IL.Sdk; @@ -48,13 +50,25 @@ private bool IsValidScanTarget(string file) public override BinaryAnalyzerContext InitializeGlobalContextFromOptions(AnalyzeOptions options, ref BinaryAnalyzerContext context) { + base.InitializeGlobalContextFromOptions(options, ref context); + if (this.Telemetry?.TelemetryClient != null) { + // Create an aggregating logger that will combine all loggers into a single logger. var aggregatingLogger = new AggregatingLogger(); + if (context.Logger is AggregatingLogger) + { + aggregatingLogger = context.Logger as AggregatingLogger; + } + else + { + aggregatingLogger.Loggers.Add(context.Logger); + } var ruleTelemetryLogger = new RuleTelemetryLogger(this.Telemetry.TelemetryClient); ruleTelemetryLogger.AnalysisStarted(); + // Combine rule telemetry with any other loggers that may be present. aggregatingLogger.Loggers.Add(ruleTelemetryLogger); context.Logger = aggregatingLogger; } @@ -65,7 +79,7 @@ public override BinaryAnalyzerContext InitializeGlobalContextFromOptions(Analyze ? options.MaxFileSizeInKilobytes.Value : long.MaxValue; - base.InitializeGlobalContextFromOptions(options, ref context); + // Update context object based on command-line parameters. context.SymbolPath = options.SymbolsPath ?? context.SymbolPath; diff --git a/src/Test.UnitTests.BinSkim.Driver/MultithreadedAnalyzeCommandTests.cs b/src/Test.UnitTests.BinSkim.Driver/MultithreadedAnalyzeCommandTests.cs index 46cb35b7..2fecd28b 100644 --- a/src/Test.UnitTests.BinSkim.Driver/MultithreadedAnalyzeCommandTests.cs +++ b/src/Test.UnitTests.BinSkim.Driver/MultithreadedAnalyzeCommandTests.cs @@ -2,11 +2,16 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Collections.Generic; using System.Text; using FluentAssertions; +using Microsoft.ApplicationInsights; +using Microsoft.ApplicationInsights.Extensibility; using Microsoft.CodeAnalysis.IL; +using Microsoft.CodeAnalysis.IL.Sdk; +using Microsoft.CodeAnalysis.Sarif.Writers; using Xunit; @@ -150,5 +155,89 @@ private static string[] Shuffle(string[] data) return data; } + + [Fact] + public void MultithreadedAnalyzeCommand_InitializeGlobalContextFromOptions_TelemetryNotSpecifiedHasOneConsoleLogger() + { + var options = new AnalyzeOptions(); + options.TargetFileSpecifiers = new List { "test.dll" }; + options.DisableTelemetry = true; + options.OutputFilePath = "test/path/"; + var context = new BinaryAnalyzerContext(); + + var command = new MultithreadedAnalyzeCommand(); + command.InitializeGlobalContextFromOptions(options, ref context); + + Assert.IsType(context.Logger); + + var aggregatingLogger = (Sarif.Driver.AggregatingLogger)context.Logger; + Assert.Contains(aggregatingLogger.Loggers, l => l is ConsoleLogger); + Assert.Equal(1, aggregatingLogger.Loggers.Count); + } + + [Fact] + public void MultithreadedAnalyzeCommand_InitializeGlobalContextFromOptions_TelemetrySpecifiedHasTwoLoggers() + { + var telemetryConfiguration = TelemetryConfiguration.CreateDefault(); + var telemetryClient = new TelemetryClient(telemetryConfiguration); + var telemetry = new Telemetry(telemetryConfiguration); + + var options = new AnalyzeOptions(); + options.TargetFileSpecifiers = new List { "test.dll" }; + options.OutputFilePath = "test/path/"; + var context = new BinaryAnalyzerContext(); + + var command = new MultithreadedAnalyzeCommand(telemetry); + command.InitializeGlobalContextFromOptions(options, ref context); + + Assert.IsType(context.Logger); + + var aggregatingLogger = (Sarif.Driver.AggregatingLogger)context.Logger; + Assert.Contains(aggregatingLogger.Loggers, l => l is ConsoleLogger); + Assert.Contains(aggregatingLogger.Loggers, l => l is RuleTelemetryLogger); + Assert.Equal(2, aggregatingLogger.Loggers.Count); + } + + [Fact] + public void MultithreadedAnalyzeCommand_InitializeGlobalContextFromOptions_QuietOptionSetHasOneRuleTelemetryLogger() + { + var telemetryConfiguration = TelemetryConfiguration.CreateDefault(); + var telemetryClient = new TelemetryClient(telemetryConfiguration); + var telemetry = new Telemetry(telemetryConfiguration); + + var options = new AnalyzeOptions(); + options.TargetFileSpecifiers = new List { "test.dll" }; + options.OutputFilePath = "test/path/"; + options.Quiet = true; + var context = new BinaryAnalyzerContext(); + + var command = new MultithreadedAnalyzeCommand(telemetry); + command.InitializeGlobalContextFromOptions(options, ref context); + + Assert.IsType(context.Logger); + + var aggregatingLogger = (Sarif.Driver.AggregatingLogger)context.Logger; + Assert.Contains(aggregatingLogger.Loggers, l => l is RuleTelemetryLogger); + Assert.Equal(1, aggregatingLogger.Loggers.Count); + } + + [Fact] + public void MultithreadedAnalyzeCommand_InitializeGlobalContextFromOptions_QuietOptionSetAndNoTelemetryHasOneConsoleLogger() + { + var options = new AnalyzeOptions(); + options.TargetFileSpecifiers = new List { "test.dll" }; + options.DisableTelemetry = true; + options.Quiet = true; + options.OutputFilePath = "test/path/"; + var context = new BinaryAnalyzerContext(); + + var command = new MultithreadedAnalyzeCommand(); + command.InitializeGlobalContextFromOptions(options, ref context); + + Assert.IsType(context.Logger); + + var aggregatingLogger = (Sarif.Driver.AggregatingLogger)context.Logger; + Assert.Equal(0, aggregatingLogger.Loggers.Count); + } } }