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.sql.Connection;
021import java.util.List;
022
023/**
024 * Interface for distributed log storage.
025 *
026 * <p>This interface defines operations for storing and querying logs
027 * from distributed workflow execution across multiple nodes.</p>
028 *
029 * <p>The interface provides singleton access for components that need
030 * database connection (e.g., WorkflowReporter). The singleton is set
031 * by RunCLI at workflow startup and cleared after execution.</p>
032 *
033 * @author devteam@scivicslab.com
034 */
035public interface DistributedLogStore extends AutoCloseable {
036
037    // ========================================================================
038    // Singleton management
039    // ========================================================================
040
041    /** Singleton instance holder */
042    class InstanceHolder {
043        private static DistributedLogStore instance;
044    }
045
046    /**
047     * Sets the singleton instance.
048     *
049     * <p>Called by RunCLI when starting workflow execution.</p>
050     *
051     * @param store the DistributedLogStore instance to use globally
052     */
053    static void setInstance(DistributedLogStore store) {
054        InstanceHolder.instance = store;
055    }
056
057    /**
058     * Gets the singleton instance.
059     *
060     * @return the global DistributedLogStore instance, or null if not set
061     */
062    static DistributedLogStore getInstance() {
063        return InstanceHolder.instance;
064    }
065
066    // ========================================================================
067    // Connection access
068    // ========================================================================
069
070    /**
071     * Gets the database connection for read-only operations.
072     *
073     * <p>Components should NOT close this connection. The connection is owned
074     * by RunCLI and will be closed when the workflow execution ends.</p>
075     *
076     * @return the JDBC connection
077     */
078    Connection getConnection();
079
080    /**
081     * Starts a new workflow execution session.
082     *
083     * @param workflowName name of the workflow being executed
084     * @param nodeCount number of nodes participating in this session
085     * @return session ID for subsequent log entries
086     */
087    long startSession(String workflowName, int nodeCount);
088
089    /**
090     * Starts a new workflow execution session with overlay and inventory info.
091     *
092     * @param workflowName name of the workflow being executed
093     * @param overlayName name of the overlay being used (may be null)
094     * @param inventoryName name of the inventory file being used (may be null)
095     * @param nodeCount number of nodes participating in this session
096     * @return session ID for subsequent log entries
097     */
098    long startSession(String workflowName, String overlayName, String inventoryName, int nodeCount);
099
100    /**
101     * Starts a new workflow execution session with full execution context.
102     *
103     * @param workflowName name of the workflow being executed
104     * @param overlayName name of the overlay being used (may be null)
105     * @param inventoryName name of the inventory file being used (may be null)
106     * @param nodeCount number of nodes participating in this session
107     * @param cwd current working directory
108     * @param gitCommit git commit hash of the workflow directory (may be null)
109     * @param gitBranch git branch name (may be null)
110     * @param commandLine the command line used to invoke actor-IaC
111     * @param actorIacVersion actor-IaC version
112     * @param actorIacCommit actor-IaC git commit hash (may be null)
113     * @return session ID for subsequent log entries
114     */
115    default long startSession(String workflowName, String overlayName, String inventoryName, int nodeCount,
116                              String cwd, String gitCommit, String gitBranch,
117                              String commandLine, String actorIacVersion, String actorIacCommit) {
118        // Default implementation for backward compatibility
119        return startSession(workflowName, overlayName, inventoryName, nodeCount);
120    }
121
122    /**
123     * Records a log entry.
124     *
125     * @param sessionId session ID from startSession()
126     * @param nodeId identifier of the node generating this log
127     * @param level log level
128     * @param message log message
129     */
130    void log(long sessionId, String nodeId, LogLevel level, String message);
131
132    /**
133     * Records a log entry with transition context.
134     *
135     * @param sessionId session ID from startSession()
136     * @param nodeId identifier of the node
137     * @param label current label in workflow
138     * @param level log level
139     * @param message log message
140     */
141    void log(long sessionId, String nodeId, String label, LogLevel level, String message);
142
143    /**
144     * Records an action result.
145     *
146     * @param sessionId session ID
147     * @param nodeId node identifier
148     * @param label label
149     * @param actionName action/method name
150     * @param exitCode command exit code (0 for success)
151     * @param durationMs execution duration in milliseconds
152     * @param output command output or result message
153     */
154    void logAction(long sessionId, String nodeId, String label,
155                   String actionName, int exitCode, long durationMs, String output);
156
157    /**
158     * Marks a node as succeeded in this session.
159     *
160     * @param sessionId session ID
161     * @param nodeId node identifier
162     */
163    void markNodeSuccess(long sessionId, String nodeId);
164
165    /**
166     * Marks a node as failed in this session.
167     *
168     * @param sessionId session ID
169     * @param nodeId node identifier
170     * @param reason failure reason
171     */
172    void markNodeFailed(long sessionId, String nodeId, String reason);
173
174    /**
175     * Ends a session with the given status.
176     *
177     * @param sessionId session ID
178     * @param status final status
179     */
180    void endSession(long sessionId, SessionStatus status);
181
182    /**
183     * Retrieves all log entries for a specific node in a session.
184     *
185     * @param sessionId session ID
186     * @param nodeId node identifier
187     * @return list of log entries
188     */
189    List<LogEntry> getLogsByNode(long sessionId, String nodeId);
190
191    /**
192     * Retrieves log entries filtered by level.
193     *
194     * @param sessionId session ID
195     * @param minLevel minimum log level to include
196     * @return list of log entries
197     */
198    List<LogEntry> getLogsByLevel(long sessionId, LogLevel minLevel);
199
200    /**
201     * Retrieves error logs for a session.
202     *
203     * @param sessionId session ID
204     * @return list of error log entries
205     */
206    default List<LogEntry> getErrors(long sessionId) {
207        return getLogsByLevel(sessionId, LogLevel.ERROR);
208    }
209
210    /**
211     * Gets a summary of the session.
212     *
213     * @param sessionId session ID
214     * @return session summary
215     */
216    SessionSummary getSummary(long sessionId);
217
218    /**
219     * Gets the most recent session ID.
220     *
221     * @return latest session ID, or -1 if no sessions exist
222     */
223    long getLatestSessionId();
224
225    /**
226     * Lists all sessions.
227     *
228     * @param limit maximum number of sessions to return
229     * @return list of session summaries
230     */
231    List<SessionSummary> listSessions(int limit);
232}