|
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