Skip to content

Merge release/dev17.12 to main #10913

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

Merged
merged 12 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
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
8 changes: 4 additions & 4 deletions eng/Version.Details.xml
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,14 @@
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
<Sha>3a25a7f1cc446b60678ed25c9d829420d6321eba</Sha>
</Dependency>
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="9.0.0-beta.24453.1">
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="9.0.0-beta.24466.2">
<Uri>https://github.com/dotnet/arcade</Uri>
<Sha>dd332f2d4e21daa8b79f84251ab156af9a0b11b2</Sha>
<Sha>04b9022eba9c184a8036328af513c22e6949e8b6</Sha>
</Dependency>
<!-- Intermediate is necessary for source build. -->
<Dependency Name="Microsoft.SourceBuild.Intermediate.arcade" Version="9.0.0-beta.24453.1">
<Dependency Name="Microsoft.SourceBuild.Intermediate.arcade" Version="9.0.0-beta.24466.2">
<Uri>https://github.com/dotnet/arcade</Uri>
<Sha>dd332f2d4e21daa8b79f84251ab156af9a0b11b2</Sha>
<Sha>04b9022eba9c184a8036328af513c22e6949e8b6</Sha>
<SourceBuild RepoName="arcade" ManagedOnly="true" />
</Dependency>
<Dependency Name="Microsoft.DotNet.XliffTasks" Version="1.0.0-beta.23475.1" CoherentParentDependency="Microsoft.DotNet.Arcade.Sdk">
Expand Down
4 changes: 2 additions & 2 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@
<PropertyGroup Label="Automated">
<MicrosoftNETCoreBrowserDebugHostTransportPackageVersion>6.0.2-servicing.22064.6</MicrosoftNETCoreBrowserDebugHostTransportPackageVersion>
<MicrosoftNETCorePlatformsPackageVersion>6.0.1</MicrosoftNETCorePlatformsPackageVersion>
<MicrosoftSourceBuildIntermediatesourcebuildreferencepackagesPackageVersion>10.0.0-alpha.1.24467.1</MicrosoftSourceBuildIntermediatesourcebuildreferencepackagesPackageVersion>
<MicrosoftSourceBuildIntermediatearcadePackageVersion>9.0.0-beta.24453.1</MicrosoftSourceBuildIntermediatearcadePackageVersion>
<MicrosoftSourceBuildIntermediatesourcebuildreferencepackagesPackageVersion>9.0.0-alpha.1.24304.1</MicrosoftSourceBuildIntermediatesourcebuildreferencepackagesPackageVersion>
<MicrosoftSourceBuildIntermediatearcadePackageVersion>9.0.0-beta.24466.2</MicrosoftSourceBuildIntermediatearcadePackageVersion>
<MicrosoftDotNetXliffTasksPackageVersion>1.0.0-beta.23475.1</MicrosoftDotNetXliffTasksPackageVersion>
<MicrosoftSourceBuildIntermediatexlifftasksPackageVersion>1.0.0-beta.23475.1</MicrosoftSourceBuildIntermediatexlifftasksPackageVersion>
<MicrosoftNetCompilersToolsetPackageVersion>4.12.0-3.24466.4</MicrosoftNetCompilersToolsetPackageVersion>
Expand Down
6 changes: 3 additions & 3 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"tools": {
"dotnet": "9.0.100-preview.7.24407.12",
"dotnet": "9.0.100-rc.1.24452.12",
"runtimes": {
"dotnet": [
"2.1.30",
Expand All @@ -17,12 +17,12 @@
}
},
"sdk": {
"version": "9.0.100-preview.7.24407.12",
"version": "9.0.100-rc.1.24452.12",
"allowPrerelease": false,
"rollForward": "latestPatch"
},
"msbuild-sdks": {
"Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.24453.1",
"Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.24466.2",
"Microsoft.Build.NoTargets": "3.7.0"
}
}
2 changes: 1 addition & 1 deletion src/Analyzers/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<RollForward Condition="'$(IsTestProject)' == 'true'">LatestMajor</RollForward>
</PropertyGroup>

