Skip to content

Commit

Permalink
profiler azure function detection rework
Browse files Browse the repository at this point in the history
  • Loading branch information
tippmar-nr committed Sep 4, 2024
1 parent 933fe52 commit 69628cd
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 23 deletions.
33 changes: 18 additions & 15 deletions src/Agent/NewRelic/Profiler/Configuration/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ namespace NewRelic { namespace Profiler { namespace Configuration {
ApplicationPoolsPtr blackList = ApplicationPoolsPtr(new ApplicationPools()),
bool poolsEnabledByDefault = true,
bool agentEnabledSetInApplicationConfiguration = false,
bool agentEnabledViaApplicationConfiguration = false)
bool agentEnabledViaApplicationConfiguration = false,
std::shared_ptr<NewRelic::Profiler::Logger::IFileDestinationSystemCalls> systemCalls = nullptr)
: _agentEnabled(agentEnabled)
, _agentEnabledInLocalConfig(false)
, _logLevel(logLevel)
Expand All @@ -132,6 +133,7 @@ namespace NewRelic { namespace Profiler { namespace Configuration {
, _applicationPoolsAreEnabledByDefault(poolsEnabledByDefault)
, _agentEnabledSetInApplicationConfiguration(agentEnabledSetInApplicationConfiguration)
, _agentEnabledViaApplicationConfiguration(agentEnabledViaApplicationConfiguration)
, _systemCalls(systemCalls)
{
}

Expand Down Expand Up @@ -603,17 +605,17 @@ namespace NewRelic { namespace Profiler { namespace Configuration {
return false;
}

if (IsW3wpProcess(processPath, parentProcessPath)) {
if (IsAzureFunction()) {
auto retVal = ShouldInstrumentAzureFunction(appPoolId, commandLine);
if (retVal == 0) {
return false;
}
if (retVal == 1) {
return true;
}
if (IsAzureFunction()) {
auto retVal = ShouldInstrumentAzureFunction(processPath, appPoolId, commandLine);
if (retVal == 0) {
return false;
}
if (retVal == 1) {
return true;
}
}

if (IsW3wpProcess(processPath, parentProcessPath)) {
return ShouldInstrumentApplicationPool(appPoolId);
}

Expand All @@ -630,31 +632,32 @@ namespace NewRelic { namespace Profiler { namespace Configuration {
/// <summary>
/// Returns 0 if the process should not be instrumented, 1 if it should be instrumented, and -1 if it is indeterminate.
/// </summary>
int ShouldInstrumentAzureFunction(xstring_t const& appPoolId, xstring_t const& commandLine)
int ShouldInstrumentAzureFunction(xstring_t const& processPath, xstring_t const& appPoolId, xstring_t const& commandLine)
{
LogInfo(_X("Azure function detected. Determining whether to instrument ") + commandLine);

bool isAzureWebJobsScriptWebHost = NewRelic::Profiler::Strings::ContainsCaseInsensitive(commandLine, appPoolId);
bool isAzureWebJobsScriptWebHost = appPoolId.length() > 0 && NewRelic::Profiler::Strings::ContainsCaseInsensitive(commandLine, appPoolId);
if (isAzureWebJobsScriptWebHost)
{
LogInfo(L"Appears to be Azure WebJobs Script WebHost based on commandLine. Not instrumenting this process.");
return 0;
}

// AzureFunctionsNetHost.exe is the typical startup command for Azure Functions
bool isAzureFunctionsNetHost = NewRelic::Profiler::Strings::ContainsCaseInsensitive(commandLine, _X("FunctionsNetHost.exe"));

bool isAzureFunctionsNetHost = Strings::EndsWith(processPath, _X("FUNCTIONSNETHOST.EXE"));
if (isAzureFunctionsNetHost)
{
LogInfo(L"FunctionNetHost.exe is a valid Azure function command. This process will be instrumented.");
return 1;
}

// func.exe is the local test tool and should not be instrumented
bool isFuncExe = NewRelic::Profiler::Strings::ContainsCaseInsensitive(commandLine, _X("Func.exe"));
bool isFuncExe = Strings::EndsWith(processPath, _X("FUNC.EXE"));
if (isFuncExe)
{
LogInfo(L"Func.exe is a tool for testing Azure functions locally. Not instrumenting this process.");
return 1;
return 0;
}

LogInfo("Couldn't determine whether this Azure Function process should be instrumented based on commandLine. Falling back to checking application pool");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,24 @@ namespace NewRelic { namespace Profiler { namespace Configuration { namespace Te
Assert::IsTrue(configuration.ShouldInstrument(L"w3wp.exe", L"", L"foo", L"", true));
}

TEST_METHOD(should_not_instrument_azure_function_func_exe_process_path)
{
std::wstring configurationXml(L"\
<?xml version=\"1.0\"?>\
<configuration>\
<log level=\"deBug\"/>\
</configuration>\
");

auto systemCalls = std::make_shared<NewRelic::Profiler::Logger::Test::SystemCalls>();
systemCalls->environmentVariables[L"FUNCTIONS_WORKER_RUNTIME"] = L"dotnet-isolated";

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

Assert::IsFalse(configuration.ShouldInstrument(L"func.exe", L"", L"FooBarBaz", L"blah blah blah FooBarBaz blah blah blah", true));
}


TEST_METHOD(instrument_process)
{
ProcessesPtr processes(new Processes());
Expand Down Expand Up @@ -457,7 +475,8 @@ namespace NewRelic { namespace Profiler { namespace Configuration { namespace Te
</configuration>\
");

Configuration configuration(configurationXml, _missingAgentEnabledConfigPair);
auto systemCalls = std::make_shared<NewRelic::Profiler::Logger::Test::SystemCalls>();
Configuration configuration(configurationXml, _missingAgentEnabledConfigPair, L"", systemCalls);
Assert::IsTrue(configuration.ShouldInstrument(L"Foo.exe", L"w3wp.exe", L"bar", L"", true));
}

Expand All @@ -472,7 +491,8 @@ namespace NewRelic { namespace Profiler { namespace Configuration { namespace Te
</configuration>\
");

Configuration configuration(configurationXml, _missingAgentEnabledConfigPair);
auto systemCalls = std::make_shared<NewRelic::Profiler::Logger::Test::SystemCalls>();
Configuration configuration(configurationXml, _missingAgentEnabledConfigPair, L"", systemCalls);
Assert::IsFalse(configuration.ShouldInstrument(L"Foo.exe", L"w3wp.exe", L"foo", L"", true));
}

Expand All @@ -487,7 +507,8 @@ namespace NewRelic { namespace Profiler { namespace Configuration { namespace Te
</configuration>\
");

Configuration configuration(configurationXml, _missingAgentEnabledConfigPair);
auto systemCalls = std::make_shared<NewRelic::Profiler::Logger::Test::SystemCalls>();
Configuration configuration(configurationXml, _missingAgentEnabledConfigPair, L"", systemCalls);
Assert::IsTrue(configuration.ShouldInstrument(L"Foo.exe", L"w3wp.exe", L"foo", L"", true));
}

Expand All @@ -502,7 +523,8 @@ namespace NewRelic { namespace Profiler { namespace Configuration { namespace Te
</configuration>\
");

Configuration configuration(configurationXml, _missingAgentEnabledConfigPair);
auto systemCalls = std::make_shared<NewRelic::Profiler::Logger::Test::SystemCalls>();
Configuration configuration(configurationXml, _missingAgentEnabledConfigPair, L"", systemCalls);
Assert::IsFalse(configuration.ShouldInstrument(L"Foo.exe", L"w3wp.exe", L"foo", L"", true));
}

Expand All @@ -517,7 +539,8 @@ namespace NewRelic { namespace Profiler { namespace Configuration { namespace Te
</configuration>\
");

Configuration configuration(configurationXml, _missingAgentEnabledConfigPair);
auto systemCalls = std::make_shared<NewRelic::Profiler::Logger::Test::SystemCalls>();
Configuration configuration(configurationXml, _missingAgentEnabledConfigPair, L"", systemCalls);
Assert::IsTrue(configuration.ShouldInstrument(L"Foo.exe", L"w3wp.exe", L"foo", L"", true));
}

Expand All @@ -536,7 +559,8 @@ namespace NewRelic { namespace Profiler { namespace Configuration { namespace Te
</configuration>\
");

Configuration configuration(configurationXml, _missingAgentEnabledConfigPair);
auto systemCalls = std::make_shared<NewRelic::Profiler::Logger::Test::SystemCalls>();
Configuration configuration(configurationXml, _missingAgentEnabledConfigPair, L"", systemCalls);
Assert::IsTrue(configuration.ShouldInstrument(L"Foo.exe", L"w3wp.exe", L"whiteFoo", L"", true));
Assert::IsTrue(configuration.ShouldInstrument(L"Foo.exe", L"w3wp.exe", L"whiteBar", L"", true));
Assert::IsFalse(configuration.ShouldInstrument(L"Foo.exe", L"w3wp.exe", L"blackFoo", L"", true));
Expand All @@ -560,7 +584,8 @@ namespace NewRelic { namespace Profiler { namespace Configuration { namespace Te
</configuration>\
");

Configuration configuration(configurationXml, _missingAgentEnabledConfigPair);
auto systemCalls = std::make_shared<NewRelic::Profiler::Logger::Test::SystemCalls>();
Configuration configuration(configurationXml, _missingAgentEnabledConfigPair, L"", systemCalls);
Assert::IsTrue(configuration.ShouldInstrument(L"Foo.exe", L"w3wp.exe", L"whiteFoo", L"", true));
Assert::IsTrue(configuration.ShouldInstrument(L"Foo.exe", L"w3wp.exe", L"whiteBar", L"", true));
Assert::IsFalse(configuration.ShouldInstrument(L"Foo.exe", L"w3wp.exe", L"blackFoo", L"", true));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
// SPDX-License-Identifier: Apache-2.0

#include "stdafx.h"
#include "../Logging/Logger.h"
#include "../Configuration/Configuration.h"
#include "../LoggingTest/DefaultFileLogLocationTest.cpp"
#include "CppUnitTest.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;
Expand All @@ -13,7 +15,9 @@ namespace NewRelic { namespace Profiler { namespace Configuration { namespace Te
TEST_METHOD(netCore_dotnet_exe_invocations_not_instrumented) {
auto processPath = _X("processPath");
auto appPoolId = _X("appPoolId");
Configuration configuration(true);
auto systemCalls = std::make_shared<NewRelic::Profiler::Logger::Test::SystemCalls>();

Configuration configuration(true, Logger::Level::LEVEL_INFO, ProcessesPtr(new Processes()),ApplicationPoolsPtr(new ApplicationPools()),ApplicationPoolsPtr(new ApplicationPools()), true, false, false, systemCalls);

auto isCoreClr = true;

Expand Down

0 comments on commit 69628cd

Please sign in to comment.