Los logs de error del IBM MQ son uno de los primeros lugares que un administrador mira cuando un Queue Manager, canal, regla de seguridad o conexión aplicacional se comporta inesperadamente. La forma tradicional de leer los logs requiere acceso al sistema de archivos del host del Queue Manager.
El IBM MQ 9.4.5 introdujo el comando PCF MQCMD_INQUIRE_ERROR_LOG. Un cliente MQ autorizado puede ahora solicitar un log de error del Queue Manager directamente al propio MQ. Esto es importante para monitorización centralizada porque no es necesario iniciar una sesión de shell con el sistema remoto ni usar un sistema de archivos compartido o tener conocimiento de la estructura de almacenamiento del Queue Manager.
Este artículo explica el modelo de solicitud y respuesta PCF y luego construye un laboratorio con:
- Un Queue Manager IBM MQ 10.0
- Un contenedor separado para el cliente Java
- Una conexión remota del cliente usando un canal MQI
- Obtención del contenido completo o incremental del
AMQERR01.LOG
Consideraciones: la configuración usa la imagen IBM MQ Advanced for Developers y un canal de desarrollo protegido por contraseña intencionalmente simple. Esta configuración es adecuada para un laboratorio en entorno de desarrollo o pruebas, y no para producción. Implementaciones en producción necesitan mecanismos más fuertes de seguridad.
1. Qué cambió en el IBM MQ 9.4.5
Surge el nuevo comando PCF:
MQCMD_INQUIRE_ERROR_LOGEstá disponible en el IBM MQ for Multiplatforms a partir de la versión 9.4.5 y también está presente en el IBM MQ 10.0. El comando obtiene el contenido de los logs de error del Queue Manager.
Cuando se usa sin parámetros, el MQ devuelve el log activo (AMQERR01.LOG). Existen dos parámetros opcionales que permiten ajustar la solicitud:
| Parámetro PCF | Finalidad |
|---|---|
MQCACF_ERROR_LOG_NAME | Seleccionar AMQERR01, AMQERR02 o AMQERR03, con o sin el sufijo .LOG |
MQCACF_ERROR_LOG_AFTER_ISOTIME | Devolver entradas cuyo timestamp sea más reciente o igual al horario UTC proporcionado |
El formato del timestamp debe ser ISO 8601 UTC terminando en Z. El IBM MQ acepta segundos, milisegundos o microssegundos, por ejemplo:
2026-07-22T10:15:00Z
2026-07-22T10:15:00.123Z
2026-07-22T10:15:00.123456ZEl MQ responde con una o más mensajes PCF:
| Parámetro de respuesta | Significado |
|---|---|
MQCACF_ERROR_LOG_RECORD | Texto del log de error solicitado |
MQCACF_ERROR_LOG_ISOTIME | Timestamp de la última entrada de error en el log |
El texto del log devuelto está sub-dividido en mensajes de respuesta de hasta 1 MB y por tanto, un recolector debe procesar cada respuesta y no solo la primera. El timestamp final es un cursor que puede almacenarse y proporcionarse en la siguiente solicitud.
2. Cómo funciona la administración PCF
El PCF es el protocolo administrativo del IBM MQ que funciona a través de mensajes con representación estructurada de comandos. Una aplicación cliente crea un mensaje de comando, añade parámetros y lo envía al servidor de comandos del Queue Manager. El servidor de comandos ejecuta la operación y devuelve mensajes de respuesta estructurados.
El flujo de comando y respuesta es:

