Contents

Imagem docker JBoss EAP 6.4: Logs em JSON e stacktrace

Ativar o log no formato JSON na imagem docker do JBoss EAP 6.4. Também vamos mudar o formato que o stacktrace aparece no JSON.

Imagem oficial

As imagens docker oficiais podem ser obtidas no registry da RedHat, em registry.redhat.io.

# login
docker login -u USER registry.redhat.io

# listar as tags disponíveis
skopeo list-tags docker://registry.redhat.io/jboss-eap-6/eap64-openshift

Ativando o log JSON

Para ativar o log do JBoss no formato JSON, basta subir um container setando a variável de ambiente ENABLE_JSON_LOGGING para true.

# executar
docker run --rm \
  --env ENABLE_JSON_LOGGING=true \
  registry.redhat.io/jboss-eap-6/eap64-openshift:1.9

# ou se você quiser ver o JSON formatado
jq -R '. as $raw | try fromjson catch $raw' <(\
  docker run --rm \
    --env ENABLE_JSON_LOGGING=true \
    registry.redhat.io/jboss-eap-6/eap64-openshift:1.9 \
)

A partir disso cada linha do log da aplicação será parecida com isso:

{
  "@version": 1,
  "@timestamp": "2020-11-20T14:20:41-03:00",
  "sequence": 7229,
  "loggerClassName": "org.jboss.as.server.ServerLogger_$logger",
  "loggerName": "org.jboss.as",
  "level": "INFO",
  "message": "JBAS015874: JBoss EAP 6.4.20.GA (AS 7.5.20.Final-redhat-1) iniciado em 65151ms - Iniciado 16089 de serviços 16123 (os serviços 121 são lazy, passivos ou em demanda)",
  "threadName": "Controller Boot Thread",
  "threadId": 19,
  "mdc": {},
  "ndc": "",
  "log-handler": "CONSOLE"
}

Se houver exceção, o log será parecido com isso:

📋 Observar que cada linha do stacktrace ficou em um fragmento de JSON, o que pode deixar um pouco chato a visualização.

Podemos configurar para que o stacktrace da exception fique no formato padrão, de quando visualizamos no console.

Formato do stacktrace da exception no log

Vamos mudar para o formato tradicional, algo parecido com:

org.jboss.msc.service.StartException in service jboss.web.deployment.default-host./xxx: org.jboss.msc.service.StartException in anonymous service: JBAS018040: Falha ao iniciar o contexto
    at org.jboss.as.web.deployment.WebDeploymentService$1.run(WebDeploymentService.java:99)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
    at org.jboss.threads.JBossThread.run(JBossThread.java:122)
Caused by: org.jboss.msc.service.StartException in anonymous service: JBAS018040: Falha ao iniciar o contexto
    at org.jboss.as.web.deployment.WebDeploymentService.doStart(WebDeploymentService.java:168)
    at org.jboss.as.web.deployment.WebDeploymentService.access$000(WebDeploymentService.java:61)
    at org.jboss.as.web.deployment.WebDeploymentService$1.run(WebDeploymentService.java:96)
    ... 6 more

Não é possível simplesmente por meio de um parâmetro da imagem. Precisamos alterar o arquivo /opt/eap/standalone/configuration/logging.properties para configurar o formatter OPENSHIFT do log4j.

Visualizar o /opt/eap/standalone/configuration/logging.properties e observar a configuração do formatter.OPENSHIFT:

docker run --rm \
  registry.redhat.io/jboss-eap-6/eap64-openshift:1.9 \
  cat -n /opt/eap/standalone/configuration/logging.properties

Agora vamos criar um Dockerfile conforme abaixo, que vai configurar o formatter.OPENSHIFT para printar o stacktrace no formato que desejamos:

FROM registry.redhat.io/jboss-eap-6/eap64-openshift:1.9

# backup do arquivo original
RUN cp -a /opt/eap/standalone/configuration/logging.properties \
          /opt/eap/standalone/configuration/logging.properties.original

# adiciona a propriedade exceptionOutputType
RUN sed -i -E \
      's|^formatter.OPENSHIFT.properties=metaData$|formatter.OPENSHIFT.properties=metaData,exceptionOutputType|' \
      /opt/eap/standalone/configuration/logging.properties

# define exceptionOutputType=FORMATTED (default: DETAILED)
RUN echo -e \
      '\nformatter.OPENSHIFT.exceptionOutputType=FORMATTED' >> \
      /opt/eap/standalone/configuration/logging.properties

📋 As três linhas de RUN podem ficar em um único RUN. Estão separadas para melhorar a visualização.

Com o Dockerfile já criado, vamos construir a imagem:

docker build -t jboss:json .

Agora é só executar como já vimos anteriormente:

# executar
docker run --rm \
  --env ENABLE_JSON_LOGGING=true \
  jboss:json

# ou se você quiser ver o JSON formatado
jq -R '. as $raw | try fromjson catch $raw' <(\
  docker run --rm \
    --env ENABLE_JSON_LOGGING=true \
    jboss:json \
)

E se houver uma exceção, o log com o stacktrace será algo parecido com:

{
  "@version": 1,
  "@timestamp": "2020-11-21T11:18:28-03:00",
  "sequence": 7086,
  "loggerClassName": "org.jboss.msc.service.ServiceLogger_$logger",
  "loggerName": "org.jboss.msc.service.fail",
  "level": "ERROR",
  "message": "MSC000001: Failed to start service jboss.web.deployment.default-host./xxx",
  "threadName": "ServerService Thread Pool -- 107",
  "threadId": 237,
  "mdc": {},
  "ndc": "",
  "stackTrace": "org.jboss.msc.service.StartException in service jboss.web.deployment.default-host./xxx: org.jboss.msc.service.StartException in anonymous service: JBAS018040: Falha ao iniciar o contexto\n\tat org.jboss.as.web.deployment.WebDeploymentService$1.run(WebDeploymentService.java:99)\n\tat java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)\n\tat java.util.concurrent.FutureTask.run(FutureTask.java:266)\n\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\n\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\n\tat java.lang.Thread.run(Thread.java:748)\n\tat org.jboss.threads.JBossThread.run(JBossThread.java:122)\nCaused by: org.jboss.msc.service.StartException in anonymous service: JBAS018040: Falha ao iniciar o contexto\n\tat org.jboss.as.web.deployment.WebDeploymentService.doStart(WebDeploymentService.java:168)\n\tat org.jboss.as.web.deployment.WebDeploymentService.access$000(WebDeploymentService.java:61)\n\tat org.jboss.as.web.deployment.WebDeploymentService$1.run(WebDeploymentService.java:96)\n\t... 6 more\n",
  "log-handler": "CONSOLE"
}

📋 Agora todo o stacktrace é um único atributo no json.

Uma ferramenta como o Kibana vai mostrar o log acima formatado, algo parecido com:

/posts/2020-11-19-jboss-eap-docker-image-stacktrace-json-log/kibana-stacktrace.png.jpg

Ou você pode salvar o log acima para um arquivo e ver formatado, assim:

while read -r line; do echo -e $line; done <log.json

Referências