unicaen/livelog
Module Le module unicaen/livelog
propose une solution pour afficher des logs "en live" dans le navigateur web,
çàd au fur et à mesure qu'ils sont "publiés".
Ceci est réalisé à l'aide de :
- un
Logger
Monolog affublé d'unLiveLogSocketLogHandler
qui envoie chaque ligne de log à une socket Unix ; - une socket Unix recevant chaque ligne de log envoyée par le
LiveLogSocketHandler
et les passant à une websocket ; - une websocket envoyant aux clients (navigateurs) connectés et identifiés chaque ligne de log.
Installation
composer require unicaen/livelog
Configuration
Copiez le fichier config/unicaen-livelog.local.php.dist
dans le répertoire config/autoload
de votre appli sans
son extension .dist
, exmeple :
cp -n vendor/unicaen-livelog/config/unicaen-livelog.local.php.dist config/autoload/unicaen-livelog.local.php
'unicaen-livelog' => [
/**
* Configuration de la websocket.
*/
'websocket' => [
/**
* Adresse "privée" à laquelle écoute la websocket.
*/
'private_url' => '0.0.0.0:7443',
/**
* Adresse "public" à laquelle la websocket est accessible par les clients (navigateurs).
* Dans cet exemple, un navigateur web pourrait se connecter à l'adresse 'wss://serveur.unicaen.fr/livelog'.
*/
'public_url' => '/livelog',
/**
* Mode verbeux ou pas.
*/
'verbose' => false,
],
/**
* Configuration de la socket.
*/
'socket' => [
/**
* Chemin de la socket Unix.
*/
'path' => 'unix:///tmp/unicaen_livelog.sock',
/**
* Mode verbeux ou pas.
*/
'verbose' => false,
],
Lancement des sockets
Pour lancer la websocket et la socket en mode verbeux, ouvrez un terminal et lancez ceci en tant que root :
runuser -u www-data -- php public/index.php unicaen-livelog run-sockets --verbose 1
Si vous rencontrez l'erreur suivante, supprimez la socket Unix (ex : rm /tmp/unicaen_livelog.sock
) :
RuntimeException
Failed to listen on Unix domain socket "unix:///tmp/unicaen_livelog.sock": Unknown error
Test de la socket
Pour tester la socket, ouvrez un 2e terminal et lancez ceci :
runuser -u www-data -- php public/index.php unicaen-livelog test
Et vous devriez voir dans le terminal de lancement un truc qui ressemble à ça :
[socket]> DATA {"formatted":"[2022-02-01T15:09:39.070488+01:00] mylogger.INFO: Ceci est un test \u00e0 2$ ! D'ac ? ~ % [] []\n","clientId":"client_61f93f2312813"}
[websocket]> SEND : Stop, client client_61f93f2312813 inconnu !
Où l'on voit que la socket reçoit bien le message de test mis en forme par le logger (date, etc.)
On voit ensuite que la websocket se plaint qu'elle ne connait pas le client client_61f93f2312813
.
C'est normal : seuls les clients (navigateurs) disposant d'un identifiant officiel fourni par l'application sont
reconnus et peuvent recevoir les logs.
Test de la websocket
Avant de pouvoir tester la websocket, il faut configurer Apache.
Plus difficile de tester la websocket si ce n'est en ouvrant une page de votre appli qui établie une connexion.
C'est possible d'utiliser websocat
(https://github.com/vi/websocat).
Inspirez-vous de cette commande pour vous connecter à la websocket :
websocat --insecure --protocol "livelog" 'wss://localhost.unicaen.fr:8003/livelog?client=client_1234'
Ensuite tapez au clavier Un message de log !
suivi de la touche "Entrée" puis "CTRL+C" pour stopper websocat
.
Vous devriez voir dans le terminal de lancement un truc qui ressemble à ça :
[websocket]> OPEN : client_1234
[websocket]> MESSAGE : un message de log !
[websocket]> CLOSE : client_1234
Configurer Apache
Pour que la websocket soit accessible depuis un navigateur web, il faut faire un peu de config Apache.
- Le module
proxy_wstunnel
doit être activé, exemple :
a2enmod proxy_wstunnel
- L'URL d'accès à la websocket (ex :
wss://localhost.unicaen.fr:8003/livelog
) doit être accessible de façon sécurisée, voici un exemple de conf à mettre dans/etc/apache2/conf-available/livelog.conf
:
# Websocket pour unicaen/livelog.
# ==> accessible de l'extérieur à l'adresse wss://serveur.unicaen.fr/livelog
SSLProxyEngine On
ProxyPass /livelog ws://0.0.0.0:7443
ProxyPassReverse /livelog ws://0.0.0.0:7443
NB : 0.0.0.0:7443
doit correspondre à la clé 'private_url'
que vous avez spécifiée dans la config du module ;
idem pour /livelog
et la clé 'public_url'
.
- Ensuite, cette conf doit être activée :
a2enconf livelog
Code
Côté contrôleur
Exemple d'une page "voir" (action voirAction
) affichant les caractéristiques d'un import de données et contenant
un bouton "Lancer l'import" (action lancerAction
).
L'action lancerAction
lance l'import via un service qui utilise un Logger
pour produire des logs.
Ce sont ces lignes de logs que l'on veut afficher au fur et à mesure qu'elles sont produites.
ImportController.php
use Laminas\Mvc\Controller\AbstractActionController;
use Monolog\Logger;
use UnicaenLiveLog\Log\LivelogSocketLogHandler;
class ImportController extends AbstractActionController
{
use LivelogSocketLogHandlerAwareTrait;
public function voirAction(): array
{
//...
}
public function lancerAction(): bool
{
//...
$logger = new Logger('livelog');
$logger->pushHandler($this->livelogSocketHandler);
$this->importService->setLogger($logger);
$result = $this->importService->runImport($import);
return false;
}
//...
}
ImportControllerFactory.php
use Psr\Container\ContainerInterface;
use UnicaenLivelog\Log\LivelogSocketLogHandler;
class ImportControllerFactory
{
function __invoke(ContainerInterface $container): ImportController
{
$controller = new ImportController();
$livelogSocketHandler = $container->get(LivelogSocketLogHandler::class);
$controller->setLivelogSocketHandler($livelogSocketHandler);
//...
return $controller;
}
}
Notez bien le LivelogSocketLogHandler
injecté dans le contrôleur puis branché sur un Logger
afin que
chaque ligne de log soit envoyée à la socket.
Côté vues
Dans la vue voir.phtml
associée à voirAction
, vous aurez typiquement un bouton déclenchant l'opération dont
les logs vous intéressent. Vous devez intercepter le clic sur ce bouton afin de lancer la requête en mode AJAX
(car il faut rester sur la page courante afin de voir les logs !) On le fait dans cet exemple uniquement lorsque la
connexion à la websocket peut être établie, permettant ainsi de retomber sur le fonctionnement non-AJAX éventuelelement
supporté.
Exemple :
<a class="btn btn-warning"
id="lancer"
href="<?php echo $this->url(
'unicaen-db-import/import/lancer',
['name' => $import->getName()]
) ?>"><span class="fas fa-play"></span> Lancer l'import</a>
<script>
$(function() {
// `conn` est de type `WebSocket` (https://developer.mozilla.org/fr/docs/Web/API/WebSocket)
let conn = $("#livelog-div").data('conn');
conn.addEventListener('open', function(e) {
$("#lancer").on('click', function(event) {
let trigger = $(this).addClass('disabled');
$.get(trigger.attr("href"), function() {
trigger.removeClass('disabled');
});
});
});
});
</script>
Vous devez créer le conteneur dans lequel s'afficheront les logs (et quelques autres petites choses) avec l'aide de vue fournie par le module.
<?php
/** @var \UnicaenLivelog\View\Helper\LivelogPanelHelper $livelogPanelHelper */
$livelogPanelHelper = $this->plugin('livelogPanel');
$livelogPanelHelper->setDivId($divId = 'livelog-div');
echo $livelogPanelHelper;
?>
Une pincée de style, peut-être :
<style>
.livelog-panel {
line-height: normal;
font-family: monospace;
font-size: 9px;
border: 2px grey dotted;
height: 300px;
overflow-y: scroll;
overflow-x: scroll;
white-space: nowrap;
padding: 0.5em;
margin-top: 1em;
}
</style>
Dans un navigateur web, lorsque vous vous rendez sur la page correspondant à voirAction
, vous devriez voir une
div contenant un message du genre :-) Connexion WebSocket OK
si la connexion à la websocket a pu être établie
(ou :-( Connexion WebSocket KO
dans le cas contraire).
Lorsque vous cliquez sur le bouton "Lancer" (ou équivalent), des lignes de logs devraient
s'afficher les unes sous les autres au fur et à mesure qu'elles sont produites dans lancerAction
.
NB : Pas de vue lancer.phtml
associée à lancerAction
puisqu'elle est requêtée en mode AJAX.