Heuristiques personnalisées
Nous utilisons le terme heuristiques pour désigner des algorithmes simples et robustes servant à détecter des problèmes tels qu’une utilisation élevée du CPU ou le click rage. Nous allons ici prendre un exemple pour comprendre comment fonctionnent les heuristiques, comment créer votre propre détecteur et voir ses résultats dans les DevTools.
Modèles
Section titled ModèlesUn modèle pour les heuristiques se trouve dans le chemin openreplay/backend/pkg/handlers/custom.
package custom
import . "openreplay/backend/pkg/messages"
type CustomHandler struct {
lastTimestamp uint64
}
func (h *CustomHandler) Handle(message Message, messageID uint64, timestamp uint64) Message {
h.lastTimestamp = timestamp
return nil
}
func (h *CustomHandler) Build() Message {
return nil
}
Une fois la méthode de l’heuristique créée, elle peut être ajoutée en modifiant le fichier main.go dans le chemin
openreplay/backend/cmd/heuristics, en important le module personnalisé et en ajoutant la fonction personnalisée au handler du processeur de messages.
package main
import (
"log"
"openreplay/backend/internal/config/heuristics"
"openreplay/backend/pkg/handlers"
web2 "openreplay/backend/pkg/handlers/web"
"openreplay/backend/pkg/intervals"
logger "openreplay/backend/pkg/log"
"openreplay/backend/pkg/messages"
"openreplay/backend/pkg/queue"
"openreplay/backend/pkg/queue/types"
"openreplay/backend/pkg/sessions"
"os"
"os/signal"
"syscall"
"time"
// Import custom modules here
)
func main() {
log.SetFlags(log.LstdFlags | log.LUTC | log.Llongfile)
// Load service configuration
cfg := heuristics.New()
// HandlersFabric returns the list of message handlers we want to be applied to each incoming message.
handlersFabric := func() []handlers.MessageProcessor {
return []handlers.MessageProcessor{
// web handlers
&web2.ClickRageDetector{},
&web2.CpuIssueDetector{},
&web2.DeadClickDetector{},
&web2.MemoryIssueDetector{},
&web2.NetworkIssueDetector{},
&web2.PerformanceAggregator{},
// Add custom handlers here
}
}
...
}
Exemple Quick Return
Section titled Exemple Quick ReturnPour cet exemple, nous allons créer l’heuristique Quick Return, qui enverra un signal chaque fois que nous revenons à la même url en moins de cinq secondes. La méthode mise en œuvre pour détecter un tel événement tirera parti des événements SetPageLocation et MouseClick. Chaque fois que survient un clic de souris, nous mettons à jour l’horodatage actuel et, si un message SetPageEvent est reçu dans les cinq secondes suivantes en pointant vers la page web actuelle, alors nous renvoyons un événement QuickReturn.
Pour commencer, créons le fichier quickreturn.go dans le chemin openreplay/backend/pkg/handlers/custom contenant le code présenté ci-dessous
package custom
import (
"log"
"encoding/json"
. "openreplay/backend/pkg/messages"
)
type QuickReturnDetector struct {
timestamp uint64
currentPage string
lastPage string
}
type CustomPayload struct {
Timestamp uint64 `json:"timestamp"`
CurrentPage string `json:"current_page"`
}
// If received SetPageLocation on same
func (h *QuickReturnDetector) HandleSetPageLocation(msg *SetPageLocation, messageID uint64, timestamp uint64) Message {
if (h.timestamp + 5000 >= msg.NavigationStart && h.lastPage == msg.URL) {
h.timestamp = msg.NavigationStart
return h.Build()
}
h.lastPage = h.currentPage
h.currentPage = msg.URL
h.timestamp = msg.NavigationStart
return nil
}
// detect when a button is clicked (selector must have string 'button' in it)
func (h *QuickReturnDetector) HandleMouseClick(msg *MouseClick, messageID uint64, timestamp uint64) {
h.timestamp = timestamp
}
func (h *QuickReturnDetector) Handle(message Message, messageID uint64, timestamp uint64) Message {
switch msg := message.(type) {
case *SetPageLocation:
if msg.NavigationStart != 0 {
return h.HandleSetPageLocation(msg, messageID, timestamp)
}
case *MouseClick:
h.HandleMouseClick(msg, messageID, timestamp)
}
return nil
}
func (h *QuickReturnDetector) Build() Message {
payload := &CustomPayload{
CurrentPage: h.currentPage,
Timestamp: h.timestamp,
}
payloadData, err := json.Marshal(payload)
if err != nil {
log.Println("JSON encoding error", err)
return nil
}
payloadString := string(payloadData)
event := &CustomEvent {
MessageID: 122,
Timestamp: h.timestamp,
Name: "quickreturn",
Payload: payloadString,
}
return event
}
Maintenant que l’heuristique est créée, il ne reste plus qu’à l’activer. Pour ce faire, nous devons ajouter l’heuristique au fichier main.go dans le chemin openreplay/backend/cmd/heuristics comme suit :
package main
import (
"log"
"openreplay/backend/internal/config/heuristics"
"openreplay/backend/pkg/handlers"
web2 "openreplay/backend/pkg/handlers/web"
"openreplay/backend/pkg/intervals"
logger "openreplay/backend/pkg/log"
"openreplay/backend/pkg/messages"
"openreplay/backend/pkg/queue"
"openreplay/backend/pkg/queue/types"
"openreplay/backend/pkg/sessions"
"os"
"os/signal"
"syscall"
"time"
// Add custom module
custom "openreplay/backend/pkg/custom"
)
func main() {
log.SetFlags(log.LstdFlags | log.LUTC | log.Llongfile)
// Load service configuration
cfg := heuristics.New()
// HandlersFabric returns the list of message handlers we want to be applied to each incoming message.
handlersFabric := func() []handlers.MessageProcessor {
return []handlers.MessageProcessor{
// web handlers
&web2.ClickRageDetector{},
&web2.CpuIssueDetector{},
&web2.DeadClickDetector{},
&web2.MemoryIssueDetector{},
&web2.NetworkIssueDetector{},
// The new handler
&custom.QuickReturnDetector{},
}
}
...
}
L’heuristique est désormais disponible et les messages sont envoyés sous forme de Custom Event. Notez que vous devrez redéployer votre back-end avant de pouvoir tirer parti de la nouvelle heuristique. Pour ce faire, suivez les étapes de la section build and deploy de la page deploy from source.
Utiliser l’événement personnalisé
Section titled Utiliser l’événement personnaliséMaintenant que votre heuristique personnalisée envoie un nouvel événement personnalisé, la prochaine chose à faire est d’utiliser cet événement d’une manière ou d’une autre. Avec l’exemple précédent, vous avez deux options :
- Vous pouvez filtrer les sessions par événement personnalisé, en veillant à ne lister que celles qui présentent ce « problème » (dans notre cas, le problème du quick return).
- Vous pouvez trouver l’événement dans l’onglet Events de la section DevTools du lecteur. Ainsi, vous pouvez identifier le moment exact où l’événement est déclenché.
Filtrer les sessions par événement personnalisé
Section titled Filtrer les sessions par événement personnaliséPour filtrer les sessions par votre nouvel événement personnalisé, utilisez simplement la fonctionnalité Omnisearch, en cliquant sur la barre de recherche et en sélectionnant « Custom Events » comme type de filtre. Une fois cela fait, vous pourrez saisir le nom de l’événement ; il devrait s’autocompléter dès que vous commencez à taper, comme vous pouvez le voir dans l’image ci-dessous :

Notez que si l’autocomplétion ne fonctionne pas ou ne renvoie pas le nom de l’événement que vous recherchez, alors il n’existe aucun événement portant ce nom dans la base de données. Dans ce cas, vous devriez revérifier votre logique pour vous assurer que vous déclenchez correctement l’envoi de l’événement personnalisé.
Trouver l’événement personnalisé dans les DevTools
Section titled Trouver l’événement personnalisé dans les DevToolsSi vous voulez comprendre exactement quand l’événement personnalisé est déclenché, vous devrez rejouer une session et cliquer sur l’onglet « Events » des DevTools. Vous le trouverez situé dans le coin inférieur droit de l’écran. Une fois cliqué, il s’ouvrira et vous verrez la liste des événements, y compris le vôtre personnalisé, comme on le voit dans l’image ci-dessous :

Dans ce processus simple, nous avons créé un nouveau détecteur. Bien entendu, votre algorithme peut être plus sophistiqué et inclure une combinaison de différents types d’événements.
Des questions ?
Section titled Des questions ?Si vous rencontrez des problèmes, connectez-vous à notre Slack ou consultez notre Forum et obtenez de l’aide de notre communauté.