Add duration as an option to dotnet-counters and fix a null reference… (#2755)
authorMike Lorbetske <mike.lorbetske@n3-p.com>
Thu, 18 Nov 2021 22:34:03 +0000 (16:34 -0600)
committerGitHub <noreply@github.com>
Thu, 18 Nov 2021 22:34:03 +0000 (22:34 +0000)
* Add duration as an option to dotnet-counters and fix a null reference exception in the JSON exporter

* Use stopwatch rather than comparing DateTime objects

src/Tools/dotnet-counters/CounterMonitor.cs
src/Tools/dotnet-counters/Exporters/JSONExporter.cs
src/Tools/dotnet-counters/Program.cs

index 45a2e2f265a13e551bc8b9ffed21a3a7338b3b99..5e5d7943118b047a5735c54faed8e331e4d46651 100644 (file)
@@ -42,6 +42,7 @@ namespace Microsoft.Diagnostics.Tools.Counters
         private string _metricsEventSourceSessionId;
         private int _maxTimeSeries;
         private int _maxHistograms;
+        private TimeSpan _duration;
 
         class ProviderEventState
         {
@@ -453,7 +454,8 @@ namespace Microsoft.Diagnostics.Tools.Counters
             string diagnosticPort,
             bool resumeRuntime,
             int maxHistograms,
-            int maxTimeSeries)
+            int maxTimeSeries,
+            TimeSpan duration)
         {
             try
             {
@@ -491,6 +493,7 @@ namespace Microsoft.Diagnostics.Tools.Counters
                         _renderer = new ConsoleWriter(useAnsi);
                         _diagnosticsClient = holder.Client;
                         _resumeRuntime = resumeRuntime;
+                        _duration = duration;
                         int ret = await Start();
                         ProcessLauncher.Launcher.Cleanup();
                         return ret;
@@ -527,7 +530,8 @@ namespace Microsoft.Diagnostics.Tools.Counters
             string diagnosticPort,
             bool resumeRuntime,
             int maxHistograms,
-            int maxTimeSeries)
+            int maxTimeSeries,
+            TimeSpan duration)
         {
             try
             {
@@ -564,6 +568,7 @@ namespace Microsoft.Diagnostics.Tools.Counters
                         _maxTimeSeries = maxTimeSeries;
                         _output = output;
                         _diagnosticsClient = holder.Client;
+                        _duration = duration;
                         if (_output.Length == 0)
                         {
                             _console.Error.WriteLine("Output cannot be an empty string");
@@ -842,6 +847,13 @@ namespace Microsoft.Diagnostics.Tools.Counters
             });
 
             monitorTask.Start();
+            var shouldStopAfterDuration = _duration != default(TimeSpan);
+            Stopwatch durationStopwatch = null;
+
+            if (shouldStopAfterDuration)
+            {
+                durationStopwatch = Stopwatch.StartNew();
+            }
 
             while(!_shouldExit.Task.Wait(250))
             {
@@ -862,7 +874,14 @@ namespace Microsoft.Diagnostics.Tools.Counters
                         _pauseCmdSet = false;
                     }
                 }
+
+                if (shouldStopAfterDuration && durationStopwatch.Elapsed >= _duration)
+                {
+                    durationStopwatch.Stop();
+                    break;
+                }
             }
+
             StopMonitor();
             return _shouldExit.Task;
         }
index 7574dbb52137716473d84324a70db9181d1858fc..8293a16119b8603fd77b5e0d47c81af6c901bbff 100644 (file)
@@ -97,6 +97,11 @@ namespace Microsoft.Diagnostics.Tools.Counters.Exporters
 
         private string JsonEscape(string input)
         {
+            if (input is null)
+            {
+                return string.Empty;
+            }
+
             int offset = input.IndexOfAny(s_escapeChars);
             if(offset == -1)
             {
index 4269c0cec244a20e1f4d46a8d51a8cf49743ca9d..75e425edf1c8c5e0f49f5f9790b83b223c82274a 100644 (file)
@@ -35,7 +35,8 @@ namespace Microsoft.Diagnostics.Tools.Counters
             string port,
             bool resumeRuntime,
             int maxHistograms,
-            int maxTimeSeries);
+            int maxTimeSeries,
+            TimeSpan duration);
         delegate Task<int> MonitorDelegate(
             CancellationToken ct,
             List<string> counter_list,
@@ -47,7 +48,8 @@ namespace Microsoft.Diagnostics.Tools.Counters
             string port,
             bool resumeRuntime,
             int maxHistograms,
-            int maxTimeSeries);
+            int maxTimeSeries,
+            TimeSpan duration);
 
         private static Command MonitorCommand() =>
             new Command(
@@ -65,7 +67,8 @@ namespace Microsoft.Diagnostics.Tools.Counters
                 DiagnosticPortOption(),
                 ResumeRuntimeOption(),
                 MaxHistogramOption(),
-                MaxTimeSeriesOption()
+                MaxTimeSeriesOption(),
+                DurationOption()
             };
         
         private static Command CollectCommand() =>
@@ -86,7 +89,8 @@ namespace Microsoft.Diagnostics.Tools.Counters
                 DiagnosticPortOption(),
                 ResumeRuntimeOption(),
                 MaxHistogramOption(),
-                MaxTimeSeriesOption()
+                MaxTimeSeriesOption(),
+                DurationOption()
             };
 
         private static Option NameOption() =>
@@ -195,6 +199,14 @@ namespace Microsoft.Diagnostics.Tools.Counters
                 Argument = new Argument<int>(name: "maxTimeSeries", getDefaultValue: () => 1000)
             };
 
+        private static Option DurationOption() =>
+            new Option(
+                alias: "--duration",
+                description: @"When specified, will run for the given timespan and then automatically stop. Provided in the form of dd:hh:mm:ss.")
+            {
+                Argument = new Argument<TimeSpan>(name: "duration-timespan", getDefaultValue: () => default)
+            };
+
         private static readonly string[] s_SupportedRuntimeVersions = new[] { "3.0", "3.1", "5.0" };
 
         public static int List(IConsole console, string runtimeVersion)