97 lines
4.5 KiB
HTML
97 lines
4.5 KiB
HTML
<div class="mb-6">
|
|
<!-- Search and Filters -->
|
|
<div class="mb-4">
|
|
<input type="text" id="logSearch" onkeyup="filterLogs()" placeholder="Search logs..."
|
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
|
|
</div>
|
|
|
|
<!-- Analytics Cards -->
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
|
|
<div class="bg-white p-4 rounded-lg shadow-sm border border-gray-200">
|
|
<h3 class="text-sm font-medium text-gray-500">Total Invocations</h3>
|
|
<p class="text-2xl font-semibold text-gray-800">{{ invocations | length }}</p>
|
|
</div>
|
|
<div class="bg-white p-4 rounded-lg shadow-sm border border-gray-200">
|
|
<h3 class="text-sm font-medium text-gray-500">Success Rate</h3>
|
|
{% set successful_invocations = invocations | selectattr('status', 'equalto', 'SUCCESS') | list %}
|
|
<p class="text-2xl font-semibold text-gray-800">
|
|
{% if invocations %}
|
|
{{ "%.2f"|format((successful_invocations|length / invocations|length) * 100) }}%
|
|
{% else %}
|
|
N/A
|
|
{% endif %}
|
|
</p>
|
|
</div>
|
|
<div class="bg-white p-4 rounded-lg shadow-sm border border-gray-200">
|
|
<h3 class="text-sm font-medium text-gray-500">Avg. Execution Time</h3>
|
|
{% set total_execution_time = invocations | sum(attribute='execution_time') %}
|
|
<p class="text-2xl font-semibold text-gray-800">
|
|
{% if invocations %}
|
|
{{ "%.2f"|format(total_execution_time / invocations|length) }}ms
|
|
{% else %}
|
|
N/A
|
|
{% endif %}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Time-series Chart -->
|
|
<div class="bg-white p-4 rounded-lg shadow-sm border border-gray-200">
|
|
<h3 class="text-base sm:text-lg font-medium text-gray-900 mb-2 sm:mb-4">Invocation History</h3>
|
|
<div class="relative h-48 sm:h-64">
|
|
<svg class="w-full h-full" viewBox="0 0 400 200" preserveAspectRatio="none">
|
|
<!-- Y-axis -->
|
|
<line x1="40" y1="20" x2="40" y2="180" stroke="#E5E7EB" stroke-width="1" />
|
|
<!-- X-axis -->
|
|
<line x1="40" y1="180" x2="380" y2="180" stroke="#E5E7EB" stroke-width="1" />
|
|
|
|
{% if invocations %}
|
|
<!-- Execution time line -->
|
|
{% set max_execution_time = [1] %}
|
|
{% for inv in invocations %}
|
|
{% if inv.execution_time > max_execution_time[0] %}{% set _ = max_execution_time.pop() %}{{
|
|
max_execution_time.append(inv.execution_time) }}{% endif %}
|
|
{% endfor %}
|
|
|
|
{% set path = namespace(d='M') %}
|
|
{% for inv in invocations | reverse %}
|
|
{% set x = 40 + (loop.index0 * (340 / (invocations|length - 1 if invocations|length > 1 else 1))) %}
|
|
{% set y = 180 - ((inv.execution_time / max_execution_time[0]) * 160) %}
|
|
{% if loop.first %}
|
|
{% set path.d = path.d ~ x ~ "," ~ y %}
|
|
{% else %}
|
|
{% set path.d = path.d ~ " L" ~ x ~ "," ~ y %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
|
|
<path d="{{ path.d }}" stroke="#10B981" stroke-width="2" fill="none" />
|
|
|
|
<!-- Data points -->
|
|
{% for inv in invocations | reverse %}
|
|
{% set x = 40 + (loop.index0 * (340 / (invocations|length - 1 if invocations|length > 1 else 1))) %}
|
|
{% set y = 180 - ((inv.execution_time / max_execution_time[0]) * 160) %}
|
|
<circle cx="{{ x }}" cy="{{ y }}" r="4" fill="#10B981">
|
|
<title>{{ inv.invocation_time.strftime('%Y-%m-%d %H:%M:%S') }}: {{ "%.2f"|format(inv.execution_time)
|
|
}}ms</title>
|
|
</circle>
|
|
{% endfor %}
|
|
{% endif %}
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function filterLogs() {
|
|
const searchInput = document.getElementById('logSearch').value.toLowerCase();
|
|
const logRows = document.querySelectorAll('.log-row');
|
|
logRows.forEach(row => {
|
|
const logContent = row.textContent.toLowerCase();
|
|
if (logContent.includes(searchInput)) {
|
|
row.style.display = '';
|
|
} else {
|
|
row.style.display = 'none';
|
|
}
|
|
});
|
|
}
|
|
</script> |