Skip to content

Commit

Permalink
chore: Update Serilog to latest (#2694)
Browse files Browse the repository at this point in the history
* Updated Serilog to latest everywhere

* Fix ilrepack issues for serilog

* Refactor GuidGenerator to work around ILRepack of System.Diagnostics.DiagnosticSource

* Null checking

* Visibility bypasser caching
  • Loading branch information
tippmar-nr authored Aug 20, 2024
1 parent e35cda3 commit d725278
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 27 deletions.
19 changes: 11 additions & 8 deletions src/Agent/NewRelic/Agent/Core/Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,20 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Serilog" Version="[3.0.1]" />
<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" Version="4.0.1" />
<PackageReference Include="Serilog.Sinks.Async" Version="2.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.Debug" Version="3.0.0" />
<PackageReference Include="Serilog.Sinks.EventLog" Version="3.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="ILRepack" Version="2.0.34">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SharpZipLib" Version="1.4.2" />
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="8.0.1" />
</ItemGroup>

<ItemGroup>
Expand All @@ -79,7 +80,6 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="6.0.1" />
<ProjectReference Include="..\Extensions\NewRelic.Agent.Extensions\NewRelic.Agent.Extensions.csproj" />
</ItemGroup>

Expand Down Expand Up @@ -110,6 +110,9 @@
<ILRepackInclude Include="@(PossibleRefsForILRepack)" Condition="'%(FileName)' == 'Serilog.Sinks.Debug'" />
<ILRepackInclude Include="@(PossibleRefsForILRepack)" Condition="'%(FileName)' == 'Serilog.Sinks.EventLog'" />
<ILRepackInclude Include="@(PossibleRefsForILRepack)" Condition="'%(FileName)' == 'Serilog.Sinks.File'" />
<!-- System.Diagnostics.DiagnosticSource and System.Threading.Channels are a dependency of Serilog -->
<ILRepackInclude Include="@(PossibleRefsForILRepack)" Condition="'%(FileName)' == 'System.Diagnostics.DiagnosticSource'" />
<ILRepackInclude Include="@(PossibleRefsForILRepack)" Condition="'%(FileName)' == 'System.Threading.Channels'" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net462'">
Expand All @@ -132,8 +135,8 @@
</ItemGroup>

<PropertyGroup>
<ILRepackIncludeCount Condition="'$(TargetFramework)' == 'net462'">18</ILRepackIncludeCount>
<ILRepackIncludeCount Condition="'$(TargetFramework)' == 'netstandard2.0'">15</ILRepackIncludeCount>
<ILRepackIncludeCount Condition="'$(TargetFramework)' == 'net462'">20</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
90 changes: 74 additions & 16 deletions src/Agent/NewRelic/Agent/Core/Utilities/GuidGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,30 @@
// SPDX-License-Identifier: Apache-2.0

using NewRelic.Agent.Extensions.Logging;
using NewRelic.Reflection;
using System;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Threading;

namespace NewRelic.Agent.Core.Utilities
{
[NrExcludeFromCodeCoverage]
public static class GuidGenerator
{
/// Our testing shows that RngCryptoServiceProvider library is threadsafe and is more performant
/// than Random library when generating random numbers during thread contention.
private static readonly RNGCryptoServiceProvider RngCryptoServiceProvider = new RNGCryptoServiceProvider();
private static Func<string> _traceGeneratorFunc = GetTraceIdFromCurrentActivity;

private static bool _initialized;
private static object _lockObj = new();
private static bool _hasDiagnosticSourceReference;

private static Func<object, object> _fieldReadAccessor;
private static Func<object, object> _valuePropertyAccessor;
private static Func<object, object> _traceIdGetter;
private static Func<object, object> _idFormatGetter;

/// <summary>
/// Returns a newrelic style guid.
/// https://source.datanerd.us/agents/agent-specs/blob/2ad6637ded7ec3784de40fbc88990e06525127b8/Cross-Application-Tracing-PORTED.md#guid
Expand All @@ -33,20 +42,26 @@ public static string GenerateNewRelicTraceId()
{
try
{
return _traceGeneratorFunc();
}
catch (Exception ex)
{
// If the app does not reference System.Diagnostics.DiagnosticSource then Activity.Current will not be available.
// A FileNotFoundException occurs when System.Diagnostics.DiagnosticSource is unavailble.

if (!(ex is FileNotFoundException))
var retVal = _traceGeneratorFunc();
if (retVal == null)
{
Log.Warn(ex, "Unexpected exception type when attempting to generate a trace ID from Activity.Current");
if (!_hasDiagnosticSourceReference)
{
// Fall back to using our standard method of generating traceIds if the application doesn't reference DiagnosticSource
Log.Info("No reference to DiagnosticSource; trace IDs will be generated using the standard generator");
Interlocked.Exchange(ref _traceGeneratorFunc, GenerateTraceId);
return _traceGeneratorFunc();
}

// couldn't get a traceId from the current activity (maybe there wasn't one), so fallback to the standard generator for this request only
return GenerateTraceId();
}

// Fall back to using our standard method of generating traceIds.
Log.Info($"Trace IDs will be generated using the standard generator");
return retVal;
}
catch (Exception e)
{
Log.Info(e, "Unexpected exception generating traceId using the current activity. Falling back to the standard generator");
Interlocked.Exchange(ref _traceGeneratorFunc, GenerateTraceId);
return _traceGeneratorFunc();
}
Expand All @@ -63,12 +78,55 @@ private static string GenerateTraceId()

private static string GetTraceIdFromCurrentActivity()
{
if (Activity.Current != default && Activity.Current.IdFormat == ActivityIdFormat.W3C)
// because we ILRepack System.Diagnostics.DiagnosticSource, we have to look for the app's reference to it (if there is one)
// and use reflection to get the trace id from the current activity

// initialize one time
if (!_initialized)
{
return Activity.Current.TraceId.ToString();
lock (_lockObj)
{
if (!_initialized)
{
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
// find System.Diagnostics.DiagnosticSource
var diagnosticSourceAssembly = Array.Find(assemblies, a => a.FullName.StartsWith("System.Diagnostics.DiagnosticSource"));
if (diagnosticSourceAssembly != null) // customer app might not reference the assembly
{
_hasDiagnosticSourceReference = true;

// find the Activity class
var activityType = diagnosticSourceAssembly.GetType("System.Diagnostics.Activity");
_fieldReadAccessor = VisibilityBypasser.Instance.GenerateFieldReadAccessor<object>(activityType, "s_current");
}

_initialized = true;
}
}
}

return GenerateTraceId();
if (!_hasDiagnosticSourceReference)
return null;

var current = _fieldReadAccessor(null); // s_current is a static, so we don't need an object instance
if (current == null)
return null;

// get the Value property
_valuePropertyAccessor ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<object>(current.GetType(), "Value");
var value = _valuePropertyAccessor(current);
if (value == null)
return null;

// get IdFormat property
_idFormatGetter ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<object>(value.GetType(), "IdFormat");
var idFormat = _idFormatGetter(value);
if (idFormat == null || Enum.GetName(idFormat.GetType(), idFormat) != "W3C") // make sure it's in W3C trace id format
return null;

// get TraceId property
_traceIdGetter ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<object>(value.GetType(), "TraceId");
return _traceIdGetter(value).ToString();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Serilog" Version="[3.0.1]" />
<PackageReference Include="Serilog.Sinks.Console" Version="[4.1.0]" />
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" />
<PackageReference Include="Serilog" Version="4.0.1" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.Debug" Version="3.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(RootProjectDirectory)\src\Agent\NewRelic\Agent\Core\Core.csproj" />
Expand Down

0 comments on commit d725278

Please sign in to comment.