Skip to content

Commit 3dcf3af

Browse files
authored
feat: Use Lambda function name if application name is not set (#2695)
1 parent 1aad20c commit 3dcf3af

File tree

9 files changed

+135
-11
lines changed

9 files changed

+135
-11
lines changed

src/Agent/NewRelic/Agent/Core/Config/BootstrapConfiguration.cs

+11-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ public interface IBootstrapConfiguration
1818
bool AgentEnabled { get; }
1919
string AgentEnabledAt { get; }
2020
ILogConfig LogConfig { get; }
21+
string ServerlessFunctionName { get; }
22+
string ServerlessFunctionVersion { get; }
2123
}
2224

2325
/// <summary>
@@ -88,6 +90,10 @@ public static IBootstrapConfiguration GetDefault()
8890
/// </summary>
8991
public bool ServerlessModeEnabled { get; private set; }
9092

93+
public string ServerlessFunctionName { get; private set; }
94+
95+
public string ServerlessFunctionVersion { get; private set; }
96+
9197
/// <summary>
9298
/// Gets the debug startup delay in seconds. This is used primarily for debugging of AWS Lambda functions.
9399
/// </summary>
@@ -126,17 +132,19 @@ public string AgentEnabledAt
126132

127133
private bool CheckServerlessModeEnabled(configuration localConfiguration)
128134
{
135+
// We may need these later even if we don't use it now.
136+
ServerlessFunctionName = ConfigLoaderHelpers.GetEnvironmentVar("AWS_LAMBDA_FUNCTION_NAME");
137+
ServerlessFunctionVersion = ConfigLoaderHelpers.GetEnvironmentVar("AWS_LAMBDA_FUNCTION_VERSION");
138+
129139
// according to the spec, environment variable takes precedence over config file
130140
var serverlessModeEnvVariable = ConfigLoaderHelpers.GetEnvironmentVar("NEW_RELIC_SERVERLESS_MODE_ENABLED");
131-
132141
if (serverlessModeEnvVariable.TryToBoolean(out var enabledViaEnvVariable))
133142
{
134143
return enabledViaEnvVariable;
135144
}
136145

137146
// env variable is not set, check for function name
138-
var awsLambdaFunctionName = ConfigLoaderHelpers.GetEnvironmentVar("AWS_LAMBDA_FUNCTION_NAME");
139-
if (!string.IsNullOrEmpty(awsLambdaFunctionName))
147+
if (!string.IsNullOrEmpty(ServerlessFunctionName))
140148
return true;
141149

142150
// fall back to config file

src/Agent/NewRelic/Agent/Core/Configuration/DefaultConfiguration.cs

+14
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,10 @@ private int TryGetAppSettingAsIntWithDefault(string key, int defaultValue)
199199

200200
public bool ServerlessModeEnabled => _bootstrapConfiguration.ServerlessModeEnabled;
201201

202+
public string ServerlessFunctionName => _bootstrapConfiguration.ServerlessFunctionName;
203+
204+
public string ServerlessFunctionVersion => _bootstrapConfiguration.ServerlessFunctionVersion;
205+
202206
private string _agentLicenseKey;
203207
public virtual string AgentLicenseKey
204208
{
@@ -270,6 +274,16 @@ private IEnumerable<string> GetApplicationNames()
270274
return appName.Split(StringSeparators.Comma);
271275
}
272276

277+
if (ServerlessModeEnabled)
278+
{
279+
if (!string.IsNullOrEmpty(ServerlessFunctionName))
280+
{
281+
Log.Info("Application name from Lambda Function Name.");
282+
_applicationNamesSource = "Environment Variable (AWS_LAMBDA_FUNCTION_NAME)";
283+
return new List<string> { ServerlessFunctionName };
284+
}
285+
}
286+
273287
if (_localConfiguration.application.name.Count > 0)
274288
{
275289
Log.Info("Application name from newrelic.config.");

src/Agent/NewRelic/Agent/Core/Configuration/ReportedConfiguration.cs

+6
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ public ReportedConfiguration(IConfiguration configuration)
3838
[JsonIgnore]
3939
public bool ServerlessModeEnabled => _configuration.ServerlessModeEnabled;
4040

41+
[JsonIgnore]
42+
public string ServerlessFunctionName => _configuration.ServerlessFunctionName;
43+
44+
[JsonIgnore]
45+
public string ServerlessFunctionVersion => _configuration.ServerlessFunctionVersion;
46+
4147
[JsonIgnore]
4248
public string AgentLicenseKey => _configuration.AgentLicenseKey;
4349

src/Agent/NewRelic/Agent/Extensions/NewRelic.Agent.Extensions/Configuration/IConfiguration.cs

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ public interface IConfiguration
1515
string AgentEnabledAt { get; }
1616

1717
bool ServerlessModeEnabled { get; }
18+
string ServerlessFunctionName { get; }
19+
string ServerlessFunctionVersion { get; }
1820

1921
string AgentLicenseKey { get; }
2022
IEnumerable<string> ApplicationNames { get; }

src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/AwsLambda/HandlerMethodWrapper.cs

+8-8
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ public bool SetEventType(string fullName, int idx)
4848
return false;
4949
}
5050

51-
public void Validate(string fallbackName)
51+
public void Validate(string fallbackName1, string fallbackName2, string versionFallback)
5252
{
53-
ValidateName(fallbackName);
54-
ValidateVersion();
53+
ValidateName(fallbackName1, fallbackName2);
54+
ValidateVersion(versionFallback);
5555
}
5656

5757
private void SetName(object lambdaContext)
@@ -60,11 +60,11 @@ private void SetName(object lambdaContext)
6060
FunctionName = functionNameGetter(lambdaContext);
6161
}
6262

