gllvm/shared/logging.go

137 lines
4.3 KiB
Go

//
// OCCAM
//
// Copyright (c) 2017, SRI International
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * Neither the name of SRI International nor the names of its contributors may
// be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
package shared
import (
"fmt"
"os"
"strings"
)
const (
errorV = iota
warningV
infoV
debugV
)
//loggingLevels is the accepted logging levels.
var loggingLevels = map[string]int{
"ERROR": errorV,
"WARNING": warningV,
"INFO": infoV,
"DEBUG": debugV,
}
var loggingPrefixes = map[int]string{
errorV: "ERROR:",
warningV: "WARNING:",
infoV: "INFO:",
debugV: "DEBUG:",
}
//loggingLevel is the user configured level of logging: ERROR, WARNING, INFO, DEBUG
var loggingLevel = warningV
//loggingFilePointer is where the logging is streamed too.
var loggingFilePointer = os.Stderr
func init() {
if LLVMLoggingLevel != "" {
if envLevelVal, ok := loggingLevels[LLVMLoggingLevel]; ok {
loggingLevel = envLevelVal
}
}
if LLVMLoggingFile != "" {
//FIXME: is it overboard to defer a close? the OS will close when the process gets cleaned up, do we win
//anything by being OCD?
if loggingFP, err := os.OpenFile(LLVMLoggingFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600); err == nil {
loggingFilePointer = loggingFP
}
}
}
func makeLogger(lvl int) func(format string, a ...interface{}) {
return func(format string, a ...interface{}) {
if loggingLevel >= lvl {
msg := fmt.Sprintf(format, a...)
if !strings.HasSuffix(msg, "\n") {
msg += "\n"
}
//FIXME: (?) if loggingFilePointer != os.Stderr, we could multiplex here
//and send output to both os.Stderr and loggingFilePointer. We wouldn't
//want the user to miss any excitement. Then the sanity checker would not
//need to futz with it.
prefix := loggingPrefixes[lvl]
if len(prefix) > 0 {
_, err := loggingFilePointer.WriteString(prefix)
if err != nil && loggingFilePointer != os.Stderr {
_, _ = os.Stderr.WriteString(fmt.Sprintf("Logging failed: %v\n", err))
return
}
}
_, err := loggingFilePointer.WriteString(msg)
if err != nil && loggingFilePointer != os.Stderr {
_, _ = os.Stderr.WriteString(fmt.Sprintf("Logging failed: %v\n", err))
return
}
}
}
}
//LogDebug logs to the configured stream if the logging level is DEBUG.
var LogDebug = makeLogger(debugV)
//LogInfo logs to the configured stream if the logging level is INFO or lower.
var LogInfo = makeLogger(infoV)
//LogWarning logs to the configured stream if the logging level is WARNING or lower.
var LogWarning = makeLogger(warningV)
//LogError logs to the configured stream if the logging level is ERROR or lower.
var LogError = makeLogger(errorV)
//LogFatal logs to the configured stream and then exits.
func LogFatal(format string, a ...interface{}) {
LogError(format, a...)
os.Exit(1)
}
//LogWrite writes to the logging stream, irregardless of levels.
var LogWrite = makeLogger(-1)
func informUser(format string, a ...interface{}) {
fmt.Fprintf(os.Stdout, format, a...)
}