<ItemGroup Condition="'$(DotNetBuildFromSource)' != 'true'">
<ItemGroup Condition="'$(DotNetBuildSourceOnly)' != 'true'">
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" NoWarn="NU1608" />
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" />
<PackageReference Include="Roslyn.Diagnostics.Analyzers" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Components;
using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts;
using Microsoft.AspNetCore.Razor.LanguageServer.Hosting;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.AspNetCore.Razor.ProjectSystem;
using Microsoft.AspNetCore.Razor.Telemetry;
using Microsoft.CodeAnalysis.Razor.Diagnostics;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
Expand All @@ -26,6 +30,7 @@ internal class DocumentPullDiagnosticsEndpoint : IRazorRequestHandler<VSInternal
private readonly IClientConnection _clientConnection;
private readonly RazorTranslateDiagnosticsService _translateDiagnosticsService;
private readonly ITelemetryReporter? _telemetryReporter;
private ImmutableDictionary<ProjectKey, int> _lastReporedProjectTagHelperCount = ImmutableDictionary<ProjectKey, int>.Empty;

public DocumentPullDiagnosticsEndpoint(
LanguageServerFeatureOptions languageServerFeatureOptions,
Expand Down Expand Up @@ -77,6 +82,8 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(VSInternalDocumentDiagno

var razorDiagnostics = await GetRazorDiagnosticsAsync(documentSnapshot).ConfigureAwait(false);

await ReportRZ10012TelemetryAsync(documentContext, razorDiagnostics, cancellationToken).ConfigureAwait(false);

var (csharpDiagnostics, htmlDiagnostics) = await GetHtmlCSharpDiagnosticsAsync(documentContext, correlationId, cancellationToken).ConfigureAwait(false);

var diagnosticCount =
Expand Down Expand Up @@ -163,4 +170,59 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(VSInternalDocumentDiagno

return (delegatedResponse.CSharpDiagnostics, delegatedResponse.HtmlDiagnostics);
}

/// <summary>
/// Reports telemetry for RZ10012 "Found markup element with unexpected name" to help track down potential issues
/// with taghelpers being discovered (or lack thereof)
/// </summary>
private async ValueTask ReportRZ10012TelemetryAsync(DocumentContext documentContext, VSInternalDiagnosticReport[]? razorDiagnostics, CancellationToken cancellationToken)
{
if (razorDiagnostics is null)
{
return;
}

if (_telemetryReporter is null)
{
return;
}

var relevantDiagnosticsCount = razorDiagnostics.Sum(CountDiagnostics);
if (relevantDiagnosticsCount == 0)
{
return;
}

var tagHelpers = await documentContext.Project.GetTagHelpersAsync(cancellationToken).ConfigureAwait(false);
var tagHelperCount = tagHelpers.Count();
var shouldReport = false;

ImmutableInterlocked.AddOrUpdate(
ref _lastReporedProjectTagHelperCount,
documentContext.Project.Key,
(k) =>
{
shouldReport = true;
return tagHelperCount;
},
(k, currentValue) =>
{
shouldReport = currentValue != tagHelperCount;
return tagHelperCount;
});

if (shouldReport)
{
_telemetryReporter.ReportEvent(
"RZ10012",
Severity.Low,
new("tagHelpers", tagHelperCount),
new("RZ10012errors", relevantDiagnosticsCount),
new("project", documentContext.Project.Key.Id));
}

static int CountDiagnostics(VSInternalDiagnosticReport report)
=> report.Diagnostics?.Count(d => d.Code == ComponentDiagnosticFactory.UnexpectedMarkupElement.Id)
?? 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@
// Licensed under the MIT license. See License.txt in the project root for license information.

using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.VisualStudio.Telemetry;
using Microsoft.AspNetCore.Razor.Telemetry;
using Microsoft.AspNetCore.Razor;
using System.IO;


#if DEBUG
using System.Linq;
Expand All @@ -16,6 +20,16 @@ namespace Microsoft.VisualStudio.Razor.Telemetry;

internal abstract class TelemetryReporter : ITelemetryReporter
{
private const string CodeAnalysisNamespace = nameof(Microsoft) + "." + nameof(CodeAnalysis);
private const string AspNetCoreNamespace = nameof(Microsoft) + "." + nameof(AspNetCore);
private const string MicrosoftVSRazorNamespace = $"{nameof(Microsoft)}.{nameof(VisualStudio)}.{nameof(Razor)}";

// Types that will not contribute to fault bucketing. Fully qualified name is
// required in order to match correctly.
private static readonly FrozenSet<string> s_faultIgnoredTypeNames = new string[] {
"Microsoft.AspNetCore.Razor.NullableExtensions"
}.ToFrozenSet();

protected ImmutableArray<TelemetrySession> TelemetrySessions { get; set; }

protected TelemetryReporter(ImmutableArray<TelemetrySession> telemetrySessions = default)
Expand Down Expand Up @@ -163,62 +177,18 @@ public void ReportFault(Exception exception, string? message, params object?[] @
return 0;
});

var (moduleName, methodName) = GetModifiedFaultParameters(exception);
faultEvent.SetFailureParameters(
failureParameter1: moduleName,
failureParameter2: methodName);

Report(faultEvent);
}
catch (Exception)
{
}
}

private static string GetExceptionDetails(Exception exception)
{
const string CodeAnalysisNamespace = nameof(Microsoft) + "." + nameof(CodeAnalysis);
const string AspNetCoreNamespace = nameof(Microsoft) + "." + nameof(AspNetCore);

// Be resilient to failing here. If we can't get a suitable name, just fall back to the standard name we
// used to report.
try
{
// walk up the stack looking for the first call from a type that isn't in the ErrorReporting namespace.
var frames = new StackTrace(exception).GetFrames();

// On the .NET Framework, GetFrames() can return null even though it's not documented as such.
// At least one case here is if the exception's stack trace itself is null.
if (frames != null)
{
foreach (var frame in frames)
{
var method = frame?.GetMethod();
var methodName = method?.Name;
if (methodName is null)
{
continue;
}

var declaringTypeName = method?.DeclaringType?.FullName;
if (declaringTypeName == null)
{
continue;
}

if (!declaringTypeName.StartsWith(CodeAnalysisNamespace) &&
!declaringTypeName.StartsWith(AspNetCoreNamespace))
{
continue;
}

return declaringTypeName + "." + methodName;
}
}
}
catch
{
}

// If we couldn't get a stack, do this
return exception.Message;
}

protected virtual void Report(TelemetryEvent telemetryEvent)
{
try
Expand Down Expand Up @@ -297,4 +267,123 @@ public TelemetryScope TrackLspRequest(string lspMethodName, string languageServe
new("eventscope.languageservername", languageServerName),
new("eventscope.correlationid", correlationId));
}


/// <summary>
/// Returns values that should be set to (failureParameter1, failureParameter2) when reporting a fault.
/// Those values represent the blamed stackframe module and method name.
/// </summary>
internal static (string?, string?) GetModifiedFaultParameters(Exception exception)
{
var frame = FindFirstRazorStackFrame(exception, static (declaringTypeName, _) =>
{
if (s_faultIgnoredTypeNames.Contains(declaringTypeName))
{
return false;
}

return true;
});

var method = frame?.GetMethod();
if (method is null)
{
return (null, null);
}

var moduleName = Path.GetFileNameWithoutExtension(method.Module.Name);
return (moduleName, method.Name);
}

private static string GetExceptionDetails(Exception exception)
{
var frame = FindFirstRazorStackFrame(exception);

if (frame is null)
{
return exception.Message;
}

var method = frame.GetMethod();

// These are checked in FindFirstRazorStackFrame
method.AssumeNotNull();
method.DeclaringType.AssumeNotNull();

var declaringTypeName = method.DeclaringType.FullName;
var methodName = method.Name;

return declaringTypeName + "." + methodName;
}

/// <summary>
/// Finds the first stack frame in exception stack that originates from razor code based on namespace
/// </summary>
/// <param name="exception">The exception to get the stack from</param>
/// <param name="predicate">Optional predicate to filter by declaringTypeName and methodName</param>
/// <returns></returns>
private static StackFrame? FindFirstRazorStackFrame(
Exception exception,
Func<string, string, bool>? predicate = null)
{
// Be resilient to failing here. If we can't get a suitable name, just fall back to the standard name we
// used to report.
try
{
// walk up the stack looking for the first call from a type that isn't in the ErrorReporting namespace.
var frames = new StackTrace(exception).GetFrames();

// On the .NET Framework, GetFrames() can return null even though it's not documented as such.
// At least one case here is if the exception's stack trace itself is null.
if (frames != null)
{
foreach (var frame in frames)
{
if (frame is null)
{
continue;
}

var method = frame.GetMethod();
var methodName = method?.Name;
if (methodName is null)
{
continue;
}

var declaringTypeName = method?.DeclaringType?.FullName;
if (declaringTypeName == null)
{
continue;
}

if (!IsInOwnedNamespace(declaringTypeName))
{
continue;
}

if (predicate is null)
{
return frame;
}

if (predicate(declaringTypeName, methodName))
{
return frame;
}
}
}

return null;
}
catch
{
return null;
}
}

private static bool IsInOwnedNamespace(string declaringTypeName)
=> declaringTypeName.StartsWith(CodeAnalysisNamespace) ||
declaringTypeName.StartsWith(AspNetCoreNamespace) ||
declaringTypeName.StartsWith(MicrosoftVSRazorNamespace);
}
Loading
Loading