-
Notifications
You must be signed in to change notification settings - Fork 0
/
Program.cs
159 lines (140 loc) · 5.52 KB
/
Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using CommandLine;
using Crayon;
namespace XELive
{
class Program
{
class StartupOptions : Profile
{
[Option('p', "profile", Required = false, HelpText = "Name of the base profile to use (configured in ~/.xelive.json)")]
public string Profile { get; set; }
[Option('q', "query", Required = false, HelpText = "Filtering expression (WHERE in CREATE EVENT SESSION ADD EVENT)")]
public string Query { get; set; }
[Option("procedure-statements", HelpText = "Include individual stored procedure statements in the output")]
public new bool IndividualStatements { get; set; }
[Option('t', "show-transaction-ids", HelpText = "Show transaction IDs in the output")]
public new bool ShowTransactionIds { get; set; }
}
static Task Main(string[] args)
=> Parser.Default.ParseArguments<StartupOptions>(args)
.WithParsedAsync(Run);
static async Task Run(StartupOptions options)
{
var cts = new CancellationTokenSource();
XEStreamer xes = null;
Task task = null;
try
{
var profiles = ReadConfigurations(
Path.Combine(AppContext.BaseDirectory, "appsettings.json"),
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".xelive.json")
);
Profile nameDefault = null, cfgDefault = null, selected = null;
var profileMap = new Dictionary<string, Profile>(StringComparer.OrdinalIgnoreCase);
await foreach (var p in profiles)
{
if (p.IsDefault)
cfgDefault = p;
if (options.Profile != null && p.Name == options.Profile)
selected = p;
if (p.Name == "default")
nameDefault = p;
if (p.Name != null)
profileMap[p.Name] = p;
}
var profile = selected ?? cfgDefault ?? nameDefault;
while (!string.IsNullOrEmpty(profile.InheritFrom) && profileMap.TryGetValue(profile.InheritFrom, out var baseProfile))
{
profileMap.Remove(profile.InheritFrom);
profile = Profile.Combine(baseProfile, profile);
}
if (options.IndividualStatements)
{
((Profile)options).IndividualStatements = true;
}
if (options.ShowTransactionIds)
{
((Profile)options).ShowTransactionIds = true;
}
profile = Profile.Combine(profile, options);
xes = new XEStreamer(profile);
task = xes.Run(options.Query, cts.Token);
}
catch (Exception err)
{
FatalError(err);
}
try
{
_ = task.ContinueWith(t =>
{
if (t.Exception != null)
{
FatalError(t.Exception);
}
});
while (!cts.IsCancellationRequested)
{
var key = Console.ReadKey(true);
switch (key.Key)
{
case ConsoleKey.Q:
case ConsoleKey.Escape:
cts.Cancel();
break;
}
}
await task;
}
catch
{
// error is already logged in task continuation
}
}
private static void Fail(IEnumerable<Error> errors)
{
foreach (var err in errors)
{
Console.WriteLine($"Argument parsing error: {Output.BrightRed(err.ToString())}");
}
}
private static void FatalError(Exception err)
{
Console.WriteLine($"ERROR: {Output.BrightRed(err.Message)} ({err.GetType()})");
Console.WriteLine(Output.Red(err.StackTrace));
}
static async IAsyncEnumerable<Profile> ReadConfigurations(params string[] paths)
{
var opts = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
};
foreach (string path in paths)
{
if (File.Exists(path))
{
using (var stream = File.OpenRead(path))
{
var cfg = await JsonSerializer.DeserializeAsync<Configuration>(stream, opts);
foreach (var profile in cfg.Profiles ?? Array.Empty<Profile>())
{
yield return profile;
}
}
}
else
{
Console.WriteLine($"Warning: {Output.BrightYellow($"Settings file {Output.Bold(path)} not found")}");
}
}
}
}
}