|
16 | 16 | package io.thekraken.grok.api; |
17 | 17 |
|
18 | 18 |
|
| 19 | +import static java.lang.String.format; |
| 20 | + |
19 | 21 | import java.util.ArrayList; |
| 22 | +import java.util.Collections; |
20 | 23 | import java.util.Iterator; |
21 | 24 | import java.util.List; |
22 | 25 | import java.util.Map; |
|
26 | 29 |
|
27 | 30 | import com.google.gson.Gson; |
28 | 31 | import com.google.gson.GsonBuilder; |
| 32 | +import io.thekraken.grok.api.exception.GrokException; |
29 | 33 |
|
30 | 34 | /** |
31 | 35 | * {@code Match} is a representation in {@code Grok} world of your log. |
@@ -141,9 +145,32 @@ public String getSubject() { |
141 | 145 | /** |
142 | 146 | * Match to the <tt>subject</tt> the <tt>regex</tt> and save the matched element into a map. |
143 | 147 | * |
| 148 | + * Multiple values for the same key are stored as list. |
| 149 | + * |
144 | 150 | */ |
145 | | - @SuppressWarnings("unchecked") |
146 | 151 | public void captures() { |
| 152 | + captures(false); |
| 153 | + |
| 154 | + } |
| 155 | + |
| 156 | + /** |
| 157 | + * Match to the <tt>subject</tt> the <tt>regex</tt> and save the matched element into a map |
| 158 | + * |
| 159 | + * Multiple values to the same key are flattened to one value: the sole non-null value will be captured. |
| 160 | + * Should there be multiple non-null values a RuntimeException is being thrown. |
| 161 | + * |
| 162 | + * This can be used in cases like: (foo (.*:message) bar|bar (.*:message) foo) where the regexp guarantees that only |
| 163 | + * one value will be captured. |
| 164 | + * |
| 165 | + * See also {@link #captures} which returns multiple values of the same key as list. |
| 166 | + * |
| 167 | + */ |
| 168 | + public void capturesFlattened() { |
| 169 | + captures(true); |
| 170 | + } |
| 171 | + |
| 172 | + @SuppressWarnings("unchecked") |
| 173 | + private void captures(boolean flattened ) { |
147 | 174 | if (match == null) { |
148 | 175 | return; |
149 | 176 | } |
@@ -187,24 +214,36 @@ public void captures() { |
187 | 214 | } |
188 | 215 |
|
189 | 216 | if (capture.containsKey(key)) { |
190 | | - Object currentValue = capture.get(key); |
191 | | - if(currentValue instanceof List) { |
192 | | - ((List<Object>) currentValue).add(value); |
193 | | - } else { |
194 | | - List<Object> list = new ArrayList<Object>(); |
195 | | - list.add(currentValue); |
196 | | - list.add(value); |
197 | | - capture.put(key, list); |
198 | | - } |
| 217 | + Object currentValue = capture.get(key); |
| 218 | + |
| 219 | + if (flattened) { |
| 220 | + if (currentValue == null && value != null) { |
| 221 | + capture.put(key, value); |
| 222 | + } if (currentValue != null && value != null) { |
| 223 | + throw new RuntimeException( |
| 224 | + format("key '%s' has multiple non-null values, this is not allowed in flattened mode, values:'%s', '%s'", |
| 225 | + key, |
| 226 | + currentValue, |
| 227 | + value)); |
| 228 | + } |
| 229 | + } else { |
| 230 | + if (currentValue instanceof List) { |
| 231 | + ((List<Object>) currentValue).add(value); |
| 232 | + } else { |
| 233 | + List<Object> list = new ArrayList<Object>(); |
| 234 | + list.add(currentValue); |
| 235 | + list.add(value); |
| 236 | + capture.put(key, list); |
| 237 | + } |
| 238 | + } |
199 | 239 | } else { |
200 | | - capture.put(key, value); |
| 240 | + capture.put(key, value); |
201 | 241 | } |
202 | 242 |
|
203 | 243 | it.remove(); // avoids a ConcurrentModificationException |
204 | 244 | } |
205 | 245 | } |
206 | 246 |
|
207 | | - |
208 | 247 | /** |
209 | 248 | * remove from the string the quote and double quote. |
210 | 249 | * |
@@ -294,4 +333,5 @@ private void cleanMap() { |
294 | 333 | public Boolean isNull() { |
295 | 334 | return this.match == null; |
296 | 335 | } |
| 336 | + |
297 | 337 | } |
0 commit comments