Skip to content

Commit 65e5a88

Browse files
authored
trace2: add performance format target (#1151)
This series adds the performance format target for TRACE2 tracing. The first two patches are small fixes for bugs I noticed as I was testing the performance format target. The first moves the `FormatTargetTypes` enum from the specific `Trace2StreamWriter` class to the shared `Trace2Writer` class. The second ensures the normal format event names are written in snake case (rather than lowercase). The third patch adds the ability to get the "depth" of the process. Because Sids and depth are process-related concepts, it removes the SidManager class and moved depth/sid-related properties and methods into the ProcessManager class. The fourth patch adds the performance format target. It includes a few notable components: 1. A new GetMessage method to ensure message strings written to normal and performance targets are not duplicated. 2. A new PerformanceFormatComponent class to track sizing of optional properties of performance format messages. 3. A BuildSpan method that Trace2Message children use to create correctly-sized "spans" for optional properties of performance format messages. A span is a piece of the message beginning with a pipe (|) and ending just before the next pipe or the end of the message. 4. A BuildTimeSpan method that adjusts spans for long/short times. In future, when we have events that include performance format string span components, we will need to add an additional method to handle them.
2 parents d1b9b8b + 59a2692 commit 65e5a88

File tree

18 files changed

+345
-77
lines changed

18 files changed

+345
-77
lines changed

src/shared/Atlassian.Bitbucket.UI.Avalonia/Program.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ private static void AppMain(object o)
4747

4848
// Set the session id (sid) for the helper process, to be
4949
// used when TRACE2 tracing is enabled.
50-
SidManager.CreateSid();
50+
ProcessManager.CreateSid();
5151
using (var context = new CommandContext())
5252
using (var app = new HelperApplication(context))
5353
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using GitCredentialManager;
2+
using Xunit;
3+
4+
namespace Core.Tests;
5+
6+
public class ProcessManagerTests
7+
{
8+
[Theory]
9+
[InlineData("", 0)]
10+
[InlineData("foo", 0)]
11+
[InlineData("foo/bar", 1)]
12+
[InlineData("foo/bar/baz", 2)]
13+
public void CreateSid_Envar_Returns_Expected_Sid(string input, int expected)
14+
{
15+
ProcessManager.Sid = input;
16+
var actual = ProcessManager.GetProcessDepth();
17+
18+
Assert.Equal(expected, actual);
19+
}
20+
21+
[Theory]
22+
[InlineData("", 0)]
23+
[InlineData("foo", 0)]
24+
[InlineData("foo/bar", 1)]
25+
[InlineData("foo/bar/baz", 2)]
26+
public void TryGetProcessDepth_Returns_Expected_Depth(string input, int expected)
27+
{
28+
ProcessManager.Sid = input;
29+
var actual = ProcessManager.GetProcessDepth();
30+
31+
Assert.Equal(expected, actual);
32+
}
33+
}

src/shared/Core.Tests/Trace2Tests.cs

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
using System;
2-
using System.Text.RegularExpressions;
3-
using GitCredentialManager.Tests.Objects;
41
using Xunit;
52

63
namespace GitCredentialManager.Tests;
@@ -30,4 +27,14 @@ public void TryGetPipeName_Windows_Returns_Expected_Value(string input, string e
3027
Assert.True(isSuccessful);
3128
Assert.Matches(actual, expected);
3229
}
30+
31+
[Theory]
32+
[InlineData(0.013772, " 0.013772 ")]
33+
[InlineData(26.316083, " 26.316083 ")]
34+
[InlineData(100.316083, "100.316083 ")]
35+
public void BuildTimeSpan_Match_Returns_Expected_String(double input, string expected)
36+
{
37+
var actual = Trace2Message.BuildTimeSpan(input);
38+
Assert.Equal(expected, actual);
39+
}
3340
}

src/shared/Core/Constants.cs

+5-3
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public static class EnvironmentVariables
5656
public const string GcmAllowWia = "GCM_ALLOW_WINDOWSAUTH";
5757
public const string GitTrace2Event = "GIT_TRACE2_EVENT";
5858
public const string GitTrace2Normal = "GIT_TRACE2";
59+
public const string GitTrace2Performance = "GIT_TRACE2_PERF";
5960

