diff --git a/app/log/internal/log_entry.go b/app/log/internal/log_entry.go
index 0beb80db..a07d52f0 100644
--- a/app/log/internal/log_entry.go
+++ b/app/log/internal/log_entry.go
@@ -13,11 +13,11 @@ type LogEntry interface {
 
 type ErrorLog struct {
 	Prefix string
-	Values []interface{}
+	Error  error
 }
 
 func (v *ErrorLog) String() string {
-	return v.Prefix + serial.Concat(v.Values...)
+	return v.Prefix + v.Error.Error()
 }
 
 type AccessLog struct {
diff --git a/app/log/log.go b/app/log/log.go
index 82b53b50..1ddcd736 100644
--- a/app/log/log.go
+++ b/app/log/log.go
@@ -51,54 +51,30 @@ func InitErrorLogger(file string) error {
 	return nil
 }
 
-// writeDebug outputs a debug log with given format and optional arguments.
-func writeDebug(val ...interface{}) {
-	debugLogger.Log(&internal.ErrorLog{
-		Prefix: "[Debug]",
-		Values: val,
-	})
-}
-
-// writeInfo outputs an info log with given format and optional arguments.
-func writeInfo(val ...interface{}) {
-	infoLogger.Log(&internal.ErrorLog{
-		Prefix: "[Info]",
-		Values: val,
-	})
-}
-
-// writeWarning outputs a warning log with given format and optional arguments.
-func writeWarning(val ...interface{}) {
-	warningLogger.Log(&internal.ErrorLog{
-		Prefix: "[Warning]",
-		Values: val,
-	})
-}
-
-// writeError outputs an error log with given format and optional arguments.
-func writeError(val ...interface{}) {
-	errorLogger.Log(&internal.ErrorLog{
-		Prefix: "[Error]",
-		Values: val,
-	})
-}
-
-func Trace(err error) {
-	s := errors.GetSeverity(err)
+func getLoggerAndPrefix(s errors.Severity) (internal.LogWriter, string) {
 	switch s {
 	case errors.SeverityDebug:
-		writeDebug(err)
+		return debugLogger, "[Debug]"
 	case errors.SeverityInfo:
-		writeInfo(err)
+		return infoLogger, "[Info]"
 	case errors.SeverityWarning:
-		writeWarning(err)
+		return infoLogger, "[Warning]"
 	case errors.SeverityError:
-		writeError(err)
+		return errorLogger, "[Error]"
 	default:
-		writeInfo(err)
+		return infoLogger, "[Info]"
 	}
 }
 
+// Trace logs an error message based on its severity.
+func Trace(err error) {
+	logger, prefix := getLoggerAndPrefix(errors.GetSeverity(err))
+	logger.Log(&internal.ErrorLog{
+		Prefix: prefix,
+		Error:  err,
+	})
+}
+
 type Instance struct {
 	config *Config
 }
diff --git a/common/errors/errors.go b/common/errors/errors.go
index 4439828f..a7ba11ce 100644
--- a/common/errors/errors.go
+++ b/common/errors/errors.go
@@ -7,6 +7,7 @@ import (
 	"v2ray.com/core/common/serial"
 )
 
+// Severity describes how severe the error is.
 type Severity int
 
 const (
@@ -78,22 +79,27 @@ func (v *Error) Severity() Severity {
 	return v.severity
 }
 
+// AtDebug sets the severity to debug.
 func (v *Error) AtDebug() *Error {
 	return v.atSeverity(SeverityDebug)
 }
 
+// AtInfo sets the severity to info.
 func (v *Error) AtInfo() *Error {
 	return v.atSeverity(SeverityInfo)
 }
 
+// AtWarning sets the severity to warning.
 func (v *Error) AtWarning() *Error {
 	return v.atSeverity(SeverityWarning)
 }
 
+// AtError sets the severity to error.
 func (v *Error) AtError() *Error {
 	return v.atSeverity(SeverityError)
 }
 
+// Path sets the path to the location where this error happens.
 func (v *Error) Path(path ...string) *Error {
 	v.path = path
 	return v