diff --git a/src/shared/Core.Tests/Trace2Tests.cs b/src/shared/Core.Tests/Trace2Tests.cs index 9816a0d3e..445c177e2 100644 --- a/src/shared/Core.Tests/Trace2Tests.cs +++ b/src/shared/Core.Tests/Trace2Tests.cs @@ -1,6 +1,3 @@ -using System; -using System.Text.RegularExpressions; -using GitCredentialManager.Tests.Objects; using Xunit; namespace GitCredentialManager.Tests; @@ -30,4 +27,14 @@ public void TryGetPipeName_Windows_Returns_Expected_Value(string input, string e Assert.True(isSuccessful); Assert.Matches(actual, expected); } + + [Theory] + [InlineData(0.013772, " 0.013772 ")] + [InlineData(26.316083, " 26.316083 ")] + [InlineData(100.316083, "100.316083 ")] + public void BuildTimeSpan_Match_Returns_Expected_String(double input, string expected) + { + var actual = Trace2Message.BuildTimeSpan(input); + Assert.Equal(expected, actual); + } } diff --git a/src/shared/Core/Constants.cs b/src/shared/Core/Constants.cs index 617aed645..e5f283b47 100644 --- a/src/shared/Core/Constants.cs +++ b/src/shared/Core/Constants.cs @@ -56,6 +56,7 @@ public static class EnvironmentVariables public const string GcmAllowWia = "GCM_ALLOW_WINDOWSAUTH"; public const string GitTrace2Event = "GIT_TRACE2_EVENT"; public const string GitTrace2Normal = "GIT_TRACE2"; + public const string GitTrace2Performance = "GIT_TRACE2_PERF"; /* * Unlike other environment variables, these proxy variables are normally lowercase only. @@ -169,9 +170,10 @@ public static class Remote public static class Trace2 { - public const string SectionName = "trace2"; - public const string EventTarget = "eventtarget"; - public const string NormalTarget = "normaltarget"; + public const string SectionName = "trace2"; + public const string EventTarget = "eventtarget"; + public const string NormalTarget = "normaltarget"; + public const string PerformanceTarget = "perftarget"; } } diff --git a/src/shared/Core/ITrace2Writer.cs b/src/shared/Core/ITrace2Writer.cs index fbe1b2297..426c69f1e 100644 --- a/src/shared/Core/ITrace2Writer.cs +++ b/src/shared/Core/ITrace2Writer.cs @@ -10,7 +10,8 @@ namespace GitCredentialManager; public enum Trace2FormatTarget { Event, - Normal + Normal, + Performance } public interface ITrace2Writer : IDisposable @@ -44,6 +45,9 @@ protected string Format(Trace2Message message) case Trace2FormatTarget.Normal: sb.Append(message.ToNormalString()); break; + case Trace2FormatTarget.Performance: + sb.Append(message.ToPerformanceString()); + break; default: Console.WriteLine($"warning: unrecognized format target '{_formatTarget}', disabling TRACE2 tracing."); Failed = true; diff --git a/src/shared/Core/Settings.cs b/src/shared/Core/Settings.cs index 55069d63b..79935f957 100644 --- a/src/shared/Core/Settings.cs +++ b/src/shared/Core/Settings.cs @@ -533,6 +533,12 @@ public Trace2Settings GetTrace2Settings() settings.FormatTargetsAndValues.Add(Trace2FormatTarget.Normal, value); } + if (TryGetSetting(Constants.EnvironmentVariables.GitTrace2Performance, KnownGitCfg.Trace2.SectionName, + Constants.GitConfiguration.Trace2.PerformanceTarget, out value)) + { + settings.FormatTargetsAndValues.Add(Trace2FormatTarget.Performance, value); + } + return settings; } diff --git a/src/shared/Core/Trace2.cs b/src/shared/Core/Trace2.cs index ecfd43c61..813ebbf3b 100644 --- a/src/shared/Core/Trace2.cs +++ b/src/shared/Core/Trace2.cs @@ -1,10 +1,8 @@ using System; -using System.Collections; using System.Collections.Generic; +using System.ComponentModel; using System.IO; using System.IO.Pipes; -using System.Linq; -using System.Runtime.Serialization; using System.Text; using Newtonsoft.Json; using Newtonsoft.Json.Converters; @@ -42,6 +40,15 @@ public class Trace2Settings new Dictionary(); } +public class PerformanceFormatSpan +{ + public int Size { get; set; } + + public int BeginPadding { get; set; } + + public int EndPadding { get; set; } +} + /// /// Represents the application's TRACE2 tracing system. /// @@ -212,7 +219,8 @@ public void WriteChildStart(DateTimeOffset startTime, Id = ++_childProcCounter, Classification = processClass, UseShell = useShell, - Argv = procArgs + Argv = procArgs, + Depth = ProcessManager.Depth }); } @@ -242,7 +250,8 @@ public void WriteChildExit( Id = _childProcCounter, Pid = pid, Code = code, - ElapsedTime = elapsedTime + ElapsedTime = elapsedTime, + Depth = ProcessManager.Depth }); } @@ -426,8 +435,11 @@ private void WriteMessage(Trace2Message message) public abstract class Trace2Message { - protected const string TimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'ffffff'Z'"; private const int SourceColumnMaxWidth = 23; + private const string NormalPerfTimeFormat = "HH:mm:ss.ffffff"; + + protected const string EmptyPerformanceSpan = "| | | | "; + protected const string TimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'ffffff'Z'"; [JsonProperty("event", Order = 1)] public Trace2Event Event { get; set; } @@ -449,34 +461,122 @@ public abstract class Trace2Message [JsonProperty("line", Order = 6)] public int Line { get; set; } + [JsonProperty("depth", Order = 7)] + public int Depth { get; set; } + public abstract string ToJson(); public abstract string ToNormalString(); - protected string BuildNormalString(string message) + public abstract string ToPerformanceString(); + + protected abstract string BuildPerformanceSpan(); + + protected string BuildNormalString() { + string message = GetEventMessage(Trace2FormatTarget.Normal); + // The normal format uses local time rather than UTC time. - string time = Time.ToLocalTime().ToString("HH:mm:ss.ffffff"); + string time = Time.ToLocalTime().ToString(NormalPerfTimeFormat); + string source = GetSource(); + // Git's TRACE2 normal format is: + // [