summaryrefslogtreecommitdiff
path: root/common/log/log.go
diff options
context:
space:
mode:
authorYawning Angel <yawning@torproject.org>2015-04-03 14:21:31 +0000
committerYawning Angel <yawning@torproject.org>2015-04-03 14:21:31 +0000
commitdf4265707999b08d220374c08e82711f264247bf (patch)
treed2ded324520a56c42dcd758c33ff6f6a4ba23cd3 /common/log/log.go
parent402fe97d8547d216746d2237010f32b691cb71e1 (diff)
Move logging wrappers into common/log, and add a DEBUG log level.
Implements feature #15576.
Diffstat (limited to 'common/log/log.go')
-rw-r--r--common/log/log.go179
1 files changed, 179 insertions, 0 deletions
diff --git a/common/log/log.go b/common/log/log.go
new file mode 100644
index 0000000..5d0a146
--- /dev/null
+++ b/common/log/log.go
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2014-2015, Yawning Angel <yawning at torproject dot org>
+ * 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.
+ *
+ * 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 log implements a simple set of leveled logging wrappers around the
+// standard log package.
+package log
+
+import (
+ "fmt"
+ "io/ioutil"
+ "log"
+ "net"
+ "os"
+ "strings"
+)
+
+const (
+ elidedAddr = "[scrubbed]"
+
+ levelError = iota
+ levelWarn
+ levelInfo
+ levelDebug
+)
+
+var logLevel = levelInfo
+var enableLogging bool
+var unsafeLogging bool
+
+// Init initializes logging with the given path, and log safety options.
+func Init(enable bool, logFilePath string, unsafe bool) error {
+ if enable {
+ f, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
+ if err != nil {
+ return err
+ }
+ log.SetOutput(f)
+ } else {
+ log.SetOutput(ioutil.Discard)
+ }
+ enableLogging = enable
+ return nil
+}
+
+// SetLogLevel sets the log level to the value indicated by the given string
+// (case-insensitive).
+func SetLogLevel(logLevelStr string) error {
+ switch strings.ToUpper(logLevelStr) {
+ case "ERROR":
+ logLevel = levelError
+ case "WARN":
+ logLevel = levelWarn
+ case "INFO":
+ logLevel = levelInfo
+ case "DEBUG":
+ logLevel = levelDebug
+ default:
+ return fmt.Errorf("invalid log level '%s'", logLevelStr)
+ }
+ return nil
+}
+
+// Noticef logs the given format string/arguments at the NOTICE log level.
+func Noticef(format string, a ...interface{}) {
+ if enableLogging {
+ msg := fmt.Sprintf(format, a...)
+ log.Print("[NOTICE]: " + msg)
+ }
+}
+
+// Errorf logs the given format string/arguments at the ERROR log level.
+func Errorf(format string, a ...interface{}) {
+ if enableLogging && logLevel >= levelError {
+ msg := fmt.Sprintf(format, a...)
+ log.Print("[ERROR]: " + msg)
+ }
+}
+
+// Warnf logs the given format string/arguments at the WARN log level.
+func Warnf(format string, a ...interface{}) {
+ if enableLogging && logLevel >= levelWarn {
+ msg := fmt.Sprintf(format, a...)
+ log.Print("[WARN]: " + msg)
+ }
+}
+
+// Infof logs the given format string/arguments at the INFO log level.
+func Infof(format string, a ...interface{}) {
+ if enableLogging && logLevel >= levelInfo {
+ msg := fmt.Sprintf(format, a...)
+ log.Print("[INFO]: " + msg)
+ }
+}
+
+// Debugf logs the given format string/arguments at the INFO log level.
+func Debugf(format string, a ...interface{}) {
+ if enableLogging && logLevel >= levelDebug {
+ msg := fmt.Sprintf(format, a...)
+ log.Print("[DEBUG]: " + msg)
+ }
+}
+
+// ElideError transforms the string representation of the provided error
+// based on the unsafeLogging setting. Callers that wish to log errors
+// returned from Go's net package should use ElideError to sanitize the
+// contents first.
+func ElideError(err error) string {
+ // Go's net package is somewhat rude and includes IP address and port
+ // information in the string representation of net.Errors. Figure out if
+ // this is the case here, and sanitize the error messages as needed.
+ if unsafeLogging {
+ return err.Error()
+ }
+
+ // If err is not a net.Error, just return the string representation,
+ // presumably transport authors know what they are doing.
+ netErr, ok := err.(net.Error)
+ if !ok {
+ return err.Error()
+ }
+
+ switch t := netErr.(type) {
+ case *net.AddrError:
+ return t.Err + " " + elidedAddr
+ case *net.DNSError:
+ return "lookup " + elidedAddr + " on " + elidedAddr + ": " + t.Err
+ case *net.InvalidAddrError:
+ return "invalid address error"
+ case *net.UnknownNetworkError:
+ return "unknown network " + elidedAddr
+ case *net.OpError:
+ return t.Op + ": " + t.Err.Error()
+ default:
+ // For unknown error types, do the conservative thing and only log the
+ // type of the error instead of assuming that the string representation
+ // does not contain sensitive information.
+ return fmt.Sprintf("network error: <%T>", t)
+ }
+}
+
+// ElideAddr transforms the string representation of the provided address based
+// on the unsafeLogging setting. Callers that wish to log IP addreses should
+// use ElideAddr to sanitize the contents first.
+func ElideAddr(addrStr string) string {
+ if unsafeLogging {
+ return addrStr
+ }
+
+ // Only scrub off the address so that it's easier to track connections
+ // in logs by looking at the port.
+ if _, port, err := net.SplitHostPort(addrStr); err == nil {
+ return elidedAddr + ":" + port
+ }
+ return elidedAddr
+}