web-dev-qa-db-fra.com

Comment traiter une entrée de journal multiligne avec un filtre de journal des transactions?

Contexte:

J'ai un fichier journal généré personnalisé qui a le modèle suivant:

[2014-03-02 17:34:20] - 127.0.0.1|ERROR| E:\xampp\htdocs\test.php|123|subject|The error message goes here ; array (
  'create' => 
  array (
    'key1' => 'value1',
    'key2' => 'value2',
    'key3' => 'value3'
  ),
)
[2014-03-02 17:34:20] - 127.0.0.1|DEBUG| flush_multi_line

La deuxième entrée [2014-03-02 17:34:20] - 127.0.0.1|DEBUG| flush_multi_line Est une ligne fictive, juste pour faire savoir à logstash que l'événement multi-lignes est terminé, cette ligne est supprimée plus tard.

Mon fichier de configuration est le suivant:

input {
  stdin{}
}

filter{
  multiline{
      pattern => "^\["
      what => "previous"
      negate=> true
  }
  grok{
    match => ['message',"\[.+\] - %{IP:ip}\|%{LOGLEVEL:loglevel}"]
  }

  if [loglevel] == "DEBUG"{ # the event flush  line
    drop{}
  }else if [loglevel] == "ERROR"  { # the first line of multievent
    grok{
      match => ['message',".+\|.+\| %{PATH:file}\|%{NUMBER:line}\|%{Word:tag}\|%{GREEDYDATA:content}"] 
    }
  }else{ # its a new line (from the multi line event)
    mutate{
      replace => ["content", "%{content} %{message}"] # Supposing each new line will override the message field
    }
  }  
}

output {
  stdout{ debug=>true }
}

Le résultat pour le champ content est: The error message goes here ; array (

Problème:

Mon problème est que je veux stocker le reste du champ multiligne dans le contenu:

The error message goes here ; array (
  'create' => 
  array (
    'key1' => 'value1',
    'key2' => 'value2',
    'key3' => 'value3'
  ),
)

Je peux donc supprimer le champ de message plus tard.

Le champ @ message contient tout l'événement multiligne, j'ai donc essayé la fonction mutate filter, avec la fonction replace là-dessus, mais je ne peux tout simplement pas pour le faire fonctionner :(.

Je ne comprends pas la façon de travailler du filtre multiligne, si quelqu'un pouvait faire la lumière là-dessus, ce serait vraiment apprécié.

Merci,

Abdou.

27
emonik

J'ai parcouru le code source et découvert que:

  • le filtre multiligne annulera tous les événements qui sont considérés comme un suivi d'un événement en attente, puis ajoutez cette ligne au champ de message d'origine, ce qui signifie tous les filtres qui sont après que le filtre multiligne ne s'applique pas dans ce cas
  • Le seul événement qui passera jamais le filtre, est celui qui est considéré comme nouvea (quelque chose qui commence par [ dans mon cas)

Voici le code de travail:

input {
   stdin{}
}  

filter{
      if "|ERROR|" in [message]{ #if this is the 1st message in many lines message
      grok{
        match => ['message',"\[.+\] - %{IP:ip}\|%{LOGLEVEL:loglevel}\| %{PATH:file}\|%{NUMBER:line}\|%{Word:tag}\|%{GREEDYDATA:content}"]
      }

      mutate {
        replace => [ "message", "%{content}" ] #replace the message field with the content field ( so it auto append later in it )
        remove_field => ["content"] # we no longer need this field
      }
    }

    multiline{ #Nothing will pass this filter unless it is a new event ( new [2014-03-02 1.... )
        pattern => "^\["
        what => "previous"
        negate=> true
    }

    if "|DEBUG| flush_multi_line" in [message]{
      drop{} # We don't need the dummy line so drop it
    }
}

output {
  stdout{ debug=>true }
}

À votre santé,

Abdou

12
emonik

la gestion des groks et des multilignes est mentionnée dans ce numéro https://logstash.jira.com/browse/LOGSTASH-509

Ajoutez simplement "(? M)" devant votre grok regex et vous n'aurez pas besoin de mutation. Exemple de problème:

pattern => "(?m)<%{POSINT:syslog_pri}>(?:%{SPACE})%{GREEDYDATA:message_remainder}"
11
sbange

Le filtre multiligne ajoutera le "\ n" au message. Par exemple:

"[2014-03-02 17:34:20] - 127.0.0.1|ERROR| E:\\xampp\\htdocs\\test.php|123|subject|The error message goes here ; array (\n  'create' => \n  array (\n    'key1' => 'value1',\n    'key2' => 'value2',\n    'key3' => 'value3'\n  ),\n)"

Cependant, le filtre grok ne peut pas analyser le "\ n". Par conséquent, vous devez remplacer le\n par un autre caractère, dit un espace vide.

mutate {
    gsub => ['message', "\n", " "]
}

Ensuite, grok pattern peut analyser le message. Par exemple:

 "content" => "The error message goes here ; array (   'create' =>    array (     'key1' => 'value1',     'key2' => 'value2',     'key3' => 'value3'   ), )"
5
Ben Lim

Le problème n'est-il pas simplement la commande des filtres. L'ordre est très important de consigner la cachette. Vous n'avez pas besoin d'une autre ligne pour indiquer que vous avez terminé la sortie de la ligne de journal multiligne. Assurez-vous simplement que le filtre multiligne apparaît avant le grok (voir ci-dessous)

P.s. J'ai réussi à analyser correctement une ligne de journal multiligne où xml a été ajouté à la fin de la ligne de journal et il s'étendait sur plusieurs lignes et j'ai toujours un objet XML propre et agréable dans ma variable équivalente de contenu (nommée xmlrequest ci-dessous). Avant de dire quoi que ce soit sur la journalisation du xml dans les journaux ... Je sais ... ce n'est pas idéal ... mais c'est pour un autre débat :)):

filter { 
multiline{
        pattern => "^\["
        what => "previous"
        negate=> true
    }

mutate {
    gsub => ['message', "\n", " "]
}

mutate {
    gsub => ['message', "\r", " "]
}

grok{
        match => ['message',"\[%{Word:ONE}\] \[%{Word:TWO}\] \[%{Word:THREE}\] %{GREEDYDATA:xmlrequest}"]
    }

xml {
source => xmlrequest
remove_field => xmlrequest
target => "request"
  }
}
1
Luis Pereira