================================== 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: .. code-block:: console $ 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 ``UID`` e ``GID`` do 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-stopped`` indica 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: .. code-block:: bash #!/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://:/healthz/liveness``. Segue retorno esperado: .. code-block:: json { "status":"UP" } **Readiness** ------------- Verifica se o serviço está pronto para receber requisições. A URL de acesso é ``http://:/healthz/readiness``. Segue retorno esperado: .. code-block:: json { "status":"UP" } **Healthz** ----------- Combina o retorno dos endpoints ``liveness`` e ``readiness``. A URL de acesso é ``http://:/healthz``. Segue o retorno esperado: .. code-block:: json { "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: .. code-block:: yaml 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`: .. code-block:: json { "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`: .. code-block:: json { "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: .. code-block:: yaml 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 : .. code-block:: 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: .. code-block:: yaml 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: .. code-block:: json { "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.", } }