未验证 提交 6db1b7a5 编写于 作者: J Joey Robichaud 提交者: GitHub

Merge pull request #41443 from JoeRobich/add-telemetry-ids

Add ProjectGuid and SolutionSessionId to API telemetry
...@@ -14,12 +14,16 @@ ...@@ -14,12 +14,16 @@
using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.VisualStudio.LanguageServices.Implementation.TaskList; using Microsoft.VisualStudio.LanguageServices.Implementation.TaskList;
using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.Internal.VisualStudio.Shell;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
{ {
[Export(typeof(VisualStudioProjectFactory))] [Export(typeof(VisualStudioProjectFactory))]
internal sealed class VisualStudioProjectFactory internal sealed class VisualStudioProjectFactory
{ {
private const string SolutionContextName = "Solution";
private const string SolutionSessionIdPropertyName = "SolutionSessionID";
private readonly VisualStudioWorkspaceImpl _visualStudioWorkspaceImpl; private readonly VisualStudioWorkspaceImpl _visualStudioWorkspaceImpl;
private readonly HostDiagnosticUpdateSource _hostDiagnosticUpdateSource; private readonly HostDiagnosticUpdateSource _hostDiagnosticUpdateSource;
private readonly ImmutableArray<Lazy<IDynamicFileInfoProvider, FileExtensionsMetadata>> _dynamicFileInfoProviders; private readonly ImmutableArray<Lazy<IDynamicFileInfoProvider, FileExtensionsMetadata>> _dynamicFileInfoProviders;
...@@ -78,7 +82,8 @@ public VisualStudioProject CreateAndAddToWorkspace(string projectSystemName, str ...@@ -78,7 +82,8 @@ public VisualStudioProject CreateAndAddToWorkspace(string projectSystemName, str
language: language, language: language,
filePath: creationInfo.FilePath, filePath: creationInfo.FilePath,
compilationOptions: creationInfo.CompilationOptions, compilationOptions: creationInfo.CompilationOptions,
parseOptions: creationInfo.ParseOptions); parseOptions: creationInfo.ParseOptions)
.WithTelemetryId(creationInfo.ProjectGuid);
// If we don't have any projects and this is our first project being added, then we'll create a new SolutionId // If we don't have any projects and this is our first project being added, then we'll create a new SolutionId
if (w.CurrentSolution.ProjectIds.Count == 0) if (w.CurrentSolution.ProjectIds.Count == 0)
...@@ -95,13 +100,16 @@ public VisualStudioProject CreateAndAddToWorkspace(string projectSystemName, str ...@@ -95,13 +100,16 @@ public VisualStudioProject CreateAndAddToWorkspace(string projectSystemName, str
} }
} }
var solutionSessionId = GetSolutionSessionId();
w.OnSolutionAdded( w.OnSolutionAdded(
SolutionInfo.Create( SolutionInfo.Create(
SolutionId.CreateNewId(solutionFilePath), SolutionId.CreateNewId(solutionFilePath),
VersionStamp.Create(), VersionStamp.Create(),
solutionFilePath, solutionFilePath,
projects: new[] { projectInfo }, projects: new[] { projectInfo },
analyzerReferences: w.CurrentSolution.AnalyzerReferences)); analyzerReferences: w.CurrentSolution.AnalyzerReferences)
.WithTelemetryId(solutionSessionId));
} }
else else
{ {
...@@ -112,6 +120,24 @@ public VisualStudioProject CreateAndAddToWorkspace(string projectSystemName, str ...@@ -112,6 +120,24 @@ public VisualStudioProject CreateAndAddToWorkspace(string projectSystemName, str
}); });
return project; return project;
static Guid GetSolutionSessionId()
{
try
{
var solutionContext = TelemetryHelper.DataModelTelemetrySession.GetContext(SolutionContextName);
var sessionIdProperty = solutionContext is object
? (string)solutionContext.SharedProperties[SolutionSessionIdPropertyName]
: "";
_ = Guid.TryParse(sessionIdProperty, out var solutionSessionId);
return solutionSessionId;
}
catch (TypeInitializationException)
{
// The TelemetryHelper cannot be constructed during unittests.
return default;
}
}
} }
} }
} }
...@@ -40,7 +40,7 @@ public async Task<(SolutionInfo, SerializableOptionSet)> CreateSolutionInfoAndOp ...@@ -40,7 +40,7 @@ public async Task<(SolutionInfo, SerializableOptionSet)> CreateSolutionInfoAndOp
var analyzerReferences = await CreateCollectionAsync<AnalyzerReference>(solutionChecksums.AnalyzerReferences, cancellationToken).ConfigureAwait(false); var analyzerReferences = await CreateCollectionAsync<AnalyzerReference>(solutionChecksums.AnalyzerReferences, cancellationToken).ConfigureAwait(false);
var info = SolutionInfo.Create(solutionAttributes.Id, solutionAttributes.Version, solutionAttributes.FilePath, projects, analyzerReferences); var info = SolutionInfo.Create(solutionAttributes.Id, solutionAttributes.Version, solutionAttributes.FilePath, projects, analyzerReferences).WithTelemetryId(solutionAttributes.TelemetryId);
var options = await GetAssetAsync<SerializableOptionSet>(solutionChecksums.Options, cancellationToken).ConfigureAwait(false); var options = await GetAssetAsync<SerializableOptionSet>(solutionChecksums.Options, cancellationToken).ConfigureAwait(false);
return (info, options); return (info, options);
} }
...@@ -91,7 +91,8 @@ public async Task<ProjectInfo> CreateProjectInfoAsync(Checksum projectChecksum, ...@@ -91,7 +91,8 @@ public async Task<ProjectInfo> CreateProjectInfoAsync(Checksum projectChecksum,
.WithHasAllInformation(projectInfo.HasAllInformation) .WithHasAllInformation(projectInfo.HasAllInformation)
.WithRunAnalyzers(projectInfo.RunAnalyzers) .WithRunAnalyzers(projectInfo.RunAnalyzers)
.WithDefaultNamespace(projectInfo.DefaultNamespace) .WithDefaultNamespace(projectInfo.DefaultNamespace)
.WithAnalyzerConfigDocuments(analyzerConfigDocumentInfos); .WithAnalyzerConfigDocuments(analyzerConfigDocumentInfos)
.WithTelemetryId(projectInfo.TelemetryId);
} }
public async Task<DocumentInfo> CreateDocumentInfoAsync(Checksum documentChecksum, CancellationToken cancellationToken) public async Task<DocumentInfo> CreateDocumentInfoAsync(Checksum documentChecksum, CancellationToken cancellationToken)
......
...@@ -69,13 +69,13 @@ public sealed class ProjectInfo ...@@ -69,13 +69,13 @@ public sealed class ProjectInfo
/// <summary> /// <summary>
/// The default namespace of the project ("" if not defined, which means global namespace), /// The default namespace of the project ("" if not defined, which means global namespace),
/// or null if it is unknown or not applicable. /// or null if it is unknown or not applicable.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Right now VB doesn't have the concept of "default namespace", but we conjure one in workspace /// Right now VB doesn't have the concept of "default namespace", but we conjure one in workspace
/// by assigning the value of the project's root namespace to it. So various features can choose to /// by assigning the value of the project's root namespace to it. So various features can choose to
/// use it for their own purpose. /// use it for their own purpose.
/// In the future, we might consider officially exposing "default namespace" for VB project /// In the future, we might consider officially exposing "default namespace" for VB project
/// (e.g. through a "defaultnamespace" msbuild property) /// (e.g. through a "defaultnamespace" msbuild property)
/// </remarks> /// </remarks>
internal string? DefaultNamespace => Attributes.DefaultNamespace; internal string? DefaultNamespace => Attributes.DefaultNamespace;
...@@ -231,7 +231,8 @@ public sealed class ProjectInfo ...@@ -231,7 +231,8 @@ public sealed class ProjectInfo
defaultNamespace: null, defaultNamespace: null,
isSubmission, isSubmission,
hasAllInformation: true, hasAllInformation: true,
runAnalyzers: true), runAnalyzers: true,
telemetryId: default),
compilationOptions, compilationOptions,
parseOptions, parseOptions,
PublicContract.ToBoxedImmutableArrayWithDistinctNonNullItems(documents, nameof(documents)), PublicContract.ToBoxedImmutableArrayWithDistinctNonNullItems(documents, nameof(documents)),
...@@ -347,6 +348,11 @@ public ProjectInfo WithMetadataReferences(IEnumerable<MetadataReference>? metada ...@@ -347,6 +348,11 @@ public ProjectInfo WithMetadataReferences(IEnumerable<MetadataReference>? metada
public ProjectInfo WithAnalyzerReferences(IEnumerable<AnalyzerReference>? analyzerReferences) public ProjectInfo WithAnalyzerReferences(IEnumerable<AnalyzerReference>? analyzerReferences)
=> With(analyzerReferences: PublicContract.ToBoxedImmutableArrayWithDistinctNonNullItems(analyzerReferences, nameof(analyzerReferences))); => With(analyzerReferences: PublicContract.ToBoxedImmutableArrayWithDistinctNonNullItems(analyzerReferences, nameof(analyzerReferences)));
internal ProjectInfo WithTelemetryId(Guid telemetryId)
{
return With(attributes: Attributes.With(telemetryId: telemetryId));
}
internal string GetDebuggerDisplay() internal string GetDebuggerDisplay()
=> nameof(ProjectInfo) + " " + Name + (!string.IsNullOrWhiteSpace(FilePath) ? " " + FilePath : ""); => nameof(ProjectInfo) + " " + Name + (!string.IsNullOrWhiteSpace(FilePath) ? " " + FilePath : "");
...@@ -425,6 +431,11 @@ internal sealed class ProjectAttributes : IChecksummedObject, IObjectWritable ...@@ -425,6 +431,11 @@ internal sealed class ProjectAttributes : IChecksummedObject, IObjectWritable
/// </summary> /// </summary>
public bool RunAnalyzers { get; } public bool RunAnalyzers { get; }
/// <summary>
/// The id report during telemetry events.
/// </summary>
public Guid TelemetryId { get; }
public ProjectAttributes( public ProjectAttributes(
ProjectId id, ProjectId id,
VersionStamp version, VersionStamp version,
...@@ -438,7 +449,8 @@ internal sealed class ProjectAttributes : IChecksummedObject, IObjectWritable ...@@ -438,7 +449,8 @@ internal sealed class ProjectAttributes : IChecksummedObject, IObjectWritable
string? defaultNamespace, string? defaultNamespace,
bool isSubmission, bool isSubmission,
bool hasAllInformation, bool hasAllInformation,
bool runAnalyzers) bool runAnalyzers,
Guid telemetryId)
{ {
Id = id; Id = id;
Name = name; Name = name;
...@@ -454,6 +466,7 @@ internal sealed class ProjectAttributes : IChecksummedObject, IObjectWritable ...@@ -454,6 +466,7 @@ internal sealed class ProjectAttributes : IChecksummedObject, IObjectWritable
IsSubmission = isSubmission; IsSubmission = isSubmission;
HasAllInformation = hasAllInformation; HasAllInformation = hasAllInformation;
RunAnalyzers = runAnalyzers; RunAnalyzers = runAnalyzers;
TelemetryId = telemetryId;
} }
public ProjectAttributes With( public ProjectAttributes With(
...@@ -468,7 +481,8 @@ internal sealed class ProjectAttributes : IChecksummedObject, IObjectWritable ...@@ -468,7 +481,8 @@ internal sealed class ProjectAttributes : IChecksummedObject, IObjectWritable
Optional<string?> defaultNamespace = default, Optional<string?> defaultNamespace = default,
Optional<bool> isSubmission = default, Optional<bool> isSubmission = default,
Optional<bool> hasAllInformation = default, Optional<bool> hasAllInformation = default,
Optional<bool> runAnalyzers = default) Optional<bool> runAnalyzers = default,
Optional<Guid> telemetryId = default)
{ {
var newVersion = version ?? Version; var newVersion = version ?? Version;
var newName = name ?? Name; var newName = name ?? Name;
...@@ -482,6 +496,7 @@ internal sealed class ProjectAttributes : IChecksummedObject, IObjectWritable ...@@ -482,6 +496,7 @@ internal sealed class ProjectAttributes : IChecksummedObject, IObjectWritable
var newIsSubmission = isSubmission.HasValue ? isSubmission.Value : IsSubmission; var newIsSubmission = isSubmission.HasValue ? isSubmission.Value : IsSubmission;
var newHasAllInformation = hasAllInformation.HasValue ? hasAllInformation.Value : HasAllInformation; var newHasAllInformation = hasAllInformation.HasValue ? hasAllInformation.Value : HasAllInformation;
var newRunAnalyzers = runAnalyzers.HasValue ? runAnalyzers.Value : RunAnalyzers; var newRunAnalyzers = runAnalyzers.HasValue ? runAnalyzers.Value : RunAnalyzers;
var newTelemetryId = telemetryId.HasValue ? telemetryId.Value : TelemetryId;
if (newVersion == Version && if (newVersion == Version &&
newName == Name && newName == Name &&
...@@ -494,7 +509,8 @@ internal sealed class ProjectAttributes : IChecksummedObject, IObjectWritable ...@@ -494,7 +509,8 @@ internal sealed class ProjectAttributes : IChecksummedObject, IObjectWritable
newDefaultNamespace == DefaultNamespace && newDefaultNamespace == DefaultNamespace &&
newIsSubmission == IsSubmission && newIsSubmission == IsSubmission &&
newHasAllInformation == HasAllInformation && newHasAllInformation == HasAllInformation &&
newRunAnalyzers == RunAnalyzers) newRunAnalyzers == RunAnalyzers &&
newTelemetryId == TelemetryId)
{ {
return this; return this;
} }
...@@ -512,7 +528,8 @@ internal sealed class ProjectAttributes : IChecksummedObject, IObjectWritable ...@@ -512,7 +528,8 @@ internal sealed class ProjectAttributes : IChecksummedObject, IObjectWritable
newDefaultNamespace, newDefaultNamespace,
newIsSubmission, newIsSubmission,
newHasAllInformation, newHasAllInformation,
newRunAnalyzers); newRunAnalyzers,
newTelemetryId);
} }
bool IObjectWritable.ShouldReuseInSerialization => true; bool IObjectWritable.ShouldReuseInSerialization => true;
...@@ -535,6 +552,7 @@ public void WriteTo(ObjectWriter writer) ...@@ -535,6 +552,7 @@ public void WriteTo(ObjectWriter writer)
writer.WriteBoolean(IsSubmission); writer.WriteBoolean(IsSubmission);
writer.WriteBoolean(HasAllInformation); writer.WriteBoolean(HasAllInformation);
writer.WriteBoolean(RunAnalyzers); writer.WriteBoolean(RunAnalyzers);
writer.WriteGuid(TelemetryId);
// TODO: once CompilationOptions, ParseOptions, ProjectReference, MetadataReference, AnalyzerReference supports // TODO: once CompilationOptions, ParseOptions, ProjectReference, MetadataReference, AnalyzerReference supports
// serialization, we should include those here as well. // serialization, we should include those here as well.
...@@ -556,6 +574,7 @@ public static ProjectAttributes ReadFrom(ObjectReader reader) ...@@ -556,6 +574,7 @@ public static ProjectAttributes ReadFrom(ObjectReader reader)
var isSubmission = reader.ReadBoolean(); var isSubmission = reader.ReadBoolean();
var hasAllInformation = reader.ReadBoolean(); var hasAllInformation = reader.ReadBoolean();
var runAnalyzers = reader.ReadBoolean(); var runAnalyzers = reader.ReadBoolean();
var telemetryId = reader.ReadGuid();
return new ProjectAttributes( return new ProjectAttributes(
projectId, projectId,
...@@ -570,7 +589,8 @@ public static ProjectAttributes ReadFrom(ObjectReader reader) ...@@ -570,7 +589,8 @@ public static ProjectAttributes ReadFrom(ObjectReader reader)
defaultNamespace, defaultNamespace,
isSubmission, isSubmission,
hasAllInformation, hasAllInformation,
runAnalyzers); runAnalyzers,
telemetryId);
} }
Checksum IChecksummedObject.Checksum Checksum IChecksummedObject.Checksum
......
...@@ -81,7 +81,8 @@ private SolutionInfo(SolutionAttributes attributes, IReadOnlyList<ProjectInfo> p ...@@ -81,7 +81,8 @@ private SolutionInfo(SolutionAttributes attributes, IReadOnlyList<ProjectInfo> p
new SolutionAttributes( new SolutionAttributes(
id ?? throw new ArgumentNullException(nameof(id)), id ?? throw new ArgumentNullException(nameof(id)),
version, version,
filePath), filePath,
telemetryId: default),
PublicContract.ToBoxedImmutableArrayWithDistinctNonNullItems(projects, nameof(projects)), PublicContract.ToBoxedImmutableArrayWithDistinctNonNullItems(projects, nameof(projects)),
PublicContract.ToBoxedImmutableArrayWithDistinctNonNullItems(analyzerReferences, nameof(analyzerReferences))); PublicContract.ToBoxedImmutableArrayWithDistinctNonNullItems(analyzerReferences, nameof(analyzerReferences)));
} }
...@@ -89,6 +90,9 @@ private SolutionInfo(SolutionAttributes attributes, IReadOnlyList<ProjectInfo> p ...@@ -89,6 +90,9 @@ private SolutionInfo(SolutionAttributes attributes, IReadOnlyList<ProjectInfo> p
internal ImmutableHashSet<string> GetProjectLanguages() internal ImmutableHashSet<string> GetProjectLanguages()
=> Projects.Select(p => p.Language).ToImmutableHashSet(); => Projects.Select(p => p.Language).ToImmutableHashSet();
internal SolutionInfo WithTelemetryId(Guid telemetryId)
=> new SolutionInfo(Attributes.With(telemetryId: telemetryId), Projects, AnalyzerReferences);
/// <summary> /// <summary>
/// type that contains information regarding this solution itself but /// type that contains information regarding this solution itself but
/// no tree information such as project info /// no tree information such as project info
...@@ -112,15 +116,37 @@ internal sealed class SolutionAttributes : IChecksummedObject, IObjectWritable ...@@ -112,15 +116,37 @@ internal sealed class SolutionAttributes : IChecksummedObject, IObjectWritable
/// </summary> /// </summary>
public string? FilePath { get; } public string? FilePath { get; }
public SolutionAttributes(SolutionId id, VersionStamp version, string? filePath) /// <summary>
/// The id report during telemetry events.
/// </summary>
public Guid TelemetryId { get; }
public SolutionAttributes(SolutionId id, VersionStamp version, string? filePath, Guid telemetryId)
{ {
Id = id; Id = id;
Version = version; Version = version;
FilePath = filePath; FilePath = filePath;
TelemetryId = telemetryId;
} }
public SolutionAttributes WithVersion(VersionStamp versionStamp) public SolutionAttributes With(
=> new SolutionAttributes(Id, versionStamp, FilePath); VersionStamp? version = null,
Optional<string?> filePath = default,
Optional<Guid> telemetryId = default)
{
var newVersion = version ?? Version;
var newFilePath = filePath.HasValue ? filePath.Value : FilePath;
var newTelemetryId = telemetryId.HasValue ? telemetryId.Value : TelemetryId;
if (newVersion == Version &&
newFilePath == FilePath &&
newTelemetryId == TelemetryId)
{
return this;
}
return new SolutionAttributes(Id, newVersion, newFilePath, newTelemetryId);
}
bool IObjectWritable.ShouldReuseInSerialization => true; bool IObjectWritable.ShouldReuseInSerialization => true;
...@@ -133,6 +159,7 @@ public void WriteTo(ObjectWriter writer) ...@@ -133,6 +159,7 @@ public void WriteTo(ObjectWriter writer)
// info.Version.WriteTo(writer); // info.Version.WriteTo(writer);
writer.WriteString(FilePath); writer.WriteString(FilePath);
writer.WriteGuid(TelemetryId);
} }
public static SolutionAttributes ReadFrom(ObjectReader reader) public static SolutionAttributes ReadFrom(ObjectReader reader)
...@@ -140,8 +167,9 @@ public static SolutionAttributes ReadFrom(ObjectReader reader) ...@@ -140,8 +167,9 @@ public static SolutionAttributes ReadFrom(ObjectReader reader)
var solutionId = SolutionId.ReadFrom(reader); var solutionId = SolutionId.ReadFrom(reader);
// var version = VersionStamp.ReadFrom(reader); // var version = VersionStamp.ReadFrom(reader);
var filePath = reader.ReadString(); var filePath = reader.ReadString();
var telemetryId = reader.ReadGuid();
return new SolutionAttributes(solutionId, VersionStamp.Create(), filePath); return new SolutionAttributes(solutionId, VersionStamp.Create(), filePath, telemetryId);
} }
Checksum IChecksummedObject.Checksum Checksum IChecksummedObject.Checksum
......
...@@ -26,9 +26,9 @@ ...@@ -26,9 +26,9 @@
namespace Microsoft.CodeAnalysis namespace Microsoft.CodeAnalysis
{ {
/// <summary> /// <summary>
/// Represents a set of projects and their source code documents. /// Represents a set of projects and their source code documents.
/// ///
/// this is a green node of Solution like ProjectState/DocumentState are for /// this is a green node of Solution like ProjectState/DocumentState are for
/// Project and Document. /// Project and Document.
/// </summary> /// </summary>
internal partial class SolutionState internal partial class SolutionState
...@@ -148,13 +148,13 @@ public SolutionState WithNewWorkspace(Workspace workspace, int workspaceVersion) ...@@ -148,13 +148,13 @@ public SolutionState WithNewWorkspace(Workspace workspace, int workspaceVersion)
/// <summary> /// <summary>
/// branch id of this solution /// branch id of this solution
/// ///
/// currently, it only supports one level of branching. there is a primary branch of a workspace and all other /// currently, it only supports one level of branching. there is a primary branch of a workspace and all other
/// branches that are branched from the primary branch. /// branches that are branched from the primary branch.
/// ///
/// one still can create multiple forked solutions from an already branched solution, but versions among those /// one still can create multiple forked solutions from an already branched solution, but versions among those
/// can't be reliably used and compared. /// can't be reliably used and compared.
/// ///
/// version only has a meaning between primary solution and branched one or between solutions from same branch. /// version only has a meaning between primary solution and branched one or between solutions from same branch.
/// </summary> /// </summary>
public BranchId BranchId => _branchId; public BranchId BranchId => _branchId;
...@@ -278,7 +278,7 @@ private void CheckInvariants() ...@@ -278,7 +278,7 @@ private void CheckInvariants()
private BranchId GetBranchId() private BranchId GetBranchId()
{ {
// currently we only support one level branching. // currently we only support one level branching.
// my reasonings are // my reasonings are
// 1. it seems there is no-one who needs sub branches. // 1. it seems there is no-one who needs sub branches.
// 2. this lets us to branch without explicit branch API // 2. this lets us to branch without explicit branch API
...@@ -440,7 +440,7 @@ private CompilationTracker GetCompilationTracker(ProjectId projectId) ...@@ -440,7 +440,7 @@ private CompilationTracker GetCompilationTracker(ProjectId projectId)
private SolutionState AddProject(ProjectId projectId, ProjectState projectState) private SolutionState AddProject(ProjectId projectId, ProjectState projectState)
{ {
// changed project list so, increment version. // changed project list so, increment version.
var newSolutionAttributes = _solutionAttributes.WithVersion(Version.GetNewerVersion()); var newSolutionAttributes = _solutionAttributes.With(version: Version.GetNewerVersion());
var newProjectIds = ProjectIds.ToImmutableArray().Add(projectId); var newProjectIds = ProjectIds.ToImmutableArray().Add(projectId);
var newStateMap = _projectIdToProjectStateMap.Add(projectId, projectState); var newStateMap = _projectIdToProjectStateMap.Add(projectId, projectState);
...@@ -552,7 +552,7 @@ public SolutionState RemoveProject(ProjectId projectId) ...@@ -552,7 +552,7 @@ public SolutionState RemoveProject(ProjectId projectId)
CheckContainsProject(projectId); CheckContainsProject(projectId);
// changed project list so, increment version. // changed project list so, increment version.
var newSolutionAttributes = _solutionAttributes.WithVersion(this.Version.GetNewerVersion()); var newSolutionAttributes = _solutionAttributes.With(version: this.Version.GetNewerVersion());
var newProjectIds = ProjectIds.ToImmutableArray().Remove(projectId); var newProjectIds = ProjectIds.ToImmutableArray().Remove(projectId);
var newStateMap = _projectIdToProjectStateMap.Remove(projectId); var newStateMap = _projectIdToProjectStateMap.Remove(projectId);
...@@ -773,7 +773,7 @@ public SolutionState WithProjectParseOptions(ProjectId projectId, ParseOptions o ...@@ -773,7 +773,7 @@ public SolutionState WithProjectParseOptions(ProjectId projectId, ParseOptions o
/// <summary> /// <summary>
/// Update a new solution instance with a fork of the specified project. /// Update a new solution instance with a fork of the specified project.
/// ///
/// TODO: https://github.com/dotnet/roslyn/issues/42448 /// TODO: https://github.com/dotnet/roslyn/issues/42448
/// this is a temporary workaround until editorconfig becomes real part of roslyn solution snapshot. /// this is a temporary workaround until editorconfig becomes real part of roslyn solution snapshot.
/// until then, this will explicitly fork current solution snapshot /// until then, this will explicitly fork current solution snapshot
...@@ -862,9 +862,9 @@ public SolutionState RemoveProjectReference(ProjectId projectId, ProjectReferenc ...@@ -862,9 +862,9 @@ public SolutionState RemoveProjectReference(ProjectId projectId, ProjectReferenc
!_projectIdToProjectStateMap.ContainsKey(projectReference.ProjectId)) !_projectIdToProjectStateMap.ContainsKey(projectReference.ProjectId))
{ {
// Two cases: // Two cases:
// 1) The project contained multiple non-equivalent references to the project, // 1) The project contained multiple non-equivalent references to the project,
// and not all of them were removed. The dependency graph doesn't change. // and not all of them were removed. The dependency graph doesn't change.
// Note that there might be two references to the same project, one with // Note that there might be two references to the same project, one with
// extern alias and the other without. These are not considered duplicates. // extern alias and the other without. These are not considered duplicates.
// 2) The referenced project is not part of the solution and hence not included // 2) The referenced project is not part of the solution and hence not included
// in the dependency graph. // in the dependency graph.
...@@ -1031,7 +1031,7 @@ public SolutionState WithProjectAnalyzerReferences(ProjectId projectId, IEnumera ...@@ -1031,7 +1031,7 @@ public SolutionState WithProjectAnalyzerReferences(ProjectId projectId, IEnumera
} }
/// <summary> /// <summary>
/// Create a new solution instance with the corresponding projects updated to include new /// Create a new solution instance with the corresponding projects updated to include new
/// documents defined by the document info. /// documents defined by the document info.
/// </summary> /// </summary>
public SolutionState AddDocuments(ImmutableArray<DocumentInfo> documentInfos) public SolutionState AddDocuments(ImmutableArray<DocumentInfo> documentInfos)
...@@ -1549,9 +1549,9 @@ bool CanReuse(ProjectId id) ...@@ -1549,9 +1549,9 @@ bool CanReuse(ProjectId id)
/// <summary> /// <summary>
/// Gets a copy of the solution isolated from the original so that they do not share computed state. /// Gets a copy of the solution isolated from the original so that they do not share computed state.
/// ///
/// Use isolated solutions when doing operations that are likely to access a lot of text, /// Use isolated solutions when doing operations that are likely to access a lot of text,
/// syntax trees or compilations that are unlikely to be needed again after the operation is done. /// syntax trees or compilations that are unlikely to be needed again after the operation is done.
/// When the isolated solution is reclaimed so will the computed state. /// When the isolated solution is reclaimed so will the computed state.
/// </summary> /// </summary>
public SolutionState GetIsolatedSolution() public SolutionState GetIsolatedSolution()
...@@ -1618,9 +1618,9 @@ private NonReentrantLock StateLock ...@@ -1618,9 +1618,9 @@ private NonReentrantLock StateLock
/// <summary> /// <summary>
/// Creates a branch of the solution that has its compilations frozen in whatever state they are in at the time, assuming a background compiler is /// Creates a branch of the solution that has its compilations frozen in whatever state they are in at the time, assuming a background compiler is
/// busy building this compilations. /// busy building this compilations.
/// ///
/// A compilation for the project containing the specified document id will be guaranteed to exist with at least the syntax tree for the document. /// A compilation for the project containing the specified document id will be guaranteed to exist with at least the syntax tree for the document.
/// ///
/// This not intended to be the public API, use Document.WithFrozenPartialSemantics() instead. /// This not intended to be the public API, use Document.WithFrozenPartialSemantics() instead.
/// </summary> /// </summary>
public SolutionState WithFrozenPartialCompilationIncludingSpecificDocument(DocumentId documentId, CancellationToken cancellationToken) public SolutionState WithFrozenPartialCompilationIncludingSpecificDocument(DocumentId documentId, CancellationToken cancellationToken)
...@@ -1749,7 +1749,7 @@ public bool TryGetCompilation(ProjectId projectId, [NotNullWhen(returnValue: tru ...@@ -1749,7 +1749,7 @@ public bool TryGetCompilation(ProjectId projectId, [NotNullWhen(returnValue: tru
/// </summary> /// </summary>
public Task<bool> HasSuccessfullyLoadedAsync(ProjectState project, CancellationToken cancellationToken) public Task<bool> HasSuccessfullyLoadedAsync(ProjectState project, CancellationToken cancellationToken)
{ {
// return HasAllInformation when compilation is not supported. // return HasAllInformation when compilation is not supported.
// regardless whether project support compilation or not, if projectInfo is not complete, we can't guarantee its reference completeness // regardless whether project support compilation or not, if projectInfo is not complete, we can't guarantee its reference completeness
return project.SupportsCompilation return project.SupportsCompilation
? this.GetCompilationTracker(project.Id).HasSuccessfullyLoadedAsync(this, cancellationToken) ? this.GetCompilationTracker(project.Id).HasSuccessfullyLoadedAsync(this, cancellationToken)
...@@ -1813,7 +1813,7 @@ public Task<MetadataReference> GetMetadataReferenceAsync(ProjectReference projec ...@@ -1813,7 +1813,7 @@ public Task<MetadataReference> GetMetadataReferenceAsync(ProjectReference projec
ProjectState fromProject) ProjectState fromProject)
{ {
// Try to get the compilation state for this project. If it doesn't exist, don't do any // Try to get the compilation state for this project. If it doesn't exist, don't do any
// more work. // more work.
if (!_projectIdToTrackerMap.TryGetValue(projectReference.ProjectId, out var state)) if (!_projectIdToTrackerMap.TryGetValue(projectReference.ProjectId, out var state))
{ {
return null; return null;
......
...@@ -38,7 +38,9 @@ private sealed class Analyzer : IIncrementalAnalyzer ...@@ -38,7 +38,9 @@ private sealed class Analyzer : IIncrementalAnalyzer
private const int Max = 2000; private const int Max = 2000;
private const string EventName = "vs/compilers/api"; private const string EventName = "vs/compilers/api";
private const string PropertyName = "vs.compilers.api.pii"; private const string ApiPropertyName = "vs.compilers.api.pii";
private const string ProjectIdPropertyName = "vs.solution.project.projectid";
private const string SessionIdPropertyName = "vs.solution.solutionsessionid";
private readonly HashSet<ProjectId> _reported = new HashSet<ProjectId>(); private readonly HashSet<ProjectId> _reported = new HashSet<ProjectId>();
...@@ -124,9 +126,14 @@ public async Task AnalyzeProjectAsync(Project project, bool semanticsChanged, In ...@@ -124,9 +126,14 @@ public async Task AnalyzeProjectAsync(Project project, bool semanticsChanged, In
{ {
if (_reported.Add(project.Id)) if (_reported.Add(project.Id))
{ {
var solutionSessionId = project.Solution.State.SolutionAttributes.TelemetryId.ToString("B");
var projectGuid = project.State.ProjectInfo.Attributes.TelemetryId.ToString("B");
// use telemetry API directly rather than Logger abstraction for PII data // use telemetry API directly rather than Logger abstraction for PII data
var telemetryEvent = new TelemetryEvent(EventName); var telemetryEvent = new TelemetryEvent(EventName);
telemetryEvent.Properties[PropertyName] = new TelemetryComplexProperty(apiPerAssembly); telemetryEvent.Properties[ApiPropertyName] = new TelemetryComplexProperty(apiPerAssembly);
telemetryEvent.Properties[SessionIdPropertyName] = new TelemetryPiiProperty(solutionSessionId);
telemetryEvent.Properties[ProjectIdPropertyName] = new TelemetryPiiProperty(projectGuid);
try try
{ {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册