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: Enable startup logging to Event Log for all applications on Windows. #1969

Merged
merged 2 commits into from Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/Agent/NewRelic/Agent/Core/Core.csproj
Expand Up @@ -43,6 +43,7 @@
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" />
<PackageReference Include="Serilog.Sinks.EventLog" Version="3.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="ILRepack" Version="2.0.16" />
Expand All @@ -60,7 +61,6 @@
<PackageReference Include="Grpc" Version="2.46.6" />
<PackageReference Include="Grpc.Core" Version="2.46.6" />
<PackageReference Include="System.Runtime.InteropServices.RuntimeInformation" Version="4.3.0" />
<PackageReference Include="Serilog.Sinks.EventLog" Version="3.1.0" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
Expand Down Expand Up @@ -129,13 +129,14 @@
<ILRepackInclude Include="@(PossibleRefsForILRepack)" Condition="'%(FileName)' == 'Serilog.Sinks.Async'" />
<ILRepackInclude Include="@(PossibleRefsForILRepack)" Condition="'%(FileName)' == 'Serilog.Sinks.Console'" />
<ILRepackInclude Include="@(PossibleRefsForILRepack)" Condition="'%(FileName)' == 'Serilog.Sinks.Debug'" />
<ILRepackInclude Include="@(PossibleRefsForILRepack)" Condition="'%(FileName)' == 'Serilog.Sinks.EventLog'" />
<ILRepackInclude Include="@(PossibleRefsForILRepack)" Condition="'%(FileName)' == 'Serilog.Sinks.File'" />
<ILRepackInclude Include="@(PossibleRefsForILRepack)" Condition="'%(FileName)' == 'ICSharpCode.SharpZipLib'" />
</ItemGroup>

<PropertyGroup>
<ILRepackIncludeCount Condition="'$(TargetFramework)' == 'net462'">20</ILRepackIncludeCount>
<ILRepackIncludeCount Condition="'$(TargetFramework)' == 'netstandard2.0'">16</ILRepackIncludeCount>
<ILRepackIncludeCount Condition="'$(TargetFramework)' == 'netstandard2.0'">17</ILRepackIncludeCount>
</PropertyGroup>

<Error Text="ILRepack of $(AssemblyName) ($(TargetFramework)) failed. A dependency is missing. Expected $(ILRepackIncludeCount) dependencies but found @(ILRepackInclude-&gt;Count())." Condition="@(ILRepackInclude-&gt;Count()) != $(ILRepackIncludeCount)" />
Expand Down
63 changes: 38 additions & 25 deletions src/Agent/NewRelic/Agent/Core/Logging/LoggerBootstrapper.cs
Expand Up @@ -11,8 +11,9 @@
using Logger = NewRelic.Agent.Core.Logging.Logger;
using NewRelic.Agent.Core.Logging;
using Serilog.Templates;
#if NETFRAMEWORK
using Serilog.Events;
#if NETSTANDARD2_0
using System.Runtime.InteropServices;
#endif

namespace NewRelic.Agent.Core
Expand Down Expand Up @@ -107,33 +108,46 @@ private static LoggerConfiguration ConfigureInMemoryLogSink(this LoggerConfigura
}

/// <summary>
/// Add the Event Log sink if running on .NET Framework
/// Configure an Event Log sink if running on Windows. Logs messages at Warning level and above. Intended for
/// use during bootstrapping and as a fallback if the file logging sink can't be created.
///
/// The Agent will create the event log source if it doesn't exist *and* if the app is running with
/// administrator privileges. Otherwise, it will silently do nothing.
///
/// It is possible to manually create the event log source in an elevated Powershell window:
/// New-EventLog -LogName "Application" -Source "New Relic .NET Agent"
///
/// </summary>
/// <param name="loggerConfiguration"></param>
private static LoggerConfiguration ConfigureEventLogSink(this LoggerConfiguration loggerConfiguration)
{
#if NETFRAMEWORK
const string eventLogName = "Application";
const string eventLogSourceName = "New Relic .NET Agent";
try
#if NETSTANDARD2_0
tippmar-nr marked this conversation as resolved.
Show resolved Hide resolved
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // event log is a Windows-only construct
{
loggerConfiguration
.WriteTo.Logger(configuration =>
{
configuration
.ExcludeAuditLog()
.WriteTo.EventLog(
source: eventLogSourceName,
logName: eventLogName,
restrictedToMinimumLevel: LogEventLevel.Warning,
outputTemplate: "{Level}: {Message}{NewLine}{Exception}",
manageEventSource: true // Serilog will create the event source if it doesn't exist *and* if the app is running with admin privileges
);
});
}
catch
{
// ignored -- there's nothing we can do at this point, as EventLog is our "fallback" logger and if it fails, we're out of luck
#endif
const string eventLogName = "Application";
const string eventLogSourceName = "New Relic .NET Agent";
try
{
loggerConfiguration
.WriteTo.Logger(configuration =>
{
configuration
.ExcludeAuditLog()
.WriteTo.EventLog(
source: eventLogSourceName,
logName: eventLogName,
restrictedToMinimumLevel: LogEventLevel.Warning,
outputTemplate: "{Level}: {Message}{NewLine}{Exception}",
manageEventSource: true
);
});
}
catch
{
// ignored -- there's nothing we can do at this point, as EventLog is our "fallback" logger and if it fails, we're out of luck
}
#if NETSTANDARD2_0
}
#endif
return loggerConfiguration;
Expand Down Expand Up @@ -197,11 +211,10 @@ private static LoggerConfiguration ConfigureFileSink(this LoggerConfiguration lo
catch (Exception ex)
{
Log.Logger.Warning(ex, "Unexpected exception when configuring file sink.");
#if NETFRAMEWORK

// Fallback to the event log sink if we cannot setup a file logger.
Log.Logger.Warning("Falling back to EventLog sink.");
loggerConfiguration.ConfigureEventLogSink();
#endif
}

return loggerConfiguration;
Expand Down