From 8a50d96da0ef10574618cd7a2b2f48699bd66779 Mon Sep 17 00:00:00 2001 From: Marty Tippin <120425148+tippmar-nr@users.noreply.github.com> Date: Fri, 27 Oct 2023 16:02:49 -0500 Subject: [PATCH] POC - razor page instrumentation. Needs work in transaction / segment naming --- .../Agent/Core/Utilities/ExtensionsLoader.cs | 1 + .../AspNetCore6Plus/Instrumentation.xml | 5 ++ ...ageActionInvokeHandlerAsyncWrapper6Plus.cs | 66 +++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AspNetCore6Plus/PageActionInvokeHandlerAsyncWrapper6Plus.cs diff --git a/src/Agent/NewRelic/Agent/Core/Utilities/ExtensionsLoader.cs b/src/Agent/NewRelic/Agent/Core/Utilities/ExtensionsLoader.cs index d97693468b..c274e15281 100644 --- a/src/Agent/NewRelic/Agent/Core/Utilities/ExtensionsLoader.cs +++ b/src/Agent/NewRelic/Agent/Core/Utilities/ExtensionsLoader.cs @@ -40,6 +40,7 @@ public static void Initialize(string installPathExtensionsDirectory) { "BuildCommonServicesWrapper6Plus", Path.Combine(_installPathExtensionsDirectory, "NewRelic.Providers.Wrapper.AspNetCore6Plus.dll") }, { "GenericHostWebHostBuilderExtensionsWrapper6Plus", Path.Combine(_installPathExtensionsDirectory, "NewRelic.Providers.Wrapper.AspNetCore6Plus.dll") }, { "InvokeActionMethodAsyncWrapper6Plus", Path.Combine(_installPathExtensionsDirectory, "NewRelic.Providers.Wrapper.AspNetCore6Plus.dll") }, + { "PageActionInvokeHandlerAsyncWrapper6Plus", Path.Combine(_installPathExtensionsDirectory, "NewRelic.Providers.Wrapper.AspNetCore6Plus.dll") }, { "ResolveAppWrapper", Path.Combine(_installPathExtensionsDirectory, "NewRelic.Providers.Wrapper.Owin.dll") }, diff --git a/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AspNetCore6Plus/Instrumentation.xml b/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AspNetCore6Plus/Instrumentation.xml index da76c6e9e4..e81652b6e3 100644 --- a/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AspNetCore6Plus/Instrumentation.xml +++ b/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AspNetCore6Plus/Instrumentation.xml @@ -20,5 +20,10 @@ SPDX-License-Identifier: Apache-2.0 + + + + + diff --git a/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AspNetCore6Plus/PageActionInvokeHandlerAsyncWrapper6Plus.cs b/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AspNetCore6Plus/PageActionInvokeHandlerAsyncWrapper6Plus.cs new file mode 100644 index 0000000000..c900d187d8 --- /dev/null +++ b/src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AspNetCore6Plus/PageActionInvokeHandlerAsyncWrapper6Plus.cs @@ -0,0 +1,66 @@ +// Copyright 2020 New Relic, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.RazorPages; +using NewRelic.Agent.Api; +using NewRelic.Agent.Api.Experimental; +using NewRelic.Agent.Extensions.Providers.Wrapper; +using NewRelic.Reflection; + +namespace NewRelic.Providers.Wrapper.AspNetCore6Plus +{ + public class PageActionInvokeHandlerAsyncWrapper6Plus : IWrapper + { + private static Func _getPageContext; + + static PageActionInvokeHandlerAsyncWrapper6Plus() + { + _getPageContext = VisibilityBypasser.Instance.GenerateFieldReadAccessor("Microsoft.AspNetCore.Mvc.RazorPages", + "Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker", "_pageContext"); + } + + public bool IsTransactionRequired => true; + + public CanWrapResponse CanWrap(InstrumentedMethodInfo methodInfo) + { + return new CanWrapResponse("PageActionInvokeHandlerAsyncWrapper6Plus".Equals(methodInfo.RequestedWrapperName)); + } + + public AfterWrappedMethodDelegate BeforeWrappedMethod(InstrumentedMethodCall instrumentedMethodCall, IAgent agent, ITransaction transaction) + { + if (instrumentedMethodCall.IsAsync) + { + transaction.AttachToAsync(); + } + + var pageContext = _getPageContext(instrumentedMethodCall.MethodCall.InvocationTarget); + + var actionDescriptor = pageContext.ActionDescriptor; + + var transactionName = CreateTransactionName(actionDescriptor); + + transaction.SetWebTransactionName(WebTransactionType.Action, transactionName, TransactionNamePriority.FrameworkHigh); + + var actionDescriptorPageTypeInfo = actionDescriptor.PageTypeInfo; + var pageTypeName = actionDescriptorPageTypeInfo.Name; + + var segment = transaction.StartMethodSegment(instrumentedMethodCall.MethodCall, pageTypeName, "uhh_what_goes_here"); + + var segmentApi = segment.GetExperimentalApi(); + segmentApi.UserCodeNamespace = actionDescriptorPageTypeInfo.FullName; + segmentApi.UserCodeFunction = "uhh_what_goes_here"; + + return Delegates.GetAsyncDelegateFor(agent, segment, TaskContinueWithOption.None); + } + + private static string CreateTransactionName(CompiledPageActionDescriptor actionDescriptor) + { + var transactionName = $"Pages{actionDescriptor.DisplayName}"; + + return transactionName; + } + } +}