using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using PayRollBLL.SAP.Config; using System; using System.Linq; using System.Text; using System.Text.Json; namespace PayRollBLL.SAP.Audit { /// /// Writes one log file per day to the configured AuditLogDirectory. /// /// File naming: SAP_Declaration_2026-05-22.log /// Each file contains REQUEST blocks (payload + parameters) and /// RESPONSE blocks (HTTP status + SAP message + raw body), timestamped to the millisecond. /// public class SapDeclarationAuditLog : ISapDeclarationAuditLog { private readonly ILogger _logger; public SapDeclarationAuditLog( IOptions options, ILogger logger) { _logger = logger; } // ── Public API ──────────────────────────────────────────────────────────────── public void LogRequest( int infotype, int declarationId, int employeeId, int periodId, string endpointPath, string description, string jsonPayload) { var sb = new StringBuilder(); string ts = Ts(); string label = Label(infotype, description, endpointPath); sb.AppendLine(); sb.AppendLine($"â–¶ REQUEST {ts} Infotype {infotype}"); sb.AppendLine(ThinBar()); sb.AppendLine($" Infotype : {infotype} ({description})"); sb.AppendLine($" Endpoint : {endpointPath}"); sb.AppendLine($" DeclarationId : {declarationId}"); sb.AppendLine($" EmployeeId : {employeeId}"); sb.AppendLine($" PeriodId : {periodId}"); sb.AppendLine(ThinBar()); sb.AppendLine(" PAYLOAD:"); sb.AppendLine(Indent(TryPrettyPrint(jsonPayload))); sb.AppendLine(ThickBar()); Write(sb.ToString()); } public void LogResponse( int infotype, string endpointPath, string description, int httpStatus, bool isSuccess, string message, string responseBody) { var sb = new StringBuilder(); string ts = Ts(); string status = isSuccess ? "SUCCESS ✔" : "FAILED ✘"; sb.AppendLine(); sb.AppendLine($"â—€ RESPONSE {ts} Infotype {infotype} HTTP {httpStatus} {status}"); sb.AppendLine(ThinBar()); sb.AppendLine($" Infotype : {infotype} ({description})"); sb.AppendLine($" Endpoint : {endpointPath}"); sb.AppendLine($" Message : {message}"); sb.AppendLine(ThinBar()); sb.AppendLine(" SAP RESPONSE BODY:"); sb.AppendLine(Indent(TryPrettyPrint(responseBody))); sb.AppendLine(ThickBar()); Write(sb.ToString()); } // ── Internal helpers ────────────────────────────────────────────────────────── private void Write(string content) { // Route through ILogger so the audit entry is captured by the configured sink // (Serilog file/stdout/aggregator) rather than a pod-local file. _logger.LogInformation("SAP Declaration Audit: {AuditEntry}", content); } private static string TryPrettyPrint(string json) { if (string.IsNullOrWhiteSpace(json)) return "(empty)"; try { using var doc = JsonDocument.Parse(json); return JsonSerializer.Serialize( doc.RootElement, new JsonSerializerOptions { WriteIndented = true }); } catch { return json; } } private static string Indent(string text) { if (string.IsNullOrWhiteSpace(text)) return " (empty)"; return string.Join( Environment.NewLine, text.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None) .Select(line => " " + line)); } private static string Label(int infotype, string description, string endpointPath) => string.IsNullOrWhiteSpace(description) ? $"IT{infotype} | {endpointPath}" : $"IT{infotype} {description} | {endpointPath}"; private static string Ts() => DateTime.UtcNow.ToString("dd-MMM-yyyy HH:mm:ss.fff"); private static string ThinBar() => new('─', 84); private static string ThickBar() => new('═', 84); } }