Filtrage des journaux OpenTelemetry

Le collecteur OpenTelemetry permet de filtrer les données de journal qu'il collecte de différentes manières. Ce document fournit des exemples de filtrage des journaux dans certains scénarios courants. Ces fonctions étant incluses uniquement dans le référentiel OpenTelemetry Collector Contrib, ces exemples requièrent cette version. Pour plus d'informations, consultez la documentation relative aux contributions du collecteur « OpenTelemetry ».

Filtrer les journaux en fonction de leur contenu

Le processeur de filtre accepte les expressions régulières qui sont appliquées au contenu des messages de journal. Tous les messages de journal qui correspondent à l'expression régulière indiquée sont supprimés et ne sont jamais transmis au destinataire à l'autre extrémité.

Exemples

Tous ces exemples suivent un modèle similaire. Une section filter doit être ajoutée au fichier de configuration d'opentelemetry-collector et ce filtre doit être inclus dans le pipeline logs/processors dans le même fichier. Si vous utilisez Helm pour installer le collecteur, la configuration se trouve dans la section config: du fichier values.yaml lors de l'installation.

Exclure les messages de journal contenant une sous-chaîne spécifique

Prenons un fichier journal contenant un horodatage, un niveau de journalisation et un message, comme dans l'exemple suivant:

2024-02-09 13:00:51 ERROR This is a test error message
2024-02-09 13:02:49 ERROR This is a test error message containing a secret

Ces journaux peuvent être mis en correspondance de manière plus générale à l'aide d'une configuration de récepteur filelog telle que celle-ci:

receivers:
  filelog/simple:
    include: [ /tmp/foo.log ]
    operators:
      - type: regex_parser
        regex: '^(?P<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) (?P<sev>[A-Z]*) (?P<msg>.*)$'
        timestamp:
          parse_from: attributes.time
          layout: '%Y-%m-%d %H:%M:%S'
        severity:
          parse_from: attributes.sev

L'expression régulière donnée affecte l'horodatage et la gravité aux groupes de capture nommés. L'horodatage layout est défini de sorte que le collecteur comprenne le format, ce qui permet d'utiliser l'horodatage correct du message de journal comme horodatage de l'enregistrement que le collecteur envoie au serveur. La gravité est envoyée sans modification.

Ce récepteur doit être ajouté au pipeline logs/receivers :

  pipelines:
    logs:
      receivers:
        - filelog/simple

Cette configuration signale tous les messages correctement formatés du journal au serveur.

Cependant, l'un des messages du journal recèle un secret. Pour exclure les messages qui contiennent des secrets, ajoutez un filtre à la section processors de la configuration. Le filtre doit contenir une expression régulière qui correspond à toute chaîne de caractères contenant le mot secret. L'exemple suivant utilise la fonction OTTL IsMatch(...) pour rechercher toute chaîne de caractères contenant le mot secret.

processors:
  filter/remove_secret:
    error_mode: ignore
    logs:
      log_record:
        - 'IsMatch(body, ".*secret.*")'

Ajoutez ce filtre au pipeline processors :

pipelines:
  logs:
    receivers:
      - filelog/simple
    processors:
      - filter/remove_secret

Avec cette configuration en place, seul le premier message de l'exemple de lignes de journal est signalé, mais le second, qui contient le mot "secret", est supprimé.

Exclure les messages syslog d'un service particulier

Prenons l'exemple d'un syslog sur un système Linux® . Si quelqu'un utilise le bureau Gnome sur ce système, il peut créer des journaux bruyants:

