log-manager/modules/loghandler/loghandler.go

273 lines
5.5 KiB
Go

package loghandler
import (
"bufio"
"encoding/json"
"fmt"
"io"
"jannex/log-manager/modules/cache"
"jannex/log-manager/modules/config"
"jannex/log-manager/modules/structs"
"jannex/log-manager/modules/utils"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"sync"
"time"
)
var FileMutexMap = make(map[string]*sync.Mutex)
var FileMutexMapLock sync.Mutex
func getFileMutex(filePath string) *sync.Mutex {
FileMutexMapLock.Lock()
defer FileMutexMapLock.Unlock()
mutex, ok := FileMutexMap[filePath]
if !ok {
mutex = &sync.Mutex{}
FileMutexMap[filePath] = mutex
}
return mutex
}
func AddLog(body structs.LogBody) {
year, month, day := time.Now().Date()
date := strconv.Itoa(day) + "-" + strconv.Itoa(int(month)) + "-" + strconv.Itoa(year)
logFolder := config.Cfg.LogFolder
fmt.Printf("Adding log to %s\n", logFolder+body.Type)
utils.CreateDirectoryIfNotExists(logFolder + body.Type)
path := logFolder + body.Type + "/" + date + ".log"
// get the mutex for this file
mutex := getFileMutex(path)
// lock the mutex to ensure the file is only opened once at a time
mutex.Lock()
defer mutex.Unlock()
file, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
for _, log := range body.Logs {
if _, err := fmt.Fprintln(file, log); err != nil {
fmt.Println(err)
}
}
marshaledLogs, err := json.Marshal(body.Logs)
if err != nil {
fmt.Println(err)
return
}
for clientId, sseClient := range cache.GetSSEClients() {
if sseClient.LogType == body.Type && sseClient.Date == date {
sseClient.MessageChannel <- structs.SSEClientChannelMessage{
ClientId: clientId,
Message: marshaledLogs,
}
}
}
}
func GetAvailableLogFiles(logType string) ([]string, error) {
var availableLogs []string
path := config.Cfg.LogFolder + logType
files, err := os.ReadDir(path)
if err != nil {
fmt.Println(err)
return []string{}, err
}
// sort the files by date
sort.Slice(files, func(i, j int) bool {
dateFormat := "2-1-2006"
dateA, _ := time.Parse(dateFormat, strings.Split(files[i].Name(), ".")[0])
dateB, _ := time.Parse(dateFormat, strings.Split(files[j].Name(), ".")[0])
return dateA.After(dateB)
})
for _, file := range files {
availableLogs = append(availableLogs, strings.Split(file.Name(), ".")[0])
}
return availableLogs, nil
}
func GetLogByDate(logType string, date string) ([]string, error) {
var logs []string
path := config.Cfg.LogFolder + logType + "/" + date + ".log"
// get the mutex for this file
mutex := getFileMutex(path)
// lock the mutex to ensure the file is only opened once at a time
mutex.Lock()
defer mutex.Unlock()
file, err := os.Open(path)
if err != nil {
fmt.Println(err)
return []string{}, err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
logs = append(logs, scanner.Text())
}
if len(logs) == 0 {
return []string{}, nil
}
return logs, nil
}
func GetAvailableLogTypes() []string {
var availableLogTypes []string
files, err := os.ReadDir(config.Cfg.LogFolder)
if err != nil {
fmt.Println(err)
return []string{}
}
for _, file := range files {
availableLogTypes = append(availableLogTypes, file.Name())
}
if len(availableLogTypes) == 0 {
return []string{}
}
return availableLogTypes
}
func StartBackgroundLogDeleter() {
ticker := time.NewTicker(24 * time.Hour)
for range ticker.C {
CheckForDeletableLogs()
}
}
func CheckForDeletableLogs() {
daysToKeepLogs := config.Cfg.DaysToKeepLogs
logFolder := config.Cfg.LogFolder
err := filepath.Walk(logFolder, func(path string, info os.FileInfo, err error) error {
if err != nil {
fmt.Println(err)
return err
}
if !info.IsDir() {
// check if the file is older than the daysToKeepLogs
// get the date from the file name
date := strings.Split(info.Name(), ".")[0]
dateFormat := "2-1-2006"
fileDate, err := time.Parse(dateFormat, date)
if err != nil {
fmt.Println(err)
return err
}
// get the date from the daysToKeepLogs
daysToKeepLogsDate := time.Now().AddDate(0, 0, -daysToKeepLogs)
// compare the dates
if fileDate.Before(daysToKeepLogsDate) {
// delete the file
err := os.Remove(path)
if err != nil {
fmt.Println(err)
return err
}
AddLog(structs.LogBody{
Type: "system",
Logs: []string{"I " + utils.GetTime() + "LogManager: Deleted log file " + path + " because it was older than " + strconv.Itoa(daysToKeepLogs) + " days."},
})
}
} else {
// Check if the directory is empty.
isEmpty, err := isDirEmpty(path)
if err != nil {
fmt.Printf("Error checking %s: %v\n", path, err)
return err
}
if isEmpty && path != logFolder {
fmt.Printf("Deleting empty directory: %s\n", path)
if err := os.Remove(path); err != nil {
fmt.Printf("Error deleting %s: %v\n", path, err)
}
AddLog(structs.LogBody{
Type: "system",
Logs: []string{"I " + utils.GetTime() + "LogManager: Deleted empty log folder " + path},
})
}
}
return nil
})
if err != nil {
fmt.Println(err)
}
}
func isDirEmpty(dirPath string) (bool, error) {
dir, err := os.Open(dirPath)
if err != nil {
return false, err
}
defer dir.Close()
_, err = dir.Readdirnames(1) // Try to read an entry from the directory.
if err == nil {
// There is at least one entry in the directory; it's not empty.
return false, nil
}
if err == io.EOF {
// The directory is empty.
return true, nil
}
return false, err
}