Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit

Permalink
Return Id generation algorithm, use Machine name on platforms which s…
Browse files Browse the repository at this point in the history
…upport that
  • Loading branch information
Liudmila Molkova committed Feb 8, 2017
1 parent 62c7055 commit 3864212
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.1-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.3-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.3-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.5-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.5-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="System\Diagnostics\DiagnosticSource.cs" />
<Compile Include="System\Diagnostics\DiagnosticListener.cs" />
Expand All @@ -35,17 +37,23 @@
</ItemGroup>
<ItemGroup Condition=" '$(TargetGroup)' != 'netstandard1.1'">
<Compile Include="System\Diagnostics\Activity.cs" />
<Compile Include="System\Diagnostics\DiagnosticSourceActivity.cs" />
<Compile Include="System\Diagnostics\DiagnosticSourceActivity.cs" />
<None Include="ActivityUserGuide.md" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetGroup)' != 'net45' And '$(TargetGroup)' != 'netstandard1.1'">
<Compile Include="System\Diagnostics\Activity.net46.cs" />
<Compile Include="System\Diagnostics\Activity.Current.net46.cs" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetGroup)' == 'net45' ">
<Compile Include="System\Diagnostics\Activity.net45.cs" />
<Compile Include="System\Diagnostics\Activity.Current.net45.cs" />
<TargetingPackReference Include="System" />
<TargetingPackReference Include="System.Runtime.Remoting" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetGroup)' == 'netstandard1.3' ">
<Compile Include="System\Diagnostics\Activity.Id.Random.cs" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetGroup)' == 'netstandard1.5' Or '$(TargetGroup)' == 'net45' Or '$(TargetGroup)' == 'netcoreapp'">
<Compile Include="System\Diagnostics\Activity.Id.MachineName.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Collections" />
<Reference Include="System.Diagnostics.Debug" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.

using System.Runtime.Remoting.Messaging;
using System.Threading;

namespace System.Diagnostics
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace System.Diagnostics
{
public partial class Activity
{
#region private
private string generateUniquePrefix()
{
int uniqNum = (int)Stopwatch.GetTimestamp();
return $"{s_rootIdPrefix}{Environment.MachineName}_{uniqNum:x}";
}
#endregion
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace System.Diagnostics
{
public partial class Activity
{
#region private
private string generateUniquePrefix()
{
byte[] bytes = new byte[8];
s_random.Value.NextBytes(bytes);

return $"{s_rootIdPrefix}{BitConverter.ToUInt64(bytes, 0):x}";
}
#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -265,34 +265,38 @@ private string GenerateId()
{
// Normal start within the process
Debug.Assert(!string.IsNullOrEmpty(Parent.Id));
ret = appendSuffix(Parent.Id, $"{Interlocked.Increment(ref Parent._currentChildId)}");
ret = appendSuffix(Parent.Id, Interlocked.Increment(ref Parent._currentChildId).ToString());
}
else if (ParentId != null)
{
// Start from outside the process (e.g. incoming HTTP)
Debug.Assert(ParentId.Length != 0);
ret = appendSuffix(ParentId, $"{Interlocked.Increment(ref s_currentRootId):x}");
ret = appendSuffix(ParentId, "I_" + Interlocked.Increment(ref s_currentRootId));
}
else
{
// A Root Activity (no parent).
ret = generateRootId();
}

// Useful place to place a conditional breakpoint.
return ret;
}


private string appendSuffix(string parentId, string suffix)
{
#if DEBUG
suffix = OperationName + "_" + suffix;
#endif
if (parentId.Length + suffix.Length <= 127)
return $"{parentId}.{suffix}";
return parentId + s_idDelimiter + suffix;

//Id overflow:
//find position in RequestId to trim
int trimPosition = parentId.Length - 1;
while (trimPosition > 0)
{
if ((parentId[trimPosition] == '.' || parentId[trimPosition] == '#')
if ((parentId[trimPosition] == s_idDelimiter || parentId[trimPosition] == s_overflowDelimiter)
&& trimPosition <= 119) //overflow suffix length is 8 + 1 for #.
break;
trimPosition--;
Expand All @@ -306,19 +310,38 @@ private string appendSuffix(string parentId, string suffix)
byte[] bytes = new byte[4];
s_random.Value.NextBytes(bytes);

return $"{parentId.Substring(0, trimPosition)}#{BitConverter.ToUInt32(bytes, 0):x8}";
return parentId.Substring(0, trimPosition) +
s_overflowDelimiter +
BitConverter.ToUInt32(bytes, 0).ToString("x8");
}

private string generateRootId()
{
byte[] bytes = new byte[8];
s_random.Value.NextBytes(bytes);
return $"/{BitConverter.ToUInt64(bytes, 0):x}";
if (s_uniqPrefix == null)
{
// Here we make an ID to represent the Process/AppDomain. Ideally we use process ID but
// it is unclear if we have that ID handy. Currently we use low bits of high freq tick
// as a unique random number (which is not bad, but loses randomness for startup scenarios).
Interlocked.CompareExchange(ref s_uniqPrefix, generateUniquePrefix(), null);
}

#if DEBUG
string ret = s_uniqPrefix + OperationName + s_idDelimiter + Interlocked.Increment(ref s_currentRootId);
#else // To keep things short, we drop the operation name
string ret = s_uniqPrefix + s_idDelimiter + Interlocked.Increment(ref s_currentRootId);
#endif
return ret;
}

// Used to generate an ID
int _currentChildId; // A unique number for all children of this activity.
static int s_currentRootId; // A unique number inside the appdomain.
private int _currentChildId; // A unique number for all children of this activity.
private static int s_currentRootId; // A unique number inside the appdomain.
private static string s_uniqPrefix;

private static char s_idDelimiter = '.';
private static char s_overflowDelimiter = '#';
private static char s_rootIdPrefix = '/';

private static readonly Lazy<Random> s_random = new Lazy<Random>();
/// <summary>
/// Having our own key-value linked list allows us to be more efficient
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,22 @@ public void IdGenerationInternalParent()
var t1 = Task.Run(() => child1.Start());
var t2 = Task.Run(() => child2.Start());
Task.WhenAll(t1, t2).Wait();
#if DEBUG
Assert.Equal($"{parent.Id}.{child1.OperationName}_1", child1.Id);
Assert.Equal($"{parent.Id}.{child2.OperationName}_2", child2.Id);
#else
Assert.Equal(parent.Id + ".1", child1.Id);
Assert.Equal(parent.Id + ".2", child2.Id);
#endif
child1.Stop();
child2.Stop();
var child3 = new Activity("child3");
child3.Start();
#if DEBUG
Assert.Equal($"{parent.Id}.{child3.OperationName}_3", child3.Id);
#else
Assert.Equal(parent.Id + ".3", child3.Id);
#endif
}

/// <summary>
Expand Down

0 comments on commit 3864212

Please sign in to comment.