Envoyer des logs applicatifs Symfony vers Slack avec Monolog

Publié le 14/03/2019 • Actualisé le 14/05/2020

Dans cet article nous allons voir comment envoyer des logs d'une application Symfony vers Slack. Une utilisation typique est de transmettre les erreurs critiques en temps réel pour pouvoir réagir rapidement en cas de problèmes. Nous pouvons bien sûr aussi envoyer d'autres types de notifications. C'est parti ! 😎


English language detected! 🇬🇧

  We noticed that your browser is using English. Do you want to read this post in this language?

Read the english version 🇬🇧 Close

» Publié dans "Une semaine Symfonique 637" (du 11 au 17 mars 2019).

[14/05/2020]: Mise à jour pour Monolog 3.5, les loggeurs peuvent désormais être autowirés (🇬🇧 auto-wired).

Configuration

Le code que vous voyez étant directement celui utilisé par ce projet Symfony, vous êtes sûr qu'il est à jour. Si vous utilisez Symfony 4.4 / 3.4, vous aurez à faire quelques adaptations pour utiliser le fichier parameters.yml au lieu du fichier .env pour les paramètres. Vous aurez aussi à déclarer le service logger. Cet article utilise les composants suivants :

  • PHP 8.3
  • Symfony 6.4.6

Configuration de l'API Slack

Quand j'ai commencé à écrire ce tutoriel, j'utilisais encore une vieille clé API. Faisons cela dans les règles de l'art. La première chose à faire est de créer une application Slack.
Accédez à cette page (loggez vous au préalable) et cliquez sur le bouton . Remplissez le formulaire, choisissez l'espace de travail voulu et validez. Votre application Slack est désormais créée.
Maintenant nous devons lui donner les droits de publier des messages sur une chaine. Ce doit être fait sur la page Features > OAuth & Permissions. Allez à la section Scopes, cliquez sur et sélectionnez les droits suivants :

  • chat:write
  • chat:write.public

Enfin, cliquez sur le bouton .

PS : Attention, si c'est une chaîne privée, il faudra aussi donner le droit chat:write:user.

Pour que nous puissions consommer cette API nous avons besoin d'un jeton OAuth. Pour le récupérer, cliquez sur le lien "Install app" dans le menu de gauche. Il se présente sous le forme: xoxp-1111111-22222222-33333333-aaaaaaaaaaaaaaaaaaaaaa.
Dans votre fichier .env ajoutez le paramètre SLACK_TOKEN :

SLACK_TOKEN=xoxp-1111111-22222222-33333333-aaaaaaaaaaaaaaaaaaaaaa

Dans le fichier .env.dist ajoutez aussi cette clé. Ici, j'aime mettre comme valeur l'URL du service ou ce jeton peut-être récupéré ou modifié. Cela permet de gagner du temps quand on aura oublié comment y accéder 🤔. Changez l'id d'application factice avec celui de votre application. C'est une chaine de neuf caractères, il est présent dans l'URL de la page ou vous pouvez le récupérer sur la page Basic Information > Credential, c'est le paramètre APP ID.

SLACK_TOKEN=https://api.slack.com/apps/ABCDEFGHI/install-on-team

Ne commitez jamais une clé d'API !

La configuration côté Symfony

Maintenant que la configuration au niveau Slack a été faite. Voyons comment l'interfacer avec notre application Symfony. Tout d'abord, veuillez créer un fichier config/packages/monolog.yaml. Comme les environnements sont en général très différents entre la prod et le dev, il n'y a pas de configuration commune à tous les environnements. Nous allons en utiliser une ici afin de simplifier la configuration. Ajouter la configuration suivante :

# config/packages/monolog.yaml
parameters:
    slack_token: '%env(SLACK_TOKEN)%'
    slack_bot_name: '@@slack'
    slack_channel: '#strangebuzz'

monolog:
    channels: ['strangebuzz'] # Change the channel name with your own one

Nous introduisons plusieurs paramètres : Le jeton que nous venons de créer, nous le récupérons de l'environnement, le nom de bot qui sera utilisé pour publier les messages et la chaîne sur laquelle ils vont être publiés. Enfin nous introduisons une chaine spécifique. Nous y reviendrons un peu plus tard. Maintenant que nous avons défini ces paramètres, modifions notre configuration monolog de prod. En effet, localement nous n'en avons pas besoin. Ouvrez votre fichier config/packages/prod/monolog.yaml et ajouter les deux handlers dans la section Slack (ce fichier est celui utilisé par ce site) :

# config/packages/prod/monolog.yaml
monolog:
    handlers:
        main:
            type: fingers_crossed
            action_level: critical
            handler: nested
            excluded_http_codes: [404, 405]
        nested:
            type: stream
            path: "%kernel.logs_dir%/%kernel.environment%.log"
            level: debug
        console:
            type:   console
            process_psr_3_messages: false
            channels: ["!event", "!doctrine"]

        # Slack ————————————————————————————————————————————————————————————————

        # Critical errors only
        slack_errors:
            type:        slack
            token:       '%slack_token%'
            channel:     '%slack_channel%'
            bot_name:    '%slack_bot_name%'
            icon_emoji:  ':ghost:' # 👻
            level:         critical
            include_extra: true

        # Application's messages
        slack:
            type:        slack
            token:       '%slack_token%'
            channel:     '%slack_channel%'
            bot_name:    '%slack_bot_name%'
            icon_emoji:  ":heavy_check_mark:" # ✅
            level:       debug
            include_extra: true
            channels:    ['strangebuzz']

Comme vous pouvez le voir nous introduisons deux nouveaux handlers. Le premier va être responsable de transmettre les erreurs critiques vers Slack et le deuxième va permettre d'envoyer toutes sortes de messages. (avertissements ou autres). Dans les deux cas nous utilisons les paramètres que nous avons introduits dans le fichier principal de configuration. Jetez un coup d'œil à la configuration complète du handler Slack.

Utilisation

Maintenant que la configuration est en place, testons tout cela. Comme nous avons uniquement modifié l'environnement de production, nous devons donc aussi l'utiliser localement afin de pouvoir tester. Dans le fichier .env, changez la valeur de la clé APP_ENV avec la valeur prod et... n'oubliez pas de vider le cache ! Maintenant, dans un contrôleur, levez une exception, par exemple :

throw new \RuntimeException('Hello Ghost!');
Une exception Symfony affichée dans Slack

C'est ce que vous allez voir sur votre chaîne Slack quand il y a aura une erreur critique. Notez que l'émoji 👻 est celui que nous avons configuré dans le paramètre icon_emoji de notre handler.
PS : Si vous voulez inclure d'autres données dans ces logs, jetez un coup d'œil à ce snippet.

Maintenant que le handler d'erreur fonctionne correctement, voyons comment utiliser le deuxième. Ici, nous allons logger quelque chose à la demande. Voyons comment utiliser ce deuxième handler dans un contrôleur. Examinons le code suivant (vous trouverez aussi une action basique permettant de provoquer une erreur critique) :

<?php

declare(strict_types=1);

// src/Controller/SlackController.php

namespace App\Controller;

use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

/**
 * Slack debugging stuff.
 */
#[Route(path: '/slack', name: 'slack_')]
final class SlackController extends AbstractController
{
    /**
     * This is a mini action to test the "slack_errors" Monolog hanlder.
     * The final route is: /slack/testError.
     */
    #[Route(path: '/testError', name: 'test_error')]
    public function testError(): Response
    {
        throw new \RuntimeException('Hello Ghost! 👻');
    }

    /**
     * This is a mini action to test the "slack" Monolog hanlder.
     * The final route is: /slack/testInfo.
     */
    #[Route(path: '/testInfo', name: 'test_info')]
    public function testInfo(LoggerInterface $strangebuzzLogger): Response
    {
        $strangebuzzLogger->info('This is an example for the blog post! Check! ✅');

        return $this->json(['success' => true]);
    }
}

Comme vous pouvez le voir nous injectons un service logger dans l'action de notre contrôleur (nous aurions aussi pu l'injecter directement dans le contructeur de la classe). Depuis Monolog 3.5, le service peut être autowiré. Pour voir les loggeurs disponibles, lancer la commande suivante dans votre terminal :

php bin/console debug:autowiring logger

Si vous ne pouvez pas utiliser l'auto-wiring, vous pouvez explicitement identifier (bind) l'argument $strangebuzzLogger dans notre fichier services.yaml pour que l'application sache quelle instance du service injecter quand elle trouve un argument avec ce nom :

# config/services.yaml
services:
    _defaults:
        bind:
            $strangebuzzLogger: '@monolog.logger.strangebuzz'

Accédez à l'adresse /slack/testInfo et le message devrait apparaître sur votre chaîne Slack. L'affichage est ici plus concis puisqu'il n'y a pas à afficher les informations relatives à une exception.


Une message applicatif affiché dans Slack

Bien sûr vous pouvez utiliser tous les niveaux de log fournit par l'interface PSR-3.

Et voilà ! J'espère que vous avez aimé. Découvrez d'autres informations en rapport à cet article avec les liens ci-dessous. Comme toujours, retours, likes et retweets sont les bienvenus. (voir la boîte ci-dessous) À tantôt ! COil. 😊

 L'API Slack  La doc Symfony  Plus sur Stackoverflow

Ils m'ont donné leurs retours et m'ont aidé à corriger des erreurs et typos dans cet article, un grand merci à : Dan_borisov. 👍

  Travaillez avec moi !


A vous de jouer !

Ces articles vous ont été utiles ? Vous pouvez m'aider à votre tour de plusieurs manières : (cf le tweet à droite pour me contacter )

  • Me remonter des erreurs ou typos.
  • Me remonter des choses qui pourraient être améliorées.
  • Aimez et retweetez !
  • Suivez moi sur Twitter
  • Inscrivez-vous au flux RSS.
  • Cliquez sur les boutons Plus sur Stackoverflow pour me faire gagner des badges "annonceur" 🏅.

Merci d'avoir tenu jusque ici et à très bientôt sur Strangebuzz ! 😉

COil