You may be better working in two phases: first, extract the monitor_name (which I am reading to be a sequence of strings, each bound by square brackets), and then, in a separate filter, extract the relevant bits out of the monitor_name (I would prefer [dissect][], since it is a lot simpler to understand and faster at extracting when the patterns of the separators is known):
filter {
grok {
"pattern_definitions" => {
"MONITOR_NAME" => "(\[[^]]+\])+"
}
"match" => {
"message" => "%{MONITOR_NAME:monitor_name}"
}
}
dissect {
mapping => {
"monitor_name" => "[%{os}][%{monitor_type}][%{remote_host}][%{}][%{}][%{}]"
}
}
}
I defined the pattern for MONITOR_NAME as (\[[^]]+\])+, because it matches any sequence of square-bracketed things:
( # open group
\[ # literal open bracket
[ # character class
^] # excluding a close bracket
]+ #closes character class, allows repetition
\] # literal close bracket
)+ # close group, allows repetition
Ideally, when you grok, you'll be anchoring your pattern to the beginning of your log line (by prefixing it with the ^ character), so your grok pattern will capture from the beginning of your log message. This hugely improves performance because the regular expression doesn't have to try the match again starting with the second character, and again with the third, and so-on until it finds a match.