<?php
namespace Modules\Admin\Server\Logs; class ModelGenerateReportFluXLogsRaw { public function generate($outputFile, $listingParams) { $model = new Model(); $listingParams->setCurrentPage(0); $listingParams->setResultsPerPage(PHP_INT_MAX); $model->list_execute($listingParams); $listRows = $model->list_getRecordsList(); $fileHandle = fopen($outputFile, 'w'); fwrite($fileHandle, <<<HTML
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>FluX Logs</title>

	<script src="https://code.jquery.com/jquery-3.6.0.slim.min.js"></script>

	<style>
		pre.output {
			margin-top: 2em;
		}
		span.id {
			float: right;
			color: #88f;
		}
		span.addTime {
			float: left;
			color: #888;
		}
		h2 {
			margin-top: 0;
			white-space: normal;
		}

		div.header {
			font-family: serif;
			position: sticky;
			top: 25px;
		}
		div.header.row-0 { background-color: hsl(50,  100%, 90%); border: 2px solid hsl(50,  100%, 70%); }
		div.header.row-1 { background-color: hsl(0,   100%, 90%); border: 2px solid hsl(0,   100%, 70%); }
		div.header.row-2 { background-color: hsl(134, 100%, 90%); border: 2px solid hsl(134, 100%, 70%); }
		div.header.row-3 { background-color: hsl(253, 100%, 90%); border: 2px solid hsl(253, 100%, 70%); }


		div.data {
			font-family: monospace;
		}
		div.data >div.row {
			transition: opacity 1.5s;
		}
		div.data >div.row.faded {
			opacity:   0.33;
			font-size: 0.01em;
			line-height: 2px;
		}
		div.data >div.row.faded:hover {
			opacity:   0.66;
			font-size: 1em;
			line-height: initial;
		}

		div.data.row-0 { background-color: hsl(50,  100%, 97%); border: 2px solid hsl(50,  100%, 70%); }
		div.data.row-1 { background-color: hsl(0,   100%, 97%); border: 2px solid hsl(0,   100%, 70%); }
		div.data.row-2 { background-color: hsl(134, 100%, 97%); border: 2px solid hsl(134, 100%, 70%); }
		div.data.row-3 { background-color: hsl(253, 100%, 97%); border: 2px solid hsl(253, 100%, 70%); }

		/** https://paletton.com/#uid=3001g0kJS6KvW5fuP8MNdeqCnl7 */
		div.data >div.row.level-0 { color: hsl(0,  10%, 75%); }
		div.data >div.row.level-1 { color: hsl(0,  50%, 45%); }
		div.data >div.row.level-2 { color: hsl(0,  70%, 33%); }
		div.data >div.row.level-3 { color: hsl(0,  80%, 25%); }
		div.data >div.row.level-4 { color: hsl(0,  95%, 17%); }
		div.data >div.row.level-5 { color: hsl(0, 100%, 7%); }

		/** https://paletton.com/#uid=3001g0k3V4WaYgf7Lb1ac80gJaQ */
		div.data >div.row >span.date { color: #817C55; font-size: 0.8em;}


		section.log-header {
			position: fixed;
			width: 100%;
			top: 0;
			left: 0;
			background-color: hsl(180,  25%, 95%);
			border-bottom: 2px solid hsl(180,  25%, 90%);
			z-index: 1;
		}
	</style>
</head>
<body>

<section class="log-header">
	<button onClick="sortByDate()">sort everything by date</button>
	<button onClick="hideLevel0()">hide level 0</button>
	<input type="text" placeholder="filter" onChange="filterText($(this).val())" />

	<script>
		function sortByDate() {
			let rows = $('div.data >div.row')
				.sort( (a, b) => {
					let a1 = $(a).find('span.date').html();
					let b1 = $(b).find('span.date').html();

					if (a1==null) {
						a1 = '';
					}

					if (b1==null) {
						b1 = '';
					}

					return a1.localeCompare(b1);
				}
			);

			$('pre.output >div.header').remove();
			$('pre.output >div.data').remove();

			$('pre.output').append($('<div class="data">').append(rows));
		}

		filterTextDelayed_timer = null;
		function filterTextDelayed(searchText) {
			if (filterTextDelayed_timer) {
				clearTimeout(filterTextDelayed_timer);
				filterTextDelayed_timer = null;
			}

			filterTextDelayed_timer = setTimeout(() => {
				filterText(searchText);
			}, 1.5 * 1000);
		}

		function filterText(searchText) {
			if (filterTextDelayed_timer) {
				clearTimeout(filterTextDelayed_timer);
				filterTextDelayed_timer = null;
			}

			let rx = new RegExp(searchText, "gi");
			$('div.data >div.row.faded').removeClass('faded');
			$('div.data >div.row').map( (i, r) => {
				let row = $(r);
				if (!row.text().match(rx)) {
					row.addClass('faded');
				}
			});
		}

		function hideLevel0() {
			$('div.data >div.row.level-0').remove();
		}
	</script>
</section>

<pre class="output">
HTML
); $rowIndex = 0; foreach ($listRows as $listRow) { $logRow = $model->getLogDetails($listRow['id']); if (!$logRow) { continue; } if (!$logRow['context']) { continue; } $loggerElement = $logRow['context']['log']; if (!($loggerElement instanceof \Engine\Logger\Context\HtmlFluXLogs)) { continue; } $fileContent = sprintf("<div class='header row-%d'><span class='addTime'>%s</span><span class='id'>%s</span>&nbsp<h2>%s</h2></div><div class='data row-%d'>%s</div>\n", $rowIndex%4, $listRow['addTime'], $listRow['id'], $listRow['message'], $rowIndex%4, $this->highlightLogs($this->filterLog($loggerElement->getRawValue())) ); fwrite($fileHandle, $fileContent); $rowIndex++; } fwrite($fileHandle, <<<HTML
</pre>
</body>
</html>
HTML
); fclose($fileHandle); return $this; } protected function filterLog($logStr) { return $logStr; } protected function highlightLogs($logStr) { $logStrArr = explode("\n", $logStr); $currentLogLevel = null; $prevLogLevel = null; $logStrArrRewritten = []; $logStrTempStack = []; $prevLineHineHasLevel = false; foreach ($logStrArr as $lineStr) { $lineHasLevel = false; $matches = []; if (preg_match("/^\[[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]+, (?P<logLevel>[0-9])\]/", $lineStr, $matches)) { $currentLogLevel = $matches['logLevel']; $lineHasLevel = true; } if ((!$prevLineHineHasLevel && $lineHasLevel) || ($prevLineHineHasLevel && $lineHasLevel)) { $logStrArrRewritten[]= sprintf("<div class='row level-%d'>%s</div>", $prevLogLevel, $this->highlightLogLine(implode("\n", $logStrTempStack))); $logStrTempStack = []; } $logStrTempStack[]= $lineStr; $prevLogLevel = $currentLogLevel; $prevLineHineHasLevel = $lineHasLevel; } if ($logStrTempStack) { $logStrArrRewritten[]= sprintf("<div class='row level-%d'>%s</div>", $currentLogLevel, $this->highlightLogLine(implode("\n", $logStrTempStack))); } return implode("", $logStrArrRewritten); } protected function highlightLogLine($logStr) { return preg_replace_callback("/^(?P<date>\[[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]+, (?P<logLevel>[0-9])\])(?P<rest>.*)/", function($matches) { return sprintf("<span class='date'>%s</span>%s", $matches['date'], $matches['rest']); }, $logStr); } } 