Skip to content

Commit 7b396bc

Browse files
committed
Started moving Seq.Bench to seqcli
1 parent 9f00f9d commit 7b396bc

File tree

2 files changed

+143
-7
lines changed

2 files changed

+143
-7
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"cases": [
3+
{
4+
"id": "count-star",
5+
"query": "select count(*) from stream",
6+
"signals": []
7+
},
8+
{
9+
"id": "starts-with",
10+
"query": "select count(*) from stream where @Message like '%abcde'",
11+
"signals": []
12+
},
13+
{
14+
"id": "mean-filter",
15+
"query": "select mean(RowCount) from stream where @EventType = 0x94002EBF",
16+
"signals": []
17+
}
18+
19+
]
20+
}
Lines changed: 123 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,51 @@
1+
// Copyright 2018 Datalust Pty Ltd
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
115
#nullable enable
16+
217
using System;
18+
using System.Collections.Generic;
19+
using System.IO;
20+
using System.Linq;
321
using System.Threading.Tasks;
22+
using Newtonsoft.Json;
23+
using Seq.Api.Model.Signals;
424
using SeqCli.Cli.Features;
25+
using SeqCli.Connection;
26+
using Serilog;
27+
using Serilog.Context;
28+
using Serilog.Core;
529

630
namespace SeqCli.Cli.Commands;
731

832
[Command("bench", "Measure query performance")]
933
class BenchCommand : Command
1034
{
35+
readonly SeqConnectionFactory _connectionFactory;
1136
int _runs = 0;
1237
readonly ConnectionFeature _connection;
1338
readonly DateRangeFeature _range;
1439
string _cases = "";
15-
40+
string _reportingServerUrl = "";
41+
string _reportingServerApiKey = "";
42+
ILogger? _reportingLogger = null;
43+
1644
const int DefaultRuns = 3;
1745

18-
public BenchCommand()
46+
public BenchCommand(SeqConnectionFactory connectionFactory)
1947
{
48+
_connectionFactory = connectionFactory;
2049
Options.Add("r|runs=", "The number of runs to execute", r =>
2150
{
2251
if (!int.TryParse(r, out _runs))
@@ -25,15 +54,102 @@ public BenchCommand()
2554
}
2655
});
2756

28-
Options.Add("c|cases=", "A JSON file containing the set of cases to run. Defaults to a standard set of cases", c => _cases = c);
29-
57+
Options.Add(
58+
"c|cases=",
59+
"A JSON file containing the set of cases to run. Defaults to a standard set of cases",
60+
c => _cases = c);
61+
3062
_connection = Enable<ConnectionFeature>();
3163
_range = Enable<DateRangeFeature>();
64+
65+
Options.Add(
66+
"reporting-server=",
67+
"The address of a Seq server to send bench results to",
68+
s => _reportingServerUrl = s);
69+
Options.Add(
70+
"reporting-apikey=",
71+
"The API key to use when connecting to the reporting server",
72+
a => _reportingServerApiKey = a);
3273
}
3374

34-
protected override Task<int> Run()
75+
protected override async Task<int> Run()
3576
{
36-
Console.WriteLine("Bench command here");
37-
return Task.FromResult(0);
77+
try
78+
{
79+
var connection = _connectionFactory.Connect(_connection);
80+
_reportingLogger = BuildReportingLogger();
81+
82+
var cases = ReadCases(_cases);
83+
84+
using (LogContext.PushProperty("BenchRunId", Guid.NewGuid()))
85+
{
86+
foreach (var c in cases.Cases)
87+
{
88+
// TODO: collect results for each run
89+
foreach (var i in Enumerable.Range(1, _runs))
90+
{
91+
var result = await connection.Data.QueryAsync(
92+
c.Query,
93+
_range.Start ?? DateTime.UtcNow.AddDays(-7),
94+
_range.End,
95+
SignalExpressionPart.FromIntersectedIds(c.Signals)
96+
);
97+
98+
var isScalarResult = result.Rows.Length == 1 && result.Rows[0].Length == 1;
99+
using (isScalarResult ? LogContext.PushProperty("Result", result.Rows[0][0]) : null)
100+
using (LogContext.PushProperty("Query", c.Query))
101+
{
102+
_reportingLogger.Information("Benchmarked query {Id} in {Elapsed:N0}ms", c.Id,
103+
result.Statistics.ElapsedMilliseconds);
104+
}
105+
}
106+
}
107+
}
108+
109+
return 0;
110+
} catch (Exception ex)
111+
{
112+
Log.Error(ex, "Benchmarking failed: {ErrorMessage}", ex.Message);
113+
return 1;
114+
}
115+
}
116+
117+
Logger BuildReportingLogger()
118+
{
119+
return string.IsNullOrWhiteSpace(_reportingServerUrl)
120+
? new LoggerConfiguration()
121+
.Enrich.FromLogContext()
122+
.WriteTo.Console()
123+
.CreateLogger()
124+
: new LoggerConfiguration()
125+
.Enrich.FromLogContext()
126+
.WriteTo.Console()
127+
.WriteTo.Seq(_reportingServerUrl, period: TimeSpan.FromMilliseconds(1))
128+
.CreateLogger();
129+
}
130+
131+
static BenchCasesCollection ReadCases(string filename)
132+
{
133+
var defaultCasesPath = Path.Combine(Path.GetDirectoryName(typeof(BenchCommand).Assembly.Location)!, "Cli/Commands/BenchCases.json");
134+
var casesString = File.ReadAllText(string.IsNullOrWhiteSpace(filename)
135+
? defaultCasesPath
136+
: filename);
137+
return JsonConvert.DeserializeObject<BenchCasesCollection>(casesString)
138+
?? new BenchCasesCollection();
38139
}
140+
}
141+
142+
class BenchCasesCollection
143+
{
144+
public IList<BenchCase> Cases = new List<BenchCase>();
145+
}
146+
147+
/*
148+
* A benchmark test case.
149+
*/
150+
class BenchCase
151+
{
152+
public string Id = "";
153+
public string Query = "";
154+
public IList<string> Signals = new List<string>();
39155
}

0 commit comments

Comments
 (0)