Files
Archive/mieru/pkg/log/mieru_client_logging.go
2025-11-25 19:40:52 +01:00

96 lines
3.0 KiB
Go

// Copyright (C) 2021 mieru authors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package log
import (
"fmt"
"io"
"os"
"sort"
"strconv"
"strings"
"time"
)
// maxClientLogFiles is the maximum number of client log files stored in the disk.
const maxClientLogFiles = 25
// cachedClientLogDir is the directory where client log files are stored.
//
// In Linux, it is typically /home/<user>/.cache/mieru
//
// In Mac OS, it is typically /Users/<user>/Library/Caches/mieru
//
// In Windows, it is typically C:\Users\<user>\AppData\Local\mieru
var cachedClientLogDir string
// NewClientLogFile returns a file handler for mieru client to write logs.
func NewClientLogFile() (io.WriteCloser, error) {
if err := prepareClientLogDir(); err != nil {
return nil, fmt.Errorf("prepareClientLogDir() failed: %w", err)
}
t := time.Now()
timeStr := fmt.Sprintf("%04d%02d%02d_%02d%02d", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute())
pid := strconv.Itoa(os.Getpid())
fileName := cachedClientLogDir + string(os.PathSeparator) + timeStr + "_" + pid + ".log"
logFile, err := os.OpenFile(fileName, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
if err != nil {
return nil, fmt.Errorf("failed to create client log file: %v", logFile)
}
return logFile, nil
}
// RemoveOldClientLogFiles deletes the oldest client log files.
func RemoveOldClientLogFiles() error {
if err := prepareClientLogDir(); err != nil {
return fmt.Errorf("prepareClientLogDir() failed: %w", err)
}
entries, err := os.ReadDir(cachedClientLogDir)
if err != nil {
return fmt.Errorf("os.ReadDir(%q) failed: %w", cachedClientLogDir, err)
}
var logFiles []string
for _, entry := range entries {
if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".log") {
logFiles = append(logFiles, entry.Name())
}
}
if len(logFiles) > maxClientLogFiles {
toDelete := len(logFiles) - maxClientLogFiles
sort.Strings(logFiles)
for i := 0; i < toDelete; i++ {
if err = os.Remove(cachedClientLogDir + string(os.PathSeparator) + logFiles[i]); err != nil {
return fmt.Errorf("os.Remove() failed: %w", err)
}
}
}
return nil
}
// prepareClientLogDir creates client log directory is needed.
func prepareClientLogDir() error {
if cachedClientLogDir != "" {
return os.MkdirAll(cachedClientLogDir, 0755)
}
cacheDir, err := os.UserCacheDir()
if err != nil {
return err
}
cachedClientLogDir = cacheDir + string(os.PathSeparator) + "mieru"
return os.MkdirAll(cachedClientLogDir, 0755)
}