github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/admin-scanner-trace.go (about)

     1  // Copyright (c) 2015-2022 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 cmd
    19  
    20  import (
    21  	"context"
    22  	"fmt"
    23  
    24  	"github.com/fatih/color"
    25  	"github.com/minio/cli"
    26  	"github.com/minio/mc/pkg/probe"
    27  	"github.com/minio/pkg/v2/console"
    28  )
    29  
    30  var adminScannerTraceFlags = []cli.Flag{
    31  	cli.BoolFlag{
    32  		Name:  "verbose, v",
    33  		Usage: "print verbose trace",
    34  	},
    35  	cli.StringSliceFlag{
    36  		Name:  "funcname",
    37  		Usage: "trace only matching func name (eg 'scanner.ScanObject')",
    38  	},
    39  	cli.StringSliceFlag{
    40  		Name:  "node",
    41  		Usage: "trace only matching servers",
    42  	},
    43  	cli.StringSliceFlag{
    44  		Name:  "path",
    45  		Usage: "trace only matching path",
    46  	},
    47  	cli.BoolFlag{
    48  		Name:  "filter-request",
    49  		Usage: "trace calls only with request bytes greater than this threshold, use with filter-size",
    50  	},
    51  	cli.BoolFlag{
    52  		Name:  "filter-response",
    53  		Usage: "trace calls only with response bytes greater than this threshold, use with filter-size",
    54  	},
    55  	cli.BoolFlag{
    56  		Name:  "response-duration",
    57  		Usage: "trace calls only with response duration greater than this threshold (e.g. `5ms`)",
    58  	},
    59  	cli.StringFlag{
    60  		Name:  "filter-size",
    61  		Usage: "filter size, use with filter (see UNITS)",
    62  	},
    63  }
    64  
    65  var adminScannerTraceCmd = cli.Command{
    66  	Name:            "trace",
    67  	Usage:           "show trace for MinIO scanner operations",
    68  	Action:          mainAdminScannerTrace,
    69  	OnUsageError:    onUsageError,
    70  	Before:          setGlobalsFromContext,
    71  	Flags:           append(adminScannerTraceFlags, globalFlags...),
    72  	HideHelpCommand: true,
    73  	CustomHelpTemplate: `NAME:
    74    {{.HelpName}} - {{.Usage}}
    75  
    76  USAGE:
    77    {{.HelpName}} [FLAGS] TARGET
    78  
    79  FLAGS:
    80    {{range .VisibleFlags}}{{.}}
    81    {{end}}
    82  
    83  UNITS
    84    --filter-size flags use with --filter-response or --filter-request accept human-readable case-insensitive number
    85    suffixes such as "k", "m", "g" and "t" referring to the metric units KB,
    86    MB, GB and TB respectively. Adding an "i" to these prefixes, uses the IEC
    87    units, so that "gi" refers to "gibibyte" or "GiB". A "b" at the end is
    88    also accepted. Without suffixes the unit is bytes.
    89  
    90  EXAMPLES:
    91    1. Show scanner trace for MinIO server
    92       {{.Prompt}} {{.HelpName}} myminio
    93  
    94    2. Show scanner trace for a specific path
    95      {{.Prompt}} {{.HelpName}} --path my-bucket/my-prefix/* myminio
    96  
    97    3. Show trace for only ScanObject operations
    98      {{.Prompt}} {{.HelpName}} --funcname=scanner.ScanObject myminio
    99  
   100    4. Avoid printing replication related S3 requests
   101      {{.Prompt}} {{.HelpName}} --request-header '!X-Minio-Source' myminio
   102  
   103    5. Show trace only for ScanObject operations request bytes greater than 1MB
   104      {{.Prompt}} {{.HelpName}} --filter-request --filter-size 1MB myminio
   105  
   106    6. Show trace only for ScanObject operations response bytes greater than 1MB
   107      {{.Prompt}} {{.HelpName}} --filter-response --filter-size 1MB myminio
   108    
   109    7. Show trace only for requests operations duration greater than 5ms
   110      {{.Prompt}} {{.HelpName}} --response-duration 5ms myminio
   111  `,
   112  }
   113  
   114  func checkAdminScannerTraceSyntax(ctx *cli.Context) {
   115  	if len(ctx.Args()) != 1 {
   116  		showCommandHelpAndExit(ctx, 1) // last argument is exit code
   117  	}
   118  	filterFlag := ctx.Bool("filter-request") || ctx.Bool("filter-response")
   119  	if filterFlag && ctx.String("filter-size") == "" {
   120  		// filter must use with filter-size flags
   121  		showCommandHelpAndExit(ctx, 1)
   122  	}
   123  }
   124  
   125  // mainAdminScannerTrace - the entry function of trace command
   126  func mainAdminScannerTrace(ctx *cli.Context) error {
   127  	// Check for command syntax
   128  	checkAdminScannerTraceSyntax(ctx)
   129  
   130  	verbose := ctx.Bool("verbose")
   131  	aliasedURL := ctx.Args().Get(0)
   132  
   133  	console.SetColor("Stat", color.New(color.FgYellow))
   134  
   135  	console.SetColor("Request", color.New(color.FgCyan))
   136  	console.SetColor("Method", color.New(color.Bold, color.FgWhite))
   137  	console.SetColor("Host", color.New(color.Bold, color.FgGreen))
   138  	console.SetColor("FuncName", color.New(color.Bold, color.FgGreen))
   139  
   140  	console.SetColor("ReqHeaderKey", color.New(color.Bold, color.FgWhite))
   141  	console.SetColor("RespHeaderKey", color.New(color.Bold, color.FgCyan))
   142  	console.SetColor("HeaderValue", color.New(color.FgWhite))
   143  	console.SetColor("RespStatus", color.New(color.Bold, color.FgYellow))
   144  	console.SetColor("ErrStatus", color.New(color.Bold, color.FgRed))
   145  
   146  	console.SetColor("Response", color.New(color.FgGreen))
   147  	console.SetColor("Body", color.New(color.FgYellow))
   148  	for _, c := range colors {
   149  		console.SetColor(fmt.Sprintf("Node%d", c), color.New(c))
   150  	}
   151  	// Create a new MinIO Admin Client
   152  	client, err := newAdminClient(aliasedURL)
   153  	if err != nil {
   154  		fatalIf(err.Trace(aliasedURL), "Unable to initialize admin client.")
   155  		return nil
   156  	}
   157  
   158  	ctxt, cancel := context.WithCancel(globalContext)
   159  	defer cancel()
   160  
   161  	opts, e := tracingOpts(ctx, []string{"scanner"})
   162  	fatalIf(probe.NewError(e), "Unable to start tracing")
   163  
   164  	mopts := matchingOpts(ctx)
   165  
   166  	// Start listening on all trace activity.
   167  	traceCh := client.ServiceTrace(ctxt, opts)
   168  	for traceInfo := range traceCh {
   169  		if traceInfo.Err != nil {
   170  			fatalIf(probe.NewError(traceInfo.Err), "Unable to listen to http trace")
   171  		}
   172  		if mopts.matches(traceInfo) {
   173  			printTrace(verbose, traceInfo)
   174  		}
   175  	}
   176  	return nil
   177  }