# Zeedhi ZhuLog

Zeedhi ZhuLog é uma biblioteca PHP que possibilita o log de requisições e respostas em aplicações Zeedhi, utilizando os eventos predefinidos pelo Zeedhi\Framework\Application.
Sendo eles: preDispatchEvent, postDispatchEvent e onExceptionEvent.

## Instalação
* Para adicionar a biblioteca pelo composer execute o comando `composer require zeedhi/zhulog` ou adicione a linha `zeedhi/zhulog: ^4` nas dependências do seu composer.json.

* Agora é necessário adicionar a configuração dos serviços do log no projeto. Existem dois arquivos *xml* de configuração de serviços: **log.xml** e **services.xml**.
    * **log.xml** é utilizado para persistir os logs. Toda configuração sobre a manipulação e persistência dos logs será realizada nesse arquivo.
    * **services.xml** é o arquivo de configuração para visualização dos logs.

* Agora também é necessário o arquivo de rotas:
    * **routes.json**, necessário para ver e configurar o log.

É importante, caso seu projeto modifique o evento preDispatch, ou possua dependencias que o modifique, copiar a chamada do método de adição do listener do log.

Também existe o arquivo **bootstrap.php** que inclui os dois arquivos *xml* e o arquivo *json* acima.

* O ZhuLog depende de uma implementação da interface *LoggerInfoProvider* encontrada em **Zeedhi\ZhuLog\Logger\LoggerInfoProvider**. Essa interface é responsável por salvar dados adicionais, para mais informações [clique aqui][LOGGER_PROVIDER_CONFIG].
* Com a interface implementada, precisamos criar um serviço no arquivo de configuração de dependências chamado **LoggerInfoProvider** com a implementação da interface de *LoggerInfoProvider* criada no passo anterior.

Para que o ZhuLog funcione por completo (backend e frontend) é necessário possuir dataSources das tabelas *OPERADOR* e *ORGANIZATION*. Estas, foram escolhidas visto o *Padrão Teknisa*.

E também a adição, no seu produto, das rotas que acessem esses dataSources. É importante que seus *paths* sejam **/operador** e **/organization**.

## Opções de configurações
### Dados de usuário e contexto
O Zhu Log armazena dados de usuário autenticado no sistema e dados de contexto, como nome do container e da widget que fizeram a requisição. É possível salvar qualquer string com até 4000 caracteres.

Interface LoggerInfoProvider
 * É recomendado salvar os dados como string JSON para facilitar o uso de filtros.

Para definir o valor salvo é necessário utilizar o serviço **LoggerInfoProvider**, esse serviço possui os métodos **getUserId**, **getOrganizationId**, **getProductId**, **getContainerName** e **getWidgetName** que devem retornar os dados a serem salvos.

Interface *[LoggerInfoProvider][LOGGER_PROVIDER_CLASS]*:
**getUserId() : String**
**getOrganizationId() : String**
**getProductId() : String**
**getContainerName() : String**
**getWidgetName() : String**

## Opções de funcionamento

### Modos de persistência
O Zhu Log possui uma interface de persistência que pode ser implementada para alterar o local de armazenamento do Log. Atualmente, existe apenas uma implementação [MultiRowSQL][MULTI_ROW_SQL_PERSISTENCE], utilizando banco de dados Oracle.

Interface *[PersistenceInterface][PERSISTENCE_INTERFACE]*:
**logRequest**(*string* $method, *string* $route, *string* $requestType, *string* $userData, *string* $contextData, *string* $content): *void*
**logResponse**(*string* $httpResponseCode, *string* $content): *void*

A implementação padrão é a *MultiRowSQL*, nela as requisições e respostas são salvas separadamente em múltiplas linhas.

Os scripts de criação das tabelas no banco de dados para utilização do log podem ser encontradas abaixo:

[ZH_LOG][ZH_LOG_CREATE]
[ZH_LOG_USER_CONF][ZH_LOG_USER_CONF_CREATE]
[ZH_LOG_PRODUCT_CONF][ZH_LOG_PRODUCT_CONF_CREATE]

### Processamento do log
O ZhuLog possui uma interface utilizada pelo logger para alterar o conteúdo das requisições e respostas. Alterando essa dependência é possível ignorar rotas, datasets muito grandes ou arquivos, ou o que seu produto precisar.

