001/* 002 * Copyright 2025 devteam@scivicslab.com 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, 011 * software distributed under the License is distributed on an 012 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the 014 * specific language governing permissions and limitations 015 * under the License. 016 */ 017 018package com.scivicslab.actoriac.log; 019 020import java.time.Duration; 021import java.time.LocalDateTime; 022import java.time.ZoneId; 023import java.time.format.DateTimeFormatter; 024import java.util.List; 025 026/** 027 * Summary of a workflow execution session. 028 * 029 * @author devteam@scivicslab.com 030 */ 031public class SessionSummary { 032 private static final DateTimeFormatter ISO_FORMATTER = 033 DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX"); 034 private static final ZoneId SYSTEM_ZONE = ZoneId.systemDefault(); 035 036 private final long sessionId; 037 private final String workflowName; 038 private final String overlayName; 039 private final String inventoryName; 040 private final LocalDateTime startedAt; 041 private final LocalDateTime endedAt; 042 private final int nodeCount; 043 private final SessionStatus status; 044 private final int successCount; 045 private final int failedCount; 046 private final List<String> failedNodes; 047 private final int totalLogEntries; 048 private final int errorCount; 049 050 // Execution context for reproducibility 051 private final String cwd; 052 private final String gitCommit; 053 private final String gitBranch; 054 private final String commandLine; 055 private final String actorIacVersion; 056 private final String actorIacCommit; 057 058 /** 059 * Legacy constructor for backward compatibility. 060 */ 061 public SessionSummary(long sessionId, String workflowName, String overlayName, 062 String inventoryName, LocalDateTime startedAt, 063 LocalDateTime endedAt, int nodeCount, SessionStatus status, 064 int successCount, int failedCount, List<String> failedNodes, 065 int totalLogEntries, int errorCount) { 066 this(sessionId, workflowName, overlayName, inventoryName, startedAt, endedAt, 067 nodeCount, status, successCount, failedCount, failedNodes, totalLogEntries, errorCount, 068 null, null, null, null, null, null); 069 } 070 071 /** 072 * Full constructor with execution context. 073 */ 074 public SessionSummary(long sessionId, String workflowName, String overlayName, 075 String inventoryName, LocalDateTime startedAt, 076 LocalDateTime endedAt, int nodeCount, SessionStatus status, 077 int successCount, int failedCount, List<String> failedNodes, 078 int totalLogEntries, int errorCount, 079 String cwd, String gitCommit, String gitBranch, 080 String commandLine, String actorIacVersion, String actorIacCommit) { 081 this.sessionId = sessionId; 082 this.workflowName = workflowName; 083 this.overlayName = overlayName; 084 this.inventoryName = inventoryName; 085 this.startedAt = startedAt; 086 this.endedAt = endedAt; 087 this.nodeCount = nodeCount; 088 this.status = status; 089 this.successCount = successCount; 090 this.failedCount = failedCount; 091 this.failedNodes = failedNodes; 092 this.totalLogEntries = totalLogEntries; 093 this.errorCount = errorCount; 094 this.cwd = cwd; 095 this.gitCommit = gitCommit; 096 this.gitBranch = gitBranch; 097 this.commandLine = commandLine; 098 this.actorIacVersion = actorIacVersion; 099 this.actorIacCommit = actorIacCommit; 100 } 101 102 public long getSessionId() { return sessionId; } 103 public String getWorkflowName() { return workflowName; } 104 public String getOverlayName() { return overlayName; } 105 public String getInventoryName() { return inventoryName; } 106 public LocalDateTime getStartedAt() { return startedAt; } 107 public LocalDateTime getEndedAt() { return endedAt; } 108 public int getNodeCount() { return nodeCount; } 109 public SessionStatus getStatus() { return status; } 110 public int getSuccessCount() { return successCount; } 111 public int getFailedCount() { return failedCount; } 112 public List<String> getFailedNodes() { return failedNodes; } 113 public int getTotalLogEntries() { return totalLogEntries; } 114 public int getErrorCount() { return errorCount; } 115 116 // Execution context getters 117 public String getCwd() { return cwd; } 118 public String getGitCommit() { return gitCommit; } 119 public String getGitBranch() { return gitBranch; } 120 public String getCommandLine() { return commandLine; } 121 public String getActorIacVersion() { return actorIacVersion; } 122 public String getActorIacCommit() { return actorIacCommit; } 123 124 public Duration getDuration() { 125 if (startedAt == null || endedAt == null) { 126 return Duration.ZERO; 127 } 128 return Duration.between(startedAt, endedAt); 129 } 130 131 @Override 132 public String toString() { 133 StringBuilder sb = new StringBuilder(); 134 sb.append("Session #").append(sessionId).append(": ").append(workflowName).append("\n"); 135 if (overlayName != null) { 136 sb.append(" Overlay: ").append(overlayName).append("\n"); 137 } 138 if (inventoryName != null) { 139 sb.append(" Inventory: ").append(inventoryName).append("\n"); 140 } 141 sb.append(" Started: ").append(formatTimestamp(startedAt)).append("\n"); 142 sb.append(" Ended: ").append(formatTimestamp(endedAt)).append("\n"); 143 144 Duration d = getDuration(); 145 if (!d.isZero()) { 146 long minutes = d.toMinutes(); 147 long seconds = d.toSecondsPart(); 148 sb.append(" Duration: ").append(minutes).append("m ").append(seconds).append("s\n"); 149 } 150 151 sb.append(" Nodes: ").append(nodeCount).append("\n"); 152 sb.append(" Status: ").append(status).append("\n"); 153 sb.append("\n"); 154 sb.append(" Results:\n"); 155 sb.append(" SUCCESS: ").append(successCount).append(" nodes\n"); 156 sb.append(" FAILED: ").append(failedCount).append(" nodes"); 157 if (failedNodes != null && !failedNodes.isEmpty()) { 158 sb.append(" (").append(String.join(", ", failedNodes)).append(")"); 159 } 160 sb.append("\n"); 161 sb.append("\n"); 162 sb.append(" Log lines: ").append(totalLogEntries).append(" (").append(errorCount).append(" errors)"); 163 return sb.toString(); 164 } 165 166 /** 167 * Formats a timestamp in ISO 8601 format with timezone. 168 */ 169 private String formatTimestamp(LocalDateTime timestamp) { 170 if (timestamp == null) { 171 return "N/A"; 172 } 173 return timestamp.atZone(SYSTEM_ZONE).format(ISO_FORMATTER); 174 } 175}