Enviando logs de exception pelo event bus (Discord e Slack)
Tags: flutter, dart, programming, tutorial
Published: 2023-09-09 04:14:38

Fala galera!
Depois de algum tempo sumido resolvi fazer esse post, pois passei por um desafio interessante que eu queria compartilhar.

Irei demonstrar como você pode emitir mensagem detalhada de log para o seu canal do Discord e até mesmo para uma thread do slack ou **ambos!** , somente passando uma exception específica para o seu sistema sem precisar se preocupar com nada!

---

Pois bem!
Qual será o nosso desafio:
Vamos fazer um aplicativo que rode até mesmo no Flutter Web com alguns botões, onde irá realizar uma consulta em uma  **API** com sucesso, um outro botão com algum problema de parse no nosso json e um outro com uma falha na url para simular uma falha da sua **API**.


## O que iremos utilizar

Vamos utilizar somente os packages:

- **[event_bus](https://pub.dev/packages/event_bus)**
- **[dio](https://pub.dev/packages/dio)**
- **[device_info_plus](https://pub.dev/packages/device_info_plus)**
- **[get_it](https://pub.dev/packages/get_it)**
- **[image_network](https://pub.dev/packages/image_network)**

---

O carinha diferente da vez é o event_bus, que eu não vejo muita gente usando. Então vou tentar dar uma breve descrição do que ele faz:

**event_bus** é uma biblioteca que facilita a comunicação entre diferentes partes de um aplicativo, permitindo que componentes ou classes enviem e recebam eventos (mensagens) de forma assíncrona. Ele é bem útil quando você precisa que componentes separados do seu aplicativo comuniquem-se de forma eficiente, especialmente quando eles não têm uma relação direta, no nosso caso uma **exception**!

Além disso, vamos usar o **device_info_plus** para poder mandar junto com o erro os dados do equipamento para análise de um possível problema e o **get_it** somente para injetar as dependências mais facilmente no nosso projeto. Vamos usar também o **image_network**, para mostrar as imagens na web, por conta do CORS!


## Criando nosso canal do Discord para receber a mensagem
Vamos criar nosso servidor no Discord, que por si só é realmente intuitivo, e após isso vamos criar um canal 

![Imagem da tela do discord](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/udyx43mxn7tg45s2es25.png)

depois de criado, vamos nas configurações do canal e vamos criar um bot

![Imagem de onde se cria o bot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l5nd96pn7yh8xlv8x9e3.png)

**Vamos copiar essa url para usar mais tarde!**

## Criando o projeto esqueleto

`flutter create --org="com.example.eventbus" --platforms=web,android -e --project-name=event_bus_exception  eventBusException`

feito isso vamos já adicionar os nossos packages de uso
`flutter pub add dio event_bus get_it device_info_plus image_network `


## Criando o caminho perfeito

Vamos iniciar o projeto criando os botões e as chamadas para as apis , deixando estourar os possíveis erros na tela para fazermos a correção posteriormente

Vamos iniciar 'de cima para baixo', iniciando a criação das chamadas das apis que vão ser consumidas pela aplicação

{%embed https://gist.github.com/brasizza/d482f05e99b64a75e5c331db15ac3528 %}

Teremos aqui somente 2 métodos, um com os dados corretos, e outro com um erro de parse no json para a transformação de objeto, para recebermos um erro e tratar


{%embed https://gist.github.com/brasizza/03938fc7585eb76812b503249e8ee087 %}

Sua implementação é extremamente intuitiva, já que o nosso intuito é somente mostrar como executar a exception


Temos também nosso **AlbumModel** que está sem nenhum problema

{%embed https://gist.github.com/brasizza/d3042c4e7b7257db7698c15852164199 %}

 e temos o **AlbumModelError**, onde eu coloquei propositamente o i do albumId minúsculo.

{%embed https://gist.github.com/brasizza/c0eb84ce052d8b71e28441848b528d65 %}

Feito isso, podemos construir nossa **MainController** com os métodos que serão chamados na página e vamos injetar nela o nosso repository **ApiCallImpl**

{%embed https://gist.github.com/brasizza/e529e8c0d2670bc411614833a9e545c5 %}
Iremos criar a exception que queremos que o event_bus dispare para o discord, então criaremos uma exception chamada **CriticalException**

{%embed https://gist.github.com/brasizza/e3b3c9e3c1d4d4fd87b546b5ff2c0054 %}
Por enquanto essa exception não faz absolutamente nada, mas logo isso vai mudar!

Iremos utilizar o **get_it** para injetar o nosso repository e a nossa controller e depois injetar a repository dentro da nossa controller para podermos fazer a chamada diretamente pela controller

 {%embed https://gist.github.com/brasizza/6662061a49bdc9679060ecb1dcabd2bf %}

Se você rodar o projeto do jeito que está agora, vai ver que ao clicar nos dois últimos botões só irá aparecer um erro no console de erro, mas SE a aplicação estiver em produção, dificilmente você irá conseguir pegar esse erro em um tempo hábil de correção. E é aí que o event_bus chega para ajudar a gente.

Como descrito acima, ele pode nos ajudar desacoplado do nosso sistema principal e ficar escutando certos eventos e executar alguma ação com esse evento, e o nosso caso vai ser disparar o erro para o Discord!

Vamos criar uma classe chamada **BroadcastController** que será encarregada de escutar o disparo do evento do **CriticalException**

Nela iremos injetar tudo que é importante para seu funcionamento, como o eventBus , a nossa classe que irá pegar os dados do device, e pra onde vamos enviar o nosso broadCast, que pode ser um ou vários!

## Criando a nossa classe de informação do dispositivo
Vamos criar uma classe  somente para pegar o modelo do equipamento que está acessando a aplicação, e no caso da web o user-agent:

{%embed https://gist.github.com/brasizza/0ff66a78ebbac2e8a7b14af98e5229fb %}


## Criando nosso primeiro channel

Vamos chamar de channel o remetente que vamos enviar nossa exception, e vamos inicialmente criar uma classe abstrata com um método chamado execute que será encarregado de enviar os dados para o channel escolhido e também um método de configure, para alguma configuração prévia no channel, como por exemplo no caso do slack, configurar para qual canal a mensagem será enviada.

{%embed https://gist.github.com/brasizza/1e8510856118842ba62df371b2ca4b45 %}


## Channel: **DiscordBroadcastImpl**

Nosso broadcast para o Discord, iremos injetar nele o Dio , para que possamos fazer o post na url que nós pegamos lá no começo do artigo. Nele não precisaremos fazer nenhuma configuração extra, pois o webhook já se encarrega de enviar para o lugar certo

{%embed https://gist.github.com/brasizza/6935bfcdc1f8e13706697272e70c0f98 %}

Agora vamos alterar o nosso main.dart para colocar o resto das injeções das dependencias no projeto

{%embed https://gist.github.com/brasizza/d38c158a098db25a950c4499b46bc89d %}


Se você rodou o projeto até aqui vai quer que .. não aconteceu absolutamente NADA, não foi pro discord e você já deve estar achando que eu estou enganando vc!

Faltou fazermos o principal, precisamos disparar o evento propriamente dito dentro da nossa exception

então vamos colocar o comando do nosso broadcast para fazer o acionamento do nosso listen lá no **BroadCastController**

{%embed https://gist.github.com/brasizza/725f67c7d2daf186120f5e60451f8c0a %}

e quando clicamos lá no botão de erro do parse do json para o objeto .. BANG!

![Erro emitido](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l6z9k9dk9o5ee2n2og2s.png)

e quanto clicamos no botão de falha do servidor

![Erro emitido](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xf689nx6fjc63ao3hovd.png)

## Criando o envio pro slack!
Como fomos pessoas precavidas e criamos uma classe abstrata para o nosso broadcast a **BroadcastBase**, a assim será extremamente rápida a criação de mais uma classe, mas dessa vez enviando para o slack!

Precisamos criar o canal do slack, e para isso precisamos criar e ir na área de webhooks e ativar a integração por lá


![Criando o canal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n4yapzkksdzycb7k9432.png)


![Selecionando o webhook](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lsr1zv49fe2wz77t9zhk.png)

Após a configuração o sistema irá te dar uma url para acessar o serviço de webhook do slack.

Vamos criar a nossa **SlackBroadCastImpl** implementando a **BroadcastBase** que nos obriga a implementar a **execute** e a **configure**
No caso do slack precisamos de uma configuração inicial, como por exemplo indicar o canal que vai ser emitida a mensagem e assim como a do Discord, também injetaremos o Dio para poder fazer a requisição na url indicada

{%embed https://gist.github.com/brasizza/81386fb16cbbf6892a3c73f5c4913f6f %}

## Como alterar a emissão entre o slack e o Discord?

Precisaremos fazer algumas modificações nas nossas injeções do main.dart. O principal é que como vamos injetar duas **BroadcastBase** precisaremos nomear nossas instâncias para que o **get_it** consiga recuperá-las.
Após isso no nosso **BroadcastController** que já espera uma lista, ou a gente inclui o slack junto ou escolhe entre eles, no nosso caso vou colocar os dois juntos para a mensagem chegar nos dois ao mesmo tempo, ficando assim:

{%embed https://gist.github.com/brasizza/de55851abf2b72351b02d1cb4f3155dd %}

Assim que a exception **CriticalException** for acionada no sistema, será enviado tanto para o Discord quanto para o slack


## Possibilidades (Ideias)

1. A exception pode chamar uma api sua que vai pro seu whatsapp

2. A exception pode emitir para o crashlytics

3. A exception pode emitir para o sentry

4. A exception pode gravar em um banco interno do seu aplicativo

e assim por diante. 

Espero que tenham gostado e segue o git abaixo!

{%embed https://github.com/brasizza/flutter-eventbus-exception %}