Skip to content

Commit

Permalink
Merge pull request #106 from nblumhardt/pretty-print
Browse files Browse the repository at this point in the history
Adds the seqcli print command
  • Loading branch information
nblumhardt authored Apr 11, 2019
2 parents a4ab735 + 46706a1 commit 7fa8197
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 10 deletions.
4 changes: 1 addition & 3 deletions src/SeqCli/Apps/AppHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Seq.Apps;
using Serilog;
Expand All @@ -37,8 +36,7 @@ public static async Task<int> Run(
if (appSettings == null) throw new ArgumentNullException(nameof(appSettings));
if (storagePath == null) throw new ArgumentNullException(nameof(storagePath));
if (seqBaseUri == null) throw new ArgumentNullException(nameof(seqBaseUri));
Console.InputEncoding = new UTF8Encoding(false);
Console.OutputEncoding = new UTF8Encoding(false);

ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;

using (var log = new LoggerConfiguration()
Expand Down
2 changes: 1 addition & 1 deletion src/SeqCli/Cli/Commands/App/RunCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

namespace SeqCli.Cli.Commands.App
{
[Command("app", "run", "Host a .NET [SeqApp] plug-in",
[Command("app", "run", "Host a .NET `[SeqApp]` plug-in",
Example = "seqcli tail --json | seqcli app run -d \"./bin/Debug/netstandard2.2\" -p [email protected]")]
class RunCommand : Command
{
Expand Down
106 changes: 106 additions & 0 deletions src/SeqCli/Cli/Commands/PrintCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright 2019 Datalust Pty Ltd and Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.IO;
using System.Threading.Tasks;
using Newtonsoft.Json;
using SeqCli.Cli.Features;
using SeqCli.Config;
using SeqCli.Ingestion;
using SeqCli.Output;
using SeqCli.Util;
using Serilog;
using Serilog.Events;
using Serilog.Sinks.SystemConsole.Themes;

namespace SeqCli.Cli.Commands
{
[Command("print", "Pretty-print events in CLEF/JSON format, from a file or `STDIN`",
Example = "seqcli print -i log-20201028.clef")]
class PrintCommand : Command
{
readonly FileInputFeature _fileInputFeature;
readonly InvalidDataHandlingFeature _invalidDataHandlingFeature;

string _filter, _template = OutputFormatFeature.DefaultOutputTemplate;
bool _noColor;

public PrintCommand(SeqCliOutputConfig outputConfig)
{
if (outputConfig == null) throw new ArgumentNullException(nameof(outputConfig));
_noColor = outputConfig.DisableColor;

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

Options.Add("f=|filter=",
"Filter expression to select a subset of events",
v => _filter = ArgumentString.Normalize(v));

Options.Add("template=",
"Specify an output template to control plain text formatting",
v => _template = ArgumentString.Normalize(v));

_invalidDataHandlingFeature = Enable<InvalidDataHandlingFeature>();

Options.Add("no-color", "Don't colorize text output", v => _noColor = true);
}

protected override async Task<int> Run()
{
var outputConfiguration = new LoggerConfiguration()
.MinimumLevel.Is(LevelAlias.Minimum)
.Enrich.With<RedundantEventTypeRemovalEnricher>()
.Enrich.With<SurrogateLevelRemovalEnricher>()
.WriteTo.Console(
outputTemplate: _template,
theme: _noColor ? ConsoleTheme.None : OutputFormatFeature.DefaultTheme);

if (_filter != null)
outputConfiguration.Filter.ByIncludingOnly(_filter);

using (var logger = outputConfiguration.CreateLogger())
{
foreach (var input in _fileInputFeature.OpenInputs())
{
using (input)
{
var reader = new JsonLogEventReader(input);

var isAtEnd = false;
do
{
try
{
var result = await reader.TryReadAsync();
isAtEnd = result.IsAtEnd;

if (result.LogEvent != null)
logger.Write(result.LogEvent);
}
catch (Exception ex)
{
if (!(ex is JsonReaderException) && !(ex is InvalidDataException) ||
_invalidDataHandlingFeature.InvalidDataHandling != InvalidDataHandling.Ignore)
throw;
}
} while (!isAtEnd);
}
}
}

return 0;
}
}
}
9 changes: 7 additions & 2 deletions src/SeqCli/Cli/Features/OutputFormatFeature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ namespace SeqCli.Cli.Features
{
class OutputFormatFeature : CommandFeature
{
public const string DefaultOutputTemplate =
"[{Timestamp:o} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}";

public static readonly ConsoleTheme DefaultTheme = SystemConsoleTheme.Literate;

bool _json, _noColor;

public OutputFormatFeature(SeqCliOutputConfig outputConfig)
Expand All @@ -40,7 +45,7 @@ public OutputFormatFeature(SeqCliOutputConfig outputConfig)

public bool Json => _json;

ConsoleTheme Theme => _noColor ? ConsoleTheme.None : SystemConsoleTheme.Literate;
ConsoleTheme Theme => _noColor ? ConsoleTheme.None : DefaultTheme;

public override void Enable(OptionSet options)
{
Expand All @@ -66,7 +71,7 @@ public Logger CreateOutputLogger()
{
outputConfiguration.Enrich.With<SurrogateLevelRemovalEnricher>();
outputConfiguration.WriteTo.Console(
outputTemplate: "[{Timestamp:o} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}",
outputTemplate: DefaultOutputTemplate,
theme: Theme);
}

Expand Down
11 changes: 11 additions & 0 deletions src/SeqCli/PlainText/Framing/FrameReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ public FrameReader(TextReader source, TextParser<TextSpan> frameStart, TimeSpan
_source = source ?? throw new ArgumentNullException(nameof(source));
_frameStart = frameStart ?? throw new ArgumentNullException(nameof(frameStart));
_trailingLineArrivalDeadline = trailingLineArrivalDeadline;

#if WINDOWS
// Somehow, PowerShell manages to send a UTF-8 BOM when piping a command's output to us
// via STDIN, regardless of how we set Console.InputEncoding. This hackily skips the BOM,
// while we all live in hope of some brighter future.
if (_source.Peek() == 65279)
_source.Read();
#endif
}

public async Task<Frame> TryReadAsync()
Expand All @@ -55,6 +63,9 @@ public async Task<Frame> TryReadAsync()
return new Frame();

var line = await _unawaitedNextLine;
if (line[0] == 65279)
line = line.Substring(1);

_unawaitedNextLine = null;
if (line == null)
return new Frame {IsAtEnd = true};
Expand Down
7 changes: 3 additions & 4 deletions src/SeqCli/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ static async Task<int> Main(string[] args)
// Windows proxy settings are respected
AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
#endif

Log.Logger = new LoggerConfiguration()
.MinimumLevel.Error()
.WriteTo.Console(
Expand All @@ -42,9 +42,8 @@ static async Task<int> Main(string[] args)

try
{
Console.InputEncoding =
Console.OutputEncoding =
new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
Console.InputEncoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
Console.OutputEncoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);

TaskScheduler.UnobservedTaskException +=
(s,e) => Log.Error(e.Exception, "Unobserved task exception");
Expand Down
2 changes: 2 additions & 0 deletions src/SeqCli/SeqCliModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ protected override void Load(ContainerBuilder builder)
.WithMetadataFrom<CommandAttribute>();
builder.RegisterType<SeqConnectionFactory>();
builder.Register(c => SeqCliConfig.Read()).SingleInstance();
builder.Register(c => c.Resolve<SeqCliConfig>().Connection).SingleInstance();
builder.Register(c => c.Resolve<SeqCliConfig>().Output).SingleInstance();
}
}
}

0 comments on commit 7fa8197

Please sign in to comment.