Feb  9 09:10:00 li-8dc514cc-2e0d-11b2-a85c-f1d7ce42b83b org.gnome.Shell.desktop[4771]: Window manager warning: Overwriting existing binding of keysym 31 with keysym 31 (keycode a).
Feb  9 09:10:00 li-8dc514cc-2e0d-11b2-a85c-f1d7ce42b83b org.gnome.Shell.desktop[4771]: Window manager warning: Overwriting existing binding of keysym 32 with keysym 32 (keycode b).
Feb  9 09:10:00 li-8dc514cc-2e0d-11b2-a85c-f1d7ce42b83b org.gnome.Shell.desktop[4771]: Window manager warning: Overwriting existing binding of keysym 33 with keysym 33 (keycode c).
Feb  9 09:10:00 li-8dc514cc-2e0d-11b2-a85c-f1d7ce42b83b org.gnome.Shell.desktop[4771]: Window manager warning: Overwriting existing binding of keysym 34 with keysym 34 (keycode d).
Feb  9 09:10:00 li-8dc514cc-2e0d-11b2-a85c-f1d7ce42b83b org.gnome.Shell.desktop[4771]: Window manager warning: Overwriting existing binding of keysym 35 with keysym 35 (keycode e).
Feb  9 09:10:00 li-8dc514cc-2e0d-11b2-a85c-f1d7ce42b83b org.gnome.Shell.desktop[4771]: Window manager warning: Overwriting existing binding of keysym 36 with keysym 36 (keycode f).
Feb  9 09:10:00 li-8dc514cc-2e0d-11b2-a85c-f1d7ce42b83b org.gnome.Shell.desktop[4771]: Window manager warning: Overwriting existing binding of keysym 37 with keysym 37 (keycode 10).
Feb  9 09:10:00 li-8dc514cc-2e0d-11b2-a85c-f1d7ce42b83b org.gnome.Shell.desktop[4771]: Window manager warning: Overwriting existing binding of keysym 38 with keysym 38 (keycode 11).
Feb  9 09:10:00 li-8dc514cc-2e0d-11b2-a85c-f1d7ce42b83b org.gnome.Shell.desktop[4771]: Window manager warning: Overwriting existing binding of keysym 39 with keysym 39 (keycode 12).
Feb  9 09:10:26 li-8dc514cc-2e0d-11b2-a85c-f1d7ce42b83b systemd[1]: fprintd.service: Succeeded.

Comme dans le premier exemple, le récepteur filelog peut surveiller ce journal et mapper l'horodatage à l'aide d'une expression régulière:

receivers:
  filelog/syslog:
    include: [ /var/log/syslog ]
    operators:
      - type: regex_parser
        regex: '^(?P<time>[A-Za-z]{3}[ ]+\d{1,2} \d{2}:\d{2}:\d{2}) (?P<msg>.*)$'
        timestamp:
          parse_from: attributes.time
          layout: '%b %e %H:%M:%S'

L'horodatage semble différent de celui du premier exemple, mais avec l'expression régulière et la définition de mise en forme appropriées, il est possible de le comprendre. Ce journal ne contient aucune gravité. Le récepteur, comme toujours, doit être inclus dans le pipeline logs/receivers :

 pipelines:
   logs:
     receivers:
       - filelog/simple
       - filelog/syslog

Sur un système serveur, vous pouvez surveiller les processus système mais exclure les journaux générés par l'environnement de bureau. Un filtre d'expression régulière peut bloquer tous les messages d'un service particulier:

processors:
  filter/remove_gnomeshell:
    error_mode: ignore
    logs:
      log_record:
        # message body will have the timestamp stripped off by the regex_parser, so it looks like:
        #  "hostname service[pid]: message"
        # Regex matches this as:
        #   [^ ]+                       <hostname> One or more non-whitespace characters, followed by
        #                               A space, followed by
        #   org.gnome.Shell.desktop     <service name> followed by
        #   [                           followed by
        #   [0-9]+                      <pid> one or more numeric digits, followed by
        #   ]:                          followed by
        #   .*                          <message> the rest of the log message
        - 'IsMatch(body, "[^ ]+ org.gnome.Shell.desktop\\[[0-9]+\\]:.*")'

Ajoutez le filtre au pipeline logs/processors :

logs:
  receivers:
    - filelog/simple
    - filelog/syslog
  processors:
    - filter/remove_secret
    - filter/remove_gnomeshell

A présent, tous les enregistrements de journal dans lesquels la zone de service est org.gnome.Shell.desktop sont supprimés.

Filtrer les journaux en fonction des données d'infrastructure

Le processeur de filtrage est capable d'effectuer un filtrage en fonction des informations fournies dans la resource attributes section de la charge utile. Ce processeur permet d'exclure tous les messages provenant, par exemple, d'un pod Kubernetes spécifique, d'un espace de noms Kubernetes entier ou d'un hôte particulier. Pour plus d'informations sur les données d'infrastructure prises en charge, consultez la section « Données d'infrastructure ».

Filtrer les journaux en fonction de leur niveau de gravité

Il peut arriver que des conteneurs soient configurés pour générer des journaux présentant différents niveaux de gravité. Dans ce cas, vous pouvez filtrer tous les messages à l'exception des messages ERROR et FATAL afin d'éviter de saturer le collecteur avec des données superflues.

Prenons l'exemple des journaux suivants :

