Skip to content

Commit 9669641

Browse files
authored
fix: Update Profiler to check whether Azure function mode support is enabled (#2822)
1 parent 7c241f8 commit 9669641

File tree

4 files changed

+85
-11
lines changed

4 files changed

+85
-11
lines changed

src/Agent/NewRelic/Home/Home.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
</Target>
1414

1515
<ItemGroup>
16-
<PackageReference Include="NewRelic.Agent.Internal.Profiler" Version="10.29.0.66"/>
16+
<PackageReference Include="NewRelic.Agent.Internal.Profiler" Version="10.31.0.15"/>
1717
</ItemGroup>
1818

1919
</Project>

src/Agent/NewRelic/Profiler/Configuration/Configuration.h

+22-7
Original file line numberDiff line numberDiff line change
@@ -605,13 +605,17 @@ namespace NewRelic { namespace Profiler { namespace Configuration {
605605
return false;
606606
}
607607

608-
if (IsAzureFunction()) {
609-
auto retVal = ShouldInstrumentAzureFunction(processPath, appPoolId, commandLine);
610-
if (retVal == 0) {
611-
return false;
612-
}
613-
if (retVal == 1) {
614-
return true;
608+
if (IsAzureFunction())
609+
{
610+
if (IsAzureFunctionModeEnabled()) // if not explicitly enabled, fall back to "legacy" behavior
611+
{
612+
auto retVal = ShouldInstrumentAzureFunction(processPath, appPoolId, commandLine);
613+
if (retVal == 0) {
614+
return false;
615+
}
616+
if (retVal == 1) {
617+
return true;
618+
}
615619
}
616620
}
617621

@@ -622,6 +626,17 @@ namespace NewRelic { namespace Profiler { namespace Configuration {
622626
return true;
623627
}
624628

629+
bool IsAzureFunctionModeEnabled() const
630+
{
631+
auto azureFunctionModeEnabled = _systemCalls->TryGetEnvironmentVariable(_X("NEW_RELIC_AZURE_FUNCTION_MODE_ENABLED"));
632+
633+
if (azureFunctionModeEnabled == nullptr || azureFunctionModeEnabled->length() == 0) {
634+
return false;
635+
}
636+
637+
return Strings::AreEqualCaseInsensitive(*azureFunctionModeEnabled, _X("true")) || Strings::AreEqualCaseInsensitive(*azureFunctionModeEnabled, _X("1"));
638+
}
639+
625640
bool IsAzureFunction() const
626641
{
627642
// Azure Functions sets the FUNCTIONS_WORKER_RUNTIME environment variable to "dotnet-isolated" when running in the .NET worker.

src/Agent/NewRelic/Profiler/ConfigurationTest/ConfigurationTest.cpp

+45
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,47 @@ namespace NewRelic { namespace Profiler { namespace Configuration { namespace Te
7373
Assert::IsFalse(configuration.ShouldInstrument(L"foo.exe", L"", L"", L"", false));
7474
}
7575

76+
// tests to verify that "legacy" behavior (before azure function support) is retained.
77+
// If NEW_RELIC_AZURE_FUNCTION_MODE_ENABLED environment variable is not set or is set to false,
78+
// we should behave as if no azure function support has been added.
79+
TEST_METHOD(azure_function_should_behave_as_legacy_if_azure_function_mode_not_specified)
80+
{
81+
std::wstring configurationXml(L"\
82+
<?xml version=\"1.0\"?>\
83+
<configuration>\
84+
<log level=\"deBug\"/>\
85+
</configuration>\
86+
");
87+
88+
auto systemCalls = std::make_shared<NewRelic::Profiler::Logger::Test::SystemCalls>();
89+
systemCalls->environmentVariables[L"FUNCTIONS_WORKER_RUNTIME"] = L"dotnet-isolated";
90+
91+
Configuration configuration(configurationXml, _missingConfig, L"", systemCalls);
92+
93+
Assert::IsTrue(configuration.ShouldInstrument(L"functionsnethost.exe", L"", L"", L"blah blah blah FooBarBaz blah blah blah", true));
94+
}
95+
96+
// tests to verify that "legacy" behavior (before azure function support) is retained.
97+
// If NEW_RELIC_AZURE_FUNCTION_MODE_ENABLED environment variable is not set or is set to false,
98+
// we should behave as if no azure function support has been added.
99+
TEST_METHOD(azure_function_should_behave_as_legacy_if_azure_function_mode_disabled)
100+
{
101+
std::wstring configurationXml(L"\
102+
<?xml version=\"1.0\"?>\
103+
<configuration>\
104+
<log level=\"deBug\"/>\
105+
</configuration>\
106+
");
107+
108+
auto systemCalls = std::make_shared<NewRelic::Profiler::Logger::Test::SystemCalls>();
109+
systemCalls->environmentVariables[L"FUNCTIONS_WORKER_RUNTIME"] = L"dotnet-isolated";
110+
systemCalls->environmentVariables[L"NEW_RELIC_AZURE_FUNCTION_MODE_ENABLED"] = L"0";
111+
112+
Configuration configuration(configurationXml, _missingConfig, L"", systemCalls);
113+
114+
Assert::IsTrue(configuration.ShouldInstrument(L"functionsnethost.exe", L"", L"", L"blah blah blah FooBarBaz blah blah blah", true));
115+
}
116+
76117
TEST_METHOD(should_not_instrument_azure_function_app_pool_id_in_commandline)
77118
{
78119
std::wstring configurationXml(L"\
@@ -84,6 +125,7 @@ namespace NewRelic { namespace Profiler { namespace Configuration { namespace Te
84125

85126
auto systemCalls = std::make_shared<NewRelic::Profiler::Logger::Test::SystemCalls>();
86127
systemCalls->environmentVariables[L"FUNCTIONS_WORKER_RUNTIME"] = L"dotnet-isolated";
128+
systemCalls->environmentVariables[L"NEW_RELIC_AZURE_FUNCTION_MODE_ENABLED"] = L"true";
87129

88130
Configuration configuration(configurationXml, _missingConfig, L"", systemCalls);
89131

@@ -101,6 +143,7 @@ namespace NewRelic { namespace Profiler { namespace Configuration { namespace Te
101143

102144
auto systemCalls = std::make_shared<NewRelic::Profiler::Logger::Test::SystemCalls>();
103145
systemCalls->environmentVariables[L"FUNCTIONS_WORKER_RUNTIME"] = L"dotnet-isolated";
146+
systemCalls->environmentVariables[L"NEW_RELIC_AZURE_FUNCTION_MODE_ENABLED"] = L"true";
104147

105148
Configuration configuration(configurationXml, _missingConfig, L"", systemCalls);
106149

@@ -118,6 +161,7 @@ namespace NewRelic { namespace Profiler { namespace Configuration { namespace Te
118161

119162
auto systemCalls = std::make_shared<NewRelic::Profiler::Logger::Test::SystemCalls>();
120163
systemCalls->environmentVariables[L"FUNCTIONS_WORKER_RUNTIME"] = L"dotnet-isolated";
164+
systemCalls->environmentVariables[L"NEW_RELIC_AZURE_FUNCTION_MODE_ENABLED"] = L"true";
121165

122166
Configuration configuration(configurationXml, _missingConfig, L"", systemCalls);
123167

@@ -135,6 +179,7 @@ namespace NewRelic { namespace Profiler { namespace Configuration { namespace Te
135179

136180
auto systemCalls = std::make_shared<NewRelic::Profiler::Logger::Test::SystemCalls>();
137181
systemCalls->environmentVariables[L"FUNCTIONS_WORKER_RUNTIME"] = L"dotnet-isolated";
182+
systemCalls->environmentVariables[L"NEW_RELIC_AZURE_FUNCTION_MODE_ENABLED"] = L"true";
138183

139184
Configuration configuration(configurationXml, _missingConfig, L"", systemCalls);
140185

tests/Agent/IntegrationTests/IntegrationTests/AzureFunction/AzureFunctionHttpTriggerTests.cs

+17-3
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,26 @@ protected AzureFunctionHttpTriggerTestsBase(TFixture fixture, ITestOutputHelper
3131
_fixture.AddActions(
3232
setupConfiguration: () =>
3333
{
34-
new NewRelicConfigModifier(fixture.DestinationNewRelicConfigFilePath)
34+
var configModifier = new NewRelicConfigModifier(fixture.DestinationNewRelicConfigFilePath);
35+
configModifier
3536
.ForceTransactionTraces()
3637
.ConfigureFasterTransactionTracesHarvestCycle(20)
3738
.ConfigureFasterMetricsHarvestCycle(15)
3839
.ConfigureFasterSpanEventsHarvestCycle(15)
3940
.SetLogLevel("finest");
41+
42+
// This is a bit of a kludge. When azure function instrumentation is disabled,
43+
// the agent instruments *two* processes: the azure function host (func.exe) and the actual function app.
44+
// Both processes use the same config files, so explicitly setting the log file name forces both
45+
// processes to log to the same file, which makes it easier to verify that the
46+
// actual function app is not being instrumented when the Invoke() method gets hit.
47+
//
48+
// Ideally, we'd prefer to look for the specific log file for the azure function app, but that's less trivial
49+
// and not worth the effort for this one test.
50+
if (!_fixture.AzureFunctionModeEnabled)
51+
{
52+
configModifier.SetLogFileName("azure_function_instrumentation_disabled.log");
53+
}
4054
},
4155
exerciseApplication: () =>
4256
{
@@ -138,8 +152,8 @@ public void Test_SimpleInvocationMode()
138152

139153
if (!_fixture.AzureFunctionModeEnabled) // look for a specific log line that indicates azure function mode is disabled
140154
{
141-
var disabledLogLine = _fixture.AgentLog.TryGetLogLine(AgentLogBase.AzureFunctionModeDisabledLogLineRegex);
142-
Assert.NotNull(disabledLogLine);
155+
var disabledLogLines = _fixture.AgentLog.TryGetLogLines(AgentLogBase.AzureFunctionModeDisabledLogLineRegex);
156+
Assert.Single(disabledLogLines);
143157
}
144158
}
145159

0 commit comments

Comments
 (0)