6061
/*
6162
* Unlike other environment variables, these proxy variables are normally lowercase only.
@@ -170,9 +171,10 @@ public static class Remote
170171

171172
public static class Trace2
172173
{
173-
public const string SectionName = "trace2";
174-
public const string EventTarget = "eventtarget";
175-
public const string NormalTarget = "normaltarget";
174+
public const string SectionName = "trace2";
175+
public const string EventTarget = "eventtarget";
176+
public const string NormalTarget = "normaltarget";
177+
public const string PerformanceTarget = "perftarget";
176178
}
177179
}
178180

src/shared/Core/ITrace2Writer.cs

+14
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@
33

44
namespace GitCredentialManager;
55

6+
/// <summary>
7+
/// The different format targets supported in the TRACE2 tracing
8+
/// system.
9+
/// </summary>
10+
public enum Trace2FormatTarget
11+
{
12+
Event,
13+
Normal,
14+
Performance
15+
}
16+
617
public interface ITrace2Writer : IDisposable
718
{
819
bool Failed { get; }
@@ -34,6 +45,9 @@ protected string Format(Trace2Message message)
3445
case Trace2FormatTarget.Normal:
3546
sb.Append(message.ToNormalString());
3647
break;
48+
case Trace2FormatTarget.Performance:
49+
sb.Append(message.ToPerformanceString());
50+
break;
3751
default:
3852
Console.WriteLine($"warning: unrecognized format target '{_formatTarget}', disabling TRACE2 tracing.");
3953
Failed = true;

src/shared/Core/ProcessManager.cs

+50-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Diagnostics;
23

34
namespace GitCredentialManager;
@@ -26,8 +27,14 @@ public interface IProcessManager
2627

2728
public class ProcessManager : IProcessManager
2829
{
30+
private const string SidEnvar = "GIT_TRACE2_PARENT_SID";
31+
2932
protected readonly ITrace2 Trace2;
3033

34+
public static string Sid { get; internal set; }
35+
36+
public static int Depth { get; internal set; }
37+
3138
public ProcessManager(ITrace2 trace2)
3239
{
3340
EnsureArgument.NotNull(trace2, nameof(trace2));
@@ -49,9 +56,51 @@ public virtual ChildProcess CreateProcess(string path, string args, bool useShel
4956
return CreateProcess(psi);
5057
}
5158

52-
5359
public virtual ChildProcess CreateProcess(ProcessStartInfo psi)
5460
{
5561
return new ChildProcess(Trace2, psi);
5662
}
63+
64+
/// <summary>
65+
/// Create a TRACE2 "session id" (sid) for this process.
66+
/// </summary>
67+
public static void CreateSid()
68+
{
69+
Sid = Environment.GetEnvironmentVariable(SidEnvar);
70+
71+
if (!string.IsNullOrEmpty(Sid))
72+
{
73+
// Use trim to ensure no accidental leading or trailing slashes
74+
Sid = $"{Sid.Trim('/')}/{Guid.NewGuid():D}";
75+
// Only check for process depth if there is a parent.
76+
// If there is not a parent, depth defaults to 0.
77+
Depth = GetProcessDepth();
78+
}
79+
else
80+
{
81+
// We are the root process; create our own 'root' SID
82+
Sid = Guid.NewGuid().ToString("D");
83+
}
84+
85+
Environment.SetEnvironmentVariable(SidEnvar, Sid);
86+
}
87+
88+
/// <summary>
89+
/// Get "depth" of current process relative to top-level GCM process.
90+
/// </summary>
91+
/// <returns>Depth of current process.</returns>
92+
internal static int GetProcessDepth()
93+
{
94+
char processSeparator = '/';
95+
96+
int count = 0;
97+
// Use AsSpan() for slight performance bump over traditional foreach loop.
98+
foreach (var c in Sid.AsSpan())
99+
{
100+
if (c == processSeparator)
101+
count++;
102+
}
103+
104+
return count;
105+
}
57106
}

src/shared/Core/Settings.cs

+6
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,12 @@ public Trace2Settings GetTrace2Settings()
538538
settings.FormatTargetsAndValues.Add(Trace2FormatTarget.Normal, value);
539539
}
540540

541+
if (TryGetSetting(Constants.EnvironmentVariables.GitTrace2Performance, KnownGitCfg.Trace2.SectionName,
542+
Constants.GitConfiguration.Trace2.PerformanceTarget, out value))
543+
{
544+
settings.FormatTargetsAndValues.Add(Trace2FormatTarget.Performance, value);
545+
}
546+
541547
return settings;
542548
}
543549

src/shared/Core/SidManager.cs

-27
This file was deleted.

0 commit comments

Comments
 (0)