Interface *[Processor][PROCESSOR_INTERFACE]*:
**processRequest**(*array* $request, *string* $route, *string* $method): *array*
**processResponse**(*array* $response): *array*

Atualmente existem três implementações: [DefaultProcessor][DEFAULT_PROCESSOR], [SkipFilesProcessor][SKIP_FILES_PROCESSOR] e [CompositeProcessor][COMPOSITE_PROCESSOR].

Class **[DefaultProcessor][DEFAULT_PROCESSOR]**:
Processor utilizado para ignorar rotas e manter, compactar ou ignorar dataSets.
**__construct**(*array* $routesToSkip, int $responseDataSetPolicy = **self::KEEP_DATA_SET**, int $requestDataSetPolicy = **self::KEEP_DATA_SET**);

*array* **$routesToSkip**:
Lista de rotas que não devem ser incluídas no log.

*int* **$responseDataSetPolicy**:
Política utilizada ao processar as respostas.
Valores válidos:

* **KEEP_DATA_SET**: Manter dataSet original
* **COMPACT_DATA_SET**: Salvar apenas a quantidade de rows do dataSet
* **REMOVE_DATA_SET**: Remover dataSet

*int* **$requestDataSetPolicy**:
Política utilizada ao processar as requisições.
Valores válidos:

* **KEEP_DATA_SET**: Manter dataSet original
* **COMPACT_DATA_SET**: Salvar apenas a quantidade de rows do dataSet
* **REMOVE_DATA_SET**: Remover dataSet

Class **[SkipFilesProcessor][SKIP_FILES_PROCESSOR]**:
Processor utilizado para ignorar arquivos enviados.
**__construct**(*array* $fileRoutes);

*array* **$fileRoutes**:
Lista de rotas que podem possuir arquivos


Class **[CompositeProcessor][COMPOSITE_PROCESSOR]**:
Processor utilizado para juntar múltiplos processors.
A classe foi criada com base no design pattern Composite, para mais informações sobre esse padrão [clique aqui][COMPOSITE_DOC].
**__construct**(*Processor* $firstProcessor, *Processor* $secondProcessor);

*Processor* **$firstProcessor**:
Primeiro processor para ser executado.

*Processor* **$secondProcessor**:
Segundo processor para ser executado.

A implementação padrão é *CompositeProcessor*, utilizando *DefaultProcessor*, ignorando a rota de log e compactando os dataSets de resposta, e *SkipFilesProcessor*, ignorando as rotas especificadas em **%upload_routes%**, como dependência.

Para implementar seu próprio processor, crie uma classe implementando a interface *[Processor][PROCESSOR_INTERFACE]* e crie os métodos **processRequest** e **processResponse**. Com a implementação pronta, adicione sua classe no seu arquivo de dependências.

## Usabilidade e configuração da camada de visão

[ZhuLogFrontend][ZHU_LOG_FRONTEND]

[ZHU_LOG_FRONTEND]: http://code.zeedhi.com/zeedhi/zhulogfrontend/tree/master
[LOGGER_PROVIDER_CONFIG]: #op-es-de-configura-es
[PERSISTENCE_INTERFACE]: src/Logger/Persistence/PersistenceInterface.php
[PROCESSOR_INTERFACE]: src/Logger/Processor/Processor.php
[MULTI_ROW_SQL_PERSISTENCE]: src/Logger/Persistence/MultiRowSQL.php
[ZH_LOG_CREATE]: scripts/ZH_LOG_CREATE.sql
[ZH_LOG_USER_CONF_CREATE]: scripts/ZH_LOG_USER_CONF_CREATE.sql
[ZH_LOG_PRODUCT_CONF_CREATE]: scripts/ZH_LOG_PRODUCT_CONF_CREATE.sql
[DEFAULT_PROCESSOR]: src/Logger/Processor/DefaultProcessor.php
[SKIP_FILES_PROCESSOR]: src/Logger/Processor/SkipFilesProcessor.php
[COMPOSITE_PROCESSOR]: src/Logger/Processor/CompositeProcessor.php
[COMPOSITE_DOC]: https://en.wikipedia.org/wiki/Composite_pattern
