diff --git a/README.md b/README.md
index de186132..f9741e0b 100644
--- a/README.md
+++ b/README.md
@@ -38,6 +38,12 @@ View and set fields in the `SeqCli.json` file; run with no arguments to list all
Show information about available commands.
+Example:
+
+```
+seqcli help search
+```
+
| Option | Description |
| ------ | ----------- |
| `-m`, `--markdown` | Generate markdown for use in documentation |
@@ -98,6 +104,8 @@ seqcli query -q "select count(*) from stream group by @Level" --start="2018-02-2
| `--end=VALUE` | Date/time to query to |
| `--signal=VALUE` | A signal expression or list of intersected signal ids to apply, for example `signal-1,signal-2` |
| `--timeout=VALUE` | The query execution timeout in milliseconds |
+| `--json` | Print events in newline-delimited JSON (the default is plain text) |
+| `--no-color` | Don't colorize text output |
| `-s`, `--server=VALUE` | The URL of the Seq server; by default the `connection.serverUrl` value will be used |
| `-a`, `--apikey=VALUE` | The API key to use when connecting to the server; by default `config.apiKey` value will be used |
diff --git a/seqcli.sln b/seqcli.sln
index d1af2409..7c8ae275 100644
--- a/seqcli.sln
+++ b/seqcli.sln
@@ -47,7 +47,6 @@ Global
{DBC69360-519B-4A9B-829B-2AE1B5412521}.Release|x64.ActiveCfg = Release|x64
{DBC69360-519B-4A9B-829B-2AE1B5412521}.Release|x64.Build.0 = Release|x64
{5E28D963-3523-49DE-B03B-E76684258415}.Debug|x64.ActiveCfg = Debug|x64
- {5E28D963-3523-49DE-B03B-E76684258415}.Debug|x64.Build.0 = Debug|x64
{5E28D963-3523-49DE-B03B-E76684258415}.Release|x64.ActiveCfg = Release|x64
{5E28D963-3523-49DE-B03B-E76684258415}.Release|x64.Build.0 = Release|x64
EndGlobalSection
diff --git a/src/SeqCli/Cli/Commands/HelpCommand.cs b/src/SeqCli/Cli/Commands/HelpCommand.cs
index 27676646..dda56ae8 100644
--- a/src/SeqCli/Cli/Commands/HelpCommand.cs
+++ b/src/SeqCli/Cli/Commands/HelpCommand.cs
@@ -21,7 +21,7 @@
namespace SeqCli.Cli.Commands
{
- [Command("help", "Show information about available commands")]
+ [Command("help", "Show information about available commands", Example = "seqcli help search")]
class HelpCommand : Command
{
readonly List, CommandMetadata>> _availableCommands;
diff --git a/src/SeqCli/Cli/Commands/QueryCommand.cs b/src/SeqCli/Cli/Commands/QueryCommand.cs
index 620efc04..018c698c 100644
--- a/src/SeqCli/Cli/Commands/QueryCommand.cs
+++ b/src/SeqCli/Cli/Commands/QueryCommand.cs
@@ -20,7 +20,6 @@
using SeqCli.Cli.Features;
using SeqCli.Config;
using SeqCli.Connection;
-using SeqCli.Csv;
using Serilog;
namespace SeqCli.Cli.Commands
@@ -29,23 +28,23 @@ namespace SeqCli.Cli.Commands
Example = "seqcli query -q \"select count(*) from stream group by @Level\" --start=\"2018-02-28T13:00Z\"")]
class QueryCommand : Command
{
+ readonly OutputFormatFeature _output;
readonly SeqConnectionFactory _connectionFactory;
readonly ConnectionFeature _connection;
readonly DateRangeFeature _range;
readonly SignalExpressionFeature _signal;
string _query;
int? _timeoutMS;
- bool _noColor;
public QueryCommand(SeqConnectionFactory connectionFactory, SeqCliConfig config)
{
+ if (config == null) throw new ArgumentNullException(nameof(config));
_connectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory));
Options.Add("q=|query=", "The query to execute", v => _query = v);
_range = Enable();
_signal = Enable();
Options.Add("timeout=", "The query execution timeout in milliseconds", v => _timeoutMS = int.Parse(v));
- Options.Add("no-color", "Don't colorize text output", v => _noColor = true);
- _noColor = config.Output.DisableColor;
+ _output = Enable(new OutputFormatFeature(config.Output));
_connection = Enable();
}
@@ -59,32 +58,41 @@ protected override async Task Run()
var connection = _connectionFactory.Connect(_connection);
- // The `rangeStartUtc` parameter of `QueryCsvAsync()` should now be optional; we can
+ // The `rangeStartUtc` parameter of `Query[Csv]Async()` should now be optional; we can
// remove the `.Value` when _Seq.Api_ is updated to reflect this.
// ReSharper disable once PossibleInvalidOperationException
- var result = await QueryCsvAsync(connection, _query, _range.Start, _range.End, _signal.Signal, _timeoutMS);
- if (_noColor)
+ if (_output.Json)
{
- Console.Write(result);
- return 0;
+ var result = await QueryAsync(connection, _query, _range.Start, _range.End, _signal.Signal, _timeoutMS);
+ Console.WriteLine(result);
+ }
+ else
+ {
+ var result = await QueryAsync(connection, _query, _range.Start, _range.End, _signal.Signal, _timeoutMS, "text/csv");
+ _output.WriteCsv(result);
}
-
- var tokens = new CsvTokenizer().Tokenize(result);
- CsvWriter.WriteCsv(tokens, OutputFormatFeature.ConsoleTheme, Console.Out, true);
return 0;
}
- static async Task QueryCsvAsync(SeqConnection connection, string query, DateTime? rangeStartUtc, DateTime? rangeEndUtc, SignalExpressionPart signalExpression, int? timeoutMS)
+ static async Task QueryAsync(
+ SeqConnection connection,
+ string query,
+ DateTime? rangeStartUtc,
+ DateTime? rangeEndUtc,
+ SignalExpressionPart signalExpression,
+ int? timeoutMS,
+ string format = null)
{
// From dates should no longer be mandatory for QueryCsvAsync (issue raised)
var parameters = new Dictionary
{
- ["q"] = query,
- ["format"] = "text/csv"
+ ["q"] = query
};
+ if (format != null)
+ parameters.Add(nameof(format), format);
if (rangeStartUtc.HasValue)
parameters.Add(nameof(rangeEndUtc), rangeStartUtc.Value);
if (rangeEndUtc.HasValue)
diff --git a/src/SeqCli/Cli/Features/OutputFormatFeature.cs b/src/SeqCli/Cli/Features/OutputFormatFeature.cs
index e483aacb..506b231b 100644
--- a/src/SeqCli/Cli/Features/OutputFormatFeature.cs
+++ b/src/SeqCli/Cli/Features/OutputFormatFeature.cs
@@ -12,7 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+using System;
using SeqCli.Config;
+using SeqCli.Csv;
using SeqCli.Output;
using Serilog;
using Serilog.Core;
@@ -31,7 +33,9 @@ public OutputFormatFeature(SeqCliOutputConfig outputConfig)
_noColor = outputConfig.DisableColor;
}
- public static ConsoleTheme ConsoleTheme => SystemConsoleTheme.Literate;
+ public bool Json => _json;
+
+ ConsoleTheme Theme => _noColor ? ConsoleTheme.None : SystemConsoleTheme.Literate;
public override void Enable(OptionSet options)
{
@@ -54,9 +58,22 @@ public Logger CreateOutputLogger()
else
outputConfiguration.WriteTo.Console(
outputTemplate: "[{Timestamp:o} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}",
- theme: _noColor ? ConsoleTheme.None : ConsoleTheme);
+ theme: Theme);
return outputConfiguration.CreateLogger();
}
+
+ public void WriteCsv(string csv)
+ {
+ if (_noColor)
+ {
+ Console.Write(csv);
+ }
+ else
+ {
+ var tokens = new CsvTokenizer().Tokenize(csv);
+ CsvWriter.WriteCsv(tokens, Theme, Console.Out, true);
+ }
+ }
}
}
diff --git a/src/SeqCli/Program.cs b/src/SeqCli/Program.cs
index 668db97c..a5289f17 100644
--- a/src/SeqCli/Program.cs
+++ b/src/SeqCli/Program.cs
@@ -13,6 +13,7 @@
// limitations under the License.
using System;
+using System.Text;
using System.Threading.Tasks;
using Autofac;
using SeqCli.Cli;
@@ -34,6 +35,10 @@ static async Task Main(string[] args)
try
{
+ Console.InputEncoding =
+ Console.OutputEncoding =
+ new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
+
TaskScheduler.UnobservedTaskException +=
(s,e) => Log.Error(e.Exception, "Unobserved task exception: {UnobservedExceptionMessage}");