[15:52:30 DEBUG] Some debug message.
[15:52:30 INFO] Some info message.
[15:52:30 ERROR] Some error message.
[15:52:30 FATAL] Some fatal message.

Pour filtrer les journaux DEBUG et INFO en fonction du niveau de gravité, vous devez d'abord définir le severity_text champ pour chaque entrée du journal. Pour ce faire, on peut utiliser le processeur transform suivant :

transform/set_log_severity:
  log_statements:
    - context: log
      statements:
        - set(severity_text, "Debug") where IsMatch(body.string, "\\[[0-9]{2}:[0-9]{2}:[0-9]{2} DEBUG\\]")
        - set(severity_text, "Info")  where IsMatch(body.string, "\\[[0-9]{2}:[0-9]{2}:[0-9]{2} INFO\\]")
        - set(severity_text, "Error") where IsMatch(body.string, "\\[[0-9]{2}:[0-9]{2}:[0-9]{2} ERROR\\]")
        - set(severity_text, "Fatal") where IsMatch(body.string, "\\[[0-9]{2}:[0-9]{2}:[0-9]{2} FATAL\\]")
Remarque : l'ordre de ces instructions est important, car chacune d'entre elles sera exécutée l'une après l'autre pour chaque entrée du journal. Lorsque l'expression régulière correspond à plusieurs motifs, c'est la dernière instruction qui prévaut. Si aucune des expressions régulières ne correspond au modèle, la variable severity_text sera définie sur une chaîne vide, ce que Instana interprétera comme un niveau de Nonegravité.

Une fois ce paramètre severity_text défini dans le fichier de journaux, vous pouvez utiliser l'exemple filter de processeur suivant pour ignorer les entrées de journal dont le niveau de gravité est inférieur à ERROR, ainsi que celles qui ne comportent pas de niveau de gravité.

filter/remove_unnecessary_logs:
  logs:
    log_record:
      - IsMatch(severity_text, "^(|Debug|Info)$")

