Skip to content
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

feat: Parse Azure Function HttpTrigger parameters #2776

Open
wants to merge 60 commits into
base: main
Choose a base branch
from

Conversation

tippmar-nr
Copy link
Member

Implements parsing for request method, request uri and response status code for Azure Functions that utilize HttpTrigger.

Includes updated integration tests that exercise an Azure Function app that uses the Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore package and one that does not, to verify that we can correctly parse the data we need in both scenarios.

(Don't be scared by the ridiculously large commit history - this branch started out as a feature work branch back when the Azure Functions feature was still around...)

tippmar-nr and others added 30 commits August 13, 2024 11:51
chore: Update Profiler NuGet Package Reference to v10.28.0.40.

Co-authored-by: tippmar-nr <[email protected]>
tippmar-nr and others added 17 commits August 30, 2024 09:31
* Added a config setting to disabled azure function mode by default, added a few unit tests in areas where function mode detection is used

* Minor cleanup

* Refactor
* Unit tests and a bug fix or two

* profiler unit tests

* Unit test tweak

* cleanup

* formatting
* Profiler update to exclude func.exe

* chore: Update Profiler NuGet Package Reference to v10.29.0.54 (#2734)

chore: Update Profiler NuGet Package Reference to v10.29.0.54.

Co-authored-by: tippmar-nr <[email protected]>

* WIP

* profiler azure function detection rework

* Azure function integration tests functional but not complete

* Upate all_solutions workflow to install azure functions tools and test the azurefunction namespace

* another install attempt

* test only azure function namespace for now

* Tweaks for the integration tests workflow

* enable all namespaces for integration tests

* cleanup

* Profiler: Allow log level override in azure function mode via NEW_RELIC_AZURE_FUNCTION_LOG_LEVEL_OVERRIDE=1

* workflow tweak

* chore: Update Profiler NuGet Package Reference to v10.29.0.66 (#2738)

chore: Update Profiler NuGet Package Reference to v10.29.0.66.

Co-authored-by: tippmar-nr <[email protected]>

* integration test tw4eaks

* profiler unit test update

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* Integration test updates, added net6.0 and net8.0 plus a test to verify behavior when azure function mode is disabled.

* Integration test rework to use different HttpTrigger invocation methods
Disable aspnetcore middleware wrapper in azure function mode, update integration tests
* Added QueueTrigger function to integration tests

* Added a missing file

* Minor refactor
…o feature/azure-function-http-trigger-parsing
@tippmar-nr tippmar-nr requested a review from a team as a code owner September 18, 2024 21:35
var inputBindingFeature = _genericFunctionInputBindingFeatureGetter.Invoke(features, []);
dynamic valueTask = _bindFunctionInputAsync.Invoke(inputBindingFeature, [functionContext]);

valueTask.AsTask().Wait(); // BindFunctionInputAsync returns a ValueTask, so we need to convert it to a Task to wait on it
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really our best option for getting access to the inputs? Feels a bit clunky.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is, unfortunately, exactly what the GRPC-generated code in an Azure function app does between when the InvokeFunctionAsync() method is called and when the actual function Run() method is called. It's ugly, but it's all we have to work with.

        public async global::System.Threading.Tasks.ValueTask ExecuteAsync(global::Microsoft.Azure.Functions.Worker.FunctionContext context)
        {
            var inputBindingFeature = context.Features.Get<global::Microsoft.Azure.Functions.Worker.Context.Features.IFunctionInputBindingFeature>();
            var inputBindingResult = await inputBindingFeature.BindFunctionInputAsync(context);
            var inputArguments = inputBindingResult.Values;

            if (string.Equals(context.FunctionDefinition.EntryPoint, "AzureFunctionApp.Function1.Run", StringComparison.Ordinal))
            {
                var instanceType = types["AzureFunctionApp.Function1"];
                var i = _functionActivator.CreateInstance(instanceType, context) as global::AzureFunctionApp.Function1;
                context.GetInvocationResult().Value = await i.Run((global::Microsoft.Azure.Functions.Worker.Http.HttpRequestData)inputArguments[0]);
            }
            else if (string.Equals(context.FunctionDefinition.EntryPoint, "AzureFunctionApp.Function2.Run", StringComparison.Ordinal))
            {
                var instanceType = types["AzureFunctionApp.Function2"];
                var i = _functionActivator.CreateInstance(instanceType, context) as global::AzureFunctionApp.Function2;
                context.GetInvocationResult().Value = i.Run((global::Microsoft.AspNetCore.Http.HttpRequest)inputArguments[0]);
            }
            else if (string.Equals(context.FunctionDefinition.EntryPoint, "AzureFunctionApp.QueueTriggerFunction.Run", StringComparison.Ordinal))
            {
                var instanceType = types["AzureFunctionApp.QueueTriggerFunction"];
                var i = _functionActivator.CreateInstance(instanceType, context) as global::AzureFunctionApp.QueueTriggerFunction;
                i.Run((string)inputArguments[0]);
            }
        }

@codecov-commenter
Copy link

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 81.23%. Comparing base (d55567f) to head (94d4855).
Report is 4 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2776      +/-   ##
==========================================
- Coverage   81.24%   81.23%   -0.02%     
==========================================
  Files         460      460              
  Lines       29229    29230       +1     
  Branches     3223     3223              
==========================================
- Hits        23747    23744       -3     
- Misses       4696     4698       +2     
- Partials      786      788       +2     
Flag Coverage Δ
Agent 82.25% <100.00%> (-0.02%) ⬇️
Profiler 72.12% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...nt/NewRelic/Agent/Core/Transactions/Transaction.cs 80.73% <100.00%> (+0.02%) ⬆️

... and 1 file with indirect coverage changes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants