diff --git a/src/plugins/trace/exe/Program.cs b/src/plugins/trace/exe/Program.cs index 4143ab536..b34134b86 100644 --- a/src/plugins/trace/exe/Program.cs +++ b/src/plugins/trace/exe/Program.cs @@ -12,47 +12,194 @@ namespace QuicTrace { class Program { - static void Main(string[] args) + static void PrintCommands() { - if (args.Length != 1) - { - Console.WriteLine("Sample *.etl file required"); - return; - } + Console.WriteLine( + "\n" + + "Commands:\n" + + " -p, --print Prints events as text\n" + + " -r, --report Prints out an analysis of possible problems in the trace\n" + ); + } - // - // Enable full event and payload parsing. - // - QuicEvent.ParseMode = QuicEventParseMode.Full; + static void PrintArgs() + { + Console.WriteLine( + "\n" + + "Quic Trace Analyzer\n" + + "\n" + + "quictrace [command]\n" + + "\n" + + "Options:\n" + + " -c, --capture Captures local events to analyze\n" + + " -f, --file Opens a local file of events to analyze\n" + + " -h, --help Prints out help text\n" + + " -t, --text Enables additional trace processing to allow for full text output" + ); + PrintCommands(); + } + static string? CaptureLocalTrace() + { + Console.WriteLine("--local capture is not currently supported!"); + return null; // TODO - Support local trace collection + } + + static QuicState ProcessTraceFile(string filePath) + { // - // Create our runtime environment, enabling cookers and adding inputs. + // Create our runtime environment, add file, enable cookers, and process. // var runtime = Engine.Create(); - runtime.AddFile(args[0]); + runtime.AddFile(filePath); runtime.EnableCooker(QuicEventCooker.CookerPath); Console.WriteLine("Processing..."); var results = runtime.Process(); + Console.WriteLine("Done.\n"); // - // Access our cooked data. + // Return our 'cooked' data. // - var quicState = results.QueryOutput(new DataOutputPath(QuicEventCooker.CookerPath, "State")); + return results.QueryOutput(new DataOutputPath(QuicEventCooker.CookerPath, "State")); + } - /*foreach (var evt in quicState.Events) - { - Console.WriteLine(evt); - }*/ + static void RunReport(QuicState quicState) + { + var workers = quicState.Workers; + Console.WriteLine("WORKERS ({0})\n", workers.Count); - Console.WriteLine("Conn, Process ID, Pointer"); - foreach (var conn in quicState.Connections) + // + // TODO - Dump Worker info + // + + var conns = quicState.Connections; + Console.WriteLine("CONNECTIONS ({0})\n", conns.Count); + + // + // TODO - Dump Connection info + // + } + + static void RunCommand(QuicState quicState, string[] args) + { + if (args[0] == "--print" || args[0] == "-p") { - Console.WriteLine($"{conn.Id}, {conn.ProcessId}, {conn.Pointer}"); - foreach (var evt in conn.Events) + if (QuicEvent.ParseMode != QuicEventParseMode.Full) + { + Console.WriteLine("--text option was not initially specified! Please rerun."); + return; + } + + foreach (var evt in quicState.Events) { Console.WriteLine(evt); } } + else if (args[0] == "--report" || args[0] == "-r") + { + RunReport(quicState); + } + else if (args[0] == "--help" || args[0] == "-h" || args[0] == "-?") + { + PrintCommands(); + } + else + { + Console.WriteLine("Unsupported command: {0}", args[0]); + return; + } + } + + static void Main(string[] args) + { + var i = 0; + string? traceFile = null; + + // + // Process input args for initial 'option' values. + // + for (; i < args.Length; ++i) + { + if (args[i] == "--capture" || args[i] == "-c") + { + traceFile = CaptureLocalTrace(); + if (traceFile == null) + { + return; + } + } + else if (args[i] == "--file" || args[i] == "-f") + { + if (i + 1 >= args.Length) + { + Console.WriteLine("Missing additional argument for --file option!"); + return; + } + + ++i; + traceFile = args[i]; + } + else if (args[i] == "--help" || args[i] == "-h" || args[i] == "-?") + { + PrintArgs(); + return; + } + else if (args[i] == "--text" || args[i] == "-t") + { + // + // Enable full event and payload parsing. + // + QuicEvent.ParseMode = QuicEventParseMode.Full; + } + else + { + break; + } + } + + // + // Make sure we have something valid to process. + // + if (traceFile == null) + { + Console.WriteLine("Missing valid option! Run '--help' for additional usage information!"); + return; + } + + // + // Process the trace file to generate the QUIC state. + // + var quicState = ProcessTraceFile(traceFile); + + if (i == args.Length) + { + // + // Run in interactive mode when no commands were specified. + // + while (true) + { + Console.Write("quictrace> "); + + var input = Console.ReadLine(); + if (input == "--exit" || input == "exit" || input == "-e") + { + return; + } + + if (input.Length > 0) + { + var cmdArgs = input.Split(" \t\r\n"); + RunCommand(quicState, cmdArgs); + } + } + } + else + { + // + // Process specified commands inline. + // + RunCommand(quicState, args[i..]); + } } } }