63-
private void ValidateName(string fallbackName)
63+
private void ValidateName(string fallback1, string fallback2)
6464
{
6565
if (string.IsNullOrEmpty(_functionDetails.FunctionName))
6666
{
67-
FunctionName = System.Environment.GetEnvironmentVariable("AWS_LAMBDA_FUNCTION_NAME") ?? fallbackName;
67+
FunctionName = fallback1 ?? fallback2;
6868
}
6969
}
7070

@@ -74,11 +74,11 @@ private void SetVersion(object lambdaContext)
7474
FunctionVersion = functionVersionGetter(lambdaContext);
7575
}
7676

77-
private void ValidateVersion()
77+
private void ValidateVersion(string fallback)
7878
{
7979
if (string.IsNullOrEmpty(FunctionVersion))
8080
{
81-
FunctionVersion = System.Environment.GetEnvironmentVariable("AWS_LAMBDA_FUNCTION_VERSION") ?? "$LATEST";
81+
FunctionVersion = fallback ?? "$LATEST";
8282
}
8383
}
8484

@@ -200,7 +200,7 @@ private void InitLambdaData(InstrumentedMethodCall instrumentedMethodCall, IAgen
200200
}
201201
}
202202

203-
_functionDetails.Validate(instrumentedMethodCall.MethodCall.Method.MethodName);
203+
_functionDetails.Validate(agent.Configuration.ServerlessFunctionName, instrumentedMethodCall.MethodCall.Method.MethodName, agent.Configuration.ServerlessFunctionVersion);
204204

205205
if (!_functionDetails.HasContext())
206206
{

tests/Agent/UnitTests/Core.UnitTest/Config/BootstrapConfigurationTests.cs

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ public void TestDefaultBootstrapConfiguration()
3333
Assert.That(config.AgentEnabledAt, Is.EqualTo("Default value"));
3434
Assert.That(config.DebugStartupDelaySeconds, Is.EqualTo(0));
3535
Assert.That(config.ServerlessModeEnabled, Is.False);
36+
Assert.That(config.ServerlessFunctionName, Is.Null);
37+
Assert.That(config.ServerlessFunctionVersion, Is.Null);
3638
});
3739
}
3840

