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.LocalDateTime;
021import java.time.ZoneId;
022import java.time.format.DateTimeFormatter;
023
024/**
025 * Represents a single log entry.
026 *
027 * @author devteam@scivicslab.com
028 */
029public class LogEntry {
030    private static final DateTimeFormatter ISO_FORMATTER =
031            DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX");
032    private static final ZoneId SYSTEM_ZONE = ZoneId.systemDefault();
033
034    private final long id;
035    private final long sessionId;
036    private final LocalDateTime timestamp;
037    private final String nodeId;
038    private final String label;
039    private final String actionName;
040    private final LogLevel level;
041    private final String message;
042    private final Integer exitCode;
043    private final Long durationMs;
044
045    public LogEntry(long id, long sessionId, LocalDateTime timestamp, String nodeId,
046                    String label, String actionName, LogLevel level, String message,
047                    Integer exitCode, Long durationMs) {
048        this.id = id;
049        this.sessionId = sessionId;
050        this.timestamp = timestamp;
051        this.nodeId = nodeId;
052        this.label = label;
053        this.actionName = actionName;
054        this.level = level;
055        this.message = message;
056        this.exitCode = exitCode;
057        this.durationMs = durationMs;
058    }
059
060    public long getId() { return id; }
061    public long getSessionId() { return sessionId; }
062    public LocalDateTime getTimestamp() { return timestamp; }
063    public String getNodeId() { return nodeId; }
064    public String getLabel() { return label; }
065    public String getActionName() { return actionName; }
066    public LogLevel getLevel() { return level; }
067    public String getMessage() { return message; }
068    public Integer getExitCode() { return exitCode; }
069    public Long getDurationMs() { return durationMs; }
070
071    @Override
072    public String toString() {
073        StringBuilder sb = new StringBuilder();
074        sb.append("[").append(formatTimestamp(timestamp)).append("] ");
075        sb.append(String.format("%-5s ", level));
076        if (label != null) {
077            sb.append("[").append(label);
078            if (actionName != null) {
079                sb.append(" -> ").append(actionName);
080            }
081            sb.append("] ");
082        }
083        sb.append(message);
084        if (exitCode != null && exitCode != 0) {
085            sb.append(" (exit=").append(exitCode).append(")");
086        }
087        if (durationMs != null) {
088            sb.append(" [").append(durationMs).append("ms]");
089        }
090        return sb.toString();
091    }
092
093    private String formatTimestamp(LocalDateTime ts) {
094        if (ts == null) {
095            return "N/A";
096        }
097        return ts.atZone(SYSTEM_ZONE).format(ISO_FORMATTER);
098    }
099}