Skip to content

Commit

Permalink
Merge release/dev17.12 to main (#10913)
Browse files Browse the repository at this point in the history
This is an automatically generated pull request from release/dev17.12
into main.


Once all conflicts are resolved and all the tests pass, you are free to
merge the pull request. 🐯

## Troubleshooting conflicts

### Identify authors of changes which introduced merge conflicts
Scroll to the bottom, then for each file containing conflicts copy its
path into the following searches:
- https://github.com/dotnet/razor/find/release/dev17.12
- https://github.com/dotnet/razor/find/main

Usually the most recent change to a file between the two branches is
considered to have introduced the conflicts, but sometimes it will be
necessary to look for the conflicting lines and check the blame in each
branch. Generally the author whose change introduced the conflicts
should pull down this PR, fix the conflicts locally, then push up a
commit resolving the conflicts.

### Resolve merge conflicts using your local repo
Sometimes merge conflicts may be present on GitHub but merging locally
will work without conflicts. This is due to differences between the
merge algorithm used in local git versus the one used by GitHub.
``` bash
git fetch --all
git checkout -t upstream/merges/release/dev17.12-to-main
git reset --hard upstream/main
git merge upstream/release/dev17.12
# Fix merge conflicts
git commit
git push upstream merges/release/dev17.12-to-main --force
```
  • Loading branch information
dotnet-bot authored Sep 26, 2024
2 parents 3e0da42 + 8ae2804 commit b12847a
Show file tree
Hide file tree
Showing 7 changed files with 271 additions and 61 deletions.
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
2 changes: 1 addition & 1 deletion eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
<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>
<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"
}
}
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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
// Licensed under the MIT license. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor;
using Microsoft.AspNetCore.Razor.Telemetry;
using Microsoft.AspNetCore.Razor.Test.Common;
using Microsoft.VisualStudio.Editor.Razor.Test.Shared;
Expand Down Expand Up @@ -392,4 +394,33 @@ public void ReportFault_InnerMostExceptionIsOperationCanceledException_SkipsFaul
// Assert
Assert.Empty(reporter.Events);
}

[Theory, MemberData(nameof(s_throwFunctions))]
public void GetModifiedFaultParameters_FiltersCorrectly(Func<object> throwAction)
{
try
{
throwAction();
}
catch (Exception ex)
{
var (param1, param2) = TestTelemetryReporter.GetModifiedFaultParameters(ex);

Assert.Equal("Microsoft.VisualStudio.LanguageServices.Razor.Test", param1);
Assert.NotNull(param2);

// Depending on debug/release the stack can contain a constructor or
// a call to this method. We expect one or the other and both
// are valid
#if DEBUG
Assert.StartsWith("<.cctor>", param2);
#else
Assert.Equal("GetModifiedFaultParameters_FiltersCorrectly", param2);
#endif
}
}

public static readonly IEnumerable<object[]> s_throwFunctions = [
[() => ((object?)null).AssumeNotNull()]
];
}
Loading

0 comments on commit b12847a

Please sign in to comment.