mirror of
https://github.com/clearlinux/clr-installer.git
synced 2026-08-21 23:26:17 +00:00
59302346d6
Signed-off-by: Mark D Horn <mark.d.horn@intel.com>
249 lines
5.9 KiB
Go
249 lines
5.9 KiB
Go
// Copyright © 2020 Intel Corporation
|
|
//
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
package log
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/clearlinux/clr-installer/conf"
|
|
"github.com/clearlinux/clr-installer/errors"
|
|
"github.com/clearlinux/clr-installer/utils"
|
|
)
|
|
|
|
const (
|
|
// LogLevelError specified the log level as: ERROR
|
|
LogLevelError = 1
|
|
|
|
// LogLevelWarning specified the log level as: WARNING
|
|
LogLevelWarning = 2
|
|
|
|
// LogLevelInfo specified the log level as: INFO
|
|
LogLevelInfo = 3
|
|
|
|
// LogLevelDebug specified the log level as: DEBUG
|
|
LogLevelDebug = 4
|
|
|
|
// LogLevelVerbose specified the log level as: VERBOSE
|
|
// This is the same as Debug, but without the repeat filtering
|
|
LogLevelVerbose = 5
|
|
|
|
// configFilePreInstalPrefix is the prefix to create a configuration// file name
|
|
configFilePreInstalPrefix = "pre-install-"
|
|
)
|
|
|
|
var (
|
|
level = LogLevelInfo
|
|
levelMap = map[int]string{}
|
|
filehandle *os.File
|
|
|
|
logFileName string
|
|
preConfName string
|
|
|
|
lineLast string
|
|
lineCount int
|
|
)
|
|
|
|
func init() {
|
|
levelMap[LogLevelError] = "LogLevelError"
|
|
levelMap[LogLevelWarning] = "LogLevelWarning"
|
|
levelMap[LogLevelInfo] = "LogLevelInfo"
|
|
levelMap[LogLevelDebug] = "LogLevelDebug"
|
|
levelMap[LogLevelVerbose] = "LogLevelVerbose"
|
|
}
|
|
|
|
// SetLogLevel sets the default log level to l
|
|
func SetLogLevel(l int) {
|
|
if l < LogLevelError {
|
|
level = LogLevelError
|
|
logTag("WRN", "Log Level '%d' too low, forcing to %s (%d)", l, levelMap[level], level)
|
|
} else if l > LogLevelVerbose {
|
|
level = LogLevelVerbose
|
|
logTag("WRN", "Log Level '%d' too high, forcing to %s (%d)", l, levelMap[level], level)
|
|
} else {
|
|
level = l
|
|
Debug("Log Level set to %s (%d)", levelMap[level], l)
|
|
}
|
|
}
|
|
|
|
// SetOutputFilename ... sets the default log output to filename instead of stdout/stderr
|
|
func SetOutputFilename(logFile string) (*os.File, error) {
|
|
logFileName = logFile
|
|
var err error
|
|
filehandle, err = os.OpenFile(logFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
log.SetOutput(filehandle)
|
|
|
|
preConfName = filepath.Join(filepath.Dir(logFileName), configFilePreInstalPrefix+conf.ConfigFile)
|
|
|
|
return filehandle, nil
|
|
}
|
|
|
|
// GetCrashInfoMsg returns the crash info message.
|
|
func GetCrashInfoMsg() string {
|
|
msg := utils.Locale.Get("Please report this crash using %s", "GitHub Issues:")
|
|
msg += "\n" + "https://github.com/clearlinux/clr-installer/issues"
|
|
msg += "\n\n" + utils.Locale.Get("Include the following as attachments to enable diagnosis:")
|
|
msg += "\n" + preConfName
|
|
msg += "\n" + logFileName
|
|
msg += "\n\n" + utils.Locale.Get("You may need to remove any personal data of concern from the attachments.")
|
|
msg += "\n" + utils.Locale.Get("The Installer will now exit.")
|
|
|
|
return msg
|
|
}
|
|
|
|
// RequestCrashInfo prints information for the user on how to properly report the
|
|
// crash of the installer and how to gather more information
|
|
func RequestCrashInfo() {
|
|
fmt.Println(GetCrashInfoMsg())
|
|
}
|
|
|
|
// GetLogFileName ... returns the filename of the current log
|
|
func GetLogFileName() string {
|
|
return logFileName
|
|
}
|
|
|
|
// GetPreConfFile ... returns the filename of where to store the pre-configuration file
|
|
func GetPreConfFile() string {
|
|
return preConfName
|
|
}
|
|
|
|
// ArchiveLogFile copies the contents of the log to the given filename
|
|
func ArchiveLogFile(archiveFile string) error {
|
|
if filehandle == nil {
|
|
return errors.Errorf("Log output should be set, see log.SetOutputFilename()")
|
|
}
|
|
|
|
a, err := os.OpenFile(archiveFile, os.O_RDWR|os.O_CREATE, 0644)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer func() {
|
|
_ = a.Close()
|
|
|
|
// Jump back to the end of the log file
|
|
_, _ = filehandle.Seek(0, 2)
|
|
}()
|
|
|
|
_ = filehandle.Sync()
|
|
|
|
// Jump to the beginning of the file
|
|
_, err = filehandle.Seek(0, 0)
|
|
if err != nil {
|
|
Error("Failed to seek log file (%v)", err)
|
|
}
|
|
|
|
var bytesCopied int64
|
|
bytesCopied, err = io.Copy(a, filehandle)
|
|
if err != nil {
|
|
Error("Failed to archive log file (%v) %q", err, archiveFile)
|
|
}
|
|
Debug("Archived %d bytes to file %q", bytesCopied, archiveFile)
|
|
_ = a.Sync()
|
|
|
|
return err
|
|
}
|
|
|
|
// LevelStr converts level to its text equivalent, if level is invalid
|
|
// an error is returned
|
|
func LevelStr(level int) (string, error) {
|
|
for k, v := range levelMap {
|
|
if k == level {
|
|
return v, nil
|
|
}
|
|
}
|
|
|
|
return "", fmt.Errorf("Invalid log level: %d", level)
|
|
}
|
|
|
|
func logTag(tag string, format string, a ...interface{}) {
|
|
// If there are no variable to pass to the format,
|
|
// then we can escape any % signs.
|
|
if len(a) < 1 {
|
|
format = strings.ReplaceAll(format, "%", "%%")
|
|
}
|
|
|
|
f := "[" + tag + "] " + format + "\n"
|
|
output := fmt.Sprintf(f, a...)
|
|
|
|
if level >= LogLevelVerbose {
|
|
log.Print(output)
|
|
return
|
|
}
|
|
|
|
if output != lineLast {
|
|
// output the previous repeated line
|
|
if lineCount > 0 {
|
|
plural := ""
|
|
if lineCount > 1 {
|
|
plural = "s"
|
|
}
|
|
|
|
repeat := fmt.Sprintf("[%s] [Previous line repeated %d time%s]\n", tag, lineCount, plural)
|
|
log.Print(repeat)
|
|
}
|
|
|
|
log.Print(output)
|
|
|
|
lineLast = output
|
|
lineCount = 0
|
|
} else { // Repeated line
|
|
lineCount++
|
|
}
|
|
}
|
|
|
|
// Debug prints a debug log entry with DBG tag
|
|
func Debug(format string, a ...interface{}) {
|
|
if level < LogLevelDebug {
|
|
return
|
|
}
|
|
|
|
logTag("DBG", format, a...)
|
|
}
|
|
|
|
// Error prints an error log entry with ERR tag
|
|
func Error(format string, a ...interface{}) {
|
|
logTag("ERR", format, a...)
|
|
}
|
|
|
|
// ErrorError prints an error log entry with ERR tag, it takes an
|
|
// error instead of format and args, if a TraceableError is provided
|
|
// then we also include the trace information in the error message
|
|
func ErrorError(err error) {
|
|
msg := err.Error()
|
|
|
|
if e, ok := err.(errors.TraceableError); ok {
|
|
msg = fmt.Sprintf("%s %s", e.Trace, e.What)
|
|
}
|
|
|
|
logTag("ERR", msg)
|
|
}
|
|
|
|
// Info prints an info log entry with INF tag
|
|
func Info(format string, a ...interface{}) {
|
|
if level < LogLevelInfo {
|
|
return
|
|
}
|
|
|
|
logTag("INF", format, a...)
|
|
}
|
|
|
|
// Warning prints an warning log entry with WRN tag
|
|
func Warning(format string, a ...interface{}) {
|
|
if level < LogLevelWarning {
|
|
return
|
|
}
|
|
|
|
logTag("WRN", format, a...)
|
|
}
|