Skip to content

Commit 27d0ed0

Browse files
authored
feat: Add an option to disable the file system watcher. (#2536)
1 parent a3d1d9e commit 27d0ed0

File tree

14 files changed

+165
-19
lines changed

14 files changed

+165
-19
lines changed

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

+17
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,8 @@ public partial class configurationService
797797

798798
private bool forceNewTransactionOnNewThreadField;
799799

800+
private bool disableFileSystemWatcherField;
801+
800802
/// <summary>
801803
/// configurationService class constructor
802804
/// </summary>
@@ -810,6 +812,7 @@ public configurationService()
810812
this.sendDataOnExitThresholdField = ((float)(60000F));
811813
this.completeTransactionsOnThreadField = false;
812814
this.forceNewTransactionOnNewThreadField = false;
815+
this.disableFileSystemWatcherField = false;
813816
}
814817

815818
public string obscuringKey
@@ -1032,6 +1035,20 @@ public bool forceNewTransactionOnNewThread
10321035
}
10331036
}
10341037

1038+
[System.Xml.Serialization.XmlAttributeAttribute()]
1039+
[System.ComponentModel.DefaultValueAttribute(false)]
1040+
public bool disableFileSystemWatcher
1041+
{
1042+
get
1043+
{
1044+
return this.disableFileSystemWatcherField;
1045+
}
1046+
set
1047+
{
1048+
this.disableFileSystemWatcherField = value;
1049+
}
1050+
}
1051+
10351052
#region Clone method
10361053
/// <summary>
10371054
/// Create a clone of this configurationService object

src/Agent/NewRelic/Agent/Core/Config/Configuration.xsd

+8
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,14 @@
223223
</xs:annotation>
224224
</xs:attribute>
225225

226+
<xs:attribute name="disableFileSystemWatcher" type="xs:boolean" default="false">
227+
<xs:annotation>
228+
<xs:documentation>
229+
If disableFileSystemWatcher is set to true, then newrelic.config and instrumentation XML file changes, additions, or deletions will not be detected and applied after the application has been started.
230+
</xs:documentation>
231+
</xs:annotation>
232+
</xs:attribute>
233+
226234
</xs:complexType>
227235
</xs:element>
228236

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

+6
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ public class ConfigurationTracker : IDisposable
2525

2626
public ConfigurationTracker(IConfigurationService configurationService, INativeMethods nativeMethods)
2727
{
28+
if (configurationService.Configuration.DisableFileSystemWatcher)
29+
{
30+
Log.Debug("Live updates to newrelic.config will not be applied because they have been disabled by local configuration.");
31+
return;
32+
}
33+
2834
_nativeMethods = nativeMethods;
2935
var fileName = configurationService.Configuration.NewRelicConfigFilePath;
3036
if (fileName == null)

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

+13
Original file line numberDiff line numberDiff line change
@@ -2058,6 +2058,19 @@ public IEnumerable<IDictionary<string, string>> IgnoredInstrumentation
20582058
}
20592059
}
20602060

2061+
public bool DisableFileSystemWatcher
2062+
{
2063+
get
2064+
{
2065+
if(ServerlessModeEnabled || !LoggingEnabled)
2066+
{
2067+
return true;
2068+
}
2069+
2070+
return EnvironmentOverrides(_localConfiguration.service.disableFileSystemWatcher, "NEW_RELIC_DISABLE_FILE_SYSTEM_WATCHER");
2071+
}
2072+
}
2073+
20612074
#region AI Monitoring
20622075

20632076
public bool AiMonitoringEnabled

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

+3
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,9 @@ public ReportedConfiguration(IConfiguration configuration)
662662
[JsonProperty("agent.instrumentation.ignore")]
663663
public IEnumerable<IDictionary<string, string>> IgnoredInstrumentation => _configuration.IgnoredInstrumentation;
664664

665+
[JsonProperty("agent.disable_file_system_watcher")]
666+
public bool DisableFileSystemWatcher => _configuration.DisableFileSystemWatcher;
667+
665668
[JsonProperty("agent.ai_monitoring.enabled")]
666669
public bool AiMonitoringEnabled => _configuration.AiMonitoringEnabled;
667670

