Un buen indicador es aquel cuyo origen puedes señalar en la base de datos. Esta guía muestra qué KPIs de Service Desk vale realmente la pena seguir en GLPI, de qué tabla y columna sale cada número, qué rangos usamos como referencia y las trampas que ya han distorsionado decisiones en los entornos que mantenemos para clientes.
Antes del KPI, el modelo de datos
El error que más vemos al hacernos cargo de un GLPI existente es medir "por encima": comparar fechas crudas en lugar de usar los campos que GLPI ya calcula. Cada ticket en la tabla glpi_tickets lleva columnas estadísticas listas, las mismas que consume el módulo de Estadísticas:
takeintoaccount_delay_stat- segundos hasta la primera toma de conocimiento (base del tiempo de respuesta / TTO).solve_delay_stat- segundos hasta la solución, ya descontando el tiempo en "Pendiente" y ajustado por el calendario laboral de la entidad (base del TMR / TTR).waiting_duration- total de segundos que el ticket estuvo en espera.time_to_resolveytime_to_own- los plazos (deadlines) del SLA de resolución y de atención.status- el estado del ticket, que define qué entra o no en el backlog.
Esto lo cambia todo: el TMR calculado como solvedate - date es distinto (y siempre mayor) de lo que devuelve solve_delay_stat, porque la resta cruda suma madrugadas, fines de semana y pausas. Elegir la columna correcta ya es la mitad del trabajo.
Los KPIs que importan y dónde vive cada uno
No se trata de tener diez indicadores en el panel; se trata de tener los que generan acción. La matriz de abajo enlaza cada KPI con su fuente técnica en GLPI y con un rango de referencia honesto. Un rango, no una meta universal: el número justo depende del contrato y del tipo de operación.
| KPI | Fuente en GLPI | Rango de referencia |
|---|---|---|
| Volumen de tickets | COUNT(*) en glpi_tickets (filtro por date) | dimensiona el equipo; sin meta fija |
| Tiempo de respuesta (TTO) | takeintoaccount_delay_stat | cuanto menor, mejor; sigue el SLA |
| Tiempo medio de resolución (TMR) | solve_delay_stat | comparar con el propio histórico |
| Cumplimiento de SLA (TTR) | solvedate <= time_to_resolve | por encima de 90-95% |
| Tasa de reapertura | glpi_logs (estado 5 a 1/2/3) | por debajo de 5% |
| Satisfacción (CSAT) | glpi_ticketsatisfactions.satisfaction | por encima de 4,0/5,0 |
| Backlog | status NOT IN (5,6) | estable o decreciente |
| Edad media del backlog | AVG(DATEDIFF(NOW(), date)) en los abiertos | baja; alta = tickets olvidados |
| Resolución en N1 | grupo asignado, sin escalado | 70-80% |
Extrayendo los números directo de la base
El módulo de Estadísticas (en Asistencia) responde bien para consulta puntual y para explorar por categoría, grupo, técnico y SLA. Pero no versiona el histórico mes a mes ni cruza varios indicadores en una sola fila comparable. Cuando necesitamos la foto consolidada que entra en el informe mensual de los clientes, vamos a la base con un usuario de solo lectura:
-- KPIs del mes en curso en una sola fila (usar un usuario de solo lectura)
-- Origen: glpi_tickets, los mismos campos que consume el módulo Estadísticas
SELECT
COUNT(*) AS volume,
SUM(status NOT IN (5,6)) AS backlog,
ROUND(AVG(NULLIF(takeintoaccount_delay_stat,0))/60, 1) AS tto_min,
ROUND(AVG(NULLIF(solve_delay_stat,0))/3600, 1) AS tmr_horas,
ROUND(
100 * SUM(solvedate IS NOT NULL AND solvedate <= time_to_resolve)
/ NULLIF(SUM(time_to_resolve IS NOT NULL AND solvedate IS NOT NULL), 0)
, 1) AS sla_ttr_pct
FROM glpi_tickets
WHERE is_deleted = 0
AND date >= DATE_FORMAT(CURDATE(), '%Y-%m-01');La reapertura no tiene columna propia: vive en el histórico de cambios de estado. En glpi_logs, una reapertura es el ticket que salió de Resuelto (estado 5) y volvió a atención. El log guarda el valor como "5 Resuelto", así que filtramos por el prefijo numérico para no depender del idioma de la instalación:
-- Reaperturas del mes: tickets que salieron de Resuelto (5) y volvieron
-- a atención. En glpi_logs, id_search_option 12 = el campo estado
SELECT COUNT(DISTINCT items_id) AS reabertos
FROM glpi_logs
WHERE itemtype = 'Ticket'
AND id_search_option = 12
AND old_value LIKE '5 %'
AND new_value REGEXP '^[123] '
AND date_mod >= DATE_FORMAT(CURDATE(), '%Y-%m-01');Automatizando la recolección mensual
Ejecutar la consulta a mano cada día 1 no escala. Programamos la extracción con el propio cron del sistema, apuntando a un archivo de credenciales .cnf (chmod 600) para no dejar nunca la contraseña en la línea de comandos, y guardamos el CSV fuera de GLPI. Así nace la serie temporal que el panel nativo no guarda:
# /etc/cron.d/glpi-kpi -> día 1 a las 06:00, como www-data
# Credenciales en el archivo .cnf (chmod 600), nunca en la línea de comandos
0 6 1 * * www-data /usr/bin/mysql --defaults-file=/etc/glpi/kpi-ro.cnf glpi \
< /opt/glpi-kpi/kpi_mensal.sql >> /var/log/glpi-kpi/kpi-$(date +\%Y-\%m).csv 2>&1Metas: rangos honestos, no números mágicos
- Cumplimiento de SLA (TTR): por encima de 90-95% es saludable para la mayoría de contratos. Un 100% constante suele indicar un SLA demasiado holgado, no excelencia.
- Reaperturas: por debajo de 5%. Por encima, investiga solución incompleta o cierre apresurado para "cumplir" el plazo.
- Resolución en N1: 70-80%. Por debajo de 60% apunta a falta de capacitación o mala categorización; muy por encima de 90%, sospecha de tickets complejos mal clasificados.
- Satisfacción (CSAT): por encima de 4,0/5,0, pero siempre leída junto con la tasa de respuesta de la encuesta.
Trampas que ya han provocado guardias
En el mantenimiento de entornos de clientes, lo primero que hacemos al asumir un GLPI que ya funcionaba es no confiar en el panel nativo hasta validar la base. En un cliente con alto volumen mensual de tickets, el TMR "oficial" parecía óptimo hasta que notamos que buena parte de los tickets tenía al mismo usuario como autor y técnico ya en la apertura: una autoasignación que pone a cero takeintoaccount_delay_stat y enmascara el tiempo real de respuesta. Estandarizamos la extracción vía SQL programado precisamente porque el módulo de Estadísticas no guarda histórico mes a mes; sin serie temporal, comparas con la memoria, no con el dato.
Las trampas de campo que más distorsionan la lectura:
- Medir el TMR por diferencia de fechas.
solvedate - dateinfla el número: entran madrugadas, fines de semana y tiempo en "Pendiente". Usasolve_delay_stat, que GLPI ya ajusta por el calendario. - Confundir Resuelto con Cerrado. Si hay cierre automático tras X días, medir solo
status = 6oculta los resueltos a la espera de confirmación. El backlog debe excluir 5 y 6. - Celebrar un TTO bajo por autoasignación. Un ticket abierto ya asignado pone a cero el tiempo de respuesta; el número baja sin que la operación haya mejorado en nada.
- Leer la satisfacción sin la tasa de respuesta. Cuando solo responde quien quedó insatisfecho, la media engaña. Cruza
satisfactioncon cuántas encuestas se respondieron realmente.
Si tu GLPI muestra números en los que nadie confía, el problema rara vez es GLPI: es la base y la forma de extraer. El mantenimiento de GLPI de NexTool incluye el modelado de estos indicadores y el informe mensual consolidado que la dirección lee sin una hoja de cálculo.
Este contenido se produjo con ayuda de inteligencia artificial y fue revisado por el equipo de Nextool Solutions.