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