// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.Text; using System.Text.Json; using System.Text.RegularExpressions; using EpicGames.Core; namespace EpicGames.Horde.Issues.Handlers { /// /// Instance of a particular compile error /// [IssueHandler(Tag = "Scoped")] public class ScopedIssueHandler : IssueHandler { const string NodeName = "Node"; const string ScopeName = "Scope"; readonly IssueHandlerContext _context; readonly List _issues = new List(); /// public override int Priority => 2; /// /// Constructor /// public ScopedIssueHandler(IssueHandlerContext context) => _context = context; /// public override bool HandleEvent(IssueEvent logEvent) { string? scope = null; foreach (JsonLogEvent line in logEvent.Lines) { JsonDocument document = JsonDocument.Parse(line.Data); string? channelType; string? channelText; if (document.RootElement.TryGetNestedProperty("properties.channel.$type", out channelType) && document.RootElement.TryGetNestedProperty("properties.channel.$text", out channelText)) { if (channelType != "Channel" || !channelText.StartsWith("Log", StringComparison.Ordinal)) { scope = null; break; } if (scope != null && scope != channelText) { scope = null; break; } scope = channelText; } } if (scope == null) { return false; } string fingerprintType = $"Scoped:{scope}"; string hashSource = logEvent.Render(); if (TryGetHash(hashSource, out Md5Hash hash)) { IssueEventGroup issue = new IssueEventGroup(fingerprintType, "{Severity} in {Meta:Node} - {Meta:Scope}", IssueChangeFilter.All); issue.Events.Add(logEvent); issue.Keys.Add(IssueKey.FromHash(hash)); issue.Metadata.Add(NodeName, _context.NodeName); issue.Metadata.Add(ScopeName, scope); _issues.Add(issue); return true; } return false; } /// public override IEnumerable GetIssues() => _issues; static bool TryGetHash(string message, out Md5Hash hash) { string sanitized = message.ToUpperInvariant(); sanitized = Regex.Replace(sanitized, @"(?