| 
									
										
										
										
											2015-09-18 14:49:06 +08:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  |  * Minio Cloud Storage, (C) 2015, 2016, 2017, 2018 Minio, Inc. | 
					
						
							| 
									
										
										
										
											2015-09-18 14:49:06 +08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  * you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  * You may obtain a copy of the License at | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  |  * See the License for the specific language governing permissions and | 
					
						
							|  |  |  |  * limitations under the License. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | package logger | 
					
						
							| 
									
										
										
										
											2015-09-18 14:49:06 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2016-10-11 15:50:27 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2018-03-31 10:13:25 +08:00
										 |  |  | 	"go/build" | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2016-10-11 15:50:27 +08:00
										 |  |  | 	"runtime" | 
					
						
							| 
									
										
										
										
											2016-05-25 17:32:35 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2015-09-18 14:49:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-17 04:36:45 +08:00
										 |  |  | 	c "github.com/minio/mc/pkg/console" | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 	"golang.org/x/crypto/ssh/terminal" | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-28 06:03:19 +08:00
										 |  |  | // Disable disables all logging, false by default. (used for "go test")
 | 
					
						
							|  |  |  | var Disable = false | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | var trimStrings []string | 
					
						
							| 
									
										
										
										
											2015-09-18 14:49:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | // Level type
 | 
					
						
							|  |  |  | type Level int8 | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | // Enumerated level types
 | 
					
						
							|  |  |  | const ( | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 	InformationLvl Level = iota + 1 | 
					
						
							|  |  |  | 	ErrorLvl | 
					
						
							|  |  |  | 	FatalLvl | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | const loggerTimeFormat string = "15:04:05 MST 01/02/2006" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var matchingFuncNames = [...]string{ | 
					
						
							|  |  |  | 	"http.HandlerFunc.ServeHTTP", | 
					
						
							|  |  |  | 	"cmd.serverMain", | 
					
						
							|  |  |  | 	"cmd.StartGateway", | 
					
						
							| 
									
										
										
										
											2018-06-19 03:04:46 +08:00
										 |  |  | 	"cmd.(*webAPIHandlers).ListBuckets", | 
					
						
							|  |  |  | 	"cmd.(*webAPIHandlers).MakeBucket", | 
					
						
							|  |  |  | 	"cmd.(*webAPIHandlers).DeleteBucket", | 
					
						
							|  |  |  | 	"cmd.(*webAPIHandlers).ListObjects", | 
					
						
							|  |  |  | 	"cmd.(*webAPIHandlers).RemoveObject", | 
					
						
							|  |  |  | 	"cmd.(*webAPIHandlers).Login", | 
					
						
							|  |  |  | 	"cmd.(*webAPIHandlers).GenerateAuth", | 
					
						
							|  |  |  | 	"cmd.(*webAPIHandlers).SetAuth", | 
					
						
							|  |  |  | 	"cmd.(*webAPIHandlers).GetAuth", | 
					
						
							|  |  |  | 	"cmd.(*webAPIHandlers).CreateURLToken", | 
					
						
							|  |  |  | 	"cmd.(*webAPIHandlers).Upload", | 
					
						
							|  |  |  | 	"cmd.(*webAPIHandlers).Download", | 
					
						
							|  |  |  | 	"cmd.(*webAPIHandlers).DownloadZip", | 
					
						
							|  |  |  | 	"cmd.(*webAPIHandlers).GetBucketPolicy", | 
					
						
							|  |  |  | 	"cmd.(*webAPIHandlers).ListAllBucketPolicies", | 
					
						
							|  |  |  | 	"cmd.(*webAPIHandlers).SetBucketPolicy", | 
					
						
							|  |  |  | 	"cmd.(*webAPIHandlers).PresignedGet", | 
					
						
							|  |  |  | 	"cmd.(*webAPIHandlers).ServerInfo", | 
					
						
							|  |  |  | 	"cmd.(*webAPIHandlers).StorageInfo", | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	// add more here ..
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | func (level Level) String() string { | 
					
						
							|  |  |  | 	var lvlStr string | 
					
						
							|  |  |  | 	switch level { | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 	case InformationLvl: | 
					
						
							| 
									
										
										
										
											2018-04-11 00:37:14 +08:00
										 |  |  | 		lvlStr = "INFO" | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 	case ErrorLvl: | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | 		lvlStr = "ERROR" | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 	case FatalLvl: | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | 		lvlStr = "FATAL" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return lvlStr | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-11 00:37:14 +08:00
										 |  |  | // Console interface describes the methods that needs to be implemented to satisfy the interface requirements.
 | 
					
						
							|  |  |  | type Console interface { | 
					
						
							|  |  |  | 	json(msg string, args ...interface{}) | 
					
						
							|  |  |  | 	quiet(msg string, args ...interface{}) | 
					
						
							|  |  |  | 	pretty(msg string, args ...interface{}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func consoleLog(console Console, msg string, args ...interface{}) { | 
					
						
							|  |  |  | 	if jsonFlag { | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 		// Strip escape control characters from json message
 | 
					
						
							|  |  |  | 		msg = ansiRE.ReplaceAllLiteralString(msg, "") | 
					
						
							| 
									
										
										
										
											2018-04-11 00:37:14 +08:00
										 |  |  | 		console.json(msg, args...) | 
					
						
							|  |  |  | 	} else if quiet { | 
					
						
							|  |  |  | 		console.quiet(msg, args...) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		console.pretty(msg, args...) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | type traceEntry struct { | 
					
						
							| 
									
										
										
										
											2018-04-11 00:37:14 +08:00
										 |  |  | 	Message   string            `json:"message,omitempty"` | 
					
						
							|  |  |  | 	Source    []string          `json:"source,omitempty"` | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	Variables map[string]string `json:"variables,omitempty"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | type args struct { | 
					
						
							|  |  |  | 	Bucket string `json:"bucket,omitempty"` | 
					
						
							|  |  |  | 	Object string `json:"object,omitempty"` | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | type api struct { | 
					
						
							|  |  |  | 	Name string `json:"name,omitempty"` | 
					
						
							| 
									
										
										
										
											2018-04-11 00:37:14 +08:00
										 |  |  | 	Args *args  `json:"args,omitempty"` | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | type logEntry struct { | 
					
						
							| 
									
										
										
										
											2018-07-19 11:17:35 +08:00
										 |  |  | 	DeploymentID string      `json:"deploymentid,omitempty"` | 
					
						
							|  |  |  | 	Level        string      `json:"level"` | 
					
						
							|  |  |  | 	Time         string      `json:"time"` | 
					
						
							|  |  |  | 	API          *api        `json:"api,omitempty"` | 
					
						
							|  |  |  | 	RemoteHost   string      `json:"remotehost,omitempty"` | 
					
						
							|  |  |  | 	RequestID    string      `json:"requestID,omitempty"` | 
					
						
							|  |  |  | 	UserAgent    string      `json:"userAgent,omitempty"` | 
					
						
							|  |  |  | 	Message      string      `json:"message,omitempty"` | 
					
						
							|  |  |  | 	Trace        *traceEntry `json:"error,omitempty"` | 
					
						
							| 
									
										
										
										
											2016-10-22 17:24:34 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | // quiet: Hide startup messages if enabled
 | 
					
						
							|  |  |  | // jsonFlag: Display in JSON format, if enabled
 | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  | 	quiet, jsonFlag bool | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 	// Custom function to format error
 | 
					
						
							|  |  |  | 	errorFmtFunc func(string, error, bool) string | 
					
						
							| 
									
										
										
										
											2018-07-19 11:17:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	deploymentID string | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-19 11:17:35 +08:00
										 |  |  | // SetDeploymentID - Used to set the deployment ID, in XL and FS mode
 | 
					
						
							|  |  |  | func SetDeploymentID(id string) { | 
					
						
							|  |  |  | 	deploymentID = id | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | // EnableQuiet - turns quiet option on.
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | func EnableQuiet() { | 
					
						
							|  |  |  | 	quiet = true | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | // EnableJSON - outputs logs in json format.
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | func EnableJSON() { | 
					
						
							|  |  |  | 	jsonFlag = true | 
					
						
							|  |  |  | 	quiet = true | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | // RegisterUIError registers the specified rendering function. This latter
 | 
					
						
							|  |  |  | // will be called for a pretty rendering of fatal errors.
 | 
					
						
							|  |  |  | func RegisterUIError(f func(string, error, bool) string) { | 
					
						
							|  |  |  | 	errorFmtFunc = f | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | // Init sets the trimStrings to possible GOPATHs
 | 
					
						
							|  |  |  | // and GOROOT directories. Also append github.com/minio/minio
 | 
					
						
							|  |  |  | // This is done to clean up the filename, when stack trace is
 | 
					
						
							|  |  |  | // displayed when an error happens.
 | 
					
						
							| 
									
										
										
										
											2018-06-19 03:04:46 +08:00
										 |  |  | func Init(goPath string, goRoot string) { | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | 	var goPathList []string | 
					
						
							| 
									
										
										
										
											2018-06-19 03:04:46 +08:00
										 |  |  | 	var goRootList []string | 
					
						
							| 
									
										
										
										
											2018-03-31 10:13:25 +08:00
										 |  |  | 	var defaultgoPathList []string | 
					
						
							| 
									
										
										
										
											2018-06-19 03:04:46 +08:00
										 |  |  | 	var defaultgoRootList []string | 
					
						
							|  |  |  | 	pathSeperator := ":" | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | 	// Add all possible GOPATH paths into trimStrings
 | 
					
						
							|  |  |  | 	// Split GOPATH depending on the OS type
 | 
					
						
							|  |  |  | 	if runtime.GOOS == "windows" { | 
					
						
							| 
									
										
										
										
											2018-06-19 03:04:46 +08:00
										 |  |  | 		pathSeperator = ";" | 
					
						
							| 
									
										
										
										
											2016-11-24 03:35:04 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-19 03:04:46 +08:00
										 |  |  | 	goPathList = strings.Split(goPath, pathSeperator) | 
					
						
							|  |  |  | 	goRootList = strings.Split(goRoot, pathSeperator) | 
					
						
							|  |  |  | 	defaultgoPathList = strings.Split(build.Default.GOPATH, pathSeperator) | 
					
						
							|  |  |  | 	defaultgoRootList = strings.Split(build.Default.GOROOT, pathSeperator) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | 	// Add trim string "{GOROOT}/src/" into trimStrings
 | 
					
						
							|  |  |  | 	trimStrings = []string{filepath.Join(runtime.GOROOT(), "src") + string(filepath.Separator)} | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | 	// Add all possible path from GOPATH=path1:path2...:pathN
 | 
					
						
							|  |  |  | 	// as "{path#}/src/" into trimStrings
 | 
					
						
							|  |  |  | 	for _, goPathString := range goPathList { | 
					
						
							|  |  |  | 		trimStrings = append(trimStrings, filepath.Join(goPathString, "src")+string(filepath.Separator)) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-31 10:13:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-19 03:04:46 +08:00
										 |  |  | 	for _, goRootString := range goRootList { | 
					
						
							|  |  |  | 		trimStrings = append(trimStrings, filepath.Join(goRootString, "src")+string(filepath.Separator)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-31 10:13:25 +08:00
										 |  |  | 	for _, defaultgoPathString := range defaultgoPathList { | 
					
						
							|  |  |  | 		trimStrings = append(trimStrings, filepath.Join(defaultgoPathString, "src")+string(filepath.Separator)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-19 03:04:46 +08:00
										 |  |  | 	for _, defaultgoRootString := range defaultgoRootList { | 
					
						
							|  |  |  | 		trimStrings = append(trimStrings, filepath.Join(defaultgoRootString, "src")+string(filepath.Separator)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Remove duplicate entries.
 | 
					
						
							|  |  |  | 	trimStrings = uniqueEntries(trimStrings) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | 	// Add "github.com/minio/minio" as the last to cover
 | 
					
						
							|  |  |  | 	// paths like "{GOROOT}/src/github.com/minio/minio"
 | 
					
						
							|  |  |  | 	// and "{GOPATH}/src/github.com/minio/minio"
 | 
					
						
							|  |  |  | 	trimStrings = append(trimStrings, filepath.Join("github.com", "minio", "minio")+string(filepath.Separator)) | 
					
						
							| 
									
										
										
										
											2015-09-19 17:36:50 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | func trimTrace(f string) string { | 
					
						
							|  |  |  | 	for _, trimString := range trimStrings { | 
					
						
							|  |  |  | 		f = strings.TrimPrefix(filepath.ToSlash(f), filepath.ToSlash(trimString)) | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | 	return filepath.FromSlash(f) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | func getSource(level int) string { | 
					
						
							|  |  |  | 	pc, file, lineNumber, ok := runtime.Caller(level) | 
					
						
							| 
									
										
										
										
											2018-04-11 00:37:14 +08:00
										 |  |  | 	if ok { | 
					
						
							|  |  |  | 		// Clean up the common prefixes
 | 
					
						
							|  |  |  | 		file = trimTrace(file) | 
					
						
							|  |  |  | 		_, funcName := filepath.Split(runtime.FuncForPC(pc).Name()) | 
					
						
							|  |  |  | 		return fmt.Sprintf("%v:%v:%v()", file, lineNumber, funcName) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return "" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | // getTrace method - creates and returns stack trace
 | 
					
						
							|  |  |  | func getTrace(traceLevel int) []string { | 
					
						
							|  |  |  | 	var trace []string | 
					
						
							|  |  |  | 	pc, file, lineNumber, ok := runtime.Caller(traceLevel) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-19 03:04:46 +08:00
										 |  |  | 	for ok && file != "" { | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | 		// Clean up the common prefixes
 | 
					
						
							|  |  |  | 		file = trimTrace(file) | 
					
						
							|  |  |  | 		// Get the function name
 | 
					
						
							|  |  |  | 		_, funcName := filepath.Split(runtime.FuncForPC(pc).Name()) | 
					
						
							|  |  |  | 		// Skip duplicate traces that start with file name, "<autogenerated>"
 | 
					
						
							|  |  |  | 		// and also skip traces with function name that starts with "runtime."
 | 
					
						
							|  |  |  | 		if !strings.HasPrefix(file, "<autogenerated>") && | 
					
						
							|  |  |  | 			!strings.HasPrefix(funcName, "runtime.") { | 
					
						
							|  |  |  | 			// Form and append a line of stack trace into a
 | 
					
						
							|  |  |  | 			// collection, 'trace', to build full stack trace
 | 
					
						
							|  |  |  | 			trace = append(trace, fmt.Sprintf("%v:%v:%v()", file, lineNumber, funcName)) | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// Ignore trace logs beyond the following conditions
 | 
					
						
							|  |  |  | 			for _, name := range matchingFuncNames { | 
					
						
							|  |  |  | 				if funcName == name { | 
					
						
							|  |  |  | 					return trace | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-01-17 23:24:46 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		traceLevel++ | 
					
						
							|  |  |  | 		// Read stack trace information from PC
 | 
					
						
							|  |  |  | 		pc, file, lineNumber, ok = runtime.Caller(traceLevel) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return trace | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | // LogIf prints a detailed error message during
 | 
					
						
							|  |  |  | // the execution of the server.
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | func LogIf(ctx context.Context, err error) { | 
					
						
							| 
									
										
										
										
											2018-04-28 06:03:19 +08:00
										 |  |  | 	if Disable { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	req := GetReqInfo(ctx) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if req == nil { | 
					
						
							|  |  |  | 		req = &ReqInfo{API: "SYSTEM"} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	API := "SYSTEM" | 
					
						
							|  |  |  | 	if req.API != "" { | 
					
						
							|  |  |  | 		API = req.API | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tags := make(map[string]string) | 
					
						
							|  |  |  | 	for _, entry := range req.GetTags() { | 
					
						
							|  |  |  | 		tags[entry.Key] = entry.Val | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Get full stack trace
 | 
					
						
							|  |  |  | 	trace := getTrace(2) | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Get the cause for the Error
 | 
					
						
							|  |  |  | 	message := err.Error() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	// Output the formatted log message at console
 | 
					
						
							|  |  |  | 	var output string | 
					
						
							|  |  |  | 	if jsonFlag { | 
					
						
							|  |  |  | 		logJSON, err := json.Marshal(&logEntry{ | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 			Level:      ErrorLvl.String(), | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 			RemoteHost: req.RemoteHost, | 
					
						
							|  |  |  | 			RequestID:  req.RequestID, | 
					
						
							|  |  |  | 			UserAgent:  req.UserAgent, | 
					
						
							|  |  |  | 			Time:       time.Now().UTC().Format(time.RFC3339Nano), | 
					
						
							| 
									
										
										
										
											2018-04-11 00:37:14 +08:00
										 |  |  | 			API:        &api{Name: API, Args: &args{Bucket: req.BucketName, Object: req.ObjectName}}, | 
					
						
							|  |  |  | 			Trace:      &traceEntry{Message: message, Source: trace, Variables: tags}, | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			panic(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		output = string(logJSON) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		// Add a sequence number and formatting for each stack trace
 | 
					
						
							|  |  |  | 		// No formatting is required for the first entry
 | 
					
						
							|  |  |  | 		for i, element := range trace { | 
					
						
							|  |  |  | 			trace[i] = fmt.Sprintf("%8v: %s", i+1, element) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		tagString := "" | 
					
						
							|  |  |  | 		for key, value := range tags { | 
					
						
							|  |  |  | 			if value != "" { | 
					
						
							|  |  |  | 				if tagString != "" { | 
					
						
							|  |  |  | 					tagString += ", " | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				tagString += key + "=" + value | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		apiString := "API: " + API + "(" | 
					
						
							|  |  |  | 		if req.BucketName != "" { | 
					
						
							|  |  |  | 			apiString = apiString + "bucket=" + req.BucketName | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if req.ObjectName != "" { | 
					
						
							|  |  |  | 			apiString = apiString + ", object=" + req.ObjectName | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		apiString += ")" | 
					
						
							|  |  |  | 		timeString := "Time: " + time.Now().Format(loggerTimeFormat) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var requestID string | 
					
						
							|  |  |  | 		if req.RequestID != "" { | 
					
						
							|  |  |  | 			requestID = "\nRequestID: " + req.RequestID | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var remoteHost string | 
					
						
							|  |  |  | 		if req.RemoteHost != "" { | 
					
						
							|  |  |  | 			remoteHost = "\nRemoteHost: " + req.RemoteHost | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var userAgent string | 
					
						
							|  |  |  | 		if req.UserAgent != "" { | 
					
						
							|  |  |  | 			userAgent = "\nUserAgent: " + req.UserAgent | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if len(tags) > 0 { | 
					
						
							|  |  |  | 			tagString = "\n       " + tagString | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 		var msg = colorFgRed(colorBold(message)) | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 		output = fmt.Sprintf("\n%s\n%s%s%s%s\nError: %s%s\n%s", | 
					
						
							|  |  |  | 			apiString, timeString, requestID, remoteHost, userAgent, | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 			msg, tagString, strings.Join(trace, "\n")) | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	fmt.Println(output) | 
					
						
							| 
									
										
										
										
											2016-11-24 08:36:26 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-04-11 00:37:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 04:51:49 +08:00
										 |  |  | // ErrCritical is the value panic'd whenever CriticalIf is called.
 | 
					
						
							|  |  |  | var ErrCritical struct{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // CriticalIf logs the provided error on the console. It fails the
 | 
					
						
							|  |  |  | // current go-routine by causing a `panic(ErrCritical)`.
 | 
					
						
							| 
									
										
										
										
											2018-04-20 08:24:43 +08:00
										 |  |  | func CriticalIf(ctx context.Context, err error) { | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		LogIf(ctx, err) | 
					
						
							| 
									
										
										
										
											2018-06-26 04:51:49 +08:00
										 |  |  | 		panic(ErrCritical) | 
					
						
							| 
									
										
										
										
											2018-04-20 08:24:43 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | // FatalIf is similar to Fatal() but it ignores passed nil error
 | 
					
						
							| 
									
										
										
										
											2018-04-11 00:37:14 +08:00
										 |  |  | func FatalIf(err error, msg string, data ...interface{}) { | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2018-04-11 00:37:14 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 	fatal(err, msg, data...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Fatal prints only fatal error message without no stack trace
 | 
					
						
							|  |  |  | // it will be called for input validation failures
 | 
					
						
							|  |  |  | func Fatal(err error, msg string, data ...interface{}) { | 
					
						
							|  |  |  | 	fatal(err, msg, data...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func fatal(err error, msg string, data ...interface{}) { | 
					
						
							|  |  |  | 	var errMsg string | 
					
						
							|  |  |  | 	if msg != "" { | 
					
						
							|  |  |  | 		errMsg = errorFmtFunc(fmt.Sprintf(msg, data...), err, jsonFlag) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		errMsg = err.Error() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	consoleLog(fatalMessage, errMsg) | 
					
						
							| 
									
										
										
										
											2018-04-11 00:37:14 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var fatalMessage fatalMsg | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type fatalMsg struct { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (f fatalMsg) json(msg string, args ...interface{}) { | 
					
						
							|  |  |  | 	logJSON, err := json.Marshal(&logEntry{ | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 		Level: FatalLvl.String(), | 
					
						
							| 
									
										
										
										
											2018-04-11 00:37:14 +08:00
										 |  |  | 		Time:  time.Now().UTC().Format(time.RFC3339Nano), | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 		Trace: &traceEntry{Message: fmt.Sprintf(msg, args...), Source: []string{getSource(6)}}, | 
					
						
							| 
									
										
										
										
											2018-04-11 00:37:14 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		panic(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	fmt.Println(string(logJSON)) | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-11 00:37:14 +08:00
										 |  |  | 	os.Exit(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (f fatalMsg) quiet(msg string, args ...interface{}) { | 
					
						
							|  |  |  | 	f.pretty(msg, args...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | var ( | 
					
						
							|  |  |  | 	logTag       = "ERROR" | 
					
						
							|  |  |  | 	logBanner    = colorBgRed(colorFgWhite(colorBold(logTag))) + " " | 
					
						
							|  |  |  | 	emptyBanner  = colorBgRed(strings.Repeat(" ", len(logTag))) + " " | 
					
						
							|  |  |  | 	minimumWidth = 80 | 
					
						
							|  |  |  | 	bannerWidth  = len(logTag) + 1 | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-11 00:37:14 +08:00
										 |  |  | func (f fatalMsg) pretty(msg string, args ...interface{}) { | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 	// Build the passed error message
 | 
					
						
							| 
									
										
										
										
											2018-04-11 00:37:14 +08:00
										 |  |  | 	errMsg := fmt.Sprintf(msg, args...) | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 	// Check terminal width
 | 
					
						
							|  |  |  | 	termWidth, _, err := terminal.GetSize(0) | 
					
						
							|  |  |  | 	if err != nil || termWidth < minimumWidth { | 
					
						
							|  |  |  | 		termWidth = minimumWidth | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Calculate available widht without the banner
 | 
					
						
							|  |  |  | 	width := termWidth - bannerWidth | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tagPrinted := false | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Print the error message: the following code takes care
 | 
					
						
							|  |  |  | 	// of splitting error text and always pretty printing the
 | 
					
						
							|  |  |  | 	// red banner along with the error message. Since the error
 | 
					
						
							|  |  |  | 	// message itself contains some colored text, we needed
 | 
					
						
							|  |  |  | 	// to use some ANSI control escapes to cursor color state
 | 
					
						
							|  |  |  | 	// and freely move in the screen.
 | 
					
						
							|  |  |  | 	for _, line := range strings.Split(errMsg, "\n") { | 
					
						
							|  |  |  | 		if len(line) == 0 { | 
					
						
							|  |  |  | 			// No more text to print, just quit.
 | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for { | 
					
						
							|  |  |  | 			// Save the attributes of the current cursor helps
 | 
					
						
							|  |  |  | 			// us save the text color of the passed error message
 | 
					
						
							|  |  |  | 			ansiSaveAttributes() | 
					
						
							|  |  |  | 			// Print banner with or without the log tag
 | 
					
						
							|  |  |  | 			if !tagPrinted { | 
					
						
							|  |  |  | 				fmt.Print(logBanner) | 
					
						
							|  |  |  | 				tagPrinted = true | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				fmt.Print(emptyBanner) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// Restore the text color of the error message
 | 
					
						
							|  |  |  | 			ansiRestoreAttributes() | 
					
						
							|  |  |  | 			ansiMoveRight(bannerWidth) | 
					
						
							|  |  |  | 			// Continue  error message printing
 | 
					
						
							|  |  |  | 			if len(line) > width { | 
					
						
							|  |  |  | 				fmt.Println(line[:width]) | 
					
						
							|  |  |  | 				line = line[width:] | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				fmt.Println(line) | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Exit because this is a fatal error message
 | 
					
						
							| 
									
										
										
										
											2018-04-11 00:37:14 +08:00
										 |  |  | 	os.Exit(1) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var info infoMsg | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type infoMsg struct { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (i infoMsg) json(msg string, args ...interface{}) { | 
					
						
							|  |  |  | 	logJSON, err := json.Marshal(&logEntry{ | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 		Level:   InformationLvl.String(), | 
					
						
							| 
									
										
										
										
											2018-04-11 00:37:14 +08:00
										 |  |  | 		Message: fmt.Sprintf(msg, args...), | 
					
						
							|  |  |  | 		Time:    time.Now().UTC().Format(time.RFC3339Nano), | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		panic(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	fmt.Println(string(logJSON)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (i infoMsg) quiet(msg string, args ...interface{}) { | 
					
						
							|  |  |  | 	i.pretty(msg, args...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (i infoMsg) pretty(msg string, args ...interface{}) { | 
					
						
							| 
									
										
										
										
											2018-04-17 04:36:45 +08:00
										 |  |  | 	c.Printf(msg, args...) | 
					
						
							| 
									
										
										
										
											2018-04-11 00:37:14 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Info :
 | 
					
						
							|  |  |  | func Info(msg string, data ...interface{}) { | 
					
						
							|  |  |  | 	consoleLog(info, msg+"\n", data...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var startupMessage startUpMsg | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type startUpMsg struct { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s startUpMsg) json(msg string, args ...interface{}) { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s startUpMsg) quiet(msg string, args ...interface{}) { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s startUpMsg) pretty(msg string, args ...interface{}) { | 
					
						
							| 
									
										
										
										
											2018-04-17 04:36:45 +08:00
										 |  |  | 	c.Printf(msg, args...) | 
					
						
							| 
									
										
										
										
											2018-04-11 00:37:14 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // StartupMessage :
 | 
					
						
							|  |  |  | func StartupMessage(msg string, data ...interface{}) { | 
					
						
							|  |  |  | 	consoleLog(startupMessage, msg+"\n", data...) | 
					
						
							|  |  |  | } |