-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
initial generation diagnostics infrastructure
- Loading branch information
Showing
18 changed files
with
340 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
using System.Threading.Channels; | ||
using Microsoft.Extensions.Hosting; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace Elastic.Markdown.Diagnostics; | ||
|
||
public class DiagnosticsChannel | ||
{ | ||
private readonly Channel<Diagnostic> _channel; | ||
private readonly CancellationTokenSource _ctxSource; | ||
public ChannelReader<Diagnostic> Reader => _channel.Reader; | ||
|
||
public CancellationToken CancellationToken => _ctxSource.Token; | ||
|
||
public DiagnosticsChannel() | ||
{ | ||
var options = new UnboundedChannelOptions { SingleReader = true, SingleWriter = false }; | ||
_ctxSource = new CancellationTokenSource(); | ||
_channel = Channel.CreateUnbounded<Diagnostic>(options); | ||
} | ||
|
||
public void TryComplete(Exception? exception = null) | ||
{ | ||
_channel.Writer.TryComplete(exception); | ||
_ctxSource.Cancel(); | ||
} | ||
|
||
public void Write(Diagnostic diagnostic) | ||
{ | ||
var written = _channel.Writer.TryWrite(diagnostic); | ||
if (!written) | ||
{ | ||
//TODO | ||
} | ||
} | ||
} | ||
|
||
|
||
public enum Severity { Error, Warning } | ||
|
||
public readonly record struct Diagnostic | ||
{ | ||
public Severity Severity { get; init; } | ||
public int Line { get; init; } | ||
public int? Position { get; init; } | ||
public string File { get; init; } | ||
public string Message { get; init; } | ||
} | ||
|
||
public interface IDiagnosticsOutput | ||
{ | ||
public void Write(Diagnostic diagnostic); | ||
} | ||
|
||
public class LogDiagnosticOutput(ILogger logger) : IDiagnosticsOutput | ||
{ | ||
public void Write(Diagnostic diagnostic) | ||
{ | ||
if (diagnostic.Severity == Severity.Error) | ||
logger.LogError($"{diagnostic.Message} ({diagnostic.File}:{diagnostic.Line})"); | ||
else | ||
logger.LogWarning($"{diagnostic.Message} ({diagnostic.File}:{diagnostic.Line})"); | ||
} | ||
} | ||
|
||
|
||
public class DiagnosticsCollector(ILoggerFactory loggerFactory, IReadOnlyCollection<IDiagnosticsOutput> outputs) | ||
: IHostedService | ||
{ | ||
private readonly IReadOnlyCollection<IDiagnosticsOutput> _outputs = | ||
[new LogDiagnosticOutput(loggerFactory.CreateLogger<LogDiagnosticOutput>()), ..outputs]; | ||
|
||
public DiagnosticsChannel Channel { get; } = new(); | ||
|
||
private long _errors; | ||
private long _warnings; | ||
public long Warnings => _warnings; | ||
public long Errors => _errors; | ||
|
||
public async Task StartAsync(Cancel ctx) | ||
{ | ||
while (!Channel.CancellationToken.IsCancellationRequested) | ||
{ | ||
while (await Channel.Reader.WaitToReadAsync(Channel.CancellationToken)) | ||
Drain(); | ||
} | ||
Drain(); | ||
|
||
void Drain() | ||
{ | ||
while (Channel.Reader.TryRead(out var item)) | ||
{ | ||
IncrementSeverityCount(item); | ||
HandleItem(item); | ||
foreach (var output in _outputs) | ||
output.Write(item); | ||
} | ||
} | ||
} | ||
|
||
private void IncrementSeverityCount(Diagnostic item) | ||
{ | ||
if (item.Severity == Severity.Error) | ||
Interlocked.Increment(ref _errors); | ||
else if (item.Severity == Severity.Warning) | ||
Interlocked.Increment(ref _warnings); | ||
} | ||
|
||
protected virtual void HandleItem(Diagnostic diagnostic) {} | ||
|
||
public virtual Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; | ||
} |
21 changes: 21 additions & 0 deletions
21
src/Elastic.Markdown/Diagnostics/ProcessorDiagnosticExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using Elastic.Markdown.Myst; | ||
using Markdig.Helpers; | ||
using Markdig.Parsers; | ||
|
||
namespace Elastic.Markdown.Diagnostics; | ||
|
||
public static class ProcessorDiagnosticExtensions | ||
{ | ||
public static void EmitError(this InlineProcessor processor, int line, int position, string message) | ||
{ | ||
var d = new Diagnostic | ||
{ | ||
Severity = Severity.Error, | ||
File = processor.GetContext().Path.FullName, | ||
Position = position, | ||
Line = line, | ||
Message = message | ||
}; | ||
processor.GetBuildContext().Collector.Channel.Write(d); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
using System.IO.Abstractions; | ||
using Markdig; | ||
using Markdig.Parsers; | ||
|
||
namespace Elastic.Markdown.Myst; | ||
|
||
public static class ParserContextExtensions | ||
{ | ||
public static BuildContext GetBuildContext(this InlineProcessor processor) => | ||
processor.GetContext().Build; | ||
|
||
public static BuildContext GetBuildContext(this BlockProcessor processor) => | ||
processor.GetContext().Build; | ||
|
||
public static ParserContext GetContext(this InlineProcessor processor) => | ||
processor.Context as ParserContext | ||
?? throw new InvalidOperationException($"Provided context is not a {nameof(ParserContext)}"); | ||
|
||
public static ParserContext GetContext(this BlockProcessor processor) => | ||
processor.Context as ParserContext | ||
?? throw new InvalidOperationException($"Provided context is not a {nameof(ParserContext)}"); | ||
} | ||
|
||
public class ParserContext : MarkdownParserContext | ||
{ | ||
public ParserContext(MarkdownParser markdownParser, | ||
IFileInfo path, | ||
YamlFrontMatter? frontMatter, | ||
BuildContext context) | ||
{ | ||
Parser = markdownParser; | ||
Path = path; | ||
FrontMatter = frontMatter; | ||
Build = context; | ||
|
||
if (frontMatter?.Properties is { } props) | ||
{ | ||
foreach (var (key, value) in props) | ||
Properties[key] = value; | ||
} | ||
} | ||
|
||
public MarkdownParser Parser { get; } | ||
public IFileInfo Path { get; } | ||
public YamlFrontMatter? FrontMatter { get; } | ||
public BuildContext Build { get; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.