La clase Java PCFMessageAgent se encarga del acceso a la cola de comandos, colas de respuesta, correlación, codificación PCF y recolección de respuestas. La aplicación aún necesita:
- Establecer una conexión cliente MQ autenticada
- Construir el comando correcto y los parámetros
- Procesar cada mensaje de respuesta
- Verificar los códigos de retorno (completion y reason)
- Guardar el timestamp final para poder ser utilizado en recolas incrementales
3. Modelo de autorización
La documentación del IBM describe la autorización +ctrl en el objeto Queue Manager como la autoridad específica necesaria para obtener el contenido de los logs de error. También es necesario tener las permisiones normales necesarias para establecer la conexión y efectuar las comunicaciones.
Un authorization record con las autorizaciones necesarias puede establecerse como se muestra a continuación:
setmqaut -m LOGQM -t qmgr -p pcfreader +connect +inq +ctrlNo conceda a un identificador de monitorización la pertenencia al grupo mqm solo para hacer que el comando funcione. En producción, cree una identidad dedicada, conceda solo las autoridades que necesita y restrinja el canal del cliente con TLS y reglas CHLAUTH.
Este laboratorio usa el usuario administrativo de la imagen de desarrollo MQ para que el ejercicio permanezca enfocado en el nuevo comando PCF.
4. Requisitos del laboratorio
Use una máquina de desarrollo con:
- Docker Engine o Docker Desktop
- Docker Compose v2
- Al menos 4 GB de memoria libre
- Acceso a través de internet a
icr.io - Un host AMD64 Linux, o Docker Desktop en Apple silicon con emulación AMD64 habilitada
El laboratorio fija la imagen de desarrollo del IBM MQ 10.0:
icr.io/ibm-messaging/mq:10.0.0.0-r2Fijar la imagen mantiene el ejercicio repetible. MQCMD_INQUIRE_ERROR_LOG está disponible porque el Queue Manager es más reciente que el nivel mínimo 9.4.5.
5. Crear el directorio del laboratorio
Cree un proyecto vacío:
mkdir -p "$HOME/mq-pcf-error-log-lab/config" \
"$HOME/mq-pcf-error-log-lab/client"
cd "$HOME/mq-pcf-error-log-lab"Registre la imagen en el archivo .env:
cat > .env <<'EOF'
MQ_IMAGE=icr.io/ibm-messaging/mq:10.0.0.0-r2
EOFObtenga explícitamente:
set -a
. ./.env
set +a
docker pull --platform linux/amd64 "$MQ_IMAGE"
docker run --rm --platform linux/amd64 \
--entrypoint dspmqver "$MQ_IMAGE"Confirme que el resultado indica el IBM MQ 10.0.0.0.
6. Configurar el Queue Manager
La imagen de desarrollo MQ puede aplicar las instrucciones MQSC durante la creación del Queue Manager. Defina una cola de prueba y use el canal administrativo preconfigurado de la imagen.
Cree config/20-config.mqsc:
cat > config/20-config.mqsc <<'MQSC'
DEFINE QLOCAL(LAB.EVENTS) DESCR('Queue used by the PCF error-log lab')
MQSCEl canal DEV.ADMIN.SVRCONN y la identidad admin son creados por la imagen de desarrollo cuando MQ_ADMIN_PASSWORD se proporciona.
La imagen del servidor MQ contiene una JVM, pero no contiene javac. Compile el cliente con una imagen JDK y obtenga el JAR all-client del IBM y sus dependencias transitivas de la runtime de Maven Central.
Cree el archivo client/pom.xml:
cat > client/pom.xml <<'XML'
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>mq-pcf-error-log-client</artifactId>
<version>1.0.0</version>
<properties>
<mq.client.version>10.0.0.0</mq.client.version>
</properties>
<dependencies>
<dependency>
<groupId>com.ibm.mq</groupId>
<artifactId>com.ibm.mq.allclient</artifactId>
<version>${mq.client.version}</version>
</dependency>
</dependencies>
</project>
XMLCree el archivo client/Dockerfile:
cat > client/Dockerfile <<'DOCKERFILE'
FROM maven:3.9.11-eclipse-temurin-21
ARG MQ_CLIENT_VERSION=10.0.0.0
COPY pom.xml /tmp/mq-client/pom.xml
RUN mvn -q -f /tmp/mq-client/pom.xml dependency:copy-dependencies \
-Dmq.client.version=${MQ_CLIENT_VERSION} \
-DincludeScope=runtime \
-DoutputDirectory=/opt/mq
WORKDIR /work
ENTRYPOINT ["/bin/bash", "-lc"]
CMD ["sleep infinity"]
DOCKERFILECree el archivo compose.yaml:
cat > compose.yaml <<'YAML'
services:
mq:
image: ${MQ_IMAGE:-icr.io/ibm-messaging/mq:10.0.0.0-r2}
platform: linux/amd64
hostname: mq
environment:
LICENSE: "accept"
MQ_QMGR_NAME: "LOGQM"
MQ_ADMIN_PASSWORD: "passw0rd"
MQ_APP_PASSWORD: "passw0rd"
ports:
- "1414:1414"
- "9443:9443"
volumes:
- qmdata:/mnt/mqm
- ./config/20-config.mqsc:/etc/mqm/20-config.mqsc:ro
healthcheck:
test: ["CMD-SHELL", "dspmq -m LOGQM | grep -q 'STATUS(Running)'"]
interval: 5s
timeout: 5s
retries: 40
pcf-client:
build:
context: ./client
args:
MQ_CLIENT_VERSION: "10.0.0.0"
profiles: ["tools"]
entrypoint: ["/bin/bash", "-lc"]
command: ["sleep infinity"]
volumes:
- ./client:/work
working_dir: /work
depends_on:
mq:
condition: service_healthy
volumes:
qmdata:
YAMLInicie el Queue Manager:
docker compose up -d mq
docker compose ps
docker compose logs --tail 40 mqConfirme la versión del MQ del contenedor en ejecución:
docker compose exec mq dspmqver7. Crear el cliente Java PCF
El programa soporta tres argumentos:
ErrorLogReader [log-name] [after-isotime] [cursor-file]- Sin argumentos, obtiene todo el
AMQERR01.LOG log-namepermite seleccionarAMQERR01,AMQERR02oAMQERR03after-isotimehabilita la recuperación incrementalcursor-filealmacena el último timestamp devuelto por el MQ
Cree el archivo client/ErrorLogReader.java:
cat > client/ErrorLogReader.java <<'JAVA'
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Hashtable;
import com.ibm.mq.MQException;
import com.ibm.mq.MQQueueManager;
import com.ibm.mq.constants.CMQC;
import com.ibm.mq.constants.CMQCFC;
import com.ibm.mq.headers.pcf.PCFMessage;
import com.ibm.mq.headers.pcf.PCFMessageAgent;
public final class ErrorLogReader {
private static final String HOST = env("MQ_HOST", "mq");
private static final int PORT = Integer.parseInt(env("MQ_PORT", "1414"));
private static final String CHANNEL = env("MQ_CHANNEL", "DEV.ADMIN.SVRCONN");
private static final String QMANAGER = env("MQ_QMGR", "LOGQM");
private static final String USER = env("MQ_USER", "admin");
private static final String PASSWORD = env("MQ_PASSWORD", "passw0rd");
private static String env(String name, String fallback) {
String value = System.getenv(name);
return value == null || value.isBlank() ? fallback : value;
}
public static void main(String[] args) throws Exception {
String logName = args.length > 0 ? args[0] : "AMQERR01.LOG";
String afterIsoTime = args.length > 1 ? args[1] : null;
Path cursorFile = args.length > 2 ? Path.of(args[2]) : null;
Hashtable<String, Object> properties = new Hashtable<>();
properties.put(CMQC.HOST_NAME_PROPERTY, HOST);
properties.put(CMQC.PORT_PROPERTY, PORT);
properties.put(CMQC.CHANNEL_PROPERTY, CHANNEL);
properties.put(CMQC.USER_ID_PROPERTY, USER);
properties.put(CMQC.PASSWORD_PROPERTY, PASSWORD);
properties.put(CMQC.TRANSPORT_PROPERTY, CMQC.TRANSPORT_MQSERIES_CLIENT);
MQQueueManager queueManager = null;
PCFMessageAgent agent = null;
try {
queueManager = new MQQueueManager(QMANAGER, properties);
agent = new PCFMessageAgent(queueManager);
PCFMessage request = new PCFMessage(CMQCFC.MQCMD_INQUIRE_ERROR_LOG);
request.addParameter(CMQCFC.MQCACF_ERROR_LOG_NAME, logName);
if (afterIsoTime != null && !afterIsoTime.isBlank()) {
request.addParameter(
CMQCFC.MQCACF_ERROR_LOG_AFTER_ISOTIME,
afterIsoTime
);
}
PCFMessage[] responses = agent.send(request);
String lastIsoTime = null;
for (PCFMessage response : responses) {
String record = optionalString(
response,
CMQCFC.MQCACF_ERROR_LOG_RECORD
);
if (record != null) {
System.out.print(record);
if (!record.endsWith(System.lineSeparator())) {
System.out.println();
}
}
String responseTime = optionalString(
response,
CMQCFC.MQCACF_ERROR_LOG_ISOTIME
);
if (responseTime != null && !responseTime.isBlank()) {
lastIsoTime = responseTime;
}
}
if (lastIsoTime != null) {
System.err.println("LAST_ISOTIME=" + lastIsoTime);
if (cursorFile != null) {
Files.writeString(
cursorFile,
lastIsoTime + System.lineSeparator(),
StandardCharsets.UTF_8,
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING
);
}
}
} catch (MQException e) {
System.err.printf(
"MQ failure: completionCode=%d reasonCode=%d%n",
e.completionCode,
e.reasonCode
);
throw e;
} finally {
if (agent != null) {
agent.disconnect();
}
if (queueManager != null && queueManager.isConnected()) {
queueManager.disconnect();
}
}
}
private static String optionalString(PCFMessage message, int parameter) {
try {
return message.getStringParameterValue(parameter);
} catch (Exception absent) {
return null;
}
}
}
JAVA8. Compilar el cliente en Docker
Inicie el contenedor del cliente PCF:
docker compose --profile tools up -d pcf-clientEste paso es necesario para el resto del laboratorio. El perfil tools mantiene el contenedor del cliente fuera de la inicialización inicial del Queue Manager. Habilitarlo aquí compila e inicia el entorno que proporciona javac, la JVM Java y las bibliotecas cliente del IBM MQ. Solo necesita ejecutar el comando nuevamente después de apagar o eliminar el contenedor.
Confirme que el JDK y el JAR all-client se obtuvieron y están presentes:
docker compose exec pcf-client javac -version
docker compose exec pcf-client \
find /opt/mq -name '*.jar' -printCompile el programa Java:
docker compose exec pcf-client bash -lc '
javac -cp "/opt/mq/*" \
ErrorLogReader.java
'El contenedor del cliente está separado del Queue Manager. Su directorio /work es el directorio client del host, y su conexión con mq(1414) atraviesa la red Compose a través del canal MQI DEV.ADMIN.SVRCONN.
9. Obtener el log de error activo
Ejecute el cliente:
docker compose exec pcf-client bash -lc '
java -cp ".:/opt/mq/*" \
ErrorLogReader AMQERR01.LOG
'La salida estándar contiene el texto devuelto del Queue Manager. El error estándar termina con un cursor similar a:
LAST_ISOTIME=2026-07-22T10:15:00.123456ZEl comando no montó /mnt/mqm del contenedor del Queue Manager. Obtuvo el log a través de una conexión cliente MQ autenticada y una solicitud PCF.
Para efectos de comparación, inspeccione el archivo localmente dentro del contenedor del Queue Manager:
docker compose exec mq \
tail -40 /var/mqm/qmgrs/LOGQM/errors/AMQERR01.LOGEl texto devuelto por el PCF debe corresponder al log de error del Queue Manager.
10. Generar un evento diagnóstico
Cree un canal SENDER cuyo destino sea la puerta TCP local intencionalmente cerrada 1. Iniciarla producirá una falla de conexión de canal en el lado del servidor que será tratada por el Queue Manager.
docker compose exec -T mq runmqsc LOGQM <<'MQSC'
DEFINE QLOCAL(BAD.XMITQ) USAGE(XMITQ)
DEFINE CHANNEL(BAD.SDR) CHLTYPE(SDR) TRPTYPE(TCP) XMITQ(BAD.XMITQ) CONNAME('127.0.0.1(1)') SHORTTMR(30) SHORTRTY(3) LONGRTY(0)
START CHANNEL(BAD.SDR)
MQSC
sleep 5Confirme que el canal está esperando para intentar de nuevo (retry):
docker compose exec -T mq runmqsc LOGQM <<'MQSC'
DISPLAY CHSTATUS(BAD.SDR) ALL
MQSCEl resultado esperado es STATUS(RETRYING). SHORTTMR(30) deja un intervalo de 30 segundos entre intentos cortos, mientras que SHORTRTY(3) permite un máximo de tres intentos. Esto da tiempo suficiente para ejecutar el comando de exhibición después de la espera de cinco segundos.
Obtenga nuevamente el contenido del log:
docker compose exec pcf-client bash -lc '
java -cp ".:/opt/mq/*" \
ErrorLogReader AMQERR01.LOG
'Busque un mensaje de conexión de canal referenciando BAD.SDR o 127.0.0.1(1), junto con sus secciones de explicación y acción. Los identificadores exactos del mensaje AMQ pueden variar con la plataforma y el tiempo de falla.
11. Implementar recolección incremental
Descargar repetidamente todo el log activo es desperdiciar recursos. El timestamp de la respuesta permite que un recolector pida solo registros a partir o después de su último punto de verificación.
Comience capturando un cursor:
docker compose exec pcf-client bash -lc '
java -cp ".:/opt/mq/*" \
ErrorLogReader AMQERR01.LOG "" last-isotime.txt \
> first-read.log
'
cat client/last-isotime.txtPare y reinicie el canal SENDER a fin de generar otro evento diagnóstico del Queue Manager:
docker compose exec -T mq runmqsc LOGQM <<'MQSC'
STOP CHANNEL(BAD.SDR) MODE(FORCE)
START CHANNEL(BAD.SDR)
MQSC
sleep 5Use el cursor guardado en la siguiente solicitud:
CURSOR=$(tr -d '\r\n' < client/last-isotime.txt)
docker compose exec pcf-client bash -lc "
java -cp \".:/opt/mq/*\" \
ErrorLogReader AMQERR01.LOG '$CURSOR' last-isotime.txt \
> incremental-read.log
"
cat client/incremental-read.log
cat client/last-isotime.txtEl IBM MQ aplica semántica de comparación "mayor-o-igual" al timestamp. Por tanto, el registro en el punto de verificación puede aparecer nuevamente. Un recolector en producción debe ser idempotente: retenga información suficiente para suprimir un registro de frontera duplicado o acepte duplicados y deduplique los a jusante.
Nunca avance el cursor almacenado antes que todos los fragmentos de respuesta PCF hayan sido procesados exitosamente. De lo contrario, una falla entre actualizar el cursor y persistir los registros puede crear una brecha de monitorización.
12. Seleccionar un log por nombre
El IBM MQ escribe errores actuales del Queue Manager en el log AMQERR01.LOG. En AIX, Linux y Windows, cuando ese archivo alcanza su límite de rotación, datos más antiguos se mueven a AMQERR02.LOG y AMQERR03.LOG.
El laboratorio no produjo datos de error suficientes para rodar el log y por tanto el AMQERR02.LOG aún no existe. Para obtener el archivo activo ejecutamos:
docker compose exec pcf-client bash -lc '
java -cp ".:/opt/mq/*" \
ErrorLogReader AMQERR01.LOG
'En un Queue Manager donde la rotación ocurrió, usamos el mismo comando con AMQERR02.LOG o AMQERR03.LOG. Un resultado vacío para cualquier nombre puede simplemente significar que el archivo correspondiente aún no fue creado.
Son válidos solo los tres nombres de log de error del Queue Manager. El comando no es un lector de archivos remoto genérico, lo cual es una parte importante de su límite de seguridad.
13. Diseño de recolector en producción
Un recolector útil es más que un loop que imprime texto. Tenga en cuenta estas consideraciones:
| Consideración | Orientación para producción |
|---|---|
| Checkpointing | Almacene un cursor por Queue Manager y nombre de log. Actualice solo después de todos los fragmentos retornados hayan sido entregados. |
| Rotación | Consultar solo AMQERR01.LOG puede perder registros si el archivo rota mientras un recolector está offline. Monitoree Queue Managers continuamente y defina una política de recuperación que pueda inspeccionar AMQERR02.LOG cuando un cursor no esté situado en el log activo. |
| Tratamiento de duplicados | Como la comparación AfterIsoTime es inclusiva, haga la ingestión a jusante idempotente. Los timestamps pueden no identificar únicamente un registro de error. |
| Back pressure | Cada respuesta puede contener hasta 1 MB de texto. Procese o envíe respuestas tan rápidamente como la API del cliente permite y aplique límites razonables en memoria, re-intentos y buferización de salida. |
| Seguridad | Use una identidad de monitorización dedicada; conceda +ctrl solo donde la recuperación de log es necesaria; habilite TLS con validación de pares; cree reglas CHLAUTH para el recolector; proteja credenciales o use autenticación basada en tokens; y aplique controles de red alrededor del canal administrativo. |
| Parsing | La respuesta PCF contiene texto de log en bruto. Preserve el texto original para diagnóstico. Si campos estructurados son necesarios, efectúe parsing a jusante y retenga el registro fuente para que cambios en el parser no destruyan evidencias. |
14. Solución de problemas
El comando no es reconocido
Confirme que la versión MQ del Queue Manager es IBM MQ 9.4.5 o posterior:
docker compose exec mq dspmqverMantenga las bibliotecas PCF del cliente en un nivel actual compatible.
Reason Code 2035
MQRC_NOT_AUTHORIZED significa que la identidad de conexión, mapeo de canal o autoridades de objeto son insuficientes. Verifique:
- El usuario que llega al Queue Manager después del mapeo efectuado por reglas de autenticación de canal (CHLAUTH)
- Autorizaciones
+connect,+inqy especialmente+ctrlen el Queue Manager - Accesos necesarios para que la mensaje PCF y sus respuestas lleguen a los destinos
- Si una identidad privilegiada está bloqueada por reglas de canal
No deshabilite autenticación de canal como corrección permanente.
No aparece ningún registro nuevo
No todo error del lado del cliente crea una entrada en el log de error del Queue Manager. Una falla que ocurre antes de alcanzar el MQ, como resolución DNS o conexión TCP rechazada, es local al cliente. Efectúe la generación de una falla que alcance el Queue Manager y luego inspeccione directamente el log del contenedor y el AMQERR01.LOG.
Salida incremental repite una entrada
Esto es consistente con el comportamiento de comparación "mayor-o-igual" usado para los timestamp. Remueva el registro de frontera o tolere a jusante.
El contenedor de herramientas sale inmediatamente
Inicie con el perfil Compose usado en el artículo:
docker compose --profile tools up -d pcf-client15. Qué demuestra el laboratorio
El resultado importante no es simplemente la obtención del log a partir de un cliente Java. El laboratorio establece un modelo operacional:
- El recolector se conecta a través del cliente MQ
- Las autorizaciones del MQ controlan el acceso
- El comando expone solo logs de error del Queue Manager
- Resultados grandes son retornados como múltiples respuestas PCF
- Un timestamp proporcionado por el servidor soporta recolección incremental
- El recolector no necesita acceso al host ni a datos compartidos
16. Documentación útil
- What's new in IBM MQ 9.4.5 for Multiplatforms
MQCMD_INQUIRE_ERROR_LOGrequestMQCMD_INQUIRE_ERROR_LOGresponse- Error logs on AIX, Linux, and Windows
- Introduction to IBM MQ Programmable Command Formats
17. Limpieza del entorno
Pare los contenedores y remueva el volumen del Queue Manager:
cd "$HOME/mq-pcf-error-log-lab"
docker compose --profile tools down -vRemueva los archivos del laboratorio cuando ya no sean necesarios:
cd "$HOME"
rm -rf "$HOME/mq-pcf-error-log-lab"