src/Agent/NewRelic/Agent/Core/Instrumentation/InstrumentationWatcher.cs

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright 2020 New Relic, Inc. All rights reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4+
using NewRelic.Agent.Configuration;
45
using NewRelic.Agent.Core.Utilities;
56
using NewRelic.Agent.Core.Wrapper;
67
using NewRelic.Core.Logging;
@@ -16,18 +17,26 @@ public class InstrumentationWatcher : IDisposable
1617

1718
private readonly IInstrumentationService _instrumentationService;
1819
private readonly IWrapperService _wrapperService;
20+
private readonly IConfigurationService _configurationService;
1921

2022
private List<FileSystemWatcher> _fileWatchers;
2123
private SignalableAction _action;
2224

23-
public InstrumentationWatcher(IWrapperService wrapperService, IInstrumentationService instrumentationService)
25+
public InstrumentationWatcher(IWrapperService wrapperService, IInstrumentationService instrumentationService, IConfigurationService configurationService)
2426
{
2527
_wrapperService = wrapperService;
2628
_instrumentationService = instrumentationService;
29+
_configurationService = configurationService;
2730
}
2831

2932
public void Start()
3033
{
34+
if (_configurationService.Configuration.DisableFileSystemWatcher)
35+
{
36+
Log.Debug("Live instrumentation updates due to instrumentation file changes will not be applied because they have been disabled by local configuration.");
37+
return;
38+
}
39+
3140
if (AgentInstallConfiguration.HomeExtensionsDirectory == null)
3241
{
3342
Log.Warn("Live instrumentation updates due to instrumentation file changes will not be applied because HomeExtensionsDirectory is null.");

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ public interface IConfiguration
212212
bool LoggingEnabled { get; }
213213
string LoggingLevel { get; }
214214
IEnumerable<IDictionary<string, string>> IgnoredInstrumentation { get; }
215-
215+
bool DisableFileSystemWatcher { get; }
216216
bool AiMonitoringEnabled { get; }
217217
bool AiMonitoringStreamingEnabled { get; }
218218
bool AiMonitoringRecordContentEnabled { get; }

tests/Agent/IntegrationTests/IntegrationTestHelpers/NewRelicConfigModifier.cs

+6
Original file line numberDiff line numberDiff line change
@@ -497,5 +497,11 @@ public void SetDebugStartupDelaySeconds(int delaySeconds)
497497
CommonUtils.ModifyOrCreateXmlAttributeInNewRelicConfig(_configFilePath, new[] { "configuration", },
498498
"debugStartupDelaySeconds", delaySeconds.ToString());
499499
}
500+
501+
public NewRelicConfigModifier SetDisableFileSystemWatcher(bool enabled = true)
502+
{
503+
CommonUtils.ModifyOrCreateXmlAttributeInNewRelicConfig(_configFilePath, new[] { "configuration", "service" }, "disableFileSystemWatcher", enabled.ToString().ToLower());
504+
return this;
505+
}
500506
}
501507
}

tests/Agent/IntegrationTests/IntegrationTests/ReJit/NetCore/RejitAddFile.cs