Cet exemple utilise la fonction OTTL ( IsMatch(...) pour exclure les journaux dans lesquels l'expression régulière spécifiée correspond à une chaîne vide, au caractère Debug«, » et aux niveaux de Info gravité des journaux.

Vous pouvez également indiquer les journaux que vous souhaitez inclure plutôt qu'exclure en fonction du niveau de gravité, en utilisant le mot-clé « not ». De cette façon, vous filtrez désormais les journaux qui ne correspondent pas aux niveaux de Error gravité ou Fatal.

filter/remove_unnecessary_logs:
  logs:
    log_record:
      - not IsMatch(severity_text, "^(Error|Fatal)$")

Dans la service/pipelines/logs/processors section, ajoutez le nouveau filtre :

processors:
  - resourcedetection
  - transform/set_log_severity
  - filter/remove_unnecessary_logs
  - batch

Filtrer les journaux en fonction des attributs des ressources

Voici une liste non exhaustive d'exemples d'attributs de ressources pouvant être utilisés pour le filtrage des journaux :

Exemples d'attributs collectés par le processeur « k8sattributes » et le processeur « resourcedetection » :

  • resource.attributes["k8s.pod.name"]: Le nom du pod « Kubernetes » qui a généré le message de journal
  • resource.attributes["k8s.container.name"]: Nom du conteneur sous-jacent à l'origine du message de journal
  • resource.attributes["k8s.namespace.name"]: Le nom de l'espace de noms contenant le pod qui a généré le message de journal
  • resource.attributes["k8s.deployment.name"]: Nom de l'objet de déploiement d' Kubernetes s qui gère le pod ayant généré le message de journal
  • resource.attributes["k8s.node.name"]: Nom du nœud de l' Kubernetes s sur lequel s'exécute le pod à l'origine du message de journalisation
  • resource.attributes["k8s.pod.hostname"]: Nom de l'hôte sur lequel s'exécute le processus à l'origine du message de journal. Si le collecteur s'exécute à l'intérieur d'un conteneur, le nom d'hôte correspond généralement au nom du conteneur, et non au nom de l'hôte sous-jacent proprement dit
  • resource.attributes["os.type"]: Le type de système d'exploitation de l'hôte sur lequel s'exécute le processus à l'origine du message de journal

En utilisant les process eurs k8sattributes,resource ettransform, les attributs définis par l'utilisateur dans le resource.attributes mappage peuvent être définis de manière dynamique et utilisés pour un filtrage personnalisable des journaux.

Exemples

Tous ces exemples suivent un modèle similaire. Une section filter doit être ajoutée au fichier de configuration d'opentelemetry-collector et ce filtre doit être inclus dans le pipeline logs/processors dans le même fichier. Si vous utilisez Helm pour installer le collecteur, la configuration se trouve dans la section config: du fichier values.yaml lors de l'installation.

Exclure les messages de journalisation d'un conteneur d' Kubernetes s spécifique

Supposons que vous souhaitiez filtrer tous les messages de journal d'un conteneur Kubernetes appelé calico-node. Dans la section processors de la configuration, ajoutez un bloc comme celui-ci:

filter/remove_calico:
  error_mode: ignore
  logs:
    log_record:
      - resource.attributes["k8s.container.name"] == "calico-node"

Ensuite, dans la section service/pipelines/logs/processors , incluez le nouveau filtre:

processors:
  - resourcedetection
  - transform/set_log_severity
  - filter/remove_calico
  - batch

Le nouveau filtre est répertorié en dernier. Les autres processeurs affichés sont uniquement destinés au contexte et ne sont pas nécessaires au fonctionnement du processeur de filtre.

Exclure les messages de journalisation de tous les systèmes d' Linux®

Si vous souhaitez bloquer tous les messages de journal provenant d'un système Linux®, dans la section 'processors de la configuration, vous pouvez ajouter:

filter/remove_linux:
  error_mode: ignore
  logs:
    log_record:
      - resource.attributes["os.type"] == "linux"

De même, dans la section service/pipelines/logs/processors , en vous fondant sur l'exemple précédent, incluez le nouveau filtre:

processors:
  - resourcedetection
  - transform/set_log_severity
  - filter/remove_calico
  - filter/remove_linux
  - batch

Exclure les messages de journalisation provenant d'un pod ou d'un déploiement « Kubernetes » comportant des étiquettes ou des annotations spécifiques

Supposons que vous disposiez du déploiement Kubernetes suivant, avec les étiquettes et les annotations à partir desquelles vous souhaitez filtrer tous les messages de journal :

apiVersion: apps/v1
kind: Deployment
metadata:
  [...]
spec:
  [...]
  template:
    metadata:
      labels:
        some-keyword-label: "ABCD-label-substring-ABCD"
      annotations:
        some-keyword-annotation: "ABCD-annotation-substring-ABCD

Si vous souhaitez filtrer par some-keyword-label ou some-keyword-annotation, vous pouvez étendre le k8sattribute processeur comme indiqué dans l'exemple suivant afin de récupérer toutes les étiquettes et annotations des pods :

processors:
  k8sattributes:
    [...]
    extract:
      metadata:
        [...]
      ## Note: The '$$1' is a placeholder for the label or annotation name and will be used in the 'resource.attributes' mapping.
      labels:
        - tag_name: $$1
          key_regex: (.*)
          from: pod
      annotations:
        - tag_name: $$1
          key_regex: (.*)
          from: pod

Utilisez l'exemple suivant pour extraire some-keyword-label l'étiquette et some-keyword-annotation l'annotation :

processors:
  k8sattributes:
    [...]
    extract:
      metadata:
        [...]
      ## Note: In this example same label or annotation names are used as the ones to be extracted.
      ## The 'tag_name' corresponds to the key in the 'resource.attributes' mapping.
      ## The 'key' corresponds to the label or annotation you want to extract.
      labels:
        - tag_name: some-keyword-label
          key: some-keyword-label
          from: pod
      annotations:
       - tag_name: some-keyword-annotation
         key: some-keyword-annotation
         from: pod

Une fois que vous avez configuré le k8sattributes processeur pour extraire les étiquettes et annotations souhaitées, vous pouvez utiliser le filter processeur filter_by_keyword ou pour exclure les messages de journal provenant des pods qui possèdent some-keyword-label l'étiquette ou some-keyword-annotation l'annotation :

filter/keyword_filter:
  logs:
    log_record:
      ## Note: You can add as many filters as you would like if there are multiple labels/annotations.
      - IsMatch(resource.attributes["some-keyword-label"], ".*(label-substring).*")
      - IsMatch(resource.attributes["some-keyword-annotation"], ".*(annotation-substring).*")

Dans la service/pipelines/logs/processors section, en reprenant l'exemple précédent, ajoutez le nouveau filtre :

processors:
  - resourcedetection
  - filter/filter_by_keyword
  - batch

Le nouveau filtre est répertorié en dernier. Les autres processeurs affichés sont uniquement destinés au contexte et ne sont pas nécessaires au fonctionnement du processeur de filtre.

Masquer les informations sensibles dans les journaux

Les messages de journal contiennent parfois des informations identifiant la personne (PII) ou d'autres données sensibles qui doivent rester privées et ne pas être envoyées au serveur ou sauvegardées. Ces informations peuvent inclure des éléments tels que des mots de passe, des numéros de carte de crédit ou un certain nombre d'autres éléments. Le processeur transform peut détecter de telles informations à l'aide d'une expression régulière et les remplacer par autre chose.

Exemples

Ces exemples suivent un modèle similaire. Une section transform doit être ajoutée au fichier de configuration d'opentelemetry-collector et cette transformation doit être incluse dans le pipeline logs/processors dans le même fichier. Si vous utilisez Helm pour installer le collecteur, la configuration se trouve dans la section config: du fichier values.yaml lors de l'installation.

Suppression des mots de passe dans les messages de journal

Supposons qu'une application consigne le mot de passe fourni chaque fois qu'un échec d'authentification se produit. L'enregistrement de journal peut se présenter comme suit:

2024-02-14 19:40:31 WARNING failed login for user bob, password=bobo

Il est important de savoir qu'une tentative de connexion a échoué, mais il n'est pas approprié de consigner le mot de passe utilisé.

L'application consigne le mot de passe dans un format connu. Le modèle est toujours password=xyz. Une expression régulière peut détecter ce modèle et le remplacer par quelque chose d'autre:

transform/redact_password:
  log_statements:
    - context: log
      statements:
        # Any log messages containing "password=xxx" or "passwd=yyy" will be matched.
        # Regex matches these as:
        #   passw                     The literal string 'passw', followed by
        #   (?:or)??                  The literal string "or" 0 or 1 times (this allows either password or passwd)
        #   d=                        The literal string "d=", followed by
        #   [^\s]*                    Any non-whitespace characters (the password), followed by
        #   (\s?)*                    0 or more whitespace characters, marking the end of the password.
        - replace_pattern(body, "passw(?:or)??d\\=[^\\s]*(\\s?)", "password=REDACTED")
        - replace_pattern(attributes["msg"], "passw(?:or)??d\\=[^\\s]*(\\s?)", "password=REDACTED")

La directive replace_pattern apparaît une fois pour le message body et une fois pour l'attribut msg . Le collecteur de télémétrie ouvert place le contenu du message dans les deux emplacements, de sorte que les deux doivent être mis à jour.

Et ajoutez la transformation au pipeline logs/processors :

logs:
  receivers:
    - otlp
    - filelog/simple
  processors:
    - transform/redact_password

La transformation transforme le message de journal initial en:

2024-02-15 15:45:37 WARNING failed login for user bob, password=REDACTED

Suppression des noms d'hôte des messages de journal

Supposons qu'une autre application écrit des noms d'hôte dans le syslog:

Feb 15 15:52:36 li-8dc514cc-2e0d-11b2-a85c-f1d7ce42b83b service[45568]: This is a test error message from where.ever.ibm.com

Si les noms d'hôte sont considérés comme confidentiels, il est possible de les empêcher d'être ajoutés au journal. Si tous les hôtes se trouvent dans le même domaine, dans cet exemple .ibm.com, une expression régulière peut reconnaître le modèle et masquer les noms:

transform/remove_hostnames:
  log_statements:
    - context: log
      statements:
        # Any log message containing a hostname ending in ".ibm.com" will have the hostname removed.
        # Regex matches as:
        #   ([a-zA-Z0-9-_\.]+)       One or more letters, digits, dashes, underscores, or dots, followed by
        #   \.ibm\.com              The literal string ".ibm.com"
        - replace_pattern(body, "([a-zA-Z0-9-_\\.]+)\\.ibm\\.com", "<hidden hostname>")
        - replace_pattern(attributes["msg"], "([a-zA-Z0-9-_\\.]+)\\.ibm\\.com", "<hidden hostname>")

A nouveau, l'attribut body et l'attribut msg sont réécrits car le texte du message de journal apparaît dans les deux emplacements.

Et encore une fois, ajoutez la transformation au pipeline:

logs:
  receivers:
    - filelog/syslog
  processors:
    - transform/redact_password
    - transform/remove_hostnames

Le message est ensuite réécrit comme suit:

Feb 15 15:52:36 li-8dc514cc-2e0d-11b2-a85c-f1d7ce42b83b service[45568]: This is a test error message from <hidden hostname>