aviorapi/essential/visible/service/helper/log/log.go
2026-08-28 12:55:50 +08:00

226 lines
5.5 KiB
Go

/*
|--------------------------------------------------------------------------
| Description
|--------------------------------------------------------------------------
|
| Name:
| - Log
|
| Purpose:
| - Provide a framework-level logging utility that records structured
| plaintext log entries to a persistent filesystem location using a
| deterministic and platform-aware storage strategy.
|
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| Instruction
|--------------------------------------------------------------------------
|
| Guideline:
| - Use to write standardized log messages from framework services and
| software features.
| - Provide a logical source identifier using the SERVICENAME/UTILITYNAME
| or SERVICENAME/FEATURENAME format.
| - Provide the human-readable log message as plain, formatted, or any
| UTF-8 string.
| - Log entries are stored in the platform-specific persistent log
| directory using the software name as the directory name.
| - Log entries are appended as complete UTF-8 plaintext lines without
| overwriting existing content.
|
| Example:
| - ObrimLog(
| "SERVICENAME/UTILITYNAME",
| "Utility operation completed",
| )
| - ObrimLog(
| "SERVICENAME/FEATURENAME",
| "Feature execution started",
| )
|
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| Credit
|--------------------------------------------------------------------------
|
| Contributor:
| - Rajon Ahmed
| - Blockonite
|
|--------------------------------------------------------------------------
*/
package log
import (
"os"
"path/filepath"
"runtime"
"strings"
"time"
)
// obrimLogSoftwareName identifies the software owning the log directory.
const obrimLogSoftwareName = "software"
// ObrimLog writes a standardized log message.
func ObrimLog(label, message string) {
obrimLogLabel, obrimLogMessage, obrimLogValid := obrimLogValidateInput(label, message)
if !obrimLogValid {
return
}
obrimLogName := obrimLogResolveName()
if obrimLogName == "" {
return
}
obrimLogDirectory, obrimLogDirectoryValid := obrimLogResolveDirectory(obrimLogName)
if !obrimLogDirectoryValid {
return
}
obrimLogFile, obrimLogFileValid := obrimLogResolveFile(obrimLogDirectory)
if !obrimLogFileValid {
return
}
obrimLogTimestamp := obrimLogGetTimestamp()
obrimLogEntry := obrimLogBuildEntry(obrimLogTimestamp, obrimLogLabel, obrimLogMessage)
obrimLogWriteEntry(obrimLogFile, obrimLogEntry)
}
// obrimLogValidateInput normalizes and validates the log input.
func obrimLogValidateInput(label, message string) (string, string, bool) {
label = strings.TrimSpace(label)
message = strings.ReplaceAll(message, "\r\n", "\n")
message = strings.ReplaceAll(message, "\r", "\n")
message = strings.ReplaceAll(message, "\n", " ")
if label == "" || message == "" {
return "", "", false
}
return label, message, true
}
// obrimLogResolveName retrieves the software name from the local constant.
func obrimLogResolveName() string {
return strings.TrimSpace(obrimLogSoftwareName)
}
// obrimLogResolveDirectory resolves and creates the platform-specific log directory.
func obrimLogResolveDirectory(softwareName string) (string, bool) {
var obrimLogDirectory string
switch runtime.GOOS {
case "linux":
obrimLogHome, obrimLogHomeError := os.UserHomeDir()
if obrimLogHomeError != nil {
return "", false
}
obrimLogDirectory = filepath.Join(
obrimLogHome,
".local",
"state",
softwareName,
"log",
"main",
)
case "windows":
obrimLogLocalAppData := strings.TrimSpace(os.Getenv("LOCALAPPDATA"))
if obrimLogLocalAppData == "" {
return "", false
}
obrimLogDirectory = filepath.Join(
obrimLogLocalAppData,
softwareName,
"log",
"main",
)
case "darwin":
obrimLogHome, obrimLogHomeError := os.UserHomeDir()
if obrimLogHomeError != nil {
return "", false
}
obrimLogDirectory = filepath.Join(
obrimLogHome,
"Library",
"Logs",
softwareName,
"log",
"main",
)
default:
return "", false
}
if obrimLogDirectory == "" {
return "", false
}
if obrimLogMkdirError := os.MkdirAll(obrimLogDirectory, 0o755); obrimLogMkdirError != nil {
return "", false
}
return obrimLogDirectory, true
}
// obrimLogResolveFile resolves and creates the main log file.
func obrimLogResolveFile(directory string) (string, bool) {
obrimLogFile := filepath.Join(directory, "main.log")
obrimLogHandle, obrimLogOpenError := os.OpenFile(
obrimLogFile,
os.O_CREATE|os.O_APPEND|os.O_WRONLY,
0o644,
)
if obrimLogOpenError != nil {
return "", false
}
if obrimLogCloseError := obrimLogHandle.Close(); obrimLogCloseError != nil {
return "", false
}
return obrimLogFile, true
}
// obrimLogGetTimestamp gets the timestamp for a log entry.
func obrimLogGetTimestamp() string {
return time.Now().Format(time.RFC3339Nano)
}
// obrimLogBuildEntry builds a complete formatted log entry.
func obrimLogBuildEntry(timestamp, label, message string) string {
return "[" + timestamp + "] [" + label + "] " + message + "\n"
}
// obrimLogWriteEntry appends a complete log entry to the log file.
func obrimLogWriteEntry(file, entry string) {
obrimLogHandle, obrimLogOpenError := os.OpenFile(
file,
os.O_APPEND|os.O_WRONLY,
0o644,
)
if obrimLogOpenError != nil {
return
}
defer obrimLogHandle.Close()
_, _ = obrimLogHandle.WriteString(entry)
}