tests/Agent/UnitTests/Core.UnitTest/Configuration/DefaultConfigurationTests.cs

+86
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using NewRelic.Testing.Assertions;
1414
using NUnit.Framework;
1515
using Telerik.JustMock;
16+
using Telerik.JustMock.Expectations.Abstraction;
1617
using Telerik.JustMock.Helpers;
1718

1819
namespace NewRelic.Agent.Core.Configuration.UnitTest
@@ -2069,7 +2070,92 @@ public void ApplicationNamesPullsNameFromProcessIdIfAppDomainAppVirtualPathIsNul
20692070
);
20702071
}
20712072

2073+
[Test]
2074+
public void ApplicationNamesUsesLambdaFunctionNameIfBlank()
2075+
{
2076+
_runTimeConfig.ApplicationNames = new List<string>();
2077+
2078+
Mock.Arrange(() => _bootstrapConfiguration.ServerlessModeEnabled).Returns(true);
2079+
Mock.Arrange(() => _bootstrapConfiguration.ServerlessFunctionName).Returns("MyFunc");
2080+
Mock.Arrange(() => _bootstrapConfiguration.ServerlessFunctionVersion).Returns("2");
2081+
//Sets to default return null for all calls unless overriden by later arrange.
2082+
Mock.Arrange(() => _environment.GetEnvironmentVariable(Arg.IsAny<string>())).Returns<string>(null);
2083+
2084+
Mock.Arrange(() => _configurationManagerStatic.GetAppSetting(Constants.AppSettingsAppName)).Returns<string>(null);
2085+
2086+
_localConfig.application.name = new List<string>();
2087+
2088+
NrAssert.Multiple(
2089+
() => Assert.That(_defaultConfig.ApplicationNames.Count(), Is.EqualTo(1)),
2090+
() => Assert.That(_defaultConfig.ApplicationNames.FirstOrDefault(), Is.EqualTo("MyFunc")),
2091+
() => Assert.That(_defaultConfig.ServerlessFunctionVersion, Is.EqualTo("2")),
2092+
() => Assert.That(_defaultConfig.ApplicationNamesSource, Is.EqualTo("Environment Variable (AWS_LAMBDA_FUNCTION_NAME)"))
2093+
);
2094+
}
2095+
2096+
[Test]
2097+
public void ApplicationNamesUsesLambdaFunctionNameIfDefault()
2098+
{
2099+
_runTimeConfig.ApplicationNames = new List<string>();
2100+
2101+
Mock.Arrange(() => _bootstrapConfiguration.ServerlessModeEnabled).Returns(true);
2102+
Mock.Arrange(() => _bootstrapConfiguration.ServerlessFunctionName).Returns("MyFunc");
2103+
//Sets to default return null for all calls unless overriden by later arrange.
2104+
Mock.Arrange(() => _environment.GetEnvironmentVariable(Arg.IsAny<string>())).Returns<string>(null);
2105+
2106+
Mock.Arrange(() => _configurationManagerStatic.GetAppSetting(Constants.AppSettingsAppName)).Returns<string>(null);
2107+
2108+
_localConfig.application.name = new List<string> { "My Application" };
2109+
2110+
NrAssert.Multiple(
2111+
() => Assert.That(_defaultConfig.ApplicationNames.Count(), Is.EqualTo(1)),
2112+
() => Assert.That(_defaultConfig.ApplicationNames.FirstOrDefault(), Is.EqualTo("MyFunc")),
2113+
() => Assert.That(_defaultConfig.ApplicationNamesSource, Is.EqualTo("Environment Variable (AWS_LAMBDA_FUNCTION_NAME)"))
2114+
);
2115+
}
20722116

2117+
[Test]
2118+
public void ApplicationNamesDoesNotUseLambdaFunctionNameIfEnvVarSet()
2119+
{
2120+
_runTimeConfig.ApplicationNames = new List<string>();
2121+
2122+
Mock.Arrange(() => _bootstrapConfiguration.ServerlessModeEnabled).Returns(true);
2123+
Mock.Arrange(() => _bootstrapConfiguration.ServerlessFunctionName).Returns("MyFunc");
2124+
//Sets to default return null for all calls unless overriden by later arrange.
2125+
Mock.Arrange(() => _environment.GetEnvironmentVariable(Arg.IsAny<string>())).Returns<string>(null);
2126+
Mock.Arrange(() => _environment.GetEnvironmentVariable("NEW_RELIC_APP_NAME")).Returns("My App Name");
2127+
2128+
Mock.Arrange(() => _configurationManagerStatic.GetAppSetting(Constants.AppSettingsAppName)).Returns<string>(null);
2129+
2130+
_localConfig.application.name = new List<string> { "My Application" };
2131+
2132+
NrAssert.Multiple(
2133+
() => Assert.That(_defaultConfig.ApplicationNames.Count(), Is.EqualTo(1)),
2134+
() => Assert.That(_defaultConfig.ApplicationNames.FirstOrDefault(), Is.EqualTo("My App Name")),
2135+
() => Assert.That(_defaultConfig.ApplicationNamesSource, Is.EqualTo("Environment Variable (NEW_RELIC_APP_NAME)"))
2136+
);
2137+
}
2138+
2139+
[Test]
2140+
public void ApplicationNamesDoesNotUseLambdaFunctionNameIfBlank()
2141+
{
2142+
_runTimeConfig.ApplicationNames = new List<string>();
2143+
2144+
Mock.Arrange(() => _bootstrapConfiguration.ServerlessModeEnabled).Returns(true);
2145+
Mock.Arrange(() => _bootstrapConfiguration.ServerlessFunctionName).Returns("");
2146+
//Sets to default return null for all calls unless overriden by later arrange.
2147+
Mock.Arrange(() => _environment.GetEnvironmentVariable(Arg.IsAny<string>())).Returns<string>(null);
2148+
2149+
Mock.Arrange(() => _configurationManagerStatic.GetAppSetting(Constants.AppSettingsAppName)).Returns<string>(null);
2150+
2151+
_localConfig.application.name = new List<string> { "My Application" };
2152+
2153+
NrAssert.Multiple(
2154+
() => Assert.That(_defaultConfig.ApplicationNames.Count(), Is.EqualTo(1)),
2155+
() => Assert.That(_defaultConfig.ApplicationNames.FirstOrDefault(), Is.EqualTo("My Application")),
2156+
() => Assert.That(_defaultConfig.ApplicationNamesSource, Is.EqualTo("NewRelic Config"))
2157+
);
2158+
}
20732159
#endregion ApplicationNames
20742160

20752161

tests/Agent/UnitTests/Core.UnitTest/DataTransport/AgentSettingsTests.cs

+2
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,8 @@ public void serializes_correctly()
355355
Assert.That(agentSettings.AgentEnabledAt, Is.Not.Null);
356356
Assert.That(agentSettings.ServerlessModeEnabled, Is.False);
357357
Assert.That(agentSettings.LoggingLevel, Is.Not.Null);
358+
Assert.That(agentSettings.ServerlessFunctionName, Is.Null);
359+
Assert.That(agentSettings.ServerlessFunctionVersion, Is.Null);
358360
Assert.That(json, Is.EqualTo(expectedJson.Condense()));
359361
});
360362
}

tests/Agent/UnitTests/Core.UnitTest/DataTransport/ExhaustiveTestConfiguration.cs

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ public class ExhaustiveTestConfiguration : IConfiguration
1818

1919
public bool ServerlessModeEnabled => false;
2020

21+
public string ServerlessFunctionName => null;
22+
23+
public string ServerlessFunctionVersion => null;
24+
2125
public string AgentLicenseKey => "AgentLicenseKey";
2226

2327
public IEnumerable<string> ApplicationNames => new[] { "name1", "name2", "name3" };

0 commit comments

Comments
 (0)