Skip to content

Commit 45431f1

Browse files
authored
Add fallback logic for rust CLI detector and additional telemetry (#990)
* Add fallback logic for rust CLI detector and additional telemetry tracing * Fix build tests * Add fallback tests * resolve comments
1 parent 88939b5 commit 45431f1

File tree

8 files changed

+843
-51
lines changed

8 files changed

+843
-51
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
namespace Microsoft.ComponentDetection.Common.Telemetry.Records;
2+
3+
public class RustGraphTelemetryRecord : BaseDetectionTelemetryRecord
4+
{
5+
public override string RecordName => "RustGraph";
6+
7+
public string CargoTomlLocation { get; set; }
8+
9+
public bool WasRustFallbackStrategyUsed { get; set; }
10+
11+
public string FallbackReason { get; set; }
12+
13+
public bool FallbackCargoLockFound { get; set; }
14+
15+
public string FallbackCargoLockLocation { get; set; }
16+
17+
public bool DidRustCliCommandFail { get; set; }
18+
19+
public string RustCliCommandError { get; set; }
20+
}

src/Microsoft.ComponentDetection.Contracts/FileComponentDetector.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ public abstract class FileComponentDetector : IComponentDetector
5757

5858
protected Dictionary<string, string> Telemetry { get; set; } = new Dictionary<string, string>();
5959

60+
/// <summary>
61+
/// List of any any additional properties as key-value pairs that we would like to capture for the detector.
62+
/// </summary>
63+
public List<(string PropertyKey, string PropertyValue)> AdditionalProperties { get; set; } = new List<(string PropertyKey, string PropertyValue)>();
64+
6065
protected IObservable<IComponentStream> ComponentStreams { get; private set; }
6166

6267
/// <inheritdoc />

src/Microsoft.ComponentDetection.Detectors/rust/RustCliDetector.cs

Lines changed: 317 additions & 36 deletions
Large diffs are not rendered by default.

src/Microsoft.ComponentDetection.Detectors/rust/RustCrateDetector.cs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ private static bool ParseDependency(string dependency, out string packageName, o
5454
version = versionMatch.Success ? versionMatch.Value : null;
5555
source = sourceMatch.Success ? sourceMatch.Value : null;
5656

57-
if (string.IsNullOrEmpty(source))
57+
if (string.IsNullOrWhiteSpace(source))
5858
{
5959
source = null;
6060
}
@@ -68,17 +68,20 @@ protected override async Task OnFileFoundAsync(ProcessRequest processRequest, ID
6868
{
6969
var singleFileComponentRecorder = processRequest.SingleFileComponentRecorder;
7070
var cargoLockFile = processRequest.ComponentStream;
71+
var reader = new StreamReader(cargoLockFile.Stream);
72+
var options = new TomlModelOptions
73+
{
74+
IgnoreMissingProperties = true,
75+
};
76+
var cargoLock = Toml.ToModel<CargoLock>(await reader.ReadToEndAsync(), options: options);
77+
this.RecordLockfileVersion(cargoLock.Version);
78+
this.ProcessCargoLock(cargoLock, singleFileComponentRecorder, cargoLockFile);
79+
}
7180

81+
private void ProcessCargoLock(CargoLock cargoLock, ISingleFileComponentRecorder singleFileComponentRecorder, IComponentStream cargoLockFile)
82+
{
7283
try
7384
{
74-
var reader = new StreamReader(cargoLockFile.Stream);
75-
var options = new TomlModelOptions
76-
{
77-
IgnoreMissingProperties = true,
78-
};
79-
var cargoLock = Toml.ToModel<CargoLock>(await reader.ReadToEndAsync(), options: options);
80-
this.RecordLockfileVersion(cargoLock.Version);
81-
8285
var seenAsDependency = new HashSet<CargoPackage>();
8386

8487
// Pass 1: Create typed components and allow lookup by name.
@@ -152,8 +155,6 @@ protected override async Task OnFileFoundAsync(ProcessRequest processRequest, ID
152155
// If something went wrong, just ignore the file
153156
this.Logger.LogError(e, "Failed to process Cargo.lock file '{CargoLockLocation}'", cargoLockFile.Location);
154157
}
155-
156-
await Task.CompletedTask;
157158
}
158159

159160
private void ProcessDependency(

src/Microsoft.ComponentDetection.Orchestrator/Experiments/ExperimentService.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ public void RecordDetectorRun(
112112
detector.Id,
113113
config.Name);
114114
}
115+
116+
if (detector is FileComponentDetector fileDetector)
117+
{
118+
experimentResults.AddAdditionalPropertiesToExperiment(fileDetector.AdditionalProperties);
119+
}
115120
}
116121
}
117122
catch (Exception e)
@@ -169,6 +174,7 @@ public async Task FinishAsync()
169174
var experimentComponents = experiment.ExperimentGroupComponents;
170175
var controlDetectors = experiment.ControlDetectors;
171176
var experimentDetectors = experiment.ExperimentalDetectors;
177+
var additionalProperties = experiment.AdditionalProperties;
172178
this.logger.LogInformation(
173179
"Experiment {Experiment} finished with {ControlCount} components in the control group and {ExperimentCount} components in the experiment group",
174180
config.Name,
@@ -185,7 +191,7 @@ public async Task FinishAsync()
185191

186192
try
187193
{
188-
var diff = new ExperimentDiff(controlComponents, experimentComponents, controlDetectors, experimentDetectors);
194+
var diff = new ExperimentDiff(controlComponents, experimentComponents, controlDetectors, experimentDetectors, additionalProperties);
189195
var tasks = this.experimentProcessors.Select(x => x.ProcessExperimentAsync(config, diff));
190196
await Task.WhenAll(tasks);
191197
}

src/Microsoft.ComponentDetection.Orchestrator/Experiments/Models/ExperimentDiff.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,18 @@ public class ExperimentDiff
1717
/// <param name="experimentGroupComponents">A set of components from the experimental group.</param>
1818
/// <param name="controlDetectors">The set of control detectors.</param>
1919
/// <param name="experimentalDetectors">The set of experimental detectors.</param>
20+
/// <param name="additionalProperties">The set of additional metrics to be captured.</param>
2021
public ExperimentDiff(
2122
IEnumerable<ExperimentComponent> controlGroupComponents,
2223
IEnumerable<ExperimentComponent> experimentGroupComponents,
2324
IEnumerable<(string DetectorId, TimeSpan DetectorRunTime)> controlDetectors = null,
24-
IEnumerable<(string DetectorId, TimeSpan DetectorRunTime)> experimentalDetectors = null)
25+
IEnumerable<(string DetectorId, TimeSpan DetectorRunTime)> experimentalDetectors = null,
26+
IEnumerable<(string PropertyKey, string PropertyValue)> additionalProperties = null)
2527
{
2628
var oldComponentDictionary = controlGroupComponents.DistinctBy(x => x.Id).ToDictionary(x => x.Id);
2729
var newComponentDictionary = experimentGroupComponents.DistinctBy(x => x.Id).ToDictionary(x => x.Id);
30+
additionalProperties ??= Array.Empty<(string PropertyKey, string PropertyValue)>();
31+
this.AdditionalProperties = additionalProperties?.Select(kv => new KeyValuePair<string, string>(kv.PropertyKey, kv.PropertyValue)).ToImmutableList();
2832

2933
this.AddedIds = newComponentDictionary.Keys.Except(oldComponentDictionary.Keys).ToImmutableList();
3034
this.RemovedIds = oldComponentDictionary.Keys.Except(newComponentDictionary.Keys).ToImmutableList();
@@ -132,6 +136,11 @@ public ExperimentDiff()
132136
/// </summary>
133137
public IReadOnlyDictionary<string, IReadOnlySet<string>> RemovedRootIds { get; init; }
134138

139+
/// <summary>
140+
/// Any additional metrics that were captured for the experiment.
141+
/// </summary>
142+
public IReadOnlyCollection<KeyValuePair<string, string>> AdditionalProperties { get; init; }
143+
135144
/// <summary>
136145
/// Stores information about a change to the development dependency status of a component.
137146
/// </summary>

src/Microsoft.ComponentDetection.Orchestrator/Experiments/Models/ExperimentResults.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ public class ExperimentResults
2323

2424
private readonly ConcurrentDictionary<string, TimeSpan> experimentalDetectors = new();
2525

26+
private readonly ConcurrentBag<(string, string)> additionalProperties = new();
27+
2628
/// <summary>
2729
/// The set of components in the control group.
2830
/// </summary>
@@ -47,6 +49,12 @@ public class ExperimentResults
4749
public IImmutableSet<(string DetectorId, TimeSpan DetectorRunTime)> ExperimentalDetectors =>
4850
this.experimentalDetectors.Select(x => (x.Key, x.Value)).ToImmutableHashSet();
4951

52+
/// <summary>
53+
/// The set of experimental detectors.
54+
/// </summary>
55+
public IImmutableSet<(string PropertyKey, string PropertyValue)> AdditionalProperties =>
56+
this.additionalProperties.ToImmutableHashSet();
57+
5058
/// <summary>
5159
/// Adds the components to the control group.
5260
/// </summary>
@@ -77,6 +85,18 @@ public void AddExperimentalDetectorTime(string experimentalDetectorId, TimeSpan
7785
public void AddComponentsToExperimentalGroup(IEnumerable<ScannedComponent> components) =>
7886
AddComponents(this.experimentGroupComponents, components);
7987

88+
/// <summary>
89+
/// Adds a custom metric to the experiment.
90+
/// </summary>
91+
/// <param name="properties">list of (key, value) tuples to be captured as additionalProperties. </param>
92+
public void AddAdditionalPropertiesToExperiment(IEnumerable<(string PropertyKey, string PropertyValue)> properties)
93+
{
94+
foreach (var (propertyKey, propertyValue) in properties)
95+
{
96+
AddAdditionalProperty(this.additionalProperties, propertyKey, propertyValue);
97+
}
98+
}
99+
80100
private static void AddComponents(ConcurrentDictionary<ExperimentComponent, byte> group, IEnumerable<ScannedComponent> components)
81101
{
82102
foreach (var experimentComponent in components.Select(x => new ExperimentComponent(x)))
@@ -89,4 +109,9 @@ private static void AddRunTime(ConcurrentDictionary<string, TimeSpan> group, str
89109
{
90110
_ = group.TryAdd(detectorId, runTime);
91111
}
112+
113+
private static void AddAdditionalProperty(ConcurrentBag<(string PropertyKey, string PropertyValue)> group, string propertyKey, string propertyValue)
114+
{
115+
group.Add((propertyKey, propertyValue));
116+
}
92117
}

0 commit comments

Comments
 (0)