regex - ¿Cómo procesar la entrada de registro de varias líneas con el filtro logstash?
multiline logstash-grok (4)
Fondo:
Tengo un archivo de registro generado personalizado que tiene el siguiente patrón:
[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 segunda entrada [2014-03-02 17:34:20] - 127.0.0.1|DEBUG| flush_multi_line
[2014-03-02 17:34:20] - 127.0.0.1|DEBUG| flush_multi_line
Es una línea ficticia, solo para que logstash sepa que el evento de varias líneas ha terminado, esta línea se elimina más adelante.
Mi archivo de configuración es el siguiente:
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 }
}
La salida para el campo de contenido es: The error message goes here ; array (
The error message goes here ; array (
Problema:
Mi problema es que quiero almacenar el resto del campo de multilínea al contenido:
The error message goes here ; array (
''create'' =>
array (
''key1'' => ''value1'',
''key2'' => ''value2'',
''key3'' => ''value3''
),
)
Así que puedo eliminar el campo del mensaje más tarde.
El campo @message contiene el evento multilínea completo, así que probé el filtro mutate , con la función de reemplazo en eso, pero no puedo hacer que funcione :(.
No entiendo la forma de trabajar del filtro Multilínea, si alguien pudiera arrojar algo de luz sobre esto, sería realmente apreciado.
Gracias,
Abdou.
El filtro multilínea agregará "/ n" al mensaje. Por ejemplo:
"[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)"
Sin embargo, el filtro de grok no puede analizar el "/ n". Por lo tanto, debe sustituir el / n por otro carácter, dice, espacio en blanco.
mutate {
gsub => [''message'', "/n", " "]
}
Entonces, el patrón de grok puede analizar el mensaje. Por ejemplo:
"content" => "The error message goes here ; array ( ''create'' => array ( ''key1'' => ''value1'', ''key2'' => ''value2'', ''key3'' => ''value3'' ), )"
El manejo de grok y multilínea se menciona en este problema https://logstash.jira.com/browse/LOGSTASH-509
Simplemente agregue "(? M)" delante de su expresión regular de grok y no necesitará la mutación. Ejemplo de problema:
pattern => "(?m)<%{POSINT:syslog_pri}>(?:%{SPACE})%{GREEDYDATA:message_remainder}"
No es el problema simplemente el orden de los filtros. El orden es muy importante para registrar el alijo. No necesita otra línea para indicar que ha terminado de generar una línea de registro multilínea. Solo asegúrese de que el filtro multilínea aparezca primero antes del grok (ver a continuación)
Ps. Me las arreglé para analizar una multa de línea de registro multilínea donde se agregó xml al final de la línea de registro y abarcó varias líneas y aún así obtuve un objeto xml limpio y agradable en mi variable equivalente de contenido (llamada xmlrequest a continuación). Antes de decir algo sobre el registro de XML en los registros ... Lo sé ... no es lo ideal ... pero eso es para otro debate :)):
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"
}
}
Revisé el código fuente y descubrí que:
- El filtro multilínea cancelará todos los eventos que se consideren como un seguimiento de un evento pendiente , luego agregará esa línea al campo del mensaje original, lo que significa que cualquier filtro que esté después del filtro multilínea no se aplicará en este caso
- El único evento que alguna vez pasará el filtro, es uno que se considera uno nuevo (algo que comienza con [ en mi caso)
Aquí está el código de trabajo:
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 }
}
Aclamaciones,
Abdou