-
Notifications
You must be signed in to change notification settings - Fork 158
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
Send assembly references to Telemetry #493
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,11 +15,12 @@ namespace Microsoft.CodeAnalysis.IL.Sdk | |
{ | ||
public class CompilerDataLogger | ||
{ | ||
private const int ChunkSize = 8192; | ||
private const string CompilerEventName = "CompilerInformation"; | ||
private const string AssemblyReferencesEventName = "AssemblyReferencesInformation"; | ||
private const string CommandLineEventName = "CommandLineInformation"; | ||
private const string CompilerEventName = "CompilerInformation"; | ||
private const string SummaryEventName = "AnalysisSummary"; | ||
|
||
private readonly int ChunkSize; | ||
private readonly bool appInsightsRegistered; | ||
private readonly string sha256; | ||
private readonly string relativeFilePath; | ||
|
@@ -32,20 +33,31 @@ public class CompilerDataLogger | |
public static bool TelemetryEnabled => s_telemetryClient != null; | ||
|
||
public CompilerDataLogger(IAnalysisContext analysisContext, | ||
IEnumerable<string> targetFileSpecifiers) | ||
IEnumerable<string> targetFileSpecifiers, | ||
TelemetryConfiguration telemetryConfiguration = null, | ||
TelemetryClient telemetryClient = null, | ||
int chunkSize = 8192) | ||
{ | ||
try | ||
s_telemetryConfiguration = telemetryConfiguration; | ||
s_telemetryClient = telemetryClient; | ||
s_sessionId = TelemetryEnabled ? Guid.NewGuid().ToString() : null; | ||
ChunkSize = chunkSize; | ||
|
||
if (!TelemetryEnabled) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the code in below block is to initialize a TelemetryClient instance to be used to send telemetry data. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also, since we are creating the compilerdatalogger for each object, we dont need to keep creating an instance of the telemetry. with that, once it is initialized, it won't create again |
||
{ | ||
string appInsightsKey = RetrieveAppInsightsKey(); | ||
if (!string.IsNullOrEmpty(appInsightsKey) && Guid.TryParse(appInsightsKey, out _)) | ||
try | ||
{ | ||
Initialize(appInsightsKey); | ||
this.appInsightsRegistered = true; | ||
string appInsightsKey = RetrieveAppInsightsKey(); | ||
if (!string.IsNullOrEmpty(appInsightsKey) && Guid.TryParse(appInsightsKey, out _)) | ||
{ | ||
Initialize(appInsightsKey); | ||
this.appInsightsRegistered = true; | ||
} | ||
} | ||
catch (SecurityException) | ||
{ | ||
// User does not have access to retrieve information from environment variables. | ||
} | ||
} | ||
catch (SecurityException) | ||
{ | ||
// User does not have access to retrieve information from environment variables. | ||
} | ||
|
||
this.sha256 = analysisContext?.Hashes?.Sha256 ?? string.Empty; | ||
|
@@ -126,6 +138,7 @@ public void Write(CompilerData compilerData) | |
if (TelemetryEnabled) | ||
{ | ||
string commandLineId = string.Empty; | ||
string assemblyReferencesId = string.Empty; | ||
var properties = new Dictionary<string, string> | ||
{ | ||
{ "target", this.relativeFilePath }, | ||
|
@@ -151,11 +164,23 @@ public void Write(CompilerData compilerData) | |
properties.Add("commandLineId", commandLineId); | ||
} | ||
|
||
if (!string.IsNullOrWhiteSpace(compilerData.AssemblyReferences)) | ||
{ | ||
assemblyReferencesId = Guid.NewGuid().ToString(); | ||
properties.Add("assemblyReferencesId", assemblyReferencesId); | ||
} | ||
|
||
s_telemetryClient.TrackEvent(CompilerEventName, properties: properties); | ||
|
||
// send big size content in chunked pieces | ||
if (!string.IsNullOrWhiteSpace(commandLineId)) | ||
{ | ||
SendChunkedCommandLine(commandLineId, compilerData.CommandLine); | ||
SendChunkedContent(CommandLineEventName, commandLineId, "commandLine", compilerData.CommandLine); | ||
} | ||
|
||
if (!string.IsNullOrWhiteSpace(assemblyReferencesId)) | ||
{ | ||
SendChunkedContent(AssemblyReferencesEventName, assemblyReferencesId, "assemblyReferences", compilerData.AssemblyReferences); | ||
} | ||
} | ||
else | ||
|
@@ -239,21 +264,21 @@ public static void Summarize(AnalysisSummary summary) | |
} | ||
} | ||
|
||
private void SendChunkedCommandLine(string commandLineId, string commandLine) | ||
private void SendChunkedContent(string eventName, string contentId, string contentName, string content) | ||
{ | ||
int j = 1; | ||
int size = (int)Math.Ceiling(1.0 * commandLine.Length / ChunkSize); | ||
for (int i = 0; i < commandLine.Length; i += ChunkSize) | ||
int size = (int)Math.Ceiling(1.0 * content.Length / ChunkSize); | ||
for (int i = 0; i < content.Length; i += ChunkSize) | ||
{ | ||
string tempCommandLine = commandLine.Substring(i, Math.Min(ChunkSize, commandLine.Length - i)); | ||
string chunckedContent = content.Substring(i, Math.Min(ChunkSize, content.Length - i)); | ||
|
||
s_telemetryClient.TrackEvent(CommandLineEventName, properties: new Dictionary<string, string> | ||
s_telemetryClient.TrackEvent(eventName, properties: new Dictionary<string, string> | ||
{ | ||
{ "sessionId", s_sessionId }, | ||
{ "commandLineId", commandLineId }, | ||
{ $"{contentName}Id", contentId }, | ||
{ "orderNumber", j.ToString() }, | ||
{ "totalNumber", size.ToString() }, | ||
{ "chunkedCommandLine", tempCommandLine }, | ||
{ $"chunked{contentName}", chunckedContent }, | ||
}); | ||
j++; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
// 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.Channel; | ||
using Microsoft.ApplicationInsights.Extensibility; | ||
using Microsoft.CodeAnalysis.IL.Sdk; | ||
|
||
using Xunit; | ||
|
||
namespace Microsoft.CodeAnalysis.BinSkim.Rules | ||
{ | ||
public class CompilerDataLoggerUnitTests | ||
{ | ||
private TelemetryConfiguration telemetryConfiguration; | ||
private TelemetryClient telemetryClient; | ||
private List<ITelemetry> sendItems; | ||
|
||
private void TestSetup() | ||
{ | ||
if (this.telemetryConfiguration == null && this.telemetryClient == null) | ||
{ | ||
this.telemetryConfiguration = new TelemetryConfiguration(); | ||
this.sendItems = new List<ITelemetry>(); | ||
this.telemetryConfiguration.TelemetryChannel = new StubTelemetryChannel { OnSend = item => this.sendItems.Add(item) }; | ||
this.telemetryConfiguration.InstrumentationKey = Guid.NewGuid().ToString(); | ||
this.telemetryConfiguration.TelemetryInitializers.Add(new OperationCorrelationTelemetryInitializer()); | ||
this.telemetryClient = new TelemetryClient(this.telemetryConfiguration); | ||
} | ||
} | ||
|
||
[Fact] | ||
public void CompilerDataLogger_Write_ShouldSendAssemblyReferencesInChunks() | ||
{ | ||
this.TestSetup(); | ||
|
||
BinaryAnalyzerContext context = new BinaryAnalyzerContext { }; | ||
string[] targetFileSpecifier = new[] { @"E:\applications\Tool\*.exe" }; | ||
int chunksize = 10; | ||
string assemblies = "Microsoft.DiaSymReader (1.3.0);Newtonsoft.Json (13.0.1)"; | ||
int chunkNumber = (assemblies.Length + chunksize - 1) / chunksize; | ||
|
||
CompilerDataLogger logger = new CompilerDataLogger(context, targetFileSpecifier, this.telemetryConfiguration, this.telemetryClient, chunksize); | ||
logger.Write(new CompilerData { CompilerName = ".NET Compiler", AssemblyReferences = assemblies }); | ||
|
||
this.sendItems.Count.Should().Be(chunkNumber + 1); // first item should be CompilerInformation | ||
} | ||
|
||
[Fact] | ||
public void CompilerDataLogger_Write_ShouldNotSend_IfNoAssemblyReferences() | ||
{ | ||
this.TestSetup(); | ||
|
||
BinaryAnalyzerContext context = new BinaryAnalyzerContext { }; | ||
string[] targetFileSpecifier = new[] { @"E:\applications\Tool\*.exe" }; | ||
int chunksize = 10; | ||
string assemblies = null; | ||
|
||
CompilerDataLogger logger = new CompilerDataLogger(context, targetFileSpecifier, this.telemetryConfiguration, this.telemetryClient, chunksize); | ||
logger.Write(new CompilerData { CompilerName = ".NET Compiler", AssemblyReferences = assemblies }); | ||
|
||
this.sendItems.Count.Should().Be(1); // first item should be CompilerInformation | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
// 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 Microsoft.ApplicationInsights.Channel; | ||
|
||
namespace Microsoft.CodeAnalysis.BinSkim.Rules | ||
{ | ||
public class StubTelemetryChannel : ITelemetryChannel | ||
{ | ||
public delegate void TelemetryAction(ITelemetry telemetry); | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="StubTelemetryChannel"/> class. | ||
/// </summary> | ||
public StubTelemetryChannel() | ||
{ | ||
this.OnSend = telemetry => { }; | ||
} | ||
|
||
/// <summary> | ||
/// Gets or sets a value indicating whether this channel is in developer mode. | ||
/// </summary> | ||
public bool? DeveloperMode { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets a value indicating the channel's URI. To this URI the telemetry is expected to be sent. | ||
/// </summary> | ||
public string EndpointAddress { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets a value indicating whether to throw an error. | ||
/// </summary> | ||
public bool ThrowError { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the callback invoked by the <see cref="Send"/> method. | ||
/// </summary> | ||
public TelemetryAction OnSend { get; set; } | ||
|
||
/// <summary> | ||
/// Implements the <see cref="ITelemetryChannel.Send"/> method by invoking the <see cref="OnSend"/> callback. | ||
/// </summary> | ||
public void Send(ITelemetry item) | ||
{ | ||
if (this.ThrowError) | ||
{ | ||
throw new Exception("test error"); | ||
} | ||
|
||
this.OnSend(item); | ||
} | ||
|
||
/// <summary> | ||
/// Implements the <see cref="IDisposable.Dispose"/> method. | ||
/// </summary> | ||
public void Dispose() | ||
{ | ||
} | ||
|
||
/// <summary> | ||
/// Mock for the Flush method in <see cref="ITelemetryChannel"/>. | ||
/// </summary> | ||
public void Flush() | ||
{ | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move this to the first, so we will have ordered by length #Closed