github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/server/debug/goroutineui/html.go (about) 1 // Copyright 2019 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 // Copyright 2017 Marc-Antoine Ruel. All rights reserved. 12 // Use of this source code is governed under the Apache License, Version 2.0 13 // that can be found in the LICENSE file. 14 15 // NB: this file's original lives at: 16 // https://github.com/maruel/panicparse/blob/master/internal/html.go 17 // 18 // Please modify this file only when absolutely necessary so that we can 19 // pick up updates easily. 20 21 package goroutineui 22 23 import ( 24 "html/template" 25 "io" 26 "time" 27 28 "github.com/maruel/panicparse/stack" 29 ) 30 31 func writeToHTML(w io.Writer, buckets []*stack.Bucket, now time.Time) error { 32 m := template.FuncMap{ 33 "funcClass": funcClass, 34 "notoColorEmoji1F4A3": notoColorEmoji1F4A3, 35 } 36 if len(buckets) > 1 { 37 m["routineClass"] = routineClass 38 } else { 39 m["routineClass"] = func(bucket *stack.Bucket) template.HTML { return "Routine" } 40 } 41 t, err := template.New("htmlTpl").Funcs(m).Parse(htmlTpl) 42 if err != nil { 43 return err 44 } 45 data := struct { 46 Buckets []*stack.Bucket 47 Now time.Time 48 }{buckets, now.Truncate(time.Second)} 49 50 return t.Execute(w, data) 51 } 52 53 func funcClass(line *stack.Call) template.HTML { 54 if line.IsStdlib { 55 if line.Func.IsExported() { 56 return "FuncStdLibExported" 57 } 58 return "FuncStdLib" 59 } else if line.IsPkgMain() { 60 return "FuncMain" 61 } else if line.Func.IsExported() { 62 return "FuncOtherExported" 63 } 64 return "FuncOther" 65 } 66 67 func routineClass(bucket *stack.Bucket) template.HTML { 68 if bucket.First { 69 return "RoutineFirst" 70 } 71 return "Routine" 72 } 73 74 const htmlTpl = `<!DOCTYPE html> 75 {{- define "RenderCall" -}} 76 {{.SrcLine}} <span class="{{funcClass .}}">{{.Func.Name}}</span>({{.Args}}) 77 {{- end -}} 78 <meta charset="UTF-8"> 79 <meta name="viewport" content="width=device-width, initial-scale=1"> 80 <title>PanicParse</title> 81 <link rel="shortcut icon" type="image/png" href="data:image/png;base64,{{notoColorEmoji1F4A3}}"/> 82 <style> 83 body { 84 background: black; 85 color: lightgray; 86 } 87 body, pre { 88 font-family: Menlo, monospace; 89 font-weight: bold; 90 } 91 .FuncStdLibExported { 92 color: #7CFC00; 93 } 94 .FuncStdLib { 95 color: #008000; 96 } 97 .FuncMain { 98 color: #C0C000; 99 } 100 .FuncOtherExported { 101 color: #FF0000; 102 } 103 .FuncOther { 104 color: #A00000; 105 } 106 .RoutineFirst { 107 } 108 .Routine { 109 } 110 </style> 111 <div id="legend">Generated on {{.Now.String}}. 112 </div> 113 <div id="content"> 114 {{range .Buckets}} 115 <h1>{{if .First}}Running {{end}}Routine</h1> 116 <span class="{{routineClass .}}">{{len .IDs}}: <span class="state">{{.State}}</span> 117 {{if .SleepMax -}} 118 {{- if ne .SleepMin .SleepMax}} <span class="sleep">[{{.SleepMin}}~{{.SleepMax}} minutes]</span> 119 {{- else}} <span class="sleep">[{{.SleepMax}} minutes]</span> 120 {{- end -}} 121 {{- end}} 122 {{if .Locked}} <span class="locked">[locked]</span> 123 {{- end -}} 124 {{- if .CreatedBy.SrcPath}} <span class="created">[Created by {{template "RenderCall" .CreatedBy}}]</span> 125 {{- end -}} 126 <h2>Stack</h2> 127 {{range .Signature.Stack.Calls}} 128 - {{template "RenderCall" .}}<br> 129 {{- end}} 130 {{if .Stack.Elided}}(...)<br>{{end}} 131 {{end}} 132 </div> 133 ` 134 135 // notoColorEmoji1F4A3 is the bomb emoji U+1F4A3 in Noto Emoji as a PNG. 136 // 137 // Source: https://www.google.com/get/noto/help/emoji/smileys-people.html 138 // License: http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL 139 // 140 // Created with: 141 // python -c "import base64;a=base64.b64encode(open('emoji_u1f4a3.png','rb').read()); print '\n'.join(a[i:i+70] for i in range(0,len(a),70))" 142 func notoColorEmoji1F4A3() template.HTML { 143 return "" + 144 "iVBORw0KGgoAAAANSUhEUgAAAIgAAACACAMAAADnN9ENAAAA5FBMVEVMaXFvTjQhISEhIS" + 145 "EhISEhISEhISEhISEhISEhISEhISEhISHRbBTRbBTRbBQhISHRbBTRbBTRbBTRbBQ6OjrR" + 146 "bBTZcBTsehbzfhf1fxfidRVOTk75oiL7uCr90zL3kB3/6zv2hhlHMR5OTk5KSkpKSkpRUV" + 147 "FKSkpKSkpMTExBQUE2NjYpKSlOTk5EREQ8PDw4ODgtLS1RUVFQUFAmJiYkJCQ0NDRLS0tT" + 148 "U1MoKCgyMjJHR0dTU1NdXV0rKytXV1dVVVUvLy9eXl5aWlpcXFxcXFxeXl5fX186OjphYW" + 149 "E/Pz9KSkrdB5CTAAAATHRSTlMAEUZggJjf/6/vcL86e1nP2//vmSC7//////9E////////" + 150 "/2WPpYHp////////////////////z/////8w6P////+p/8f///////+/QBb3BQAACWJJRE" + 151 "FUeAHslgWC6yAURUOk1N3d3d29+9/SzzxCStvQEfp9zgZycu8DnvTNN78YJCuqqsry77WQ" + 152 "NRum2BX0u7JQiYWJw/l7NBz4AderQkFut8frdn+kFBu2wodeYeHxBwjBkFd6StiFOYiboF" + 153 "CAxf9MRXHc9KGpqurDBpqghzcYuCOCeMp21oKelTBVCQt5kDiisXhCJ5aMQkFu6+lg4tDY" + 154 "r2rikRCPKFgQYlGeiYpN7OHbpMj8OgQ8PAGdWIIlnnwbFKYdtgDAJj+MDgZSX/Zwsx4mby" + 155 "YR6RbntRZVegQDX7/tI1YexMTNObQ+y992EUWRQJIJQjqTzWRyRjtRiMTqKtWQJCTCD4TM" + 156 "aS6bBzLGxLKRKNer1MELX0wEmYHk8pSMGUmIlMI+LC7uTeEQmhEvnZBC/kqGTolfkmSn72" + 157 "NPbFhoWOHswmczeYYC7YaV4MfBHl+BEYmCSJYVSUM3ukgRM5C7g4edqAqLMBq0m1sRh8oe" + 158 "Fl4zzp8swtFApXKlmkIkECD8+mpYEZ8iWZGq1YFKKazg582IDiu8bk7Ob5YaOnVCs9UWu+" + 159 "C99D7LWR5fVeY/YpVOp9Po9rp1g25/AIGIXmhp0yMLgSTIhcYDVYaj0ag1Hk/a0yZ1qVVK" + 160 "6KsmfnMVSbMepBkv32M2nw87rfZioatMxsveirqUBLoxHr1CJpvNZmBQSSB+icd6M9dFpt" + 161 "tt21CZ4EHfKKny9Ug4awA/kNRmt993loPBAFSICcbtFpRUeuViFIPFiENpp9NYHg6HexW8" + 162 "1Suaiaysscc8gsg6jdTxpFNf6oALUaEmBz2SsMBKEkjeL88Bt8VFWj1fCKvWdDolKmYoYD" + 163 "L5ejcSApNoMsZqBH+0byfbiStNEICbFZt/uIN3WtpASWIUwgOiZWgMyPL7v8+tCuIkBdlw" + 164 "W4WWHS/AdyKzRCEfXy7Iw+PHntlti+k0TZ1FKCJJgteV0wHGhr/1Lvp4/HGQvGdJVVVTZy" + 165 "HFl6TGDEIM3FiUIvnrv53zkXyH4PNzm5mknrhUNo7CUjAeSIbGmNW3Vih/gHGKY1jE53uc" + 166 "1BJYSOF4KCmM6YcqaPmvy/86l88MKPbzcXIKLKSwFJFUPMDtpvPDKT63cZKMJSCRglJE4k" + 167 "7x0hjTaZHAOpzjYBIKCpsThpQLSc4D3GaOdWQ0+CEFEo7HSkpIxjzAraXz4RxbURhJQQtK" + 168 "gYSdYE2mPMBtZYWxjMggIRYLKSiFks0Gw9nExjy16XBnxYBxNHghRSTcE65JEXM4rTl2qI" + 169 "OKkRdnIcWXcDgzXktam8s76zBQzOcZ4q6IsIBCSVVhYTmckpJ2HWBA8XoMMEri1oQnJ89L" + 170 "x++3cF6U46hYI8CQ4ks4HBzhYdHK0+TDc5ABxDsCCygi4ZpIJYvF0EIGqzsdffvtskschA" + 171 "4wLGHrcrRoCYfDSnBVe+nc5Yis4zAWRwYHFQwpFxKBuEq6Uyt5untBCs8hjB1DCiVnlfDg" + 172 "5PkCdzUT3TmYDINxezqH46jY7+3FxF0Vd75EVcLZdPPCmEH4cFb202RBfIdT2K4ONo5CyQ" + 173 "iSE+T5NJvu8q4z/LE/fBYWwsHY/Xgn45NxGEr8SvyDc4R06zt+W0S7wyGrk1MhdJAhkr2T" + 174 "rEXy09ng/toLL2SfcENkMHRoiYVkrERBnKQKriSynzmqORlAlMObjgyHs+G5kSXp5sGV/N" + 175 "jZQmQyKMQOxnNIpBI1m40sCSoJOjgPux0LKW4XQgkOjpqNBwm9wPYtJFGToeNaJaPjbPS2" + 176 "utRh98bvu/1rLZAMEFWISAjxl0RBNkE//Fb2U4sTBI5bkJ2/JBqCFCHfOH27mBMHKXzI4R" + 177 "pk/1PI8zmkCpnNx3aXaYh1NICkF5BZwKOkYz+1aBUS+OYmsp9aa8i+wWjUjuDc9BqvyPa9" + 178 "AkSW9b5Tg0yNeWm8ItusmkwuniP6wUrHBSTREFmSpk+R7dZMq4l6sh6uP1kdBLc09WQVyL" + 179 "D5Rc1eCGtAkiPk5pLIZDKuiH7EM40hD4R426oqufmlNwHEOs4hSdN7WmQhqYOoLxslEYd8" + 180 "1ejTK5C6MWTtIN6SuHPD4fgSOvxCrnznBZxfQtbPrOTi7kyJdkghNyCpMV+NIP31+4gQVs" + 181 "Itubg9yzVerqxyePWKhEHWDiLnhpVQAgoCBh08u7qQuyCv69FSKrmQgLLDm3jHEIdXiJ5M" + 182 "IOTxdZ0B4h0cSvzfnFswzh1SiJ5MACSyn7h89iuhJIMEFCoc49KhJxN2aghxlSiJvJdg1n" + 183 "DMnUMV4k0m9Dmysp/3zErOJKDAwrxahnKcCuFkAp6sjP20qauEwzmTgIJAAYbvuCjEhzT/" + 184 "0htkr/VmyX0VCSnOwoABR0EHBnOlkLw55Ct7HTvImUQoFsN4L1rVS0VVSMh9pD/P4pmTYD" + 185 "giUW98Y4/BPvRgJGnzG1pk698oiX4HblwK5ZC3rHSE31kf7FJOZxtfQgotEmGIQw1GEvLr" + 186 "dzCaJ6WthJKKElAQGs4Y1x0Bv2uYp9E8Ls8kpIhFEI5Bx5SO44nxIcG/9CL7GF2WM5FgPK" + 187 "DAwlBBBs4LHbqQgN++yCAeJcMzCSiwiCahAgyM5YZjFvZn4Kd4FJdOgo0VCizEwAAG69AO" + 188 "P5Ow9yOrOB6lw2FZniSWIhbJBAphYE+VI+yNEfMVxyZ/o8SjwMKIAgzUoR1MFfpH4EcTx8" + 189 "9HiVBgAeaUqTDoGMKhCgl/0TowcZFbCRcFFFokQJwx4FCM0PesrMTE6QISjwKLRBSWIWOh" + 190 "o4VCmBdjTL7IheIsxEioEMYVB9/FByYyxtQLSkiBBaFAFML4mWN235+OesaYzcKnwEIMEV" + 191 "CAcd2x4N9rQtMZGFPkXVJoIQYBAgrFUIOJghkcTtJ1ElBgAcZLSYVmSFK1qUHDqbqk0AIM" + 192 "AwQUYNChF4SDCU/HnZxNlxRY3qBhiPAUOsOC33Z3ZTWgxLOAg8AAhWJI2vhLONeEElqoEY" + 193 "JSKAdP7r15FIlgJBqhHVzUtiTLblBKOlqUVIsAx9LQ0aYkGTZlLCYtO3h2iobjKceG56XF" + 194 "PLwYm7pBKYupsRlE39rOk3GZLn51Owpj89VpmyH/lVCkv0LZYCoDjqXtdPoGqf5lQHlaGN" + 195 "Tx0L6BeegZJFnmV1djg6OitqPtRKSYZDrTMyrTOuC/BIJbGRhmXKfLktmkk8QwphfQRkA6" + 196 "jz1zIy+PAbsRbInQi8qgF6C4H9PvfQ2E8NXrR7z9tJvf+Z1/ANt+S+GBXoDpAAAAAElFTk" + 197 "SuQmCC" 198 }