1 2 <!DOCTYPE HTML>3 <html>4 <head>5 <meta http-equiv="Content-Type" CONTENT="text/html; charset=UTF-8">6 <link rel="stylesheet" type="text/css" href="/ShareCode/preview/8c1a5d631ddc3adf144497d95c7a573d/css" title="default">7 <script src="/ShareCode/preview/8c1a5d631ddc3adf144497d95c7a573d/js" type="text/javascript"></script>8 </head>9 <body>10 <!DOCTYPE html>11 <html>12 <head>13 <title>Trace viewer</title>14 <style type="text/css">15 16 html {17 font-family: sans-serif;18 }19 20 .logs {21 font-family: monospace;22 }23 24 .logs .log-entry {25 font-family: monospace;26 white-space: pre-wrap;27 }28 29 .logs .log-entry[level="DEBUG"] { color: darkblue; }30 .logs .log-entry[level="INFO"] { color: green; }31 .logs .log-entry[level="WARNING"] { color: darkorange; }32 .logs .log-entry[level="ERROR"] { color: purple; }33 .logs .log-entry[level="FATAL"] { color: red; }34 35 .logs .log-entry[select="1"] { background-color: rgba(0,0,0,0.05); }36 .logs .log-entry[select="2"] { background-color: rgba(0,0,255,0.05); }37 .logs .log-entry[select="3"] { background-color: rgba(0,255,0,0.05); }38 .logs .log-entry[select="4"] { background-color: rgba(0,255,255,0.05); }39 .logs .log-entry[select="5"] { background-color: rgba(255,0,0,0.05); }40 .logs .log-entry[select="6"] { background-color: rgba(255,0,255,0.05); }41 .logs .log-entry[select="7"] { background-color: rgba(255,255,0,0.05); }42 .logs .log-entry[select="8"] { background-color: rgba(0,0,127,0.05); }43 .logs .log-entry[select="9"] { background-color: rgba(0,127,0,0.05); }44 .logs .log-entry[select="0"] { background-color: rgba(0,127,127,0.05); }45 46 .logs[select="1"] .log-entry[select="1"],47 .logs[select="2"] .log-entry[select="2"],48 .logs[select="3"] .log-entry[select="3"],49 .logs[select="4"] .log-entry[select="4"],50 .logs[select="5"] .log-entry[select="5"],51 .logs[select="6"] .log-entry[select="6"],52 .logs[select="7"] .log-entry[select="7"],53 .logs[select="8"] .log-entry[select="8"],54 .logs[select="9"] .log-entry[select="9"],55 .logs[select="0"] .log-entry[select="0"] {56 background-color: rgba(0,255,0,0.45);57 }58 59 .viewer {60 position: relative;61 _border: solid silver 1px;62 height: 200px;63 }64 65 .viewer .span {66 background-color: rgba(200,220,255,0.6);67 position: absolute;68 height: 16px;69 cursor: pointer;70 text-align: center;71 font-size: 10px;72 line-height: 16px;73 text-overflow: ellipsis;74 overflow: hidden;75 white-space: nowrap;76 font-family: monospace;77 transition: all 0.5s ease;78 }79 80 .viewer[span_parallel="true"] .span[paralell_index="0"] { top: 0px !important; }81 .viewer[span_parallel="true"] .span[paralell_index="1"] { top: 18px !important; }82 .viewer[span_parallel="true"] .span[paralell_index="2"] { top: 36px !important; }83 .viewer[span_parallel="true"] .span[paralell_index="3"] { top: 0px !important; }84 .viewer[span_parallel="true"] .span[paralell_index="4"] { top: 0px !important; }85 .viewer[span_parallel="true"] .span[paralell_index="5"] { top: 0px !important; }86 .viewer[span_parallel="true"] .span[paralell_index="6"] { top: 0px !important; }87 .viewer[span_parallel="true"] .span[paralell_index="7"] { top: 0px !important; }88 .viewer[span_parallel="true"] .span[paralell_index="8"] { top: 0px !important; }89 .viewer[span_parallel="true"] .span[paralell_index="9"] { top: 0px !important; }90 .viewer[span_parallel="true"] .span[paralell_index="10"] { top: 0px !important; }91 92 .viewer .span:hover {93 box-shadow: 0 0 1px blue;94 } 95 96 .traces [trace_id] {97 font-family: monospace;98 white-space: pre-wrap;99 cursor: pointer;100 }101 102 .traces [trace_id]:hover {103 color: blue;104 }105 106 .traces [selected="true"] {107 color: blue;108 font-weight: bold;109 }110 111 .details {112 display: none;113 position: fixed;114 top: 0;115 bottom: 0;116 right: 0;117 left: 0;118 background-color: rgba(255,255,255,0.8);119 }120 121 .detail {122 position: absolute;123 top: 50%;124 left: 50%;125 min-width: 400px;126 min-height: 300px;127 max-width: 90%;128 max-height: 90%;129 transform: translate(-50%, -50%);130 border: solid silver 1px;131 background-color: rgba(255,255,255,0.6);132 padding: 16px;133 border-radius: 3px;134 box-shadow: 2px 2px 6px rgba(0,0,0,0.2);135 overflow: auto;136 }137 138 .detail-content {139 font-family: monospace;140 white-space: pre-wrap;141 }142 143 .detail-close {144 color: blue;145 text-align: right;146 cursor: pointer;147 position: absolute;148 top: 0;149 right: 0;150 padding: 3px 6px;151 font-size: 85%;152 }153 154 155 </style>156 </head>157 <body>158 159 <h1>Trace viewer 2</h1>160 161 <div>Spans parallel <input id="checkbox_spans_parallel" type="checkbox"></div>162 163 <div class="viewer" id="viewer"></div>164 165 <div style="float:left; width: 340px;">166 <h2>Traces</h2>167 <div>Paste your traces here <textarea id="input_traces" rows="1"></textarea></div>168 <div class="traces" id="div_traces"></div> 169 </div>170 171 <div style="margin-left: 340px;"> 172 <h2>Logs</h2>173 <div class="logs" id="div_logs"></div>174 175 <!--176 <h2>Spare logs</h2>177 <div class="logs" id="spare_logs"></div>178 -->179 </div>180 181 <div id="details" class="details">182 <div id="detail" class="detail">183 <div id="detail-close" class="detail-close">close</div>184 <div id="detail-content" class="detail-content">185 hello186 </div>187 </div>188 </div>189 190 <script type="text/javascript">191 192 var details = document.getElementById('details');193 var detail_content = document.getElementById('detail-content');194 var detail_close = document.getElementById('detail-close');195 196 function closeDetail() {197 details.style.display = 'none';198 }199 200 function showDetail(content) {201 details.style.display = 'block';202 detail_content.textContent = content;203 }204 205 detail_close.addEventListener('click', closeDetail, true);206 207 208 var checkbox_spans_parallel = document.getElementById('checkbox_spans_parallel');209 checkbox_spans_parallel.addEventListener('click', function() {210 var viewer = document.getElementById('viewer');211 viewer.setAttribute('span_parallel', this.checked);212 }, true);213 214 215 var lines = [];216 217 var add_line = function(line) {218 lines.push(line);219 };220 221 var span_parallell = true;222 223 var traces = {};224 225 var add_trace = function(line) {226 227 var parts = line.split('|');228 229 if ('TRACE.CREATE' == parts[1]) {230 var details = JSON.parse(parts[4]);231 var traceId = details.traceId;232 233 if (traceId in traces) {234 return true; // Already created :D235 }236 237 var trace = {238 id: traceId,239 namespace: parts[2],240 timestamp: parts[3],241 spans: {},242 }243 traces[traceId] = trace;244 245 print_trace_index(trace);246 247 return true; // Trace created :D248 249 } else if ('TRACE.SPAN.START' == parts[1]) {250 // "V1|TRACE.SPAN.START|ns|ac115589-d06d-49c7-81d5-525eedb48989|1517055732001191061|{"spanId":"71e51a26-c5d8-4de1-a258-463ca8f167af","monitoredResource":{"_id":"59bb80e520988c09f76c8e1f"},"startTime":1517055732001191061,"name":"","kind":"HTTP_SERVER","details":{"protocol":"http"}}"251 252 var traceId = parts[3];253 254 var trace = traces[traceId];255 if (!trace) {256 return false;257 }258 259 var details = JSON.parse(parts[5]);260 261 var spanId = details.spanId;262 263 var span = trace.spans[spanId];264 if (!span) {265 details.logs = [];266 trace.spans[spanId] = details;267 }268 269 return true;270 271 } else if ('TRACE.SPAN.FINISH' == parts[1]) {272 // "V1|TRACE.SPAN.FINISH|ns|ac115589-d06d-49c7-81d5-525eedb48989|1517055732005564980|{"spanId":"71e51a26-c5d8-4de1-a258-463ca8f167af","monitoredResource":{"_id":"59bb80e520988c09f76c8e1f"},"endTime":1517055732005500355,"details":{"http_response_status":201},"properties":{"handler":"/v0/organizations/{organization}:createNamespace","method":"POST","path":"/v0/organizations/jj:createNamespace","url":"/v0/organizations/jj:createNamespace"}}"273 274 var traceId = parts[3];275 276 var trace = traces[traceId];277 if (!trace) {278 return false;279 }280 281 var details = JSON.parse(parts[5]);282 283 var spanId = details.spanId;284 285 var span = trace.spans[spanId];286 if (!span) {287 console.log('span not started :_( ');288 return false;289 }290 291 span.endTime = details.endTime;292 span.properties = details.properties;293 span.details = details.details;294 295 return true;296 }297 298 };299 300 var last_selected_trace = null;301 302 var print_trace_index = function(trace) {303 var parent = document.getElementById('div_traces');304 305 var div = document.createElement('div');306 div.setAttribute('trace_id', trace.id);307 div.textContent = trace.id; 308 div.addEventListener('click', function(e) {309 if (last_selected_trace) {310 last_selected_trace.setAttribute('selected', 'false');311 }312 last_selected_trace = div;313 last_selected_trace.setAttribute('selected', 'true');314 var trace_id = this.getAttribute('trace_id');315 print_trace(trace_id);316 }, true);317 318 parent.appendChild(div);319 };320 321 322 var pretty_nanos = function(nanos) {323 324 var power = 1000;325 var units = ['ns', 'µs', 'ms'];326 var i = 0;327 for (; nanos > power;) {328 i++;329 nanos /= power;330 }331 332 return nanos.toFixed(1) + units[i];333 334 };335 336 var print_trace = function(traceId) {337 338 var viewer = document.getElementById('viewer');339 viewer.innerHTML = '';340 341 var div_logs = document.getElementById('div_logs');342 div_logs.innerHTML = '';343 344 var trace = traces[traceId];345 346 var timestamp_min = null;347 var timestamp_max = null;348 349 var span2color={};350 var color2span={};351 var spanCounter=0;352 353 for (var spanId in trace.spans) {354 var span = trace.spans[spanId];355 356 if (null === timestamp_min || timestamp_min>span.startTime) {357 timestamp_min = span.startTime;358 }359 360 if (null === timestamp_max || timestamp_max<span.endTime) {361 timestamp_max = span.endTime;362 }363 364 var color = span2color[spanId]365 if (!color) {366 span2color[spanId] = spanCounter;367 color2span[spanCounter] = spanId;368 spanCounter++;369 }370 371 }372 373 var timestamp_range = timestamp_max - timestamp_min;374 375 var span_deep = function(span) {376 377 var MAX_DEEP = 100;378 379 for (var deep = 0; deep<MAX_DEEP; deep++) {380 381 var parentSpanId = span.parentSpanId;382 if (!parentSpanId) {383 return deep;384 }385 386 span = trace.spans[parentSpanId];387 if (!span) {388 return deep;389 }390 }391 392 return undefined;393 };394 395 var logs = [];396 var i=0;397 for (var spanId in trace.spans) {398 var span = trace.spans[spanId];399 400 var span_delay = span.endTime-span.startTime;401 402 span.logs.map(function(log) {logs.push(log); });403 404 var left = (100*(span.startTime-timestamp_min)/timestamp_range).toFixed(2)405 406 var div = document.createElement('div');407 div.setAttribute('span_id', span.spanId);408 div.className = 'span';409 div.style.top = i*18 + 'px';410 div.setAttribute('paralell_index', span_deep(span));411 /*412 if (span_parallell) {413 div.style.top = span_deep(span)*18 + 'px';414 } else {415 div.style.top = i*18 + 'px';416 }*/417 div.style.left = left + '%';418 div.style.width = 100*(span.endTime-span.startTime)/timestamp_range + '%';419 div.addEventListener('mouseover', function(e){420 div_logs.setAttribute('select', span2color[this.getAttribute('span_id')] );421 }, true);422 div.addEventListener('click', function() {423 var s = trace.spans[this.getAttribute('span_id')];424 showDetail(JSON.stringify(s, '', ' '));425 }, true);426 427 var content = ' ';428 if (span.name) {429 content += span.name + ' ';430 } else {431 content += '<no-name> ';432 }433 content += '(' + pretty_nanos(span_delay) + ') ';434 if (span.logs.length) {435 content += span.logs[0].message;436 }437 438 div.textContent = content;439 div.setAttribute('title', content);440 441 viewer.appendChild(div);442 443 i++;444 }445 446 // TODO: sort logs by timestamp...447 logs.sort( (a,b) => a.timestamp - b.timestamp );448 449 logs.map(function(log) {450 var div = document.createElement('div');451 div.className = 'log-entry';452 div.setAttribute('level', log.level);453 div.setAttribute('span_id', log.spanId);454 div.setAttribute('select', span2color[log.spanId]);455 div.textContent = (new Date(log.timestamp/1000000))+ '\t' +log.level + '\t' + log.message;456 div_logs.appendChild(div);457 });458 459 };460 461 var spare_logs = document.getElementById('spare_logs');462 463 var add_log = function(log) {464 465 //V1|LOG.INFO|ns|59bb80e520988c09f76c8e1f|7b35c96c-7405-4705-bba2-417e5f6415dc|78c84606-f966-41f1-8509-fc71c473e0d8|1517069566344381262|Response status: '200 OK'466 467 var parts = log.split('|');468 469 var traceId = parts[4];470 471 var trace = traces[traceId];472 if (!trace) {473 return false;474 }475 476 var spanId = parts[5];477 var span = trace.spans[spanId];478 if (!span) {479 return false;480 }481 482 var level = parts[1].split('.')[1];483 var message = parts[7];484 485 span.logs.push({486 spanId: spanId,487 level: level,488 message: message,489 timestamp: parts[6],490 });491 492 return true;493 };494 495 var input_traces = document.getElementById('input_traces');496 input_traces.addEventListener('paste', function(e) {497 var text = e.clipboardData.getData('text');498 process_text(text);499 }, true);500 501 input_traces.addEventListener('keyup', function(e) {502 if (13 == e.keyCode) {503 process_text(this.value);504 }505 }, true);506 507 var process_text = function(text) {508 var lines = text.split('\n');509 lines.map(add_line);510 process_lines();511 };512 513 var process_lines = function() {514 var n = 1;515 while (n) {516 n = process_lines_iterative();517 }518 };519 520 var process_lines_iterative = function() {521 522 var remove = [];523 524 for (var i in lines) {525 var line = lines[i];526 527 var processed = false;528 if (line.startsWith('V1|LOG')) {529 processed = add_log(line);530 } else if (line.startsWith('V1|TRACE')) {531 processed = add_trace(line);532 }533 534 if (processed) {535 remove.push(i);536 }537 }538 539 for (var i=remove.length-1; i>=0; i--) {540 var j = remove[i];541 lines.splice(j, 1);542 }543 544 return remove.length;545 };546 547 </script>548 549 550 551 552 </body>553 </html></body>554 </html>555
Enlace
El enlace para compartir es: