github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/logger/reqinfo.go (about)

     1  // Copyright (c) 2015-2021 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package logger
    19  
    20  import (
    21  	"context"
    22  	"fmt"
    23  	"sync"
    24  
    25  	"github.com/minio/minio/internal/auth"
    26  )
    27  
    28  // Key used for Get/SetReqInfo
    29  type contextKeyType string
    30  
    31  const contextLogKey = contextKeyType("miniolog")
    32  
    33  // KeyVal - appended to ReqInfo.Tags
    34  type KeyVal struct {
    35  	Key string
    36  	Val interface{}
    37  }
    38  
    39  // ObjectVersion object version key/versionId
    40  type ObjectVersion struct {
    41  	ObjectName string
    42  	VersionID  string `json:"VersionId,omitempty"`
    43  }
    44  
    45  // ReqInfo stores the request info.
    46  // Reading/writing directly to struct requires appropriate R/W lock.
    47  type ReqInfo struct {
    48  	RemoteHost   string           // Client Host/IP
    49  	Host         string           // Node Host/IP
    50  	UserAgent    string           // User Agent
    51  	DeploymentID string           // x-minio-deployment-id
    52  	RequestID    string           // x-amz-request-id
    53  	API          string           // API name - GetObject PutObject NewMultipartUpload etc.
    54  	BucketName   string           `json:",omitempty"` // Bucket name
    55  	ObjectName   string           `json:",omitempty"` // Object name
    56  	VersionID    string           `json:",omitempty"` // corresponding versionID for the object
    57  	Objects      []ObjectVersion  `json:",omitempty"` // Only set during MultiObject delete handler.
    58  	Cred         auth.Credentials `json:"-"`
    59  	Region       string           `json:"-"`
    60  	Owner        bool             `json:"-"`
    61  	AuthType     string           `json:"-"`
    62  	tags         []KeyVal         // Any additional info not accommodated by above fields
    63  	sync.RWMutex
    64  }
    65  
    66  // NewReqInfo :
    67  func NewReqInfo(remoteHost, userAgent, deploymentID, requestID, api, bucket, object string) *ReqInfo {
    68  	return &ReqInfo{
    69  		RemoteHost:   remoteHost,
    70  		UserAgent:    userAgent,
    71  		API:          api,
    72  		DeploymentID: deploymentID,
    73  		RequestID:    requestID,
    74  		BucketName:   bucket,
    75  		ObjectName:   object,
    76  	}
    77  }
    78  
    79  // AppendTags - appends key/val to ReqInfo.tags
    80  func (r *ReqInfo) AppendTags(key string, val interface{}) *ReqInfo {
    81  	if r == nil {
    82  		return nil
    83  	}
    84  	r.Lock()
    85  	defer r.Unlock()
    86  	r.tags = append(r.tags, KeyVal{key, val})
    87  	return r
    88  }
    89  
    90  // SetTags - sets key/val to ReqInfo.tags
    91  func (r *ReqInfo) SetTags(key string, val interface{}) *ReqInfo {
    92  	if r == nil {
    93  		return nil
    94  	}
    95  	r.Lock()
    96  	defer r.Unlock()
    97  	// Search of tag key already exists in tags
    98  	var updated bool
    99  	for _, tag := range r.tags {
   100  		if tag.Key == key {
   101  			tag.Val = val
   102  			updated = true
   103  			break
   104  		}
   105  	}
   106  	if !updated {
   107  		// Append to the end of tags list
   108  		r.tags = append(r.tags, KeyVal{key, val})
   109  	}
   110  	return r
   111  }
   112  
   113  // GetTags - returns the user defined tags
   114  func (r *ReqInfo) GetTags() []KeyVal {
   115  	if r == nil {
   116  		return nil
   117  	}
   118  	r.RLock()
   119  	defer r.RUnlock()
   120  	return append(make([]KeyVal, 0, len(r.tags)), r.tags...)
   121  }
   122  
   123  // GetTagsMap - returns the user defined tags in a map structure
   124  func (r *ReqInfo) GetTagsMap() map[string]interface{} {
   125  	if r == nil {
   126  		return nil
   127  	}
   128  	r.RLock()
   129  	defer r.RUnlock()
   130  	m := make(map[string]interface{}, len(r.tags))
   131  	for _, t := range r.tags {
   132  		m[t.Key] = t.Val
   133  	}
   134  	return m
   135  }
   136  
   137  // PopulateTagsMap - returns the user defined tags in a map structure
   138  func (r *ReqInfo) PopulateTagsMap(tagsMap map[string]interface{}) {
   139  	if r == nil {
   140  		return
   141  	}
   142  	if tagsMap == nil {
   143  		return
   144  	}
   145  	r.RLock()
   146  	defer r.RUnlock()
   147  	for _, t := range r.tags {
   148  		tagsMap[t.Key] = t.Val
   149  	}
   150  	return
   151  }
   152  
   153  // SetReqInfo sets ReqInfo in the context.
   154  func SetReqInfo(ctx context.Context, req *ReqInfo) context.Context {
   155  	if ctx == nil {
   156  		LogIf(context.Background(), fmt.Errorf("context is nil"))
   157  		return nil
   158  	}
   159  	return context.WithValue(ctx, contextLogKey, req)
   160  }
   161  
   162  // GetReqInfo returns ReqInfo if set.
   163  func GetReqInfo(ctx context.Context) *ReqInfo {
   164  	if ctx != nil {
   165  		r, ok := ctx.Value(contextLogKey).(*ReqInfo)
   166  		if ok {
   167  			return r
   168  		}
   169  		r = &ReqInfo{}
   170  		return r
   171  	}
   172  	return nil
   173  }