Documentação do Job Logs Monitor¶
Visão Geral¶
O serviço Job Logs Monitor permite monitorar logs de execução de jobs.
Guia de Instalação¶
Nesta seção são descritos os requisitos, os passos para instalação e configuração do serviço Job Logs Monitor.
Requisitos¶
Para a execução do serviço Job Logs Monitor são necessárias as seguintes dependências:
Docker
Acesso de leitura ao diretório contendo os arquivos de logs
Instalação¶
O serviço Job Logs Monitor é executado via Docker, então é necessário que a imagem seja transferida para a máquina de execução. Ela está no repositório repo.tecgraf.puc-rio.br:18089 e no caminho soma/soma-job-logs-monitor. Assim para pegar a versão x.y.z o seguinte comando deve ser usado:
$ docker pull repo.tecgraf.puc-rio.br:18089/soma/soma-job-logs-monitor:x.y.z
Configuração¶
Algumas configurações são necessárias para executar o serviço.
Volumes¶
O seguinte volume deve ser definido e mapedo:
- /job_logs_root
Diretório raiz onde estão os arquivos de logs das execuções dos jobs.
Variáveis de ambiente¶
As seguintes variáveis de ambiente devem ser definidas para a execução do serviço:
- JOB_LOGS_MONITOR_SERVICES_PROJECTSERVICE_CLIENTBASEURL
URL para o servidor REST que será utilizado para verificar a permissão de acesso do usuário ao projeto. Valor de exemplo
http://localhost:8010/v1.- JOB_LOGS_MONITOR_PROJECT_PERMISSION_CHECK_ENABLE
Flag para ativar/desativar a verificação de permissão de acesso do usuário ao projeto. Valor padrão é
true.- JOB_LOGS_MONITOR_SERVICES_JOBSERVICE_CLIENTBASEURL
URL para o serviço que será utilizado para verificar se o job e o arquivo de log existem. Valor de exemplo
http://localhost:8089/v1.- JOB_LOGS__MONITOR_LOGSDIR_PATTERN
Padrão do caminho usado para localizar os arquivos de logs dos jobs. Os seguintes marcadores devem ser utilizados:
- __ROOT__
diretório raiz onde estão os arquivos de logs (o caminho deve sempre ter esse item no início)
- __PROJECT__
identificador do projeto
- __JOB__
identificador do job
Pode-se utilizar também texto para complementar o caminho. Por exemplo
__ROOT__/__PROJECT__/.cmds/__JOB__/logs.
Já as variáveis a seguir são opcionais e podem ser definidas para alterar a configuração padrão:
- JOB_LOGS_MONITOR_WATCHER_THREAD_POOL_SIZE
Tamanho do pool de threads responsável por processar os eventos de alteração de arquivos. Cada diretório monitorado tem o seu pool particular. O valor padrão para o tamanho do pool é
4.- JOB_LOGS_MONITOR_READER_MAX_LENGTH_SIZE
Tamanho padrão máximo, em bytes, do trecho do arquivo de log que será lido, em cada evento de alteração no arquivo. O valor padrão é
10485760(10 MB).- JOB_LOGS_MONITOR_READER_CHARSET_DEFAULT
Charset padrão usado para ler o conteúdo de arquivos de log quando a heurística de identificação do charset falhar/tiver baixa confiança. Valor padrão é
ISO-8859-1.- JOB_LOGS_MONITOR_WEBSOCKET_CORS_ORIGINS
Lista de origens – separadas por vírgula – aceitas usada pelo filtro CORS. Por exemplo
http://origin.com,http://www.origin.io. O valor padrão é*, indicando que qualquer origem é aceita.
Portas¶
A seguinte portas devem ser exportadas:
- 8090
Porta para acesso ao endpoint do serviço websocket.
Configurações avançadas¶
As seguintes variáveis de ambiente podem ser usadas para fazer configurações avançadas:
- JOB_LOGS_MONITOR_WEBSOCKET_PATH
Define o caminho da URL de acesso ao serviço. O valor padrão é
/v1/job_logs_monitor
Execução¶
Para executar deve-se usar o comando docker run com as seguintes opções:
- --user user_id:group_id
Executar informando o
UIDeGIDdo usuário que irá executar o serviço. Ele deve ter acesso de leitura ao diretório raiz onde estão dos arquivos de logs das execuções de jobs.- --restart=unless-stopped
Define a política de reinício do container Docker. O valor
unless-stoppedindica que o container deve ser reiniciado sempre, menos se ele foi parado antes do daemon Docker ter sido parado. Mais detalhes em Docker run reference:Restart policies.
e juntamente com a configuração definida. Segue exemplo de script para iniciar um container Docker usando a imagem do serviço Job Logs Monitor:
#!/bin/bash
REPO=repo.tecgraf.puc-rio.br:18089
IMAGE=soma/soma-job-logs-monitor
VERSION=x.y.z
WORKING_DIR=$(dirname "$PWD")
CONTAINER_NAME=soma-job-logs-monitor-${VERSION}
function start() {
docker run -d \
--name ${CONTAINER_NAME} \
-p 8090:8090 \
-v "/path/to/logs/root":/job_logs_root \
-e "JOB_LOGS_MONITOR_SERVICES_PROJECTSERVICE_CLIENTBASEURL=http://server:8010/v1" \
-e "JOB_LOGS_MONITOR_SERVICES_JOBSERVICE_CLIENTBASEURL=http://server:8089/v1" \
-e "JOB_LOGS__MONITOR_LOGSDIR_PATTERN=__ROOT__/__PROJECT__/.cmds/__JOB__/logs" \
--restart=unless-stopped \
--user "$(id -u "${USER}")":"$(id -g "${USER}")" \
${REPO}/${IMAGE}:${VERSION}
}
function stop() {
docker stop ${CONTAINER_NAME}
}
case "$1" in
start)
start
;;
stop)
stop
;;
*)
echo "Usage: ${0} {start|stop}"
;;
esac
Monitoramento¶
O serviço possui os endpoints de /healthz, /healthz/readiness e /healthz/liveness para monitorar o estado do serviço:
Liveness¶
Verifica se o serviço está ativo. A URL de acesso é http://<host>:<port>/healthz/liveness. Segue retorno esperado:
{
"status":"UP"
}
Readiness¶
Verifica se o serviço está pronto para receber requisições. A URL de acesso é http://<host>:<port>/healthz/readiness. Segue retorno esperado:
{
"status":"UP"
}
Healthz¶
Combina o retorno dos endpoints liveness e readiness. A URL de acesso é http://<host>:<port>/healthz. Segue o retorno esperado:
{
"status":"UP",
"components":{
"livenessState":{
"status":"UP"
},
"ping":{
"status":"UP"
},
"readinessState":{
"status":"UP"
}
},
"groups":[
"liveness",
"readiness"
]
}
API de Monitoração¶
A monitoração para captura das alterações dos arquivos de log pode ser feita observando os arquivos de log de interesse através da API do serviço Job Logs Monitor.
Inscrição para Notificação¶
Para receber as notificações das alterações, é necessário enviar uma mensagem com o comando SUBSCRIBE e o tópico de interesse. O tópico de logs de jobs é o jobLogs e deve conter o projeto, o job, o nó do fluxo e o nome do arquivo. Além disso, a mensagem deve ter o seqnum para indicar o “momento” do início das notificações. Segue a especificação da mensagem:
Message:
type: object
required:
- command
- subscriptionId
- topic
properties:
command:
$ref: "#/components/schemas/Command"
subscriptionId:
description: ID of the subscription (generated by the client).
type: string
topic:
oneOf:
- $ref: '#/components/schemas/Topic'
discriminator:
propertyName: topicType
mapping:
jobLogs: '#/components/schemas/JobLogTopic'
seqnum:
description: it’s a seqnum indicating the last state known to the client, thus only changes after the moment indicated by this seqnum shall be notified.
type: integer
format: int64
Command:
type: string
enum:
- SUBSCRIBE
- UNSUBSCRIBE
TopicType:
type: string
enum:
- jobLogs
Topic:
type: object
discriminator:
propertyName: topicType
required:
- topicType
properties:
topicType:
$ref: "#/components/schemas/TopicType"
JobLogTopic:
type: object
required:
- projectId
- jobId
properties:
topicType:
description: Type of the topic to subscribe or unsubscribe.
$ref: "#/components/schemas/TopicType"
projectId:
description: ID of the project which the job logs to be watched.
type: string
jobId:
description: ID of the job or group to be watched.
type: string
flowNodeId:
description: ID of the flow node to be watched.
type: integer
logName:
description: name of the log to be watched.
type: string
encoding:
description: optional encoding to be used to read the monitored log file. The supported encodes are US-ASCII, ISO-8859-1 e UTF-8. If an unsupported, an invalid or a null values is informed the default encoding will be used.
type: string
Exemplo de mensagem de SUBSCRIBE:
{
"command":"SUBSCRIBE",
"subscriptionId":"subId1",
"topic":{
"topicType":"jobLogs",
"projectId":"dXNlci9Qcm9qZWN0",
"jobId":"dXNlckBQcm9qLkVCT1A2SDIyTjU=",
"flowNodeId":0,
"logName":"log.out",
"encoding":"UTF-8"
},
"seqnum":0
}
Exemplo de mensagem de UNSUBSCRIBE:
{
"command":"UNSUBSCRIBE",
"subscriptionId":"subId1",
"topic":{
"topicType":"jobLogs",
"projectId":"dXNlci9Qcm9qZWN0",
"jobId":"dXNlckBQcm9qLkVCT1A2SDIyTjU=",
"flowNodeId":0,
"logName":"log.out"
}
}
Notificação de Alteração¶
Alterações nos arquivos de log são informadas através da mensagem Notification que contém o evento da notificação. Este evento contém as seguintes informações:
- jobId
identificador do job
- projectId
identificador do projeto
- logName
nome do arquivo de log
- chunks
array de chunk de dados – atualmente esse array tem apenas um elemento. Cada chunk é referente a um trecho dos dados enviados e possuem as seguintes informações:
- offset
deslocamento, a partir do início do arquivo de log, referente ao chunk (em bytes)
- length
tamanho referente ao chunk (em bytes)
- data
trecho de log enviado
- offset
deslocamento, a partir do início do arquivo de log, referente aos dados enviados (em bytes)
- length
tamanho dos dados enviados (em bytes)
- totalSize
tamanho total do arquivo de log (em bytes)
- fileEncoding
encoding usado para ler o arquivo
Segue a especificação da mensagem de notificação:
Notification:
type: object
required:
- subscriptionId
- topicType
- event
properties:
subscriptionId:
type: string
topicType:
$ref: "#/components/schemas/TopicType"
topicEvent:
oneOf:
- $ref: '#/components/schemas/TopicEvent'
discriminator:
propertyName: topicEventType
mapping:
jobLogsEvent: '#/components/schemas/JobLogsEventTopic'
TopicEventType:
type: string
enum:
- jobLogsEvent
TopicEvent:
type: object
discriminator:
propertyName: topicEventType
required:
- topicEventType
properties:
topicEventType:
$ref: "#/components/schemas/TopicEventType"
JobLogsEventTopic:
type: object
required:
- projectId
- jobId
- flowNodeId
- logName
- seqnum
- offset
- length
- fileEncoding
- chunks
properties:
topicType:
description: Type of the topic to subscribe or unsubscribe.
$ref: "#/components/schemas/TopicType"
projectId:
description: ID of the project which the job logs to be watched.
type: string
jobId:
description: ID of the job or group to be watched.
type: string
flowNodeId:
description: ID of the flow node to be watched.
type: integer
logName:
description: name of the log to be watched.
type: string
seqnum:
type: integer
format: int64
offset:
type: integer
format: int64
length:
type: integer
totalSize:
type: integer
format: int64
fileEncoding:
description: encoding used to read the file
type: string
chunks:
type: array
items:
$ref: "#/components/schemas/DataChunk"
DataChunk:
type: object
required:
- offset
- length
- data
properties:
offset:
type: integer
format: int64
length:
type: integer
data:
type: string
Segue exemplo de notificação retornada no formato JSON :
{
"subscriptionId": "subId1",
"topicType": "jobLogs",
"topicEvent": {
"topicEventType": "jobLogsEvent",
"projectId": "user/Project",
"jobId": "user@Proj.EBOP6H22N5",
"flowNodeId": 0,
"logName": "log.out",
"seqnum": 53,
"offset": 32,
"length": 21,
"totalSize": 53,
"fileEncoding": "UTF-8",
"chunks": [
{
"offset": 32,
"length": 10,
"data": "A"
},
{
"offset": 42,
"length": 11,
"data": "B"
}
]
}
}
Notificações de Erros¶
O serviço de monitoração enviará também mensagens de erro. As mensagens de erro seguem a seguinte especificação:
NotificationError:
type: object
Required:
- subscriptionId
- errorMessage
- errorType
- event
Properties:
subscriptionId:
type: string
errorMessage:
type: string
errorType:
$ref: "#/components/schemas/ErrorType"
errorEvent:
oneOf:
- $ref: "#/components/schemas/ErrorEvent"
Discriminator:
propertyName: errorTypeEvent
Mapping:
- invalidMessageError: "#/components/schemas/InvalidMessageErrorEvent"
- projectPermissionErrorEvent: "#/components/schemas/ProjectPermissionErrorEvent"
- missingFieldEvent: "#/components/schemas/MissingFieldErrorEvent"
- invalidFieldValue: "#/components/schemas/InvalidFieldErrorEvent"
- resourceError: "#/components/schemas/JobLogFileErrorEvent"
Components:
Schemas:
ErrorType:
type: string
Enum:
- InvalidMessageError
- ProjectPermissionError
- MissingFieldError
- InvalidFieldValueError
- JobLogFileError
GeneralErrorEvent:
type: object
Properties:
exceptionMessage:
description: A short error message description
type: string
ProjectPermissionErrorEvent:
type: object
Properties:
projectId:
description: A encoded base64 projectId
type: string
MissingFieldErrorEvent:
type: object
Properties:
fieldName:
description: The field name
type: string
InvalidFieldErrorEvent:
type: object
Properties:
fieldName:
type: string
fieldValue:
type: string
JobLogFileErrorEvent:
type: object
Properties:
details:
description: the exception error message details
type: string
Como exemplo, temos a seguinte mensagem de erro:
{
"subscriptionId": "subId1",
"errorMessage": "Error when monitoring job log file",
"errorType": "JobLogFileError",
"errorEvent": {
"details": "File /projects/admin/test/.cmds/admi_test_CBOI65RCUO/logs/out.log does not exists.",
}
}