journal/Journal.DevTool/Core/RunEventLogReader.cs

100 lines
3.4 KiB
C#

using System.Text.Json;
namespace Sdt.Core;
public sealed record RunEventLogFile(
string Path,
string Name,
DateTimeOffset LastWriteTime,
long SizeBytes);
public sealed class RunEventLogReader
{
public IReadOnlyList<RunEventLogFile> ListEventFiles(string projectRoot)
{
var eventsRoot = Path.Combine(projectRoot, ".sdt", "events");
if (!Directory.Exists(eventsRoot))
return [];
return Directory.EnumerateFiles(eventsRoot, "*.jsonl", SearchOption.TopDirectoryOnly)
.Select(path =>
{
var info = new FileInfo(path);
return new RunEventLogFile(
Path: path,
Name: info.Name,
LastWriteTime: info.LastWriteTime,
SizeBytes: info.Length);
})
.OrderByDescending(f => f.LastWriteTime)
.ToList();
}
public IReadOnlyList<RunEvent> ReadEvents(string filePath)
{
var results = new List<RunEvent>();
if (!File.Exists(filePath))
return results;
foreach (var line in File.ReadLines(filePath))
{
if (string.IsNullOrWhiteSpace(line))
continue;
if (TryParseLine(line, out var evt))
results.Add(evt!);
}
return results;
}
internal static bool TryParseLine(string jsonLine, out RunEvent? evt)
{
evt = null;
try
{
using var doc = JsonDocument.Parse(jsonLine);
var root = doc.RootElement;
var category = root.TryGetProperty("category", out var c) ? c.GetString() : null;
var typeRaw = root.TryGetProperty("type", out var t) ? t.GetString() : null;
var message = root.TryGetProperty("message", out var m) ? m.GetString() : null;
var workflowId = root.TryGetProperty("workflowId", out var wf) ? wf.GetString() : null;
var stepId = root.TryGetProperty("stepId", out var st) ? st.GetString() : null;
var tool = root.TryGetProperty("tool", out var tl) ? tl.GetString() : null;
var success = root.TryGetProperty("success", out var s) && s.ValueKind != JsonValueKind.Null ? s.GetBoolean() : (bool?)null;
var exitCode = root.TryGetProperty("exitCode", out var ec) && ec.ValueKind != JsonValueKind.Null ? ec.GetInt32() : (int?)null;
DateTimeOffset? occurred = null;
if (root.TryGetProperty("occurredAt", out var ts) && ts.ValueKind == JsonValueKind.String &&
DateTimeOffset.TryParse(ts.GetString(), out var parsed))
{
occurred = parsed;
}
if (string.IsNullOrWhiteSpace(category) ||
string.IsNullOrWhiteSpace(typeRaw) ||
string.IsNullOrWhiteSpace(message) ||
!Enum.TryParse<RunEventType>(typeRaw, ignoreCase: true, out var type))
{
return false;
}
evt = new RunEvent(
Category: category!,
Type: type,
Message: message!,
WorkflowId: workflowId,
StepId: stepId,
Tool: tool,
Success: success,
ExitCode: exitCode,
Timestamp: occurred);
return true;
}
catch
{
return false;
}
}
}