Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
47832f6
Update docs for the latest release version
nblumhardt May 8, 2024
8af28fa
Merge pull request #348 from nblumhardt/update-command-help
KodrAus May 8, 2024
0bd42e5
Pascal case permissions
sctmike May 14, 2024
3137325
ignore case when parsing permission string into Seq.Api.Model.Securit…
sctmike May 15, 2024
b62577b
Merge pull request #353 from sctmike/dev
nblumhardt May 15, 2024
6f786ea
Update README.md with `update` example [skip ci]
nblumhardt May 23, 2024
c35500d
Add environment variables doc
liammclennan Jun 11, 2024
1a19799
Merge pull request #356 from liammclennan/add-environmentvariables-doc
KodrAus Jun 11, 2024
e64d4a8
update dotnet toolchain to 8.0.302
KodrAus Jun 30, 2024
c3421e5
Merge pull request #357 from KodrAus/chore/dotnet-version
nblumhardt Jul 1, 2024
1fec903
Only include detailed HTTP diagnostics in `node health` output when `…
nblumhardt Jul 8, 2024
fa7c50b
Allow the -i <FILENAME> argument to be specified multiple times
nblumhardt Jul 9, 2024
cafc038
Merge pull request #359 from nblumhardt/multiple-i-args
KodrAus Jul 9, 2024
dc131b4
Fix test
nblumhardt Jul 9, 2024
13c8ae8
Merge pull request #358 from nblumhardt/tidy-health-output
nblumhardt Jul 9, 2024
3dfdf3a
Add Organization to the list of permissions documented for the `apike…
nblumhardt Jul 10, 2024
31d9a7c
Merge pull request #360 from nblumhardt/list-perms
KodrAus Jul 10, 2024
69c8221
update to .NET 8.0.303
KodrAus Jul 10, 2024
0bc9d1a
Merge pull request #361 from datalust/chore/dotnet-8-0-303
nblumhardt Jul 11, 2024
69d7199
Use restrictive global.json during CI builds only
nblumhardt Aug 1, 2024
6786bd1
Use ci.global.json in CI setup
nblumhardt Sep 13, 2024
34dff11
Same change for Linux
nblumhardt Sep 13, 2024
118d6ec
Merge pull request #363 from nblumhardt/global-json-only-ci
nblumhardt Sep 13, 2024
b313db5
Align seqcli's environment override handling with Seq's
nblumhardt Oct 11, 2024
b4a2b45
Doc improvements
nblumhardt Oct 11, 2024
7896085
Retain the old file read/init behavior for now
nblumhardt Oct 11, 2024
dc29e0c
Merge pull request #366 from nblumhardt/env-var-config
nblumhardt Oct 11, 2024
94230a9
Update all NuGet dependencies
nblumhardt Oct 11, 2024
26ffcad
Merge pull request #368 from nblumhardt/nuget-updates-2024-10
nblumhardt Oct 11, 2024
7f4e543
Fix exception when writing `connection.apiKey` values
nblumhardt Oct 11, 2024
5b5d5c9
One further tweak; since env vars now use the KeyValueSettings.Set() …
nblumhardt Oct 11, 2024
8c0e0e2
Merge pull request #369 from nblumhardt/exception-when-setting-config
nblumhardt Oct 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -287,3 +287,6 @@ __pycache__/
*.xsd.cs

.DS_Store

# ci.global.json is used in CI; local builds are unconstrained
global.json
16 changes: 16 additions & 0 deletions Build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,32 @@ function Publish-Docs($version)
if($LASTEXITCODE -ne 0) { throw "Build failed" }
}

function Remove-GlobalJson
{
if(Test-Path ./global.json) { rm ./global.json }
}

function Create-GlobalJson
{
# It's very important that SeqCli use the same .NET SDK version as its matching Seq version, to avoid
# container and installer bloat. But, highly-restrictive global.json files are annoying during development. So,
# we create a temporary global.json from ci.global.json to use during CI builds.
Remove-GlobalJson
cp ./ci.global.json global.json
}

Write-Output "Building version $version"

$env:Path = "$pwd/.dotnetcli;$env:Path"

Clean-Output
Create-ArtifactDir
Create-GlobalJson
Restore-Packages
Publish-Archives($version)
Publish-DotNetTool($version)
Execute-Tests($version)
Publish-Docs($version)
Remove-GlobalJson

Pop-Location
313 changes: 307 additions & 6 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Setup.ps1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
$ErrorActionPreference = "Stop"

$RequiredDotnetVersion = $(cat ./global.json | convertfrom-json).sdk.version
$RequiredDotnetVersion = $(cat ./ci.global.json | convertfrom-json).sdk.version

New-Item -ItemType Directory -Force "./build/" | Out-Null

Expand Down
5 changes: 5 additions & 0 deletions ci.global.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"sdk": {
"version": "8.0.303"
}
}
5 changes: 0 additions & 5 deletions global.json

This file was deleted.

2 changes: 1 addition & 1 deletion seqcli.sln
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sln", "sln", "{2EA56595-519
.gitignore = .gitignore
appveyor.yml = appveyor.yml
Build.ps1 = Build.ps1
global.json = global.json
LICENSE = LICENSE
README.md = README.md
setup.sh = setup.sh
Build.Docker.ps1 = Build.Docker.ps1
docker-publish.ps1 = docker-publish.ps1
Setup.ps1 = Setup.ps1
CONTRIBUTING.md = CONTRIBUTING.md
ci.global.json = ci.global.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{3587B633-0C03-4235-8903-6226900328F1}"
Expand Down
2 changes: 1 addition & 1 deletion setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ set -o pipefail
sudo apt-get update || true
sudo apt-get install -y --no-install-recommends jq

RequiredDotnetVersion=$(jq -r '.sdk.version' global.json)
RequiredDotnetVersion=$(jq -r '.sdk.version' ci.global.json)

curl https://dot.net/v1/dotnet-install.sh -sSfL --output dotnet-install.sh
chmod +x dotnet-install.sh
Expand Down
4 changes: 2 additions & 2 deletions src/Roastery/Roastery.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Serilog" Version="3.1.1" />
<PackageReference Include="SerilogTracing" Version="1.0.0" />
<PackageReference Include="Serilog" Version="4.0.2" />
<PackageReference Include="SerilogTracing" Version="2.1.2" />
</ItemGroup>

</Project>
4 changes: 2 additions & 2 deletions src/SeqCli/Cli/Commands/ApiKey/CreateCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public CreateCommand(SeqConnectionFactory connectionFactory, SeqCliConfig config

Options.Add(
"permissions=",
"A comma-separated list of permissions to delegate to the API key; valid permissions are `Ingest` (default), `Read`, `Write`, `Project` and `System`",
"A comma-separated list of permissions to delegate to the API key; valid permissions are `Ingest` (default), `Read`, `Write`, `Project`, `Organization`, and `System`",
v => _permissions = ArgumentString.NormalizeList(v));

Options.Add(
Expand Down Expand Up @@ -133,7 +133,7 @@ protected override async Task<int> Run()
{
foreach (var permission in _permissions)
{
if (!Enum.TryParse<Permission>(permission, out var p))
if (!Enum.TryParse<Permission>(permission, true, out var p))
{
Log.Error("Unrecognized permission {Permission}", permission);
return 1;
Expand Down
116 changes: 13 additions & 103 deletions src/SeqCli/Cli/Commands/ConfigCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,24 +44,25 @@ protected override Task<int> Run()

try
{
var config = SeqCliConfig.Read();

var config = SeqCliConfig.ReadFromFile(RuntimeConfigurationLoader.DefaultConfigFilename);
if (_key != null)
{
if (_clear)
{
verb = "clear";
Clear(config, _key);
SeqCliConfig.Write(config);
KeyValueSettings.Clear(config, _key);
SeqCliConfig.WriteToFile(config, RuntimeConfigurationLoader.DefaultConfigFilename);
}
else if (_value != null)
{
verb = "update";
Set(config, _key, _value);
SeqCliConfig.Write(config);
KeyValueSettings.Set(config, _key, _value);
SeqCliConfig.WriteToFile(config, RuntimeConfigurationLoader.DefaultConfigFilename);
}
else
{
verb = "print";
Print(config, _key);
}
}
Expand All @@ -78,114 +79,23 @@ protected override Task<int> Run()
return Task.FromResult(1);
}
}

static void Print(SeqCliConfig config, string key)
{
if (config == null) throw new ArgumentNullException(nameof(config));
if (key == null) throw new ArgumentNullException(nameof(key));

var pr = ReadPairs(config).SingleOrDefault(p => p.Key == key);
if (pr.Key == null)
throw new ArgumentException($"Option {key} not found.");

Console.WriteLine(Format(pr.Value));
}

static void Set(SeqCliConfig config, string key, string? value)
{
if (config == null) throw new ArgumentNullException(nameof(config));
if (key == null) throw new ArgumentNullException(nameof(key));

var steps = key.Split('.');
if (steps.Length != 2)
throw new ArgumentException("The format of the key is incorrect; run the command without any arguments to view all keys.");

var first = config.GetType().GetTypeInfo().DeclaredProperties
.Where(p => p.CanRead && p.GetMethod!.IsPublic && !p.GetMethod.IsStatic)
.SingleOrDefault(p => Camelize(p.Name) == steps[0]);

if (first == null)
throw new ArgumentException("The key could not be found; run the command without any arguments to view all keys.");

if (first.PropertyType == typeof(Dictionary<string, SeqCliConnectionConfig>))
throw new NotSupportedException("Use `seqcli profile create` to configure connection profiles.");

var second = first.PropertyType.GetTypeInfo().DeclaredProperties
.Where(p => p.CanRead && p.GetMethod!.IsPublic && !p.GetMethod.IsStatic)
.SingleOrDefault(p => Camelize(p.Name) == steps[1]);

if (second == null)
throw new ArgumentException("The key could not be found; run the command without any arguments to view all keys.");
if (!KeyValueSettings.TryGetValue(config, key, out var value, out _))
throw new ArgumentException($"Option {key} not found");

if (!second.CanWrite || !second.SetMethod!.IsPublic)
throw new ArgumentException("The value is not writeable.");

var targetValue = Convert.ChangeType(value, second.PropertyType, CultureInfo.InvariantCulture);
var configItem = first.GetValue(config);
second.SetValue(configItem, targetValue);
}

static void Clear(SeqCliConfig config, string key)
{
Set(config, key, null);
Console.WriteLine(value);
}

static void List(SeqCliConfig config)
{
foreach (var (key, value) in ReadPairs(config))
{
Console.WriteLine($"{key}:");
Console.WriteLine($" {Format(value)}");
}
}

static IEnumerable<KeyValuePair<string, object?>> ReadPairs(object config)
{
foreach (var property in config.GetType().GetTypeInfo().DeclaredProperties
.Where(p => p.CanRead && p.GetMethod!.IsPublic && !p.GetMethod.IsStatic && !p.Name.StartsWith("Encoded"))
.OrderBy(p => p.Name))
foreach (var (key, value, _) in KeyValueSettings.Inspect(config))
{
var propertyName = Camelize(property.Name);
var propertyValue = property.GetValue(config);

if (propertyValue is IDictionary dict)
{
foreach (var elementKey in dict.Keys)
{
foreach (var elementPair in ReadPairs(dict[elementKey]!))
{
yield return new KeyValuePair<string, object?>(
$"{propertyName}[{elementKey}].{elementPair.Key}",
elementPair.Value);
}
}
}
else if (propertyValue?.GetType().Namespace?.StartsWith("SeqCli.Config") ?? false)
{
foreach (var childPair in ReadPairs(propertyValue))
{
var name = propertyName + "." + childPair.Key;
yield return new KeyValuePair<string, object?>(name, childPair.Value);
}
}
else
{
yield return new KeyValuePair<string, object?>(propertyName, propertyValue);
}
Console.WriteLine($"{key}={value}");
}
}

static string Camelize(string s)
{
if (s.Length < 2)
throw new NotSupportedException("No camel-case support for short names");
return char.ToLowerInvariant(s[0]) + s.Substring(1);
}

static string Format(object? value)
{
return value is IFormattable formattable
? formattable.ToString(null, CultureInfo.InvariantCulture)
: value?.ToString() ?? "";
}
}
2 changes: 1 addition & 1 deletion src/SeqCli/Cli/Commands/IngestCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class IngestCommand : Command
public IngestCommand(SeqConnectionFactory connectionFactory)
{
_connectionFactory = connectionFactory;
_fileInputFeature = Enable(new FileInputFeature("File(s) to ingest", supportsWildcard: true));
_fileInputFeature = Enable(new FileInputFeature("File(s) to ingest", allowMultiple: true));
_invalidDataHandlingFeature = Enable<InvalidDataHandlingFeature>();
_properties = Enable<PropertiesFeature>();

Expand Down
7 changes: 5 additions & 2 deletions src/SeqCli/Cli/Commands/Node/HealthCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,16 @@ protected override async Task<int> Run()
try
{
var response = await connection.Client.HttpClient.GetAsync("health");
Console.WriteLine($"HTTP {response.Version} {((int)response.StatusCode).ToString(CultureInfo.InvariantCulture)} {response.ReasonPhrase}");
Log.Information("HTTP {HttpVersion} {StatusCode} {ReasonPhrase}", response.Version, (int)response.StatusCode, response.ReasonPhrase);

foreach (var (key, values) in response.Headers.Concat(response.Content.Headers))
foreach (var value in values)
{
Console.WriteLine($"{key}: {value}");
Log.Information("{HeaderName}: {HeaderValue}", key, value);
}

Console.WriteLine(await response.Content.ReadAsStringAsync());

return response.IsSuccessStatusCode ? 0 : 1;
}
catch (Exception ex)
Expand Down
2 changes: 1 addition & 1 deletion src/SeqCli/Cli/Commands/PrintCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public PrintCommand(SeqCliOutputConfig outputConfig)
_noColor = outputConfig.DisableColor;
_forceColor = outputConfig.ForceColor;

_fileInputFeature = Enable(new FileInputFeature("CLEF file to read", supportsWildcard: true));
_fileInputFeature = Enable(new FileInputFeature("CLEF file to read", allowMultiple: true));

Options.Add("f=|filter=",
"Filter expression to select a subset of events",
Expand Down
4 changes: 2 additions & 2 deletions src/SeqCli/Cli/Commands/Profile/CreateCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ int RunSync()

try
{
var config = SeqCliConfig.Read();
var config = SeqCliConfig.ReadFromFile(RuntimeConfigurationLoader.DefaultConfigFilename);
config.Profiles[_name] = new SeqCliConnectionConfig { ServerUrl = _url, ApiKey = _apiKey };
SeqCliConfig.Write(config);
SeqCliConfig.WriteToFile(config, RuntimeConfigurationLoader.DefaultConfigFilename);
return 0;
}
catch (Exception ex)
Expand Down
2 changes: 1 addition & 1 deletion src/SeqCli/Cli/Commands/Profile/ListCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class ListCommand : Command
{
protected override Task<int> Run()
{
var config = SeqCliConfig.Read();
var config = RuntimeConfigurationLoader.Load();

foreach (var profile in config.Profiles.OrderBy(p => p.Key))
{
Expand Down
4 changes: 2 additions & 2 deletions src/SeqCli/Cli/Commands/Profile/RemoveCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ int RunSync()

try
{
var config = SeqCliConfig.Read();
var config = SeqCliConfig.ReadFromFile(RuntimeConfigurationLoader.DefaultConfigFilename);
if (!config.Profiles.Remove(_name))
{
Log.Error("No profile with name {ProfileName} was found", _name);
return 1;
}

SeqCliConfig.Write(config);
SeqCliConfig.WriteToFile(config, RuntimeConfigurationLoader.DefaultConfigFilename);

return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion src/SeqCli/Cli/Commands/Signal/ImportCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ protected override async Task<int> Run()
{
var connection = _connectionFactory.Connect(_connection);

using var input = _fileInputFeature.OpenInput();
using var input = _fileInputFeature.OpenSingleInput();
var line = await input.ReadLineAsync();
while (line != null)
{
Expand Down
Loading