100 lines
3.4 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|