db2diag.log es el registro central de diagnóstico de una instancia Db2 y, junto con el log de notificación, es uno de los primeros lugares que conviene revisar cuando hay fallos de conexión, problemas de locks, deadlocks o comportamientos inesperados del motor Db2. El problema de siempre ha sido el acceso: texto libre, varias formas de salida, campos posicionales y un parsing frágil cuando se quiere automatizar el análisis.
Db2 12.1.3.0 introdujo la opción -json en db2diag. Cuando se usa, la salida del comando pasa a ser JSON Lines: un objeto JSON por línea, con campos estructurados que pueden filtrarse y agregarse con jq. El objetivo de este artículo es mostrar lo que se puede hacer con ese formato JSON. Los lock timeouts y los deadlocks son solo el ejemplo práctico utilizado para hacer visible la diferencia entre texto libre y datos estructurados.
1. Objetivos e introducción de la lab
Al finalizar esta lab deberías poder:
- entender qué tipo de análisis se vuelve más fácil con
db2diag -json - identificar los parámetros que controlan el registro de diagnóstico y de eventos de lock
- entender el enfoque tradicional de
db2diagy sus limitaciones - usar
db2diag -jsonpara inspeccionar los campos disponibles en un mensaje concreto - transformar la salida JSON en tablas legibles con
jqycolumn - crear una plantilla reutilizable para repetir el análisis más adelante
La idea es mostrar por qué la salida JSON mejora el triaje, la correlación y la automatización cuando Db2 empieza a producir eventos de diagnóstico difíciles de leer manualmente.
2. Lo que vas a necesitar para ejecutar la lab
Vas a necesitar:
- Db2 LUW 12.1.3.0 o superior
- Un sistema Linux. Presta atención a las versiones mínimas admitidas. Para Red Hat usa 9.4 o superior; para Ubuntu usa 22.04.5 o superior.
- Acceso a la cuenta propietaria de la instancia Db2
jqcolumnawk,grep,sed,bashy utilidades estándar de shell
Si Db2 no está instalado, obténlo desde el portal oficial de descargas de software de IBM o desde el mecanismo de distribución asociado a tu licencia o entitlement. Db2 Community Edition es suficiente.
Si hace falta, instala Db2 y crea la instancia que vas a utilizar en la lab.
Para instalar el software auxiliar, ejecuta:
En RHEL, Rocky, AlmaLinux, SLES
sudo dnf install -y jq util-linuxEn Debian o distribuciones basadas en Debian
sudo apt-get install -y jq util-linuxLos comandos siguientes deben ejecutarse con la cuenta propietaria de la instancia Db2.
Los parámetros que vamos a modificar son:
| Parámetro | Nivel | Función |
|---|---|---|
| DIAGLEVEL | DBM CFG | Controla qué severidades se escriben en db2diag.log |
| NOTIFYLEVEL | DBM CFG | Controla qué eventos se escriben en el log de notificación |
| LOCKTIMEOUT | DB CFG | Define cuánto puede durar la espera por un lock |
| DLCHKTIME | DB CFG | Define el intervalo de detección de deadlocks en milisegundos |
| MON_LCK_MSG_LVL | DB CFG | Controla el registro de deadlocks, lock timeouts y lock waits |
Para esta lab:
| Valor | Efecto |
|---|---|
| DIAGLEVEL 3 | Garantiza que se registren eventos Warning, Error y Severe |
| NOTIFYLEVEL 3 | Mantiene útil el log de notificación para operaciones normales |
| LOCKTIMEOUT 5 | Fuerza un lock timeout rápido |
| DLCHKTIME 1000 | Hace que la detección de deadlocks ocurra antes de que venza un timeout de 5 segundos |
| MON_LCK_MSG_LVL 3 | Registra deadlocks, lock timeouts y lock waits en db2diag.log |
3. Mecanismos tradicionales de visualización del diagnóstico
db2diag
El comando db2diag sigue siendo la herramienta central para leer db2diag.log. Permite filtrar por severidad y por intervalo temporal y otros criterios, ofrece opciones básicas de formato y búsqueda, y es útil cuando investigas un incidente en tiempo real.
Ejemplo:
db2diag -t "$(date -d '1 hour ago' '+%Y-%m-%d-%H.%M.%S')" -l Warning,Error,SevereSin embargo, tiene algunas limitaciones:
- es difícil agregar por
pid,tid, componente o función sin parsing adicional - los mensajes con campos anidados requieren regex u otras técnicas frágiles de parsing
greptrabaja línea a línea y, aunque pidas líneas adyacentes, no entiende el contexto completo de un bloque de diagnóstico- exportar a CSV o correlacionar eventos requiere más trabajo del que debería
Vistas administrativas
Las vistas administrativas, como SYSIBMADM.PDLOGMSGS_LAST24HOURS, son útiles para monitorización operativa. Ofrecen flexibilidad SQL, pero leen el log de notificación y no db2diag.log. Son buenas para eventos de arranque, parada y eventos operativos generales.
Ejemplo:
db2 connect to DIAGJSON
db2 "SELECT TIMESTAMP, MSGSEVERITY, SUBSTR(MSG,1,256) AS MSG FROM SYSIBMADM.PDLOGMSGS_LAST24HOURS ORDER BY TIMESTAMP DESC FETCH FIRST 20 ROWS ONLY"Limitaciones principales:
- dependen de que Db2 esté operativo
- no muestran todos los detalles internos del diagnóstico
Table functions y monitorización SQL
Las table functions y las vistas de monitorización ayudan con dashboards y observabilidad continua, pero también dependen de una instancia Db2 sana. Son muy útiles cuando la instancia y la base de datos están arriba, pero mucho menos cuando no lo están, que es precisamente cuando la información de diagnóstico importa más.
En resumen:
db2diages la fuente más cercana al evento real- las vistas y funciones SQL son buenas para observabilidad cuando el sistema está sano
4. Soporte de salida JSON en Db2 (db2diag -json)
A partir de Db2 12.1.3.0, puedes añadir -json a db2diag.
Eso cambia dos cosas:
- la salida pasa a ser JSON Lines, con un objeto JSON por línea
- los campos pasan a ser estructurados y pueden consumirse sin parsing de texto libre
Las ventajas son claras:
- los datos se entregan en un formato estructurado que las plataformas de observabilidad pueden consumir mejor
- herramientas que procesan JSON, como
jq, pueden explorar los datos con flexibilidad
Para el tipo de análisis que cubre este artículo, JSON no sustituye al db2diag clásico; lo complementa. Usa el formato tradicional para una inspección rápida y JSON cuando necesites más flexibilidad de filtrado, parsing y formato.
5. Escenario y ejecución de la lab
Vamos a crear una base de datos, objetos de schema y datos de ejemplo, y luego generaremos varios lock timeouts y un escenario de deadlock para producir registros de contención en db2diag.log. Usaremos la nueva capacidad de formato JSON para inspeccionar la información de diagnóstico resultante.
Establecer la configuración necesaria a nivel de base de datos e instancia
Empieza creando la base de datos y estableciendo los parámetros necesarios de la instancia y de la base de datos Db2.
db2 create database DIAGJSON
db2 connect to DIAGJSON
db2 "UPDATE DB CFG FOR DIAGJSON USING LOCKTIMEOUT 5 MON_LCK_MSG_LVL 3"
db2 update dbm cfg using DIAGLEVEL 3 NOTIFYLEVEL 3
db2stop force
db2startPara confirmar los valores, ejecuta:
db2 get dbm cfg | grep -iE "diaglevel|notifylevel"
db2 get db cfg for DIAGJSON | grep -iE "locktimeout|mon_lck_msg_lvl"Crea los objetos de schema y carga los datos de ejemplo:
db2 connect to DIAGJSON
db2 "CREATE SCHEMA app"
db2 "CREATE TABLE app.accounts (id INTEGER NOT NULL, balance DECIMAL(10,2), PRIMARY KEY (id))"
db2 "INSERT INTO app.accounts VALUES (1, 5000.00)"
db2 "INSERT INTO app.accounts VALUES (2, 3000.00)"
db2 commit
db2 connect resetGeneración del problema y de la evidencia de diagnóstico
Vamos a generar un lock timeout. Para ello iniciamos dos sesiones. Una sesión mantiene un lock y la otra intenta acceder a la fila bloqueada hasta que vence el tiempo de espera.
cat > /tmp/hold_lock.sh <<'EOF'
#!/bin/bash
db2 connect to DIAGJSON
db2 +c "UPDATE app.accounts SET balance = balance - 100 WHERE id = 1"
sleep 30
db2 commit
db2 connect reset
EOF
chmod +x /tmp/hold_lock.sh
bash /tmp/hold_lock.sh &
LOCK_PID=$!
sleep 3
db2 connect to DIAGJSON
db2 "UPDATE app.accounts SET balance = balance + 100 WHERE id = 1"
kill $LOCK_PID 2>/dev/null
wait $LOCK_PID 2>/dev/null
db2 connect resetAhora generaremos un deadlock. Usaremos dos sesiones que actualizan filas de la misma tabla en orden opuesto. Ninguna de las dos podrá adquirir el segundo lock porque la otra sesión ya mantiene la fila necesaria.
Para esta prueba, desactivamos el timeout por sesión con CURRENT LOCK TIMEOUT = -1 y reducimos DLCHKTIME a 1000, para que la detección del deadlock ocurra antes de que el escenario se degrade en un timeout.
db2 connect to DIAGJSON
db2 "UPDATE DB CFG FOR DIAGJSON USING DLCHKTIME 1000"
db2 connect reset
cat > /tmp/deadlock_a.sh <<'EOF'
#!/bin/bash
db2 connect to DIAGJSON
db2 "SET CURRENT LOCK TIMEOUT -1"
db2 +c "UPDATE app.accounts SET balance = balance - 100 WHERE id = 1"
sleep 2
db2 +c "UPDATE app.accounts SET balance = balance + 100 WHERE id = 2"
db2 rollback
db2 connect reset
EOF
cat > /tmp/deadlock_b.sh <<'EOF'
#!/bin/bash
db2 connect to DIAGJSON
db2 "SET CURRENT LOCK TIMEOUT -1"
db2 +c "UPDATE app.accounts SET balance = balance - 100 WHERE id = 2"
sleep 2
db2 +c "UPDATE app.accounts SET balance = balance + 100 WHERE id = 1"
db2 rollback
db2 connect reset
EOF
chmod +x /tmp/deadlock_a.sh /tmp/deadlock_b.sh
bash /tmp/deadlock_a.sh &
bash /tmp/deadlock_b.sh &
waitDespués de la prueba, restaura el intervalo de detección por defecto si quieres volver al comportamiento habitual:
db2 connect to DIAGJSON
db2 "UPDATE DB CFG FOR DIAGJSON USING DLCHKTIME 10000"
db2 connect resetAhora podemos pasar al formato JSON. La salida JSON de db2diag produce líneas en las que cada línea es un objeto JSON independiente.
Si el timeout por sesión sigue por debajo del intervalo de detección de deadlocks, Db2 puede devolver SQL0911N con reason code 68 y registrar solo la contención como ADM5506W. Por eso el escenario de deadlock siguiente ajusta CURRENT LOCK TIMEOUT y DLCHKTIME antes de repetir la prueba.
El archivo de schema JSON que define la estructura esperada está en ~/sqllib/misc/db2diag.schema.json:
Inspecciónalo directamente:
sed -n '1,80p' ~/sqllib/misc/db2diag.schema.jsonYa tenemos una idea de la estructura del schema antes de mirar la salida real de db2diag.
Examina un mensaje concreto de lock timeout y compáralo con el schema:
db2diag -level Warning -g msg:=ADM5506W -json -V > /tmp/adm5506w.jsonl
head -1 /tmp/adm5506w.jsonlAhora usa jq con pretty print para el mismo efecto:
db2diag -level Warning -g msg:=ADM5506W -json -V | head -1 | jq '.'Vamos a listar los nombres de los campos de nivel superior disponibles en la primera entrada que corresponda a ADM5506W:
db2diag -level Warning -g msg:=ADM5506W -json -V |
jq -nr 'first(inputs) | keys_unsorted[]'Esta técnica es útil para descubrir rápidamente qué campos existen sin depender de leer manualmente el texto completo de un mensaje.
Ahora haremos el ejemplo más práctico. Filtramos con parámetros de db2diag y luego usamos jq y column para obtener una tabla limpia en el terminal. column se usa para alinear las columnas en el terminal. Si vas a escribir la salida en un archivo, puedes omitir column.
El ejemplo extrae campos estructurados del JSON y, al mismo tiempo, hace parsing de partes textuales dentro de message. Es mucho más estable que intentar hacer lo mismo con grep sobre la salida de db2diag.
db2diag -level Warning -g msg:=ADM5506W -json -V |
jq -nr '
def msg: (.message // "" | gsub("[\n ]+"; " "));
def cap($re): (msg | capture($re).v? // "-");
["timestamp","timezone","level","pid","tid","process","instance","member","database","apphdl","appid","uowid","actid","authid","hostname","eduid","eduname","function","probe","event_type","lock_id","event_ts","affected_app","workload","affected_appid","role"],
(
inputs
| [
(.timestamp // "-"),
(.timezone // "-"),
(.level // "-"),
(.pid // "-"),
(.tid // "-"),
(.process // "-"),
(.instance // "-"),
(.member // "-"),
(.database // "-"),
(.apphdl // "-"),
(.appid // "-"),
(.uowid // "-"),
(.actid // "-"),
(.authid // "-"),
(.hostname // "-"),
(.eduid // "-"),
(.eduname // "-"),
(.function // "-"),
(.probe // "-"),
cap("type of the event is: \"(?<v>[^\"]+)\""),
cap("identifier of the lock on which this event happened is: \"(?<v>[^\"]+)\""),
cap("timestamp of the event is: \"(?<v>[^\"]+)\""),
cap("affected application is named \"(?<v>[^\"]+)\""),
cap("workload named \"(?<v>[^\"]+)\""),
cap("application identifier is: \"(?<v>[^\"]+)\""),
cap("role that this application plays with respect to this lock is: \"(?<v>[^\"]+)\"")
]
)
| @tsv
' |
column -t -s $'\t'Cuando repitas el análisis más de una vez, conviene guardar la especificación en un archivo y reutilizarla desde jq. Crea el archivo de definiciones:
mkdir -p ~/db2diag-jq
vi ~/db2diag-jq/adm5506w-locks.jqPega el siguiente contenido en el archivo:
def msg: (.message // "" | gsub("[\n ]+"; " "));
def cap($re): (msg | capture($re).v? // "-");
["timestamp","timezone","level","pid","tid","process","instance","member","database","apphdl","appid","uowid","actid","authid","hostname","eduid","eduname","function","probe","event_type","lock_id","event_ts","affected_app","workload","affected_appid","role"],
(
inputs
| [
(.timestamp // "-"),
(.timezone // "-"),
(.level // "-"),
(.pid // "-"),
(.tid // "-"),
(.process // "-"),
(.instance // "-"),
(.member // "-"),
(.database // "-"),
(.apphdl // "-"),
(.appid // "-"),
(.uowid // "-"),
(.actid // "-"),
(.authid // "-"),
(.hostname // "-"),
(.eduid // "-"),
(.eduname // "-"),
(.function // "-"),
(.probe // "-"),
cap("type of the event is: \"(?<v>[^\"]+)\""),
cap("identifier of the lock on which this event happened is: \"(?<v>[^\"]+)\""),
cap("timestamp of the event is: \"(?<v>[^\"]+)\""),
cap("affected application is named \"(?<v>[^\"]+)\""),
cap("workload named \"(?<v>[^\"]+)\""),
cap("application identifier is: \"(?<v>[^\"]+)\""),
cap("role that this application plays with respect to this lock is: \"(?<v>[^\"]+)\"")
]
)
| @tsvRepite el ejemplo anterior, esta vez usando el archivo en lugar de pasar todos los parámetros por línea de comandos:
db2diag -level Warning -g msg:=ADM5506W -json -V |
jq -nr -f ~/db2diag-jq/adm5506w-locks.jq |
column -t -s $'\t'6. Consideraciones finales y resumen
La salida tradicional de db2diag es adecuada para una inspección rápida, pero tiene limitaciones. Con db2diag -json, cada evento pasa a ser un objeto estructurado, lo que facilita:
- contar eventos por componente
- agrupar por
pidotid - exportar a TSV o CSV
- integrar con automatización y sistemas de observabilidad
7. Cleanup
Al terminar la lab, ejecuta:
db2 connect reset
db2 drop database DIAGJSONElimina también los archivos temporales:
rm -f /tmp/hold_lock.sh /tmp/deadlock_a.sh /tmp/deadlock_b.sh
rm -f ~/db2diag-jq/adm5506w-locks.jqDocumentación útil de IBM
Para profundizar, las referencias de IBM más útiles para este tema son: