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:
poornas 2019-10-11 18:50:54 -07:00 committed by Harshavardhana
parent 8964ef821f
commit d7060c4c32
28 changed files with 116 additions and 72 deletions

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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...)
}

View File

@ -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()))
}
}

View File

@ -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
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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))
}
}

View File

@ -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)
}
}

View File

@ -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...)
}

View File

@ -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"`

View File

@ -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)

View File

@ -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:

View File

@ -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

View File

@ -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)
}
}

View File

@ -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 {

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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{}
}

View File

@ -186,6 +186,7 @@
"http": {
"target1": {
"enabled": false,
"type": "minio",
"endpoint": "https://username:password@example.com/api"
}
}

View File

@ -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

View File

@ -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,

View File

@ -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",