This commit is contained in:
2025-05-23 15:11:03 +04:00
parent c86165f88c
commit 92b9c356b8
83 changed files with 450 additions and 810 deletions

View File

@@ -5,7 +5,7 @@ import (
"log"
"strconv" // Added strconv for JobID parsing
"github.com/freeflowuniverse/heroagent/pkg/herojobs"
"git.ourworld.tf/herocode/heroagent/pkg/herojobs"
"github.com/gofiber/fiber/v2"
)

View File

@@ -10,7 +10,7 @@ import (
"net/http/httptest"
"testing"
"github.com/freeflowuniverse/heroagent/pkg/herojobs"
"git.ourworld.tf/herocode/heroagent/pkg/herojobs"
"github.com/gofiber/fiber/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"

View File

@@ -7,7 +7,7 @@ import (
"strings"
"time"
"github.com/freeflowuniverse/heroagent/pkg/logger"
"git.ourworld.tf/herocode/heroagent/pkg/logger"
"github.com/gofiber/fiber/v2"
)
@@ -65,40 +65,40 @@ func NewLogHandler(logPath string) (*LogHandler, error) {
type LogType string
const (
LogTypeSystem LogType = "system"
LogTypeService LogType = "service"
LogTypeJob LogType = "job"
LogTypeProcess LogType = "process"
LogTypeAll LogType = "all" // Special type to retrieve logs from all sources
LogTypeSystem LogType = "system"
LogTypeService LogType = "service"
LogTypeJob LogType = "job"
LogTypeProcess LogType = "process"
LogTypeAll LogType = "all" // Special type to retrieve logs from all sources
)
// GetLogs renders the logs page with logs content
func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
// Check which logger to use based on the log type parameter
logTypeParam := c.Query("log_type", string(LogTypeSystem))
// Parse query parameters
category := c.Query("category", "")
logItemType := parseLogType(c.Query("type", ""))
maxItems := c.QueryInt("max_items", 100)
page := c.QueryInt("page", 1)
itemsPerPage := 20 // Default items per page
// Parse time range
fromTime := parseTimeParam(c.Query("from", ""))
toTime := parseTimeParam(c.Query("to", ""))
// Create search arguments
searchArgs := logger.SearchArgs{
Category: category,
LogType: logItemType,
MaxItems: maxItems,
Category: category,
LogType: logItemType,
MaxItems: maxItems,
}
if !fromTime.IsZero() {
searchArgs.TimestampFrom = &fromTime
}
if !toTime.IsZero() {
searchArgs.TimestampTo = &toTime
}
@@ -107,7 +107,7 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
var logs []logger.LogItem
var err error
var logTypeTitle string
// Check if we want to merge logs from all sources
if LogType(logTypeParam) == LogTypeAll {
// Get merged logs from all loggers
@@ -116,7 +116,7 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
} else {
// Select the appropriate logger based on the log type
var selectedLogger *logger.Logger
switch LogType(logTypeParam) {
case LogTypeService:
selectedLogger = h.serviceLogger
@@ -131,13 +131,13 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
selectedLogger = h.systemLogger
logTypeTitle = "System Logs"
}
// Check if the selected logger is properly initialized
if selectedLogger == nil {
return c.Render("admin/system/logs", fiber.Map{
"title": logTypeTitle,
"error": "Logger not initialized",
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"title": logTypeTitle,
"error": "Logger not initialized",
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"selectedLogType": logTypeParam,
})
}
@@ -149,25 +149,24 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
// Handle search error
if err != nil {
return c.Render("admin/system/logs", fiber.Map{
"title": logTypeTitle,
"error": err.Error(),
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"title": logTypeTitle,
"error": err.Error(),
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"selectedLogType": logTypeParam,
})
}
// Calculate total pages
totalLogs := len(logs)
totalPages := (totalLogs + itemsPerPage - 1) / itemsPerPage
// Apply pagination
startIndex := (page - 1) * itemsPerPage
endIndex := startIndex + itemsPerPage
if endIndex > totalLogs {
endIndex = totalLogs
}
// Slice logs for current page
pagedLogs := logs
if startIndex < totalLogs {
@@ -175,7 +174,7 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
} else {
pagedLogs = []logger.LogItem{}
}
// Convert logs to a format suitable for the UI
formattedLogs := make([]fiber.Map, 0, len(pagedLogs))
for _, log := range pagedLogs {
@@ -185,7 +184,7 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
logTypeStr = "ERROR"
logTypeClass = "log-error"
}
formattedLogs = append(formattedLogs, fiber.Map{
"timestamp": log.Timestamp.Format("2006-01-02T15:04:05"),
"category": log.Category,
@@ -194,20 +193,20 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
"typeClass": logTypeClass,
})
}
return c.Render("admin/system/logs", fiber.Map{
"title": logTypeTitle,
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"title": logTypeTitle,
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"selectedLogType": logTypeParam,
"logs": formattedLogs,
"total": totalLogs,
"showing": len(formattedLogs),
"page": page,
"totalPages": totalPages,
"categoryParam": category,
"typeParam": c.Query("type", ""),
"fromParam": c.Query("from", ""),
"toParam": c.Query("to", ""),
"logs": formattedLogs,
"total": totalLogs,
"showing": len(formattedLogs),
"page": page,
"totalPages": totalPages,
"categoryParam": category,
"typeParam": c.Query("type", ""),
"fromParam": c.Query("from", ""),
"toParam": c.Query("to", ""),
})
}
@@ -215,27 +214,27 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error {
// Check which logger to use based on the log type parameter
logTypeParam := c.Query("log_type", string(LogTypeSystem))
// Parse query parameters
category := c.Query("category", "")
logItemType := parseLogType(c.Query("type", ""))
maxItems := c.QueryInt("max_items", 100)
// Parse time range
fromTime := parseTimeParam(c.Query("from", ""))
toTime := parseTimeParam(c.Query("to", ""))
// Create search arguments
searchArgs := logger.SearchArgs{
Category: category,
LogType: logItemType,
MaxItems: maxItems,
Category: category,
LogType: logItemType,
MaxItems: maxItems,
}
if !fromTime.IsZero() {
searchArgs.TimestampFrom = &fromTime
}
if !toTime.IsZero() {
searchArgs.TimestampTo = &toTime
}
@@ -243,7 +242,7 @@ func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error {
// Variables for logs and error
var logs []logger.LogItem
var err error
// Check if we want to merge logs from all sources
if LogType(logTypeParam) == LogTypeAll {
// Get merged logs from all loggers
@@ -251,7 +250,7 @@ func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error {
} else {
// Select the appropriate logger based on the log type
var selectedLogger *logger.Logger
switch LogType(logTypeParam) {
case LogTypeService:
selectedLogger = h.serviceLogger
@@ -262,7 +261,7 @@ func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error {
default:
selectedLogger = h.systemLogger
}
// Check if the selected logger is properly initialized
if selectedLogger == nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
@@ -280,7 +279,7 @@ func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error {
"error": err.Error(),
})
}
// Convert logs to a format suitable for the UI
response := make([]fiber.Map, 0, len(logs))
for _, log := range logs {
@@ -288,7 +287,7 @@ func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error {
if log.LogType == logger.LogTypeError {
logTypeStr = "ERROR"
}
response = append(response, fiber.Map{
"timestamp": log.Timestamp.Format(time.RFC3339),
"category": log.Category,
@@ -296,9 +295,9 @@ func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error {
"type": logTypeStr,
})
}
return c.JSON(fiber.Map{
"logs": response,
"logs": response,
"total": len(logs),
})
}
@@ -309,29 +308,29 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error {
// Check which logger to use based on the log type parameter
logTypeParam := c.Query("log_type", string(LogTypeSystem))
// Parse query parameters
category := c.Query("category", "")
logItemType := parseLogType(c.Query("type", ""))
maxItems := c.QueryInt("max_items", 100)
page := c.QueryInt("page", 1)
itemsPerPage := 20 // Default items per page
// Parse time range
fromTime := parseTimeParam(c.Query("from", ""))
toTime := parseTimeParam(c.Query("to", ""))
// Create search arguments
searchArgs := logger.SearchArgs{
Category: category,
LogType: logItemType,
MaxItems: maxItems,
Category: category,
LogType: logItemType,
MaxItems: maxItems,
}
if !fromTime.IsZero() {
searchArgs.TimestampFrom = &fromTime
}
if !toTime.IsZero() {
searchArgs.TimestampTo = &toTime
}
@@ -340,7 +339,7 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error {
var logs []logger.LogItem
var err error
var logTypeTitle string
// Check if we want to merge logs from all sources
if LogType(logTypeParam) == LogTypeAll {
// Get merged logs from all loggers
@@ -349,7 +348,7 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error {
} else {
// Select the appropriate logger based on the log type
var selectedLogger *logger.Logger
switch LogType(logTypeParam) {
case LogTypeService:
selectedLogger = h.serviceLogger
@@ -364,13 +363,13 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error {
selectedLogger = h.systemLogger
logTypeTitle = "System Logs"
}
// Check if the selected logger is properly initialized
if selectedLogger == nil {
return c.Render("admin/system/logs_fragment", fiber.Map{
"title": logTypeTitle,
"error": "Logger not initialized",
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"title": logTypeTitle,
"error": "Logger not initialized",
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"selectedLogType": logTypeParam,
})
}
@@ -382,24 +381,24 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error {
// Handle search error
if err != nil {
return c.Render("admin/system/logs_fragment", fiber.Map{
"title": logTypeTitle,
"error": err.Error(),
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"title": logTypeTitle,
"error": err.Error(),
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"selectedLogType": logTypeParam,
})
}
// Calculate total pages
totalLogs := len(logs)
totalPages := (totalLogs + itemsPerPage - 1) / itemsPerPage
// Apply pagination
startIndex := (page - 1) * itemsPerPage
endIndex := startIndex + itemsPerPage
if endIndex > totalLogs {
endIndex = totalLogs
}
// Slice logs for current page
pagedLogs := logs
if startIndex < totalLogs {
@@ -407,7 +406,7 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error {
} else {
pagedLogs = []logger.LogItem{}
}
// Convert logs to a format suitable for the UI
formattedLogs := make([]fiber.Map, 0, len(pagedLogs))
for _, log := range pagedLogs {
@@ -417,7 +416,7 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error {
logTypeStr = "ERROR"
logTypeClass = "log-error"
}
formattedLogs = append(formattedLogs, fiber.Map{
"timestamp": log.Timestamp.Format("2006-01-02T15:04:05"),
"category": log.Category,
@@ -426,18 +425,18 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error {
"typeClass": logTypeClass,
})
}
// Set layout to empty to disable the layout for fragment responses
return c.Render("admin/system/logs_fragment", fiber.Map{
"title": logTypeTitle,
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"title": logTypeTitle,
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"selectedLogType": logTypeParam,
"logs": formattedLogs,
"total": totalLogs,
"showing": len(formattedLogs),
"page": page,
"totalPages": totalPages,
"layout": "", // Disable layout for partial template
"logs": formattedLogs,
"total": totalLogs,
"showing": len(formattedLogs),
"page": page,
"totalPages": totalPages,
"layout": "", // Disable layout for partial template
})
}
@@ -458,12 +457,12 @@ func parseTimeParam(timeStr string) time.Time {
if timeStr == "" {
return time.Time{}
}
t, err := time.Parse(time.RFC3339, timeStr)
if err != nil {
return time.Time{}
}
return t
}
@@ -471,10 +470,10 @@ func parseTimeParam(timeStr string) time.Time {
func (h *LogHandler) getMergedLogs(args logger.SearchArgs) ([]logger.LogItem, error) {
// Create a slice to hold all logs
allLogs := make([]logger.LogItem, 0)
// Create a map to track errors
errors := make(map[string]error)
// Get logs from system logger if available
if h.systemLogger != nil {
systemLogs, err := h.systemLogger.Search(args)
@@ -488,7 +487,7 @@ func (h *LogHandler) getMergedLogs(args logger.SearchArgs) ([]logger.LogItem, er
allLogs = append(allLogs, systemLogs...)
}
}
// Get logs from service logger if available
if h.serviceLogger != nil {
serviceLogs, err := h.serviceLogger.Search(args)
@@ -502,7 +501,7 @@ func (h *LogHandler) getMergedLogs(args logger.SearchArgs) ([]logger.LogItem, er
allLogs = append(allLogs, serviceLogs...)
}
}
// Get logs from job logger if available
if h.jobLogger != nil {
jobLogs, err := h.jobLogger.Search(args)
@@ -516,7 +515,7 @@ func (h *LogHandler) getMergedLogs(args logger.SearchArgs) ([]logger.LogItem, er
allLogs = append(allLogs, jobLogs...)
}
}
// Get logs from process logger if available
if h.processLogger != nil {
processLogs, err := h.processLogger.Search(args)
@@ -530,7 +529,7 @@ func (h *LogHandler) getMergedLogs(args logger.SearchArgs) ([]logger.LogItem, er
allLogs = append(allLogs, processLogs...)
}
}
// Check if we have any logs
if len(allLogs) == 0 && len(errors) > 0 {
// Combine error messages
@@ -540,16 +539,16 @@ func (h *LogHandler) getMergedLogs(args logger.SearchArgs) ([]logger.LogItem, er
}
return nil, fmt.Errorf("failed to retrieve logs: %s", strings.Join(errorMsgs, "; "))
}
// Sort logs by timestamp (newest first)
sort.Slice(allLogs, func(i, j int) bool {
return allLogs[i].Timestamp.After(allLogs[j].Timestamp)
})
// Apply max items limit if specified
if args.MaxItems > 0 && len(allLogs) > args.MaxItems {
allLogs = allLogs[:args.MaxItems]
}
return allLogs, nil
}

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"time"
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
"git.ourworld.tf/herocode/heroagent/pkg/system/stats"
"github.com/gofiber/fiber/v2"
)
@@ -43,8 +43,8 @@ func (h *ProcessHandler) GetProcessStatsJSON(c *fiber.Ctx) error {
// Convert to fiber.Map for JSON response
response := fiber.Map{
"total": processData.Total,
"filtered": processData.Filtered,
"total": processData.Total,
"filtered": processData.Filtered,
"timestamp": time.Now().Unix(),
}
@@ -61,7 +61,7 @@ func (h *ProcessHandler) GetProcessStatsJSON(c *fiber.Ctx) error {
"is_current": proc.IsCurrent,
}
}
response["processes"] = processes
// Return JSON response
@@ -127,8 +127,8 @@ func (h *ProcessHandler) GetProcessesData(c *fiber.Ctx) error {
// Check if StatsManager is properly initialized
if h.statsManager == nil {
return c.Render("admin/system/processes_data", fiber.Map{
"error": "System error: Stats manager not initialized",
"layout": "",
"error": "System error: Stats manager not initialized",
"layout": "",
})
}
@@ -156,7 +156,7 @@ func (h *ProcessHandler) GetProcessesData(c *fiber.Ctx) error {
} else {
processData, err = h.statsManager.GetProcessStatsFresh(0)
}
if err != nil {
// Handle AJAX requests differently from regular requests
isAjax := c.Get("X-Requested-With") == "XMLHttpRequest"
@@ -165,8 +165,8 @@ func (h *ProcessHandler) GetProcessesData(c *fiber.Ctx) error {
}
// For regular requests, render the error within the fragment
return c.Render("admin/system/processes_data", fiber.Map{
"error": "Failed to get process data: " + err.Error(),
"layout": "",
"error": "Failed to get process data: " + err.Error(),
"layout": "",
})
}
}
@@ -197,9 +197,7 @@ func (h *ProcessHandler) GetProcessesData(c *fiber.Ctx) error {
"processStats": processStats,
"layout": "", // Disable layout for partial template
}
// Return only the table HTML content directly to be injected into the processes-table-content div
return c.Render("admin/system/processes_data", templateData)
}

View File

@@ -4,8 +4,8 @@ import (
"fmt"
"time"
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces/openrpc"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces/openrpc"
"github.com/gofiber/fiber/v2"
)

View File

@@ -5,7 +5,7 @@ import (
"strings"
"time"
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
"git.ourworld.tf/herocode/heroagent/pkg/system/stats"
"github.com/gofiber/fiber/v2"
"github.com/shirou/gopsutil/v3/host"
)
@@ -335,7 +335,7 @@ func (h *SystemHandler) GetProcessStatsAPI(c *fiber.Ctx) error {
"is_current": proc.IsCurrent,
}
}
response["processes"] = processes
// Return JSON response