Agora a gente vai para o passo 3 da implementação da instrumentação do login. Nós vamos utilizar o Logback para fazer essa implementação, a biblioteca do Logback. O conhecimento que a gente implementar pode ser replicado para o Log4j ou outra biblioteca, mas aqui a gente vai utilizar o log4j por simplicidade mesmo, para facilitar o entendimento. São duas bibliotecas aqui que a gente vai usar até o final aqui da implementação de Login. O Logback core, que tem as funcionalidades mais relevantes, importantes ali do Logback, que é a parte mais fundamental, a receita de log, alguma formatação, alguns componentes que a gente vai olhar aqui na prática. E o segundo é um complemento, e aí ele segue o conceito de extensão, que é uma ferramenta que estende as funcionalidades do Logstash, especificamente para coisas mais como formatar o resultado dado em formato JSON, por exemplo, que o Logback no Core não suporta e você poder implementar utilizando uma ferramenta mais tenso. O legal dessa implementação é que você também pode implementar, estender o Logback e criar os seus componentes customizados, os seus app, a gente vai olhar aqui na prática, desde que, é importante que você siga as boas práticas, simplesmente utilizando uma biblioteca, enfim, é importante que encapsule isso em uma biblioteca, sem deixar de utilizar o Logback, mas com alguma customização. Vamos começar primeiro importando a dependência do logback. Depois a gente implementa o do encoder aqui que a gente vai usar do Logstash. A gente vai na aplicação, põe o XML. Eu vou colocar logo no topo, eu faço isso, eu gosto de colocar essas dependências no final, mas só para garantir aqui, só para facilitar o entendimento, eu vou colocar no topo com evidência. O foco aqui é mais observabilidade. Coloquei, inclusive, com comentário para facilitar. Eu já tenho a biblioteca importada no meu Maven Cache local, então, por isso que não está vermelhinho, mas se você estiver aparecendo vermelho aqui, você vai precisar baixar, ela vai baixar automático, enfim, ou você pode vir aqui no Maven e atualizar, ou dar um run aqui em Maven Clean Install, ele vai baixar essa dependência. Vamos fazer até uma tangente antes de partir para a implementação do encoder. Vamos ver aos poucos o resultado dessa implementação do encoder, vamos ver aos poucos o resultado dessa implementação. Eu implementei o logback aqui, e a gente vai lá no passo 5 antes, depois a gente vai fazer o passo 5 completo, mas vamos utilizar aqui já uma formatação, vamos começar a aplicar a formatação no log, já utilizando o logback. Uma das formas de formatar o log de saída é utilizando um arquivo chamado logback.xml, que vai na pasta resources. Eu já implementei aqui uma versão reduzida, sem as funcionalidades, por exemplo, de conversão em formato JSON, etc. Mas para explicar e simplificar aqui o processo. Então, é o arquivo aqui, eu tenho ele na íntegra, eu tenho uma versão minificável dele apenas para facilitar o entendimento. Vou voltar aqui no passo 3, só para a gente não continuar dele depois. Então, o que eu tenho aqui no arquivo logback? A estrutura mais importante do arquivo logback é formada basicamente aqui, o configuration tem os appenders, os appenders, e eu tenho a tag root level, perdão, a tag root. E dentro da tag root eu tenho as configurações do appenderev. Essas são as tags mais importantes da configuração do Logback. Os Appenders são a, vamos dizer assim, a configuração dos objetos, das classes, dos componentes que vai, de fato, converter os eventos. Converter os eventos de log que são chegados através dessas interfaces do 4G. Converter esses eventos no formato são chegados através dessas interfaces da 4G, converter esses eventos no formato de saída que você customizar aqui. E aí que está a mágica da implementação de bibliotecas como o Login Back. Imagina se você tivesse que implementar isso na aplicação e trazer toda essa complexidade para a aplicação. O VC Appender tem ele tem um name, esse name você que diz, pode colocar qualquer nome aqui, mas o nome faça sentido, porque lá embaixo a gente vai referenciar esse nome e a classe que ele vai utilizar. Essa classe, eu deveria passar o caminho completo dela aqui. Aqui, por exemplo. Eu estou passando apenas o nome porque eu posso utilizar esse artifício que são as tags de import e eu posso dizer para o LogBack importar esses módulos em tempo de execução para que ele... Se eu tivesse mais desses appenders, eu não precisaria ficar repetindo o nome da classe. Isso vale também para dentro, por exemplo, aqui no encoder tem um pattern, já vamos chegar nele. Aí, por exemplo, essa classe appender, ela é uma classe mesmo, utilizando o mecanismo de engenharia reversa do intagj, eu vou acessar a classe aqui apertando F3, eu posso ir na classe file appender lá que está no pacote do Logback Core. E aí ela está toda essa implementação. Imagina trazer essa complexidade para a aplicação. Ou trazer para o time essa complexidade, enfim, de customizar. Inclusive ela está na versão 1.5.6. Então, enfim, já é bastante utilizada, tem um uso bastante difundido. Não faz sentido você trazer essa complexidade. Eu tenho uma variável adicional, por exemplo, timestamp, que eu posso utilizar essa variável ao longo aqui do meu logback, ao longo da configuração. Exemplo, se eu estou utilizando um file appender, eu tenho que especificar o caminho do arquivo, e aqui já no caminho do arquivo eu posso dizer se eu quero utilizar, interpolar o nome do arquivo O timestamp Eu poderia simplesmente dizer Que não ia usar nenhum Nenhum campo adicional Mas aqui eu estou dizendo o seguinte Utilize o timestamp como parte do nome E aqui eu estou até utilizando Um pattern específico Estou utilizando para gravar os logs com o formato ano, mês, dia, de timing, e aí eu quero que ele grave por minuto, hora e minuto. Então ele vai logar o arquivo application, traço, na pasta logs, dentro da aplicação, na pasta logs, como eu estou passando um caminho específico aqui, ele vai logar dentro da pasta da minha aplicação na pasta logs como não passando um caminho específico aqui ele vai logar dentro da pasta da minha aplicação se eu tivesse rodando direto a partir do já ele logaria provavelmente no caminho relativo ao pasta já é um arquivo chamado application.trades do time stamp que tá nesse formato aqui dentro também do appender tem um encoder para mim esse provavelmente esse é o segundo maior segundo elemento mais é mais importante depois do aprender e do root é esse vai ao terceiro dentro do da classe aprendeu é o mais importante segundo nível de importância porque é ele que de fato vai converter ele ele vai ser chamado aqui pelo FileAppender e vai converter de fato os eventos que chegarem através aqui das interfaces no formato que você especificar aqui em Pattern. Eu estou utilizando o PatternLayoutEncoder, e como eu estou especificando esse PatternLayoutEncoder, esse encoder, se eu buscar na classe, ele espera um campo de pattern, e o pattern que eu vou especificar aqui é um pattern que ele está esperando, que ele sabe tratar. E aí, o que tem nesse pattern? Eu vou escrever no log, cada linha do log vai ser composta pelo timestamp, pela thread, pela identificação da thread que está chamando login, log error log debug, etc, o nível do log, o chamador a classe chamadora e a mensagem de saída e alguns casos aqui, por exemplo, separado por traço é talvez você se pergunte, nossa, mas como que eu, onde eu consulto essa informação para eu saber configurar melhor ou customizar esse pattern aí? No próprio documentação do Logback, se você acessar a documentação do Logback, você vai ter aqui, por exemplo, aqui em Documentation, Documentation, Logback Manual, Logback, enfim, o site ali, aqui dentro de Chapter 6, Layouts. E aí você tem toda a definição. Aqui ali do Pattern, desde configuração de tamanho, length, enfim, se você vai utilizar algum padrão de data, formato de data que você vai utilizar, exceção, etc. Então, você pode seguir a documentação oficial para saber como customizar aqui. Aqui eu coloquei esses elementos aqui de forma mais reduzida para simplificar. Eu tenho um appender de file e se eu quiser, por exemplo, escrever no sysout, no sysout, o console, por exemplo, no sisal tido no no sisal tido com o console por exemplo da aplicação eu consigo consegue se cria um aprender o nome de novo aqui eu chamei de este doutor em porque eu não tô te diria nenhuma formatação tô jogando a minha como como ela vier eu tô utilizando com só ela prender diferente do file apender eu estou usando o console apender dentro do console apender eu tenho um encoder de novo como eu estou usando o pattern eu vou precisar utilizar um pattern layout encoder e aqui até coloquei um pattern mais reduzido para simplificar mesmo e mostrar como que funciona e lá embaixo eu vou dizer root level inf, que é a tag de grande importância aqui, e qual appender que eu vou utilizar e habilitar. Nesse caso eu estou habilitando os dois, inclusive. Estou utilizando o file appender aqui, o file appender que está aqui, e o stdout que está aqui. Eu vou usar os dois em convivência. Uma coisa que vale acrescentar é o seguinte, é que tem essa configuração de log level, mas você pode customizar o NG log por certos pacotes. Eventualmente, eu vou mostrar isso na prática, mas, por exemplo, se a sua aplicação aloga informações de debug e você precisa habilitar, se você habilitar debug aqui ele vai habilitar para tudo, existe uma forma de você habilitar somente para aplicação, para um trecho específico, para um pacote específico no caminho de package do Java da aplicação que você quer usar. Por padrão aqui, seguindo a hierarquia, com info ele vai exibir. Se não tiver algo customizado, específico, ele vai exibir na hierarquia logs de info, logs de warning e logs de error. Se eu colocasse debug, ele ia exibir debug, info, warning, error e assim sucessivamente. Vamos dar um play, vamos ver como é que vai funcionar essa aplicação. Lembrando que a gente está no passo 3. Vamos executar essa aplicação, lembrando que a gente está no passo 3, vamos executar a aplicação, e enquanto ele vai subindo, é o seguinte, observe que aqui ele já até mudou o layout aqui, vamos deixar ele logar até completar, no file appender, eu comentei com você em um vídeo anterior que existe um conceito de buffering. E aqui eu estou instruindo, eventualmente, aqui eu estou instruindo o file appender utilizar hora e minuto e potencialmente ele vai, se ele entender que faz sentido, ele pode acabar fazendo um buffering por hora e minuto, inclusive. E aí quando ele precisa mudar, quando muda o minuto, ele faz o flush dos dados ali de fato para o arquivo. Mas vamos lá. Apareceu já os logs, observe que já veio um pouco mais reduzido. Então, como eu estou olhando para o console, está aparecendo a hora, no formato aqui, o level, se a infa, o warner apareceu ali, não teve nenhum erro por enquanto, vamos gerar um erro já já, e a mensagem aqui do log. Vamos ver como que ele gerou o log de, o log, ele não gerou nenhum, observa que ele não gerou nenhum porque ele está fazendo, ele está utilizando o buffering ali, enfim, provavelmente não está... Não virou o minuto ainda para ele disponibilizar esse log. Já vai aparecer. Opa, já apareceu lá. Foi bem na hora, apareceu lá. Já apareceu o log com o minuto 26. Está com o minuto 27. Quando chegar no minuto 28, ele vai gerar o arquivo 27 com os logs do 27. Olha lá, aqui tem mais eventos agora. Tem a timestamp ali. Aqui eu estou logando. Deixa eu relembrar como que eu estou fazendo. Eu estou exibindo também a thread, a thread main. A log level. A classe que fez a requisição, no caso aqui veio desse startup, porque são logs específicos, no caso aqui, por exemplo, específicos do Spring, o Catalina aqui, logs do pacote do Spring, e aqui a mensagem, o log e a mensagem que está exibindo vamos fazer uma requisição agora para ver o que vai acontecer, vou fazer uma requisição para criar uma nova order, vou fazer uma requisição de um produto válido, fazer algumas inclusive fazer uma requisição de um produto válido, perdão, de uma order válida, vou fazer uma requisição com uma order mas sem passar a lista de itens opa sem passar a lista de itens vou fazer de novo a requisição agora passando o produto inválido colocando um número que não tem beleza e aí vamos ver como isso refletiu no log vamos olhar primeiro no console, aqui em run, ó, tem aqui já algumas exceções, algumas receptions aqui, vamos começar lá de cima, já parado aqui, e aí ele exibiu, ó, beleza, inicializando o serverlet, e completando, e aqui, ó, esses aqui são os logs que a gente criou, request request new order request for order id, could not find a exceção vamos descer aqui request for order id com not find de novo, que eu chamei várias vezes aqui eu fui chamando várias vezes aqui eu tenho request for order id 1 para ele cadastrar uma ordem uma order, cria uma nova ah não, aqui eu consult request for a grande um para ele cadastrar uma ordem uma ordem é cria uma nova hora que eu consultei o order a gente foi com sucesso aqui uma nova ordem é aqui foi passando com a lista de itens em branco carrinho vazio e aí deu erro e assim por diante. Vamos ver como ficou o arquivo de log do minuto 26 aqui. Ele cadastrou lá, o not find order 22 e ficou até mais interessante aqui, a IDE está conseguindo até formatar legal os eventos aqui para a gente olhar os logs. E aí os próximos passos agora seriam implementar utilizando uma formatação e enriquecendo os logs com alguns dados específicos como do MDC para trazer dados de contexto.