+29-9
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,12 @@ public abstract class RejitAddFileBase<TFixture> : NewRelicIntegrationTest<TFixt
2525
where TFixture:AspNetCoreReJitMvcApplicationFixture
2626
{
2727
private readonly AspNetCoreReJitMvcApplicationFixture _fixture;
28+
private readonly bool _disableFileSystemWatcher;
2829

29-
protected RejitAddFileBase(TFixture fixture, ITestOutputHelper output) : base(fixture)
30+
protected RejitAddFileBase(TFixture fixture, ITestOutputHelper output, bool disableFileSystemWatcher) : base(fixture)
3031
{
3132
_fixture = fixture;
33+
_disableFileSystemWatcher = disableFileSystemWatcher;
3234

3335
_fixture.TestLogger = output;
3436
_fixture.Actions(
@@ -37,6 +39,7 @@ protected RejitAddFileBase(TFixture fixture, ITestOutputHelper output) : base(fi
3739
var configModifier = new NewRelicConfigModifier(_fixture.DestinationNewRelicConfigFilePath);
3840
configModifier.SetLogLevel("finest");
3941
configModifier.AutoInstrumentBrowserMonitoring(false);
42+
configModifier.SetDisableFileSystemWatcher(disableFileSystemWatcher);
4043
},
4144
exerciseApplication: () =>
4245
{
@@ -61,20 +64,29 @@ public void Test()
6164
{
6265
//transactions
6366
new Assertions.ExpectedMetric { metricName = @"WebTransaction/MVC/Home/Index", callCount = 1 },
64-
new Assertions.ExpectedMetric { metricName = @"WebTransaction/Custom/MyCustomAddMetricName", callCount = 1 },
6567
new Assertions.ExpectedMetric { metricName = @"WebTransaction/MVC/Rejit/GetAddFile", callCount = 1 },
6668

6769
// Unscoped
6870
new Assertions.ExpectedMetric { metricName = @"DotNet/HomeController/Index", callCount = 1 },
69-
new Assertions.ExpectedMetric { metricName = @"Custom/MyCustomAddMetricName", callCount = 1 },
70-
new Assertions.ExpectedMetric { metricName = @"DotNet/RejitController/GetAddFile", callCount = 2 },
7171

7272
// Scoped
7373
new Assertions.ExpectedMetric { metricName = @"DotNet/HomeController/Index", metricScope = "WebTransaction/MVC/Home/Index", callCount = 1 },
74-
new Assertions.ExpectedMetric { metricName = @"Custom/MyCustomAddMetricName", metricScope = "WebTransaction/Custom/MyCustomAddMetricName", callCount = 1 },
7574
new Assertions.ExpectedMetric { metricName = @"DotNet/RejitController/GetAddFile", metricScope = "WebTransaction/MVC/Rejit/GetAddFile", callCount = 1 }
7675
};
7776

77+
// Id file system watcher is disabled, these won't exist.
78+
if (_disableFileSystemWatcher)
79+
{
80+
expectedMetrics.Add(new Assertions.ExpectedMetric { metricName = @"DotNet/RejitController/GetAddFile", callCount = 1 });
81+
}
82+
else
83+
{
84+
expectedMetrics.Add(new Assertions.ExpectedMetric { metricName = @"WebTransaction/Custom/MyCustomAddMetricName", callCount = 1 });
85+
expectedMetrics.Add(new Assertions.ExpectedMetric { metricName = @"Custom/MyCustomAddMetricName", callCount = 1 });
86+
expectedMetrics.Add(new Assertions.ExpectedMetric { metricName = @"Custom/MyCustomAddMetricName", metricScope = "WebTransaction/Custom/MyCustomAddMetricName", callCount = 1 });
87+
expectedMetrics.Add(new Assertions.ExpectedMetric { metricName = @"DotNet/RejitController/GetAddFile", callCount = 2 });
88+
}
89+
7890
var metrics = CommonUtils.GetMetrics(_fixture.AgentLog);
7991
_fixture.TestLogger?.WriteLine(_fixture.AgentLog.GetFullLogAsString());
8092

@@ -84,18 +96,26 @@ public void Test()
8496
}
8597
}
8698

87-
public class RejitAddFile : RejitAddFileBase<AspNetCoreReJitMvcApplicationFixture>
99+
public class RejitAddFileWithFileWatcherEnabled : RejitAddFileBase<AspNetCoreReJitMvcApplicationFixture>
100+
{
101+
public RejitAddFileWithFileWatcherEnabled(AspNetCoreReJitMvcApplicationFixture fixture, ITestOutputHelper output)
102+
: base(fixture, output, false)
103+
{
104+
}
105+
}
106+
107+
public class RejitAddFileWithFileWatcherDisabled : RejitAddFileBase<AspNetCoreReJitMvcApplicationFixture>
88108
{
89-
public RejitAddFile(AspNetCoreReJitMvcApplicationFixture fixture, ITestOutputHelper output)
90-
: base(fixture, output)
109+
public RejitAddFileWithFileWatcherDisabled(AspNetCoreReJitMvcApplicationFixture fixture, ITestOutputHelper output)
110+
: base(fixture, output, true)
91111
{
92112
}
93113
}
94114

95115
public class RejitAddFileWithTieredCompilation : RejitAddFileBase<AspNetCoreReJitMvcApplicationFixtureWithTieredCompilation>
96116
{
97117
public RejitAddFileWithTieredCompilation(AspNetCoreReJitMvcApplicationFixtureWithTieredCompilation fixture, ITestOutputHelper output)
98-
: base(fixture, output)
118+
: base(fixture, output, false)
99119
{
100120
}
101121
}

tests/Agent/IntegrationTests/IntegrationTests/ReJit/NetFramework/RejitAddFile.cs

+35-6
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,25 @@ namespace NewRelic.Agent.IntegrationTests.ReJit.NetFramework
2020
/// Files: Integration.Testing.AddXmlFileTest.xml
2121
/// </summary>
2222
[NetFrameworkTest]
23-
public class RejitAddFile : NewRelicIntegrationTest<AspNetFrameworkReJitMvcApplicationFixture>
23+
public abstract class RejitAddFileBase<TFixture> : NewRelicIntegrationTest<TFixture>
24+
where TFixture : AspNetFrameworkReJitMvcApplicationFixture
2425
{
2526
private readonly AspNetFrameworkReJitMvcApplicationFixture _fixture;
27+
private readonly bool _disableFileSystemWatcher;
2628

27-
public RejitAddFile(AspNetFrameworkReJitMvcApplicationFixture fixture, ITestOutputHelper output)
29+
public RejitAddFileBase(TFixture fixture, ITestOutputHelper output, bool disableFileSystemWatcher)
2830
: base(fixture)
2931
{
3032
_fixture = fixture;
33+
_disableFileSystemWatcher = disableFileSystemWatcher;
3134

3235
_fixture.TestLogger = output;
3336
_fixture.Actions(
3437
setupConfiguration: () =>
3538
{
3639
var configModifier = new NewRelicConfigModifier(_fixture.DestinationNewRelicConfigFilePath);
3740
configModifier.AutoInstrumentBrowserMonitoring(false);
41+
configModifier.SetDisableFileSystemWatcher(disableFileSystemWatcher);
3842
},
3943
exerciseApplication: () =>
4044
{
@@ -59,20 +63,29 @@ public void Test()
5963
{
6064
//transactions
6165
new Assertions.ExpectedMetric { metricName = @"WebTransaction/MVC/HomeController/Index", CallCountAllHarvests = 1 },
62-
new Assertions.ExpectedMetric { metricName = @"WebTransaction/Custom/MyCustomAddMetricName", CallCountAllHarvests = 1 },
6366
new Assertions.ExpectedMetric { metricName = @"WebTransaction/MVC/RejitController/GetAddFile", CallCountAllHarvests = 1 },
6467

6568
// Unscoped
6669
new Assertions.ExpectedMetric { metricName = @"DotNet/HomeController/Index", CallCountAllHarvests = 1 },
67-
new Assertions.ExpectedMetric { metricName = @"Custom/MyCustomAddMetricName", CallCountAllHarvests = 1 },
68-
new Assertions.ExpectedMetric { metricName = @"DotNet/RejitController/GetAddFile", CallCountAllHarvests = 2 },
6970

7071
// Scoped
7172
new Assertions.ExpectedMetric { metricName = @"DotNet/HomeController/Index", metricScope = "WebTransaction/MVC/HomeController/Index", CallCountAllHarvests = 1 },
72-
new Assertions.ExpectedMetric { metricName = @"Custom/MyCustomAddMetricName", metricScope = "WebTransaction/Custom/MyCustomAddMetricName", CallCountAllHarvests = 1 },
7373
new Assertions.ExpectedMetric { metricName = @"DotNet/RejitController/GetAddFile", metricScope = "WebTransaction/MVC/RejitController/GetAddFile", CallCountAllHarvests = 1 }
7474
};
7575

76+
// Id file system watcher is disabled, these won't exist.
77+
if (_disableFileSystemWatcher)
78+
{
79+
expectedMetrics.Add(new Assertions.ExpectedMetric { metricName = @"DotNet/RejitController/GetAddFile", CallCountAllHarvests = 1 });
80+
}
81+
else
82+
{
83+
expectedMetrics.Add(new Assertions.ExpectedMetric { metricName = @"WebTransaction/Custom/MyCustomAddMetricName", CallCountAllHarvests = 1 });
84+
expectedMetrics.Add(new Assertions.ExpectedMetric { metricName = @"Custom/MyCustomAddMetricName", CallCountAllHarvests = 1 });
85+
expectedMetrics.Add(new Assertions.ExpectedMetric { metricName = @"Custom/MyCustomAddMetricName", metricScope = "WebTransaction/Custom/MyCustomAddMetricName", CallCountAllHarvests = 1 });
86+
expectedMetrics.Add(new Assertions.ExpectedMetric { metricName = @"DotNet/RejitController/GetAddFile", CallCountAllHarvests = 2 });
87+
}
88+
7689
var metrics = CommonUtils.GetMetrics(_fixture.AgentLog);
7790
_fixture.TestLogger?.WriteLine(_fixture.AgentLog.GetFullLogAsString());
7891

@@ -81,4 +94,20 @@ public void Test()
8194
);
8295
}
8396
}
97+
98+
public class RejitAddFileWithFileWatcherEnabled : RejitAddFileBase<AspNetFrameworkReJitMvcApplicationFixture>
99+
{
100+
public RejitAddFileWithFileWatcherEnabled(AspNetFrameworkReJitMvcApplicationFixture fixture, ITestOutputHelper output)
101+
: base(fixture, output, false)
102+
{
103+
}
104+
}
105+
106+
public class RejitAddFileWithFileWatcherDisabled : RejitAddFileBase<AspNetFrameworkReJitMvcApplicationFixture>
107+
{
108+
public RejitAddFileWithFileWatcherDisabled(AspNetFrameworkReJitMvcApplicationFixture fixture, ITestOutputHelper output)
109+
: base(fixture, output, true)
110+
{
111+
}
112+
}
84113
}

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

+33
Original file line numberDiff line numberDiff line change
@@ -4023,6 +4023,39 @@ public void LoggingLevelValueIsCached()
40234023

40244024
#endregion Agent Logs
40254025

4026+
[TestCase(false, null, true, false, ExpectedResult = false)] // default
4027+
[TestCase(true, null, true, false, ExpectedResult = true)]
4028+
[TestCase(false, true, true, false, ExpectedResult = true)]
4029+
[TestCase(true, false, true, false, ExpectedResult = false)]
4030+
[TestCase(false, null, false, false, ExpectedResult = true)]
4031+
[TestCase(false, null, false, true, ExpectedResult = true)]
4032+
[TestCase(false, null, true, true, ExpectedResult = true)]
4033+
[TestCase(true, null, false, false, ExpectedResult = true)]
4034+
[TestCase(true, null, false, true, ExpectedResult = true)]
4035+
[TestCase(true, null, true, true, ExpectedResult = true)]
4036+
[TestCase(false, true, false, false, ExpectedResult = true)]
4037+
[TestCase(false, true, false, true, ExpectedResult = true)]
4038+
[TestCase(false, true, true, true, ExpectedResult = true)]
4039+
[TestCase(true, false, false, false, ExpectedResult = true)]
4040+
[TestCase(true, false, false, true, ExpectedResult = true)]
4041+
[TestCase(true, false, true, true, ExpectedResult = true)]
4042+
public bool ValidateDisableFileSystemWatcher(bool localWatcherDisabled, bool? envWatcherDisabled, bool loggingEnabled, bool serverlessMode)
4043+
{
4044+
// Setup config values
4045+
_localConfig.service.disableFileSystemWatcher = localWatcherDisabled;
4046+
4047+
if (envWatcherDisabled.HasValue)
4048+
{
4049+
Mock.Arrange(() => _environment.GetEnvironmentVariable("NEW_RELIC_DISABLE_FILE_SYSTEM_WATCHER")).Returns(envWatcherDisabled.ToString().ToLower());
4050+
}
4051+
4052+
_localConfig.log.enabled = loggingEnabled;
4053+
Mock.Arrange(() => _bootstrapConfiguration.ServerlessModeEnabled).Returns(serverlessMode);
4054+
4055+
// test
4056+
return _defaultConfig.DisableFileSystemWatcher;
4057+
}
4058+
40264059
private void CreateDefaultConfiguration()
40274060
{
40284061
_defaultConfig = new TestableDefaultConfiguration(_environment, _localConfig, _serverConfig, _runTimeConfig, _securityPoliciesConfiguration, _bootstrapConfiguration, _processStatic, _httpRuntimeStatic, _configurationManagerStatic, _dnsStatic);

0 commit comments

Comments
 (0)