Add admin Infra page with Redis and PostgreSQL monitoring
Shows real-time stats with color-coded indicators: - Redis: version, memory, hit rate, ops/sec, evicted keys - PostgreSQL: version, db size, connections, cache hit ratio, dead tuples Uses MESSENGER_TRANSPORT_DSN for Redis auth (works in dev and prod). Accessible via /admin/infra with nav link. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
<a href="{{ path('app_admin_events') }}" class="px-3 py-1.5 text-xs font-black uppercase tracking-widest transition-all {{ current_route starts with 'app_admin_event' ? 'admin-nav-active' : 'hover:bg-gray-100' }}">Evenements</a>
|
||||
<a href="{{ path('app_admin_orders') }}" class="px-3 py-1.5 text-xs font-black uppercase tracking-widest transition-all {{ current_route == 'app_admin_orders' ? 'admin-nav-active' : 'hover:bg-gray-100' }}">Commandes</a>
|
||||
<a href="{{ path('app_admin_logs') }}" class="px-3 py-1.5 text-xs font-black uppercase tracking-widest transition-all {{ current_route == 'app_admin_logs' ? 'admin-nav-active' : 'hover:bg-gray-100' }}">Logs</a>
|
||||
<a href="{{ path('app_admin_infra') }}" class="px-3 py-1.5 text-xs font-black uppercase tracking-widest transition-all {{ current_route == 'app_admin_infra' ? 'admin-nav-active' : 'hover:bg-gray-100' }}">Infra</a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
|
||||
98
templates/admin/infra.html.twig
Normal file
98
templates/admin/infra.html.twig
Normal file
@@ -0,0 +1,98 @@
|
||||
{% extends 'admin/base.html.twig' %}
|
||||
|
||||
{% block title %}Infrastructure{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h1 class="text-3xl font-black uppercase tracking-tighter italic heading-page mb-8">Infrastructure</h1>
|
||||
|
||||
<div class="flex flex-wrap gap-6 mb-8">
|
||||
{# Redis #}
|
||||
<div class="flex-1 min-w-[400px]">
|
||||
<div class="admin-card">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="text-sm font-black uppercase tracking-widest">Redis</h2>
|
||||
{% if redis.connected %}
|
||||
<span class="admin-badge-green text-xs font-black uppercase">Connecte</span>
|
||||
{% else %}
|
||||
<span class="admin-badge-red text-xs font-black uppercase">Deconnecte</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if redis.connected %}
|
||||
<div class="flex flex-col gap-0">
|
||||
{{ _self.infra_row('Version', redis.version) }}
|
||||
{{ _self.infra_row('Uptime', redis.uptime_days ~ ' jours') }}
|
||||
{{ _self.infra_row('Role', redis.role) }}
|
||||
{{ _self.infra_row('Clients connectes', redis.connected_clients) }}
|
||||
{{ _self.infra_row('Ops/sec', redis.instantaneous_ops_per_sec) }}
|
||||
|
||||
<div class="border-t border-gray-200 my-2"></div>
|
||||
<p class="text-[10px] font-black uppercase tracking-widest text-gray-400 mb-1">Memoire</p>
|
||||
{{ _self.infra_row('Utilisee', redis.used_memory_human) }}
|
||||
{{ _self.infra_row('Pic', redis.used_memory_peak_human) }}
|
||||
|
||||
<div class="border-t border-gray-200 my-2"></div>
|
||||
<p class="text-[10px] font-black uppercase tracking-widest text-gray-400 mb-1">Cache</p>
|
||||
{{ _self.infra_row('Commandes traitees', redis.total_commands_processed|number_format(0, '.', ' ')) }}
|
||||
{{ _self.infra_row('Hits', redis.keyspace_hits|number_format(0, '.', ' ')) }}
|
||||
{{ _self.infra_row('Misses', redis.keyspace_misses|number_format(0, '.', ' ')) }}
|
||||
{{ _self.infra_row_colored('Hit Rate', redis.hit_rate, redis.hit_rate != 'N/A' and redis.hit_rate|replace({'%': ''})|number_format > 80 ? 'green' : (redis.hit_rate == 'N/A' ? 'gray' : 'red')) }}
|
||||
{{ _self.infra_row('Cles expirees', redis.expired_keys|number_format(0, '.', ' ')) }}
|
||||
{{ _self.infra_row_colored('Cles evictees', redis.evicted_keys, redis.evicted_keys == '0' ? 'green' : 'red') }}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-sm text-red-500 font-bold">{{ redis.error }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# PostgreSQL #}
|
||||
<div class="flex-1 min-w-[400px]">
|
||||
<div class="admin-card">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="text-sm font-black uppercase tracking-widest">PostgreSQL</h2>
|
||||
{% if postgres.connected %}
|
||||
<span class="admin-badge-green text-xs font-black uppercase">Connecte</span>
|
||||
{% else %}
|
||||
<span class="admin-badge-red text-xs font-black uppercase">Deconnecte</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if postgres.connected %}
|
||||
<div class="flex flex-col gap-0">
|
||||
{{ _self.infra_row('Version', postgres.version) }}
|
||||
{{ _self.infra_row('Uptime', postgres.uptime) }}
|
||||
{{ _self.infra_row('Taille BDD', postgres.db_size) }}
|
||||
{{ _self.infra_row('Tables', postgres.table_count) }}
|
||||
|
||||
<div class="border-t border-gray-200 my-2"></div>
|
||||
<p class="text-[10px] font-black uppercase tracking-widest text-gray-400 mb-1">Connexions</p>
|
||||
{{ _self.infra_row('Actives', postgres.active_connections) }}
|
||||
{{ _self.infra_row('Total', postgres.total_connections ~ ' / ' ~ postgres.max_connections) }}
|
||||
|
||||
<div class="border-t border-gray-200 my-2"></div>
|
||||
<p class="text-[10px] font-black uppercase tracking-widest text-gray-400 mb-1">Performance</p>
|
||||
{{ _self.infra_row_colored('Cache Hit Ratio', postgres.cache_hit_ratio, postgres.cache_hit_ratio != 'N/A' and postgres.cache_hit_ratio|replace({'%': ''})|number_format > 95 ? 'green' : (postgres.cache_hit_ratio == 'N/A' ? 'gray' : 'yellow')) }}
|
||||
{{ _self.infra_row_colored('Dead Tuples', postgres.dead_tuples|number_format(0, '.', ' '), postgres.dead_tuples < 10000 ? 'green' : (postgres.dead_tuples < 100000 ? 'yellow' : 'red')) }}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-sm text-red-500 font-bold">{{ postgres.error }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% macro infra_row(label, value) %}
|
||||
<div class="flex justify-between py-1.5 text-sm">
|
||||
<span class="text-gray-500 font-bold">{{ label }}</span>
|
||||
<span class="font-black">{{ value }}</span>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro infra_row_colored(label, value, color) %}
|
||||
<div class="flex justify-between py-1.5 text-sm">
|
||||
<span class="text-gray-500 font-bold">{{ label }}</span>
|
||||
<span class="font-black {% if color == 'green' %}text-green-600{% elseif color == 'red' %}text-red-600{% elseif color == 'yellow' %}text-yellow-600{% else %}text-gray-400{% endif %}">{{ value }}</span>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
Reference in New Issue
Block a user