mirror of https://github.com/minio/minio.git
Allow logging targets to be configured to receive `minio` (#8347)
specific errors, `application` errors or `all` by default. console logging on server by default lists all logs - enhance admin console API to accept `type` as query parameter to subscribe to application/minio logs.
This commit is contained in:
parent
8964ef821f
commit
d7060c4c32
|
@ -194,7 +194,7 @@ func (a adminAPIHandlers) ServiceActionHandler(w http.ResponseWriter, r *http.Re
|
|||
case madmin.ServiceActionStop:
|
||||
serviceSig = serviceStop
|
||||
default:
|
||||
logger.LogIf(ctx, fmt.Errorf("Unrecognized service action %s requested", action))
|
||||
logger.LogIf(ctx, fmt.Errorf("Unrecognized service action %s requested", action), logger.Application)
|
||||
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMalformedPOSTRequest), r.URL)
|
||||
return
|
||||
}
|
||||
|
@ -705,7 +705,7 @@ func extractHealInitParams(vars map[string]string, qParms url.Values, r io.Reade
|
|||
if hip.clientToken == "" {
|
||||
jerr := json.NewDecoder(r).Decode(&hip.hs)
|
||||
if jerr != nil {
|
||||
logger.LogIf(context.Background(), jerr)
|
||||
logger.LogIf(context.Background(), jerr, logger.Application)
|
||||
err = ErrRequestBodyParse
|
||||
return
|
||||
}
|
||||
|
@ -1517,7 +1517,7 @@ func (a adminAPIHandlers) SetConfigHandler(w http.ResponseWriter, r *http.Reques
|
|||
password := globalServerConfig.GetCredential().SecretKey
|
||||
configBytes, err := madmin.DecryptData(password, io.LimitReader(r.Body, r.ContentLength))
|
||||
if err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
logger.LogIf(ctx, err, logger.Application)
|
||||
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), r.URL)
|
||||
return
|
||||
}
|
||||
|
@ -1525,7 +1525,7 @@ func (a adminAPIHandlers) SetConfigHandler(w http.ResponseWriter, r *http.Reques
|
|||
// Validate JSON provided in the request body: check the
|
||||
// client has not sent JSON objects with duplicate keys.
|
||||
if err = quick.CheckDuplicateKeys(string(configBytes)); err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
logger.LogIf(ctx, err, logger.Application)
|
||||
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), r.URL)
|
||||
return
|
||||
}
|
||||
|
@ -1656,6 +1656,13 @@ func (a adminAPIHandlers) ConsoleLogHandler(w http.ResponseWriter, r *http.Reque
|
|||
if err != nil {
|
||||
limitLines = 10
|
||||
}
|
||||
|
||||
logKind := r.URL.Query().Get("logType")
|
||||
if logKind == "" {
|
||||
logKind = string(logger.All)
|
||||
}
|
||||
logKind = strings.ToUpper(logKind)
|
||||
|
||||
// Avoid reusing tcp connection if read timeout is hit
|
||||
// This is needed to make r.Context().Done() work as
|
||||
// expected in case of read timeout
|
||||
|
@ -1672,7 +1679,7 @@ func (a adminAPIHandlers) ConsoleLogHandler(w http.ResponseWriter, r *http.Reque
|
|||
return
|
||||
}
|
||||
|
||||
globalConsoleSys.Subscribe(logCh, doneCh, node, limitLines, nil)
|
||||
globalConsoleSys.Subscribe(logCh, doneCh, node, limitLines, logKind, nil)
|
||||
|
||||
for _, peer := range peers {
|
||||
if node == "" || strings.EqualFold(peer.host.Name, node) {
|
||||
|
@ -1689,7 +1696,7 @@ func (a adminAPIHandlers) ConsoleLogHandler(w http.ResponseWriter, r *http.Reque
|
|||
select {
|
||||
case entry := <-logCh:
|
||||
log := entry.(madmin.LogInfo)
|
||||
if log.SendLog(node) {
|
||||
if log.SendLog(node, logKind) {
|
||||
if err := enc.Encode(log); err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -142,7 +142,7 @@ func checkAdminRequestAuthType(ctx context.Context, r *http.Request, region stri
|
|||
if s3Err != ErrNone {
|
||||
reqInfo := (&logger.ReqInfo{}).AppendTags("requestHeaders", dumpRequest(r))
|
||||
ctx := logger.SetReqInfo(ctx, reqInfo)
|
||||
logger.LogIf(ctx, errors.New(getAPIError(s3Err).Description))
|
||||
logger.LogIf(ctx, errors.New(getAPIError(s3Err).Description), logger.Application)
|
||||
}
|
||||
return s3Err
|
||||
}
|
||||
|
@ -235,7 +235,7 @@ func getClaimsFromToken(r *http.Request) (map[string]interface{}, error) {
|
|||
if err != nil {
|
||||
// Base64 decoding fails, we should log to indicate
|
||||
// something is malforming the request sent by client.
|
||||
logger.LogIf(context.Background(), err)
|
||||
logger.LogIf(context.Background(), err, logger.Application)
|
||||
return nil, errAuthentication
|
||||
}
|
||||
claims[iampolicy.SessionPolicyName] = string(spBytes)
|
||||
|
@ -312,7 +312,7 @@ func checkRequestAuthTypeToAccessKey(ctx context.Context, r *http.Request, actio
|
|||
// To extract region from XML in request body, get copy of request body.
|
||||
payload, err := ioutil.ReadAll(io.LimitReader(r.Body, maxLocationConstraintSize))
|
||||
if err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
logger.LogIf(ctx, err, logger.Application)
|
||||
return accessKey, owner, ErrMalformedXML
|
||||
}
|
||||
|
||||
|
|
|
@ -354,7 +354,7 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter,
|
|||
|
||||
// Read incoming body XML bytes.
|
||||
if _, err := io.ReadFull(r.Body, deleteXMLBytes); err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
logger.LogIf(ctx, err, logger.Application)
|
||||
writeErrorResponse(ctx, w, toAdminAPIErr(ctx, err), r.URL, guessIsBrowserReq(r))
|
||||
return
|
||||
}
|
||||
|
@ -362,7 +362,7 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter,
|
|||
// Unmarshal list of keys to be deleted.
|
||||
deleteObjects := &DeleteObjectsRequest{}
|
||||
if err := xml.Unmarshal(deleteXMLBytes, deleteObjects); err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
logger.LogIf(ctx, err, logger.Application)
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMalformedXML), r.URL, guessIsBrowserReq(r))
|
||||
return
|
||||
}
|
||||
|
@ -596,7 +596,7 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
|
|||
// Read multipart data and save in memory and in the disk if needed
|
||||
form, err := reader.ReadForm(maxFormMemory)
|
||||
if err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
logger.LogIf(ctx, err, logger.Application)
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMalformedPOSTRequest), r.URL, guessIsBrowserReq(r))
|
||||
return
|
||||
}
|
||||
|
@ -607,7 +607,7 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
|
|||
// Extract all form fields
|
||||
fileBody, fileName, fileSize, formValues, err := extractPostPolicyFormValues(ctx, form)
|
||||
if err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
logger.LogIf(ctx, err, logger.Application)
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMalformedPOSTRequest), r.URL, guessIsBrowserReq(r))
|
||||
return
|
||||
}
|
||||
|
|
|
@ -254,7 +254,7 @@ func handleCommonEnvVars() {
|
|||
|
||||
func logStartupMessage(msg string, data ...interface{}) {
|
||||
if globalConsoleSys != nil {
|
||||
globalConsoleSys.Send(msg)
|
||||
globalConsoleSys.Send(msg, string(logger.All))
|
||||
}
|
||||
logger.StartupMessage(msg, data...)
|
||||
}
|
||||
|
|
|
@ -336,14 +336,14 @@ func (s *serverConfig) lookupConfigs() {
|
|||
for _, l := range s.Logger.HTTP {
|
||||
if l.Enabled {
|
||||
// Enable http logging
|
||||
logger.AddTarget(http.New(l.Endpoint, loggerUserAgent, NewCustomHTTPTransport()))
|
||||
logger.AddTarget(http.New(l.Endpoint, loggerUserAgent, string(logger.All), NewCustomHTTPTransport()))
|
||||
}
|
||||
}
|
||||
|
||||
for _, l := range s.Logger.Audit {
|
||||
if l.Enabled {
|
||||
// Enable http audit logging
|
||||
logger.AddAuditTarget(http.New(l.Endpoint, loggerUserAgent, NewCustomHTTPTransport()))
|
||||
logger.AddAuditTarget(http.New(l.Endpoint, loggerUserAgent, string(logger.All), NewCustomHTTPTransport()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ func (sys *HTTPConsoleLoggerSys) HasLogListeners() bool {
|
|||
}
|
||||
|
||||
// Subscribe starts console logging for this node.
|
||||
func (sys *HTTPConsoleLoggerSys) Subscribe(subCh chan interface{}, doneCh chan struct{}, node string, last int, filter func(entry interface{}) bool) {
|
||||
func (sys *HTTPConsoleLoggerSys) Subscribe(subCh chan interface{}, doneCh chan struct{}, node string, last int, logKind string, filter func(entry interface{}) bool) {
|
||||
// Enable console logging for remote client even if local console logging is disabled in the config.
|
||||
if !globalServerConfig.Logger.Console.Enabled && !sys.pubsub.HasSubscribers() {
|
||||
logger.AddTarget(globalConsoleSys.Console())
|
||||
|
@ -83,7 +83,7 @@ func (sys *HTTPConsoleLoggerSys) Subscribe(subCh chan interface{}, doneCh chan s
|
|||
lastN = make([]madmin.LogInfo, last)
|
||||
sys.logBufLk.RLock()
|
||||
sys.logBuf.Do(func(p interface{}) {
|
||||
if p != nil && (p.(madmin.LogInfo)).SendLog(node) {
|
||||
if p != nil && (p.(madmin.LogInfo)).SendLog(node, logKind) {
|
||||
lastN[cnt%last] = p.(madmin.LogInfo)
|
||||
cnt++
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ func (sys *HTTPConsoleLoggerSys) Console() *HTTPConsoleLoggerSys {
|
|||
|
||||
// Send log message 'e' to console and publish to console
|
||||
// log pubsub system
|
||||
func (sys *HTTPConsoleLoggerSys) Send(e interface{}) error {
|
||||
func (sys *HTTPConsoleLoggerSys) Send(e interface{}, logKind string) error {
|
||||
var lg madmin.LogInfo
|
||||
switch e := e.(type) {
|
||||
case log.Entry:
|
||||
|
@ -136,7 +136,7 @@ func (sys *HTTPConsoleLoggerSys) Send(e interface{}) error {
|
|||
sys.logBufLk.Unlock()
|
||||
|
||||
if globalServerConfig.Logger.Console.Enabled {
|
||||
return sys.console.Send(e)
|
||||
return sys.console.Send(e, string(logger.All))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -260,7 +260,7 @@ func (endpoints EndpointList) UpdateIsLocal() error {
|
|||
reqInfo := (&logger.ReqInfo{}).AppendTags("host", endpoints[i].HostName)
|
||||
reqInfo.AppendTags("elapsedTime", humanize.RelTime(startTime, startTime.Add(timeElapsed), "elapsed", ""))
|
||||
ctx := logger.SetReqInfo(context.Background(), reqInfo)
|
||||
logger.LogIf(ctx, err)
|
||||
logger.LogIf(ctx, err, logger.Application)
|
||||
}
|
||||
} else {
|
||||
resolvedList[i] = true
|
||||
|
|
|
@ -138,12 +138,12 @@ func initFormatCache(ctx context.Context, drives []string) (formats []*formatCac
|
|||
}
|
||||
if !os.IsNotExist(err) {
|
||||
logger.GetReqInfo(ctx).AppendTags("drive", drive)
|
||||
logger.LogIf(ctx, err)
|
||||
logger.LogIf(ctx, err, logger.Application)
|
||||
return nil, err
|
||||
}
|
||||
if err = os.Mkdir(drive, 0777); err != nil {
|
||||
logger.GetReqInfo(ctx).AppendTags("drive", drive)
|
||||
logger.LogIf(ctx, err)
|
||||
logger.LogIf(ctx, err, logger.Application)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -280,7 +280,7 @@ func (fs *FSObjects) PutObjectPart(ctx context.Context, bucket, object, uploadID
|
|||
|
||||
// Validate input data size and it can never be less than -1.
|
||||
if data.Size() < -1 {
|
||||
logger.LogIf(ctx, errInvalidArgument)
|
||||
logger.LogIf(ctx, errInvalidArgument, logger.Application)
|
||||
return pi, toObjectErr(errInvalidArgument)
|
||||
}
|
||||
|
||||
|
|
12
cmd/fs-v1.go
12
cmd/fs-v1.go
|
@ -548,7 +548,7 @@ func (fs *FSObjects) GetObjectNInfo(ctx context.Context, bucket, object string,
|
|||
// Check if range is valid
|
||||
if off > size || off+length > size {
|
||||
err = InvalidRange{off, length, size}
|
||||
logger.LogIf(ctx, err)
|
||||
logger.LogIf(ctx, err, logger.Application)
|
||||
closeFn()
|
||||
rwPoolUnlocker()
|
||||
nsUnlocker()
|
||||
|
@ -587,13 +587,13 @@ func (fs *FSObjects) getObject(ctx context.Context, bucket, object string, offse
|
|||
|
||||
// Offset cannot be negative.
|
||||
if offset < 0 {
|
||||
logger.LogIf(ctx, errUnexpected)
|
||||
logger.LogIf(ctx, errUnexpected, logger.Application)
|
||||
return toObjectErr(errUnexpected, bucket, object)
|
||||
}
|
||||
|
||||
// Writer cannot be nil.
|
||||
if writer == nil {
|
||||
logger.LogIf(ctx, errUnexpected)
|
||||
logger.LogIf(ctx, errUnexpected, logger.Application)
|
||||
return toObjectErr(errUnexpected, bucket, object)
|
||||
}
|
||||
|
||||
|
@ -622,7 +622,7 @@ func (fs *FSObjects) getObject(ctx context.Context, bucket, object string, offse
|
|||
return toObjectErr(perr, bucket, object)
|
||||
}
|
||||
if objEtag != etag {
|
||||
logger.LogIf(ctx, InvalidETag{})
|
||||
logger.LogIf(ctx, InvalidETag{}, logger.Application)
|
||||
return toObjectErr(InvalidETag{}, bucket, object)
|
||||
}
|
||||
}
|
||||
|
@ -648,7 +648,7 @@ func (fs *FSObjects) getObject(ctx context.Context, bucket, object string, offse
|
|||
// Reply back invalid range if the input offset and length fall out of range.
|
||||
if offset > size || offset+length > size {
|
||||
err = InvalidRange{offset, length, size}
|
||||
logger.LogIf(ctx, err)
|
||||
logger.LogIf(ctx, err, logger.Application)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -864,7 +864,7 @@ func (fs *FSObjects) putObject(ctx context.Context, bucket string, object string
|
|||
|
||||
// Validate input data size and it can never be less than zero.
|
||||
if data.Size() < -1 {
|
||||
logger.LogIf(ctx, errInvalidArgument)
|
||||
logger.LogIf(ctx, errInvalidArgument, logger.Application)
|
||||
return ObjectInfo{}, errInvalidArgument
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import (
|
|||
"io/ioutil"
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
|
@ -158,14 +159,14 @@ EXAMPLES:
|
|||
// Handler for 'minio gateway gcs' command line.
|
||||
func gcsGatewayMain(ctx *cli.Context) {
|
||||
projectID := ctx.Args().First()
|
||||
if projectID == "" && env.Get("GOOGLE_APPLICATION_CREDENTIALS", "") == "" {
|
||||
logger.LogIf(context.Background(), errGCSProjectIDNotFound)
|
||||
if projectID == "" && os.Getenv("GOOGLE_APPLICATION_CREDENTIALS") == "" {
|
||||
logger.LogIf(context.Background(), errGCSProjectIDNotFound, logger.Application)
|
||||
cli.ShowCommandHelpAndExit(ctx, "gcs", 1)
|
||||
}
|
||||
if projectID != "" && !isValidGCSProjectIDFormat(projectID) {
|
||||
reqInfo := (&logger.ReqInfo{}).AppendTags("projectID", ctx.Args().First())
|
||||
contxt := logger.SetReqInfo(context.Background(), reqInfo)
|
||||
logger.LogIf(contxt, errGCSInvalidProjectID)
|
||||
logger.LogIf(contxt, errGCSInvalidProjectID, logger.Application)
|
||||
cli.ShowCommandHelpAndExit(ctx, "gcs", 1)
|
||||
}
|
||||
|
||||
|
@ -762,7 +763,7 @@ func (l *gcsGateway) GetObject(ctx context.Context, bucket string, key string, s
|
|||
// if we want to mimic S3 behavior exactly, we need to verify if bucket exists first,
|
||||
// otherwise gcs will just return object not exist in case of non-existing bucket
|
||||
if _, err := l.client.Bucket(bucket).Attrs(ctx); err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
logger.LogIf(ctx, err, logger.Application)
|
||||
return gcsToObjectError(err, bucket)
|
||||
}
|
||||
|
||||
|
@ -775,7 +776,7 @@ func (l *gcsGateway) GetObject(ctx context.Context, bucket string, key string, s
|
|||
|
||||
r, err := object.NewRangeReader(ctx, startOffset, length)
|
||||
if err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
logger.LogIf(ctx, err, logger.Application)
|
||||
return gcsToObjectError(err, bucket, key)
|
||||
}
|
||||
defer r.Close()
|
||||
|
@ -873,7 +874,7 @@ func (l *gcsGateway) GetObjectInfo(ctx context.Context, bucket string, object st
|
|||
// if we want to mimic S3 behavior exactly, we need to verify if bucket exists first,
|
||||
// otherwise gcs will just return object not exist in case of non-existing bucket
|
||||
if _, err := l.client.Bucket(bucket).Attrs(ctx); err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
logger.LogIf(ctx, err, logger.Application)
|
||||
return minio.ObjectInfo{}, gcsToObjectError(err, bucket)
|
||||
}
|
||||
|
||||
|
@ -893,7 +894,7 @@ func (l *gcsGateway) PutObject(ctx context.Context, bucket string, key string, r
|
|||
// if we want to mimic S3 behavior exactly, we need to verify if bucket exists first,
|
||||
// otherwise gcs will just return object not exist in case of non-existing bucket
|
||||
if _, err := l.client.Bucket(bucket).Attrs(ctx); err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
logger.LogIf(ctx, err, logger.Application)
|
||||
return minio.ObjectInfo{}, gcsToObjectError(err, bucket)
|
||||
}
|
||||
|
||||
|
|
|
@ -519,13 +519,13 @@ func (l *ossObjects) ListObjectsV2(ctx context.Context, bucket, prefix, continua
|
|||
// length indicates the total length of the object.
|
||||
func ossGetObject(ctx context.Context, client *oss.Client, bucket, key string, startOffset, length int64, writer io.Writer, etag string) error {
|
||||
if length < 0 && length != -1 {
|
||||
logger.LogIf(ctx, fmt.Errorf("Invalid argument"))
|
||||
logger.LogIf(ctx, fmt.Errorf("Invalid argument"), logger.Application)
|
||||
return ossToObjectError(fmt.Errorf("Invalid argument"), bucket, key)
|
||||
}
|
||||
|
||||
bkt, err := client.Bucket(bucket)
|
||||
if err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
logger.LogIf(ctx, err, logger.Application)
|
||||
return ossToObjectError(err, bucket, key)
|
||||
}
|
||||
|
||||
|
|
|
@ -155,6 +155,6 @@ func AuditLog(w http.ResponseWriter, r *http.Request, api string, reqClaims map[
|
|||
entry.API.StatusCode = statusCode
|
||||
entry.API.TimeToFirstByte = timeToFirstByte.String()
|
||||
entry.API.TimeToResponse = timeToResponse.String()
|
||||
_ = t.Send(entry)
|
||||
_ = t.Send(entry, string(All))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -273,36 +273,53 @@ func hashString(input string) string {
|
|||
return hex.EncodeToString(checksum)
|
||||
}
|
||||
|
||||
// Kind specifies the kind of error log
|
||||
type Kind string
|
||||
|
||||
const (
|
||||
// Minio errors
|
||||
Minio Kind = "MINIO"
|
||||
// Application errors
|
||||
Application Kind = "APPLICATION"
|
||||
// All errors
|
||||
All Kind = "ALL"
|
||||
)
|
||||
|
||||
// LogAlwaysIf prints a detailed error message during
|
||||
// the execution of the server.
|
||||
func LogAlwaysIf(ctx context.Context, err error) {
|
||||
func LogAlwaysIf(ctx context.Context, err error, errKind ...interface{}) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
logIf(ctx, err)
|
||||
logIf(ctx, err, errKind...)
|
||||
}
|
||||
|
||||
// LogIf prints a detailed error message during
|
||||
// the execution of the server, if it is not an
|
||||
// ignored error.
|
||||
func LogIf(ctx context.Context, err error) {
|
||||
func LogIf(ctx context.Context, err error, errKind ...interface{}) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err.Error() != diskNotFoundError {
|
||||
logIf(ctx, err)
|
||||
logIf(ctx, err, errKind...)
|
||||
}
|
||||
}
|
||||
|
||||
// logIf prints a detailed error message during
|
||||
// the execution of the server.
|
||||
func logIf(ctx context.Context, err error) {
|
||||
func logIf(ctx context.Context, err error, errKind ...interface{}) {
|
||||
if Disable {
|
||||
return
|
||||
}
|
||||
|
||||
logKind := string(Minio)
|
||||
if len(errKind) > 0 {
|
||||
if ek, ok := errKind[0].(Kind); ok {
|
||||
logKind = string(ek)
|
||||
}
|
||||
}
|
||||
req := GetReqInfo(ctx)
|
||||
|
||||
if req == nil {
|
||||
|
@ -330,6 +347,7 @@ func logIf(ctx context.Context, err error) {
|
|||
entry := log.Entry{
|
||||
DeploymentID: req.DeploymentID,
|
||||
Level: ErrorLvl.String(),
|
||||
LogKind: logKind,
|
||||
RemoteHost: req.RemoteHost,
|
||||
Host: req.Host,
|
||||
RequestID: req.RequestID,
|
||||
|
@ -359,7 +377,7 @@ func logIf(ctx context.Context, err error) {
|
|||
|
||||
// Iterate over all logger targets to send the log entry
|
||||
for _, t := range Targets {
|
||||
t.Send(entry)
|
||||
t.Send(entry, entry.LogKind)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -368,9 +386,9 @@ var ErrCritical struct{}
|
|||
|
||||
// CriticalIf logs the provided error on the console. It fails the
|
||||
// current go-routine by causing a `panic(ErrCritical)`.
|
||||
func CriticalIf(ctx context.Context, err error) {
|
||||
func CriticalIf(ctx context.Context, err error, errKind ...interface{}) {
|
||||
if err != nil {
|
||||
LogIf(ctx, err)
|
||||
LogIf(ctx, err, errKind...)
|
||||
panic(ErrCritical)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ type logOnceType struct {
|
|||
}
|
||||
|
||||
// One log message per error.
|
||||
func (l *logOnceType) logOnceIf(ctx context.Context, err error, id interface{}) {
|
||||
func (l *logOnceType) logOnceIf(ctx context.Context, err error, id interface{}, errKind ...interface{}) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ func (l *logOnceType) logOnceIf(ctx context.Context, err error, id interface{})
|
|||
l.Unlock()
|
||||
|
||||
if shouldLog {
|
||||
LogIf(ctx, err)
|
||||
LogIf(ctx, err, errKind...)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,6 +76,6 @@ var logOnce = newLogOnceType()
|
|||
// LogOnceIf - Logs notification errors - once per error.
|
||||
// id is a unique identifier for related log messages, refer to cmd/notification.go
|
||||
// on how it is used.
|
||||
func LogOnceIf(ctx context.Context, err error, id interface{}) {
|
||||
logOnce.logOnceIf(ctx, err, id)
|
||||
func LogOnceIf(ctx context.Context, err error, id interface{}, errKind ...interface{}) {
|
||||
logOnce.logOnceIf(ctx, err, id, errKind...)
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ type API struct {
|
|||
type Entry struct {
|
||||
DeploymentID string `json:"deploymentid,omitempty"`
|
||||
Level string `json:"level"`
|
||||
LogKind string `json:"errKind"`
|
||||
Time string `json:"time"`
|
||||
API *API `json:"api,omitempty"`
|
||||
RemoteHost string `json:"remotehost,omitempty"`
|
||||
|
|
|
@ -32,7 +32,7 @@ import (
|
|||
type Target struct{}
|
||||
|
||||
// Send log message 'e' to console
|
||||
func (c *Target) Send(e interface{}) error {
|
||||
func (c *Target) Send(e interface{}, logKind string) error {
|
||||
entry, ok := e.(log.Entry)
|
||||
if !ok {
|
||||
return fmt.Errorf("Uexpected log entry structure %#v", e)
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"errors"
|
||||
"net/http"
|
||||
gohttp "net/http"
|
||||
"strings"
|
||||
|
||||
xhttp "github.com/minio/minio/cmd/http"
|
||||
)
|
||||
|
@ -39,6 +40,7 @@ type Target struct {
|
|||
endpoint string
|
||||
// User-Agent to be set on each log request sent to the `endpoint`
|
||||
userAgent string
|
||||
logKind string
|
||||
client gohttp.Client
|
||||
}
|
||||
|
||||
|
@ -75,10 +77,11 @@ func (h *Target) startHTTPLogger() {
|
|||
|
||||
// New initializes a new logger target which
|
||||
// sends log over http to the specified endpoint
|
||||
func New(endpoint, userAgent string, transport *gohttp.Transport) *Target {
|
||||
func New(endpoint, userAgent, logKind string, transport *gohttp.Transport) *Target {
|
||||
h := Target{
|
||||
endpoint: endpoint,
|
||||
userAgent: userAgent,
|
||||
logKind: strings.ToUpper(logKind),
|
||||
client: gohttp.Client{
|
||||
Transport: transport,
|
||||
},
|
||||
|
@ -90,7 +93,10 @@ func New(endpoint, userAgent string, transport *gohttp.Transport) *Target {
|
|||
}
|
||||
|
||||
// Send log message 'e' to http target.
|
||||
func (h *Target) Send(entry interface{}) error {
|
||||
func (h *Target) Send(entry interface{}, errKind string) error {
|
||||
if h.logKind != errKind && h.logKind != "ALL" {
|
||||
return nil
|
||||
}
|
||||
select {
|
||||
case h.logCh <- entry:
|
||||
default:
|
||||
|
|
|
@ -20,7 +20,7 @@ package logger
|
|||
// a single log entry and Send it to the log target
|
||||
// e.g. Send the log to a http server
|
||||
type Target interface {
|
||||
Send(entry interface{}) error
|
||||
Send(entry interface{}, errKind string) error
|
||||
}
|
||||
|
||||
// Targets is the set of enabled loggers
|
||||
|
|
|
@ -329,7 +329,7 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req
|
|||
return
|
||||
}
|
||||
|
||||
logger.LogIf(ctx, err)
|
||||
logger.LogIf(ctx, err, logger.Application)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -948,7 +948,7 @@ func (s *peerRESTServer) ConsoleLogHandler(w http.ResponseWriter, r *http.Reques
|
|||
defer close(doneCh)
|
||||
|
||||
ch := make(chan interface{}, 2000)
|
||||
globalConsoleSys.Subscribe(ch, doneCh, "", 0, nil)
|
||||
globalConsoleSys.Subscribe(ch, doneCh, "", 0, string(logger.All), nil)
|
||||
|
||||
enc := gob.NewEncoder(w)
|
||||
for {
|
||||
|
|
|
@ -37,7 +37,14 @@ func writeSTSErrorResponse(ctx context.Context, w http.ResponseWriter, errCode S
|
|||
if errCtxt != nil {
|
||||
stsErrorResponse.Error.Message = fmt.Sprintf("%v", errCtxt)
|
||||
}
|
||||
logger.LogIf(ctx, errCtxt)
|
||||
logKind := logger.All
|
||||
switch errCode {
|
||||
case ErrSTSInternalError, ErrSTSNotInitialized:
|
||||
logKind = logger.Minio
|
||||
default:
|
||||
logKind = logger.Application
|
||||
}
|
||||
logger.LogIf(ctx, errCtxt, logKind)
|
||||
encodedErrorResponse := encodeResponse(stsErrorResponse)
|
||||
writeResponse(w, err.HTTPStatusCode, encodedErrorResponse, mimeXML)
|
||||
}
|
||||
|
|
|
@ -297,7 +297,7 @@ func (xl xlObjects) PutObjectPart(ctx context.Context, bucket, object, uploadID
|
|||
|
||||
// Validate input data size and it can never be less than zero.
|
||||
if data.Size() < -1 {
|
||||
logger.LogIf(ctx, errInvalidArgument)
|
||||
logger.LogIf(ctx, errInvalidArgument, logger.Application)
|
||||
return pi, toObjectErr(errInvalidArgument)
|
||||
}
|
||||
|
||||
|
|
|
@ -206,7 +206,7 @@ func (xl xlObjects) getObject(ctx context.Context, bucket, object string, startO
|
|||
|
||||
// Start offset cannot be negative.
|
||||
if startOffset < 0 {
|
||||
logger.LogIf(ctx, errUnexpected)
|
||||
logger.LogIf(ctx, errUnexpected, logger.Application)
|
||||
return errUnexpected
|
||||
}
|
||||
|
||||
|
@ -258,7 +258,7 @@ func (xl xlObjects) getObject(ctx context.Context, bucket, object string, startO
|
|||
|
||||
// Reply back invalid range if the input offset and length fall out of range.
|
||||
if startOffset > xlMeta.Stat.Size || startOffset+length > xlMeta.Stat.Size {
|
||||
logger.LogIf(ctx, InvalidRange{startOffset, length, xlMeta.Stat.Size})
|
||||
logger.LogIf(ctx, InvalidRange{startOffset, length, xlMeta.Stat.Size}, logger.Application)
|
||||
return InvalidRange{startOffset, length, xlMeta.Stat.Size}
|
||||
}
|
||||
|
||||
|
@ -570,7 +570,7 @@ func (xl xlObjects) putObject(ctx context.Context, bucket string, object string,
|
|||
|
||||
// Validate input data size and it can never be less than zero.
|
||||
if data.Size() < -1 {
|
||||
logger.LogIf(ctx, errInvalidArgument)
|
||||
logger.LogIf(ctx, errInvalidArgument, logger.Application)
|
||||
return ObjectInfo{}, toObjectErr(errInvalidArgument)
|
||||
}
|
||||
|
||||
|
@ -636,7 +636,7 @@ func (xl xlObjects) putObject(ctx context.Context, bucket string, object string,
|
|||
// Should return IncompleteBody{} error when reader has fewer bytes
|
||||
// than specified in request header.
|
||||
if n < data.Size() {
|
||||
logger.LogIf(ctx, IncompleteBody{})
|
||||
logger.LogIf(ctx, IncompleteBody{}, logger.Application)
|
||||
return ObjectInfo{}, IncompleteBody{}
|
||||
}
|
||||
|
||||
|
|
|
@ -186,6 +186,7 @@
|
|||
"http": {
|
||||
"target1": {
|
||||
"enabled": false,
|
||||
"type": "minio",
|
||||
"endpoint": "https://username:password@example.com/api"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ type AMQPTarget struct {
|
|||
conn *amqp.Connection
|
||||
connMutex sync.Mutex
|
||||
store Store
|
||||
loggerOnce func(ctx context.Context, err error, id interface{})
|
||||
loggerOnce func(ctx context.Context, err error, id interface{}, errKind ...interface{})
|
||||
}
|
||||
|
||||
// ID - returns TargetID.
|
||||
|
@ -215,7 +215,7 @@ func (target *AMQPTarget) Close() error {
|
|||
}
|
||||
|
||||
// NewAMQPTarget - creates new AMQP target.
|
||||
func NewAMQPTarget(id string, args AMQPArgs, doneCh <-chan struct{}, loggerOnce func(ctx context.Context, err error, id interface{})) (*AMQPTarget, error) {
|
||||
func NewAMQPTarget(id string, args AMQPArgs, doneCh <-chan struct{}, loggerOnce func(ctx context.Context, err error, id interface{}, errKind ...interface{})) (*AMQPTarget, error) {
|
||||
var conn *amqp.Connection
|
||||
var err error
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ type RedisTarget struct {
|
|||
pool *redis.Pool
|
||||
store Store
|
||||
firstPing bool
|
||||
loggerOnce func(ctx context.Context, err error, id interface{})
|
||||
loggerOnce func(ctx context.Context, err error, id interface{}, errKind ...interface{})
|
||||
}
|
||||
|
||||
// ID - returns target ID.
|
||||
|
@ -222,7 +222,7 @@ func (target *RedisTarget) Close() error {
|
|||
}
|
||||
|
||||
// NewRedisTarget - creates new Redis target.
|
||||
func NewRedisTarget(id string, args RedisArgs, doneCh <-chan struct{}, loggerOnce func(ctx context.Context, err error, id interface{})) (*RedisTarget, error) {
|
||||
func NewRedisTarget(id string, args RedisArgs, doneCh <-chan struct{}, loggerOnce func(ctx context.Context, err error, id interface{}, errKind ...interface{})) (*RedisTarget, error) {
|
||||
pool := &redis.Pool{
|
||||
MaxIdle: 3,
|
||||
IdleTimeout: 2 * 60 * time.Second,
|
||||
|
|
|
@ -35,12 +35,14 @@ type LogInfo struct {
|
|||
}
|
||||
|
||||
// SendLog returns true if log pertains to node specified in args.
|
||||
func (l LogInfo) SendLog(node string) bool {
|
||||
return node == "" || strings.EqualFold(node, l.NodeName)
|
||||
func (l LogInfo) SendLog(node, logKind string) bool {
|
||||
nodeFltr := (node == "" || strings.EqualFold(node, l.NodeName))
|
||||
typeFltr := strings.EqualFold(logKind, "all") || strings.EqualFold(l.LogKind, logKind)
|
||||
return nodeFltr && typeFltr
|
||||
}
|
||||
|
||||
// GetLogs - listen on console log messages.
|
||||
func (adm AdminClient) GetLogs(node string, lineCnt int, doneCh <-chan struct{}) <-chan LogInfo {
|
||||
func (adm AdminClient) GetLogs(node string, lineCnt int, logKind string, doneCh <-chan struct{}) <-chan LogInfo {
|
||||
logCh := make(chan LogInfo, 1)
|
||||
|
||||
// Only success, start a routine to start reading line by line.
|
||||
|
@ -49,6 +51,7 @@ func (adm AdminClient) GetLogs(node string, lineCnt int, doneCh <-chan struct{})
|
|||
urlValues := make(url.Values)
|
||||
urlValues.Set("node", node)
|
||||
urlValues.Set("limit", strconv.Itoa(lineCnt))
|
||||
urlValues.Set("logType", logKind)
|
||||
for {
|
||||
reqData := requestData{
|
||||
relPath: "/v1/log",
|
||||
|
|
Loading…
Reference in New Issue