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 }