/* |-------------------------------------------------------------------------- | 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) }