/src/fluent-bit/src/flb_record_accessor.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* Fluent Bit |
4 | | * ========== |
5 | | * Copyright (C) 2015-2022 The Fluent Bit Authors |
6 | | * |
7 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | | * you may not use this file except in compliance with the License. |
9 | | * You may obtain a copy of the License at |
10 | | * |
11 | | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | | * |
13 | | * Unless required by applicable law or agreed to in writing, software |
14 | | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | | * See the License for the specific language governing permissions and |
17 | | * limitations under the License. |
18 | | */ |
19 | | |
20 | | #include <fluent-bit/flb_info.h> |
21 | | #include <fluent-bit/flb_mem.h> |
22 | | #include <fluent-bit/flb_env.h> |
23 | | #include <fluent-bit/flb_log.h> |
24 | | #include <fluent-bit/flb_pack.h> |
25 | | #include <fluent-bit/flb_sds.h> |
26 | | #include <fluent-bit/flb_sds_list.h> |
27 | | #include <fluent-bit/flb_record_accessor.h> |
28 | | #include <fluent-bit/flb_ra_key.h> |
29 | | #include <fluent-bit/record_accessor/flb_ra_parser.h> |
30 | | #include <monkey/mk_core.h> |
31 | | #include <msgpack.h> |
32 | | |
33 | | #include <ctype.h> |
34 | | |
35 | | static struct flb_ra_parser *ra_parse_string(struct flb_record_accessor *ra, |
36 | | flb_sds_t buf, int start, int end) |
37 | 163k | { |
38 | 163k | int len; |
39 | 163k | struct flb_ra_parser *rp; |
40 | | |
41 | 163k | len = end - start; |
42 | 163k | rp = flb_ra_parser_string_create(buf + start, len); |
43 | 163k | if (!rp) { |
44 | 9 | return NULL; |
45 | 9 | } |
46 | | |
47 | 163k | return rp; |
48 | 163k | } |
49 | | |
50 | | /* Create a parser context for a key map or function definition */ |
51 | | static struct flb_ra_parser *ra_parse_meta(struct flb_record_accessor *ra, |
52 | | flb_sds_t buf, int start, int end) |
53 | 161k | { |
54 | 161k | int len; |
55 | 161k | struct flb_ra_parser *rp; |
56 | | |
57 | 161k | len = end - start; |
58 | 161k | rp = flb_ra_parser_meta_create(buf + start, len); |
59 | 161k | if (!rp) { |
60 | 221 | return NULL; |
61 | 221 | } |
62 | | |
63 | 161k | return rp; |
64 | 161k | } |
65 | | |
66 | | /* |
67 | | * Supported data |
68 | | * |
69 | | * ${X} => environment variable |
70 | | * $key, $key['x'], $key['x'][N]['z'] => record key value or array index |
71 | | * $0, $1,..$9 => regex id |
72 | | * $X() => built-in function |
73 | | */ |
74 | | static int ra_parse_buffer(struct flb_record_accessor *ra, flb_sds_t buf) |
75 | 1.98k | { |
76 | 1.98k | int i; |
77 | 1.98k | int n; |
78 | 1.98k | int c; |
79 | 1.98k | int t; |
80 | 1.98k | int len; |
81 | 1.98k | int pre = 0; |
82 | 1.98k | int end = 0; |
83 | 1.98k | int quote_cnt; |
84 | 1.98k | struct flb_ra_parser *rp; |
85 | 1.98k | struct flb_ra_parser *rp_str = NULL; |
86 | | |
87 | 1.98k | len = flb_sds_len(buf); |
88 | | |
89 | 573k | for (i = 0; i < len; i++) { |
90 | 571k | if (buf[i] != '$') { |
91 | 406k | continue; |
92 | 406k | } |
93 | | |
94 | | /* |
95 | | * Before to add the number entry, add the previous text |
96 | | * before hitting this. |
97 | | */ |
98 | 164k | if (i > pre) { |
99 | 162k | rp = ra_parse_string(ra, buf, pre, i); |
100 | 162k | if (!rp) { |
101 | 6 | return -1; |
102 | 6 | } |
103 | 162k | mk_list_add(&rp->_head, &ra->list); |
104 | 162k | } |
105 | 164k | pre = i; |
106 | | |
107 | | |
108 | 164k | n = i + 1; |
109 | 164k | if (n >= len) { |
110 | | /* Finalize, nothing to do */ |
111 | 69 | break; |
112 | 69 | } |
113 | | |
114 | | /* |
115 | | * If the next character is a digit like $0,$1,$2..$9, means the user wants to use |
116 | | * the result of a regex capture. |
117 | | * |
118 | | * We support up to 10 regex ids [0-9] |
119 | | */ |
120 | 164k | if (isdigit(buf[n])) { |
121 | | /* Add REGEX_ID entry */ |
122 | 1.84k | c = atoi(buf + n); |
123 | 1.84k | rp = flb_ra_parser_regex_id_create(c); |
124 | 1.84k | if (!rp) { |
125 | 1 | return -1; |
126 | 1 | } |
127 | | |
128 | 1.84k | mk_list_add(&rp->_head, &ra->list); |
129 | 1.84k | i++; |
130 | 1.84k | pre = i + 1; |
131 | 1.84k | continue; |
132 | 1.84k | } |
133 | | |
134 | | /* |
135 | | * If the next 3 character are 'TAG', the user might want to include the tag or |
136 | | * part of it (e.g: TAG[n]). |
137 | | */ |
138 | 163k | if (n + 2 < len && strncmp(buf + n, "TAG", 3) == 0) { |
139 | | /* Check if some [] was added */ |
140 | 1.63k | if (n + 4 < len) { |
141 | 1.60k | end = -1; |
142 | 1.60k | if (buf[n + 3] == '[') { |
143 | 1.18k | t = n + 3; |
144 | | |
145 | | /* Look for the ending ']' */ |
146 | 1.18k | end = mk_string_char_search(buf + t, ']', len - t); |
147 | 1.18k | if (end == 0) { |
148 | 0 | end = -1; |
149 | 0 | } |
150 | | |
151 | | /* continue processsing */ |
152 | 1.18k | c = atoi(buf + t + 1); |
153 | | |
154 | 1.18k | rp = flb_ra_parser_tag_part_create(c); |
155 | 1.18k | if (!rp) { |
156 | 1 | return -1; |
157 | 1 | } |
158 | 1.18k | mk_list_add(&rp->_head, &ra->list); |
159 | | |
160 | 1.18k | i = t + end + 1; |
161 | 1.18k | pre = i; |
162 | 1.18k | continue; |
163 | 1.18k | } |
164 | 1.60k | } |
165 | | |
166 | | /* Append full tag */ |
167 | 451 | rp = flb_ra_parser_tag_create(); |
168 | 451 | if (!rp) { |
169 | 1 | return -1; |
170 | 1 | } |
171 | 450 | mk_list_add(&rp->_head, &ra->list); |
172 | 450 | i = n + 3; |
173 | 450 | pre = n + 3; |
174 | 450 | continue; |
175 | 451 | } |
176 | | |
177 | 161k | quote_cnt = 0; |
178 | 1.28M | for (end = i + 1; end < len; end++) { |
179 | 1.28M | if (buf[end] == '\'') { |
180 | 14.7k | ++quote_cnt; |
181 | 14.7k | } |
182 | 1.26M | else if (buf[end] == '.' && (quote_cnt & 0x01)) { |
183 | | /* ignore '.' if it is inside a string/subkey */ |
184 | 1.72k | continue; |
185 | 1.72k | } |
186 | 1.26M | else if (buf[end] == '.' || buf[end] == ' ' || buf[end] == ',' || buf[end] == '"') { |
187 | 160k | break; |
188 | 160k | } |
189 | 1.28M | } |
190 | 161k | if (end > len) { |
191 | 0 | end = len; |
192 | 0 | } |
193 | | |
194 | | /* Parse the content, we use 'end' as the separator position */ |
195 | 161k | rp = ra_parse_meta(ra, buf, i, end); |
196 | 161k | if (!rp) { |
197 | 221 | return -1; |
198 | 221 | } |
199 | | |
200 | | /* Generate fixed length string */ |
201 | 161k | if (pre < i) { |
202 | 0 | rp_str = ra_parse_string(ra, buf, pre, i); |
203 | 0 | if (!rp_str) { |
204 | 0 | flb_ra_parser_destroy(rp); |
205 | 0 | return -1; |
206 | 0 | } |
207 | 0 | } |
208 | 161k | else { |
209 | 161k | rp_str = NULL; |
210 | 161k | } |
211 | | |
212 | 161k | if (rp_str) { |
213 | 0 | mk_list_add(&rp_str->_head, &ra->list); |
214 | 0 | } |
215 | 161k | mk_list_add(&rp->_head, &ra->list); |
216 | 161k | pre = end; |
217 | 161k | i = end; |
218 | 161k | } |
219 | | |
220 | | /* Append remaining string */ |
221 | 1.75k | if ((i - 1 > end && pre < i) || i == 1 /*allow single character*/) { |
222 | 702 | end = flb_sds_len(buf); |
223 | 702 | rp_str = ra_parse_string(ra, buf, pre, end); |
224 | 702 | if (rp_str) { |
225 | 699 | mk_list_add(&rp_str->_head, &ra->list); |
226 | 699 | } |
227 | 702 | } |
228 | | |
229 | 1.75k | return 0; |
230 | 1.98k | } |
231 | | |
232 | | void flb_ra_destroy(struct flb_record_accessor *ra) |
233 | 1.98k | { |
234 | 1.98k | struct mk_list *tmp; |
235 | 1.98k | struct mk_list *head; |
236 | 1.98k | struct flb_ra_parser *rp; |
237 | | |
238 | 328k | mk_list_foreach_safe(head, tmp, &ra->list) { |
239 | 328k | rp = mk_list_entry(head, struct flb_ra_parser, _head); |
240 | 328k | mk_list_del(&rp->_head); |
241 | 328k | flb_ra_parser_destroy(rp); |
242 | 328k | } |
243 | | |
244 | 1.98k | if (ra->pattern) { |
245 | 1.98k | flb_sds_destroy(ra->pattern); |
246 | 1.98k | } |
247 | 1.98k | flb_free(ra); |
248 | 1.98k | } |
249 | | |
250 | | int flb_ra_subkey_count(struct flb_record_accessor *ra) |
251 | 0 | { |
252 | 0 | struct mk_list *head; |
253 | 0 | struct flb_ra_parser *rp; |
254 | 0 | int ret = -1; |
255 | 0 | int tmp; |
256 | |
|
257 | 0 | if (ra == NULL) { |
258 | 0 | return -1; |
259 | 0 | } |
260 | 0 | mk_list_foreach(head, &ra->list) { |
261 | 0 | rp = mk_list_entry(head, struct flb_ra_parser, _head); |
262 | 0 | tmp = flb_ra_parser_subkey_count(rp); |
263 | 0 | if (tmp > ret) { |
264 | 0 | ret = tmp; |
265 | 0 | } |
266 | 0 | } |
267 | |
|
268 | 0 | return ret; |
269 | 0 | } |
270 | | |
271 | | struct flb_record_accessor *flb_ra_create(char *str, int translate_env) |
272 | 1.99k | { |
273 | 1.99k | int ret; |
274 | 1.99k | size_t hint = 0; |
275 | 1.99k | char *p; |
276 | 1.99k | flb_sds_t buf = NULL; |
277 | 1.99k | struct flb_env *env; |
278 | 1.99k | struct mk_list *head; |
279 | 1.99k | struct flb_ra_parser *rp; |
280 | 1.99k | struct flb_record_accessor *ra; |
281 | | |
282 | 1.99k | p = str; |
283 | 1.99k | if (translate_env == FLB_TRUE) { |
284 | | /* |
285 | | * Check if some environment variable has been created as part of the |
286 | | * string. Upon running the environment variable will be pre-set in the |
287 | | * string. |
288 | | */ |
289 | 0 | env = flb_env_create(); |
290 | 0 | if (!env) { |
291 | 0 | flb_error("[record accessor] cannot create environment context"); |
292 | 0 | return NULL; |
293 | 0 | } |
294 | | |
295 | | /* Translate string */ |
296 | 0 | buf = flb_env_var_translate(env, str); |
297 | 0 | if (!buf) { |
298 | 0 | flb_error("[record accessor] cannot translate string"); |
299 | 0 | flb_env_destroy(env); |
300 | 0 | return NULL; |
301 | 0 | } |
302 | 0 | flb_env_destroy(env); |
303 | 0 | p = buf; |
304 | 0 | } |
305 | | |
306 | | /* Allocate context */ |
307 | 1.99k | ra = flb_calloc(1, sizeof(struct flb_record_accessor)); |
308 | 1.99k | if (!ra) { |
309 | 4 | flb_errno(); |
310 | 4 | flb_error("[record accessor] cannot create context"); |
311 | 4 | if (buf) { |
312 | 0 | flb_sds_destroy(buf); |
313 | 0 | } |
314 | 4 | return NULL; |
315 | 4 | } |
316 | 1.98k | ra->pattern = flb_sds_create(str); |
317 | 1.98k | if (!ra->pattern) { |
318 | 2 | flb_error("[record accessor] could not allocate pattern"); |
319 | 2 | flb_free(ra); |
320 | 2 | if (buf) { |
321 | 0 | flb_sds_destroy(buf); |
322 | 0 | } |
323 | 2 | return NULL; |
324 | 2 | } |
325 | | |
326 | 1.98k | mk_list_init(&ra->list); |
327 | | |
328 | | /* |
329 | | * The buffer needs to processed where we create a list of parts, basically |
330 | | * a linked list of sds using 'slist' api. |
331 | | */ |
332 | 1.98k | ret = ra_parse_buffer(ra, p); |
333 | 1.98k | if (buf) { |
334 | 0 | flb_sds_destroy(buf); |
335 | 0 | } |
336 | 1.98k | if (ret == -1) { |
337 | 230 | flb_ra_destroy(ra); |
338 | 230 | return NULL; |
339 | 230 | } |
340 | | |
341 | | /* Calculate a hint of an outgoing size buffer */ |
342 | 297k | mk_list_foreach(head, &ra->list) { |
343 | 297k | rp = mk_list_entry(head, struct flb_ra_parser, _head); |
344 | 297k | if (rp->key) { |
345 | 292k | if (rp->type == FLB_RA_PARSER_REGEX_ID) { |
346 | 0 | hint += 32; |
347 | 0 | } |
348 | 292k | else { |
349 | 292k | hint += flb_sds_len(rp->key->name); |
350 | 292k | } |
351 | 292k | } |
352 | 297k | } |
353 | 1.75k | ra->size_hint = hint + 128; |
354 | 1.75k | return ra; |
355 | 1.98k | } |
356 | | |
357 | | /* |
358 | | flb_ra_create_str_from_list returns record accessor string from string list. |
359 | | e.g. {"aa", "bb", "cc", NULL} -> "$aa['bb']['cc']" |
360 | | Return value should be freed using flb_sds_destroy after using. |
361 | | */ |
362 | | flb_sds_t flb_ra_create_str_from_list(struct flb_sds_list *str_list) |
363 | 0 | { |
364 | 0 | int i = 0; |
365 | 0 | int ret_i = 0; |
366 | 0 | int offset = 0; |
367 | |
|
368 | 0 | char *fmt = NULL; |
369 | 0 | char **strs = NULL; |
370 | 0 | flb_sds_t str; |
371 | 0 | flb_sds_t tmp_sds; |
372 | |
|
373 | 0 | if (str_list == NULL || flb_sds_list_size(str_list) == 0) { |
374 | 0 | return NULL; |
375 | 0 | } |
376 | | |
377 | 0 | str = flb_sds_create_size(256); |
378 | 0 | if (str == NULL) { |
379 | 0 | flb_errno(); |
380 | 0 | return NULL; |
381 | 0 | } |
382 | | |
383 | 0 | strs = flb_sds_list_create_str_array(str_list); |
384 | 0 | if (strs == NULL) { |
385 | 0 | flb_error("%s flb_sds_list_create_str_array failed", __FUNCTION__); |
386 | 0 | return NULL; |
387 | 0 | } |
388 | | |
389 | 0 | while(strs[i] != NULL) { |
390 | 0 | if (i == 0) { |
391 | 0 | fmt = "$%s"; |
392 | 0 | } |
393 | 0 | else { |
394 | 0 | fmt = "['%s']"; |
395 | 0 | } |
396 | |
|
397 | 0 | ret_i = snprintf(str+offset, flb_sds_alloc(str)-offset-1, fmt, strs[i]); |
398 | 0 | if (ret_i > flb_sds_alloc(str)-offset-1) { |
399 | 0 | tmp_sds = flb_sds_increase(str, ret_i); |
400 | 0 | if (tmp_sds == NULL) { |
401 | 0 | flb_errno(); |
402 | 0 | flb_sds_list_destroy_str_array(strs); |
403 | 0 | flb_sds_destroy(str); |
404 | 0 | return NULL; |
405 | 0 | } |
406 | 0 | str = tmp_sds; |
407 | 0 | ret_i = snprintf(str+offset, flb_sds_alloc(str)-offset-1, fmt, strs[i]); |
408 | 0 | if (ret_i > flb_sds_alloc(str)-offset-1) { |
409 | 0 | flb_errno(); |
410 | 0 | flb_sds_list_destroy_str_array(strs); |
411 | 0 | flb_sds_destroy(str); |
412 | 0 | return NULL; |
413 | 0 | } |
414 | 0 | } |
415 | 0 | offset += ret_i; |
416 | 0 | i++; |
417 | 0 | } |
418 | 0 | flb_sds_list_destroy_str_array(strs); |
419 | |
|
420 | 0 | return str; |
421 | 0 | } |
422 | | |
423 | | struct flb_record_accessor *flb_ra_create_from_list(struct flb_sds_list *str_list, int translate_env) |
424 | 0 | { |
425 | 0 | flb_sds_t tmp = NULL; |
426 | 0 | struct flb_record_accessor *ret = NULL; |
427 | |
|
428 | 0 | tmp = flb_ra_create_str_from_list(str_list); |
429 | 0 | if (tmp == NULL) { |
430 | 0 | flb_errno(); |
431 | 0 | return NULL; |
432 | 0 | } |
433 | | |
434 | 0 | ret = flb_ra_create(tmp, translate_env); |
435 | 0 | flb_sds_destroy(tmp); |
436 | |
|
437 | 0 | return ret; |
438 | 0 | } |
439 | | |
440 | | void flb_ra_dump(struct flb_record_accessor *ra) |
441 | 1.69k | { |
442 | 1.69k | struct mk_list *head; |
443 | 1.69k | struct flb_ra_parser *rp; |
444 | | |
445 | 294k | mk_list_foreach(head, &ra->list) { |
446 | 294k | rp = mk_list_entry(head, struct flb_ra_parser, _head); |
447 | 294k | printf("\n"); |
448 | 294k | flb_ra_parser_dump(rp); |
449 | 294k | } |
450 | 1.69k | } |
451 | | |
452 | | static flb_sds_t ra_translate_regex_id(struct flb_ra_parser *rp, |
453 | | struct flb_regex_search *result, |
454 | | flb_sds_t buf) |
455 | 0 | { |
456 | 0 | int ret; |
457 | 0 | ptrdiff_t start; |
458 | 0 | ptrdiff_t end; |
459 | 0 | flb_sds_t tmp; |
460 | |
|
461 | 0 | ret = flb_regex_results_get(result, rp->id, &start, &end); |
462 | 0 | if (ret == -1) { |
463 | 0 | return buf; |
464 | 0 | } |
465 | | |
466 | 0 | tmp = flb_sds_cat(buf, result->str + start, end - start); |
467 | 0 | return tmp; |
468 | 0 | } |
469 | | |
470 | | static flb_sds_t ra_translate_tag(struct flb_ra_parser *rp, flb_sds_t buf, |
471 | | char *tag, int tag_len) |
472 | 0 | { |
473 | 0 | flb_sds_t tmp; |
474 | |
|
475 | 0 | tmp = flb_sds_cat(buf, tag, tag_len); |
476 | 0 | return tmp; |
477 | 0 | } |
478 | | |
479 | | static flb_sds_t ra_translate_tag_part(struct flb_ra_parser *rp, flb_sds_t buf, |
480 | | char *tag, int tag_len) |
481 | 0 | { |
482 | 0 | int i = 0; |
483 | 0 | int id = -1; |
484 | 0 | int end; |
485 | 0 | flb_sds_t tmp = buf; |
486 | |
|
487 | 0 | while (i < tag_len) { |
488 | 0 | end = mk_string_char_search(tag + i, '.', tag_len - i); |
489 | 0 | if (end == -1) { |
490 | 0 | if (i == 0) { |
491 | 0 | break; |
492 | 0 | } |
493 | 0 | end = tag_len - i; |
494 | 0 | } |
495 | 0 | id++; |
496 | 0 | if (rp->id == id) { |
497 | 0 | tmp = flb_sds_cat(buf, tag + i, end); |
498 | 0 | break; |
499 | 0 | } |
500 | | |
501 | 0 | i += end + 1; |
502 | 0 | } |
503 | | |
504 | | /* No dots in the tag */ |
505 | 0 | if (rp->id == 0 && id == -1 && i < tag_len) { |
506 | 0 | tmp = flb_sds_cat(buf, tag, tag_len); |
507 | 0 | return tmp; |
508 | 0 | } |
509 | | |
510 | 0 | return tmp; |
511 | 0 | } |
512 | | |
513 | | static flb_sds_t ra_translate_string(struct flb_ra_parser *rp, flb_sds_t buf) |
514 | 146k | { |
515 | 146k | flb_sds_t tmp; |
516 | | |
517 | 146k | tmp = flb_sds_cat(buf, rp->key->name, flb_sds_len(rp->key->name)); |
518 | 146k | return tmp; |
519 | 146k | } |
520 | | |
521 | | static flb_sds_t ra_translate_keymap(struct flb_ra_parser *rp, flb_sds_t buf, |
522 | | msgpack_object map, int *found) |
523 | 145k | { |
524 | 145k | int len; |
525 | 145k | char *js; |
526 | 145k | char str[32]; |
527 | 145k | flb_sds_t tmp = NULL; |
528 | 145k | struct flb_ra_value *v; |
529 | | |
530 | | /* Lookup key or subkey value */ |
531 | 145k | if (rp->key == NULL) { |
532 | 751 | *found = FLB_FALSE; |
533 | 751 | return buf; |
534 | 751 | } |
535 | | |
536 | 144k | v = flb_ra_key_to_value(rp->key->name, map, rp->key->subkeys); |
537 | 144k | if (!v) { |
538 | 16.1k | *found = FLB_FALSE; |
539 | 16.1k | return buf; |
540 | 16.1k | } |
541 | 128k | else { |
542 | 128k | *found = FLB_TRUE; |
543 | 128k | } |
544 | | |
545 | | /* Based on data type, convert to it string representation */ |
546 | 128k | if (v->type == FLB_RA_BOOL) { |
547 | | /* Check if is a map or a real bool */ |
548 | 47.1k | if (v->o.type == MSGPACK_OBJECT_MAP) { |
549 | | /* Convert msgpack map to JSON string */ |
550 | 46.4k | js = flb_msgpack_to_json_str(1024, &v->o); |
551 | 46.4k | if (js) { |
552 | 46.4k | len = strlen(js); |
553 | 46.4k | tmp = flb_sds_cat(buf, js, len); |
554 | 46.4k | flb_free(js); |
555 | 46.4k | } |
556 | 46.4k | } |
557 | 686 | else if (v->o.type == MSGPACK_OBJECT_BOOLEAN) { |
558 | 686 | if (v->val.boolean) { |
559 | 250 | tmp = flb_sds_cat(buf, "true", 4); |
560 | 250 | } |
561 | 436 | else { |
562 | 436 | tmp = flb_sds_cat(buf, "false", 5); |
563 | 436 | } |
564 | 686 | } |
565 | 47.1k | } |
566 | 81.2k | else if (v->type == FLB_RA_INT) { |
567 | 13.3k | len = snprintf(str, sizeof(str) - 1, "%" PRId64, v->val.i64); |
568 | 13.3k | tmp = flb_sds_cat(buf, str, len); |
569 | 13.3k | } |
570 | 67.9k | else if (v->type == FLB_RA_FLOAT) { |
571 | 1.75k | len = snprintf(str, sizeof(str) - 1, "%f", v->val.f64); |
572 | 1.75k | if (len >= sizeof(str)) { |
573 | 194 | tmp = flb_sds_cat(buf, str, sizeof(str)-1); |
574 | 194 | } |
575 | 1.56k | else { |
576 | 1.56k | tmp = flb_sds_cat(buf, str, len); |
577 | 1.56k | } |
578 | 1.75k | } |
579 | 66.1k | else if (v->type == FLB_RA_STRING) { |
580 | 65.1k | tmp = flb_sds_cat(buf, v->val.string, flb_sds_len(v->val.string)); |
581 | 65.1k | } |
582 | 985 | else if (v->type == FLB_RA_NULL) { |
583 | 985 | tmp = flb_sds_cat(buf, "null", 4); |
584 | 985 | } |
585 | | |
586 | 128k | flb_ra_key_value_destroy(v); |
587 | 128k | return tmp; |
588 | 144k | } |
589 | | |
590 | | /* |
591 | | * Translate a record accessor buffer, tag and records are optional |
592 | | * parameters. |
593 | | * |
594 | | * For safety, the function returns a newly created string that needs |
595 | | * to be destroyed by the caller. |
596 | | */ |
597 | | flb_sds_t flb_ra_translate(struct flb_record_accessor *ra, |
598 | | char *tag, int tag_len, |
599 | | msgpack_object map, struct flb_regex_search *result) |
600 | 1.75k | { |
601 | 1.75k | return flb_ra_translate_check(ra, tag, tag_len, map, result, FLB_FALSE); |
602 | 1.75k | } |
603 | | |
604 | | /* |
605 | | * Translate a record accessor buffer, tag and records are optional |
606 | | * parameters. |
607 | | * |
608 | | * For safety, the function returns a newly created string that needs |
609 | | * to be destroyed by the caller. |
610 | | * |
611 | | * Returns NULL if `check` is FLB_TRUE and any key lookup in the record failed |
612 | | */ |
613 | | flb_sds_t flb_ra_translate_check(struct flb_record_accessor *ra, |
614 | | char *tag, int tag_len, |
615 | | msgpack_object map, struct flb_regex_search *result, |
616 | | int check) |
617 | 1.75k | { |
618 | 1.75k | flb_sds_t tmp = NULL; |
619 | 1.75k | flb_sds_t buf; |
620 | 1.75k | struct mk_list *head; |
621 | 1.75k | struct flb_ra_parser *rp; |
622 | 1.75k | int found = FLB_FALSE; |
623 | | |
624 | 1.75k | buf = flb_sds_create_size(ra->size_hint); |
625 | 1.75k | if (!buf) { |
626 | 5 | flb_error("[record accessor] cannot create outgoing buffer"); |
627 | 5 | return NULL; |
628 | 5 | } |
629 | | |
630 | 294k | mk_list_foreach(head, &ra->list) { |
631 | 294k | rp = mk_list_entry(head, struct flb_ra_parser, _head); |
632 | 294k | if (rp->type == FLB_RA_PARSER_STRING) { |
633 | 146k | tmp = ra_translate_string(rp, buf); |
634 | 146k | } |
635 | 147k | else if (rp->type == FLB_RA_PARSER_KEYMAP) { |
636 | 145k | tmp = ra_translate_keymap(rp, buf, map, &found); |
637 | 145k | if (check == FLB_TRUE && found == FLB_FALSE) { |
638 | 0 | flb_warn("[record accessor] translation failed, root key=%s", rp->key->name); |
639 | 0 | flb_sds_destroy(buf); |
640 | 0 | return NULL; |
641 | 0 | } |
642 | 145k | } |
643 | 2.48k | else if (rp->type == FLB_RA_PARSER_REGEX_ID && result) { |
644 | 0 | tmp = ra_translate_regex_id(rp, result, buf); |
645 | 0 | } |
646 | 2.48k | else if (rp->type == FLB_RA_PARSER_TAG && tag) { |
647 | 0 | tmp = ra_translate_tag(rp, buf, tag, tag_len); |
648 | 0 | } |
649 | 2.48k | else if (rp->type == FLB_RA_PARSER_TAG_PART && tag) { |
650 | 0 | tmp = ra_translate_tag_part(rp, buf, tag, tag_len); |
651 | 0 | } |
652 | | |
653 | | //else if (rp->type == FLB_RA_PARSER_FUNC) { |
654 | | //tmp = ra_translate_func(rp, buf, tag, tag_len); |
655 | | //} |
656 | | |
657 | 294k | if (!tmp) { |
658 | 52 | flb_error("[record accessor] translation failed"); |
659 | 52 | flb_sds_destroy(buf); |
660 | 52 | return NULL; |
661 | 52 | } |
662 | 294k | if (tmp != buf) { |
663 | 271 | buf = tmp; |
664 | 271 | } |
665 | 294k | } |
666 | | |
667 | 1.69k | return buf; |
668 | 1.75k | } |
669 | | |
670 | | /* |
671 | | * If the record accessor rules do not generate content based on a keymap or |
672 | | * regex, it's considered to be 'static', so the value returned will always be |
673 | | * the same. |
674 | | * |
675 | | * If the 'ra' is static, return FLB_TRUE, otherwise FLB_FALSE. |
676 | | */ |
677 | | int flb_ra_is_static(struct flb_record_accessor *ra) |
678 | 1.75k | { |
679 | 1.75k | struct mk_list *head; |
680 | 1.75k | struct flb_ra_parser *rp; |
681 | | |
682 | 5.35k | mk_list_foreach(head, &ra->list) { |
683 | 5.35k | rp = mk_list_entry(head, struct flb_ra_parser, _head); |
684 | 5.35k | if (rp->type == FLB_RA_PARSER_STRING) { |
685 | 2.66k | continue; |
686 | 2.66k | } |
687 | 2.68k | else if (rp->type == FLB_RA_PARSER_KEYMAP) { |
688 | 1.17k | return FLB_FALSE; |
689 | 1.17k | } |
690 | 1.51k | else if (rp->type == FLB_RA_PARSER_REGEX_ID) { |
691 | 29 | return FLB_FALSE; |
692 | 29 | } |
693 | 1.48k | else if (rp->type == FLB_RA_PARSER_TAG) { |
694 | 398 | continue; |
695 | 398 | } |
696 | 1.08k | else if (rp->type == FLB_RA_PARSER_TAG_PART) { |
697 | 1.08k | continue; |
698 | 1.08k | } |
699 | 5.35k | } |
700 | | |
701 | 552 | return FLB_TRUE; |
702 | 1.75k | } |
703 | | |
704 | | /* |
705 | | * Compare a string value against the first entry of a record accessor component, used |
706 | | * specifically when the record accessor refers to a single key name. |
707 | | */ |
708 | | int flb_ra_strcmp(struct flb_record_accessor *ra, msgpack_object map, |
709 | | char *str, int len) |
710 | 0 | { |
711 | 0 | struct flb_ra_parser *rp; |
712 | |
|
713 | 0 | rp = mk_list_entry_first(&ra->list, struct flb_ra_parser, _head); |
714 | 0 | return flb_ra_key_strcmp(rp->key->name, map, rp->key->subkeys, |
715 | 0 | rp->key->name, flb_sds_len(rp->key->name)); |
716 | 0 | } |
717 | | |
718 | | /* |
719 | | * Check if a regular expression matches a record accessor key in the |
720 | | * given map |
721 | | */ |
722 | | int flb_ra_regex_match(struct flb_record_accessor *ra, msgpack_object map, |
723 | | struct flb_regex *regex, struct flb_regex_search *result) |
724 | 0 | { |
725 | 0 | struct flb_ra_parser *rp; |
726 | |
|
727 | 0 | rp = mk_list_entry_first(&ra->list, struct flb_ra_parser, _head); |
728 | 0 | if (rp == NULL || rp->key == NULL) { |
729 | 0 | return -1; |
730 | 0 | } |
731 | 0 | return flb_ra_key_regex_match(rp->key->name, map, rp->key->subkeys, |
732 | 0 | regex, result); |
733 | 0 | } |
734 | | |
735 | | |
736 | | static struct flb_ra_parser* get_ra_parser(struct flb_record_accessor *ra) |
737 | 0 | { |
738 | 0 | struct flb_ra_parser *rp = NULL; |
739 | |
|
740 | 0 | if (mk_list_size(&ra->list) == 0) { |
741 | 0 | return NULL; |
742 | 0 | } |
743 | 0 | rp = mk_list_entry_first(&ra->list, struct flb_ra_parser, _head); |
744 | 0 | if (!rp->key) { |
745 | 0 | return NULL; |
746 | 0 | } |
747 | 0 | return rp; |
748 | 0 | } |
749 | | |
750 | | /* |
751 | | * If 'record accessor' pattern matches an entry in the 'map', set the |
752 | | * reference in 'out_key' and 'out_val' for the entries in question. |
753 | | * |
754 | | * Returns FLB_TRUE if the pattern matched a kv pair, otherwise it returns |
755 | | * FLB_FALSE. |
756 | | */ |
757 | | int flb_ra_get_kv_pair(struct flb_record_accessor *ra, msgpack_object map, |
758 | | msgpack_object **start_key, |
759 | | msgpack_object **out_key, msgpack_object **out_val) |
760 | 0 | { |
761 | 0 | struct flb_ra_parser *rp; |
762 | |
|
763 | 0 | rp = get_ra_parser(ra); |
764 | 0 | if (rp == NULL) { |
765 | 0 | return FLB_FALSE; |
766 | 0 | } |
767 | | |
768 | 0 | return flb_ra_key_value_get(rp->key->name, map, rp->key->subkeys, |
769 | 0 | start_key, out_key, out_val); |
770 | 0 | } |
771 | | |
772 | | struct flb_ra_value *flb_ra_get_value_object(struct flb_record_accessor *ra, |
773 | | msgpack_object map) |
774 | 0 | { |
775 | 0 | struct flb_ra_parser *rp; |
776 | |
|
777 | 0 | rp = get_ra_parser(ra); |
778 | 0 | if (rp == NULL) { |
779 | 0 | return NULL; |
780 | 0 | } |
781 | | |
782 | 0 | return flb_ra_key_to_value(rp->key->name, map, rp->key->subkeys); |
783 | 0 | } |
784 | | |
785 | | /** |
786 | | * Update key and/or value of the map using record accessor. |
787 | | * |
788 | | * @param ra the record accessor to specify key/value pair |
789 | | * @param map the original map. |
790 | | * @param in_key the pointer to overwrite key. If NULL, key will not be updated. |
791 | | * @param in_val the pointer to overwrite val. If NULL, val will not be updated. |
792 | | * @param out_map the updated map. If the API fails, out_map will be NULL. |
793 | | * |
794 | | * @return result of the API. 0:success, -1:fail |
795 | | */ |
796 | | |
797 | | int flb_ra_update_kv_pair(struct flb_record_accessor *ra, msgpack_object map, |
798 | | void **out_map, size_t *out_size, |
799 | | msgpack_object *in_key, msgpack_object *in_val) |
800 | 0 | { |
801 | 0 | struct flb_ra_parser *rp; |
802 | 0 | msgpack_packer mp_pck; |
803 | 0 | msgpack_sbuffer mp_sbuf; |
804 | 0 | int ret; |
805 | |
|
806 | 0 | msgpack_object *s_key; |
807 | 0 | msgpack_object *o_key; |
808 | 0 | msgpack_object *o_val; |
809 | |
|
810 | 0 | if (in_key == NULL && in_val == NULL) { |
811 | | /* no key and value. nothing to do */ |
812 | 0 | flb_error("%s: no inputs", __FUNCTION__); |
813 | 0 | return -1; |
814 | 0 | } |
815 | 0 | else if (ra == NULL || out_map == NULL || out_size == NULL) { |
816 | | /* invalid input */ |
817 | 0 | flb_error("%s: invalid input", __FUNCTION__); |
818 | 0 | return -1; |
819 | 0 | } |
820 | 0 | else if ( flb_ra_get_kv_pair(ra, map, &s_key, &o_key, &o_val) != 0) { |
821 | | /* key and value are not found */ |
822 | 0 | flb_error("%s: no value", __FUNCTION__); |
823 | 0 | return -1; |
824 | 0 | } |
825 | | |
826 | 0 | rp = get_ra_parser(ra); |
827 | 0 | if (rp == NULL) { |
828 | 0 | return -1; |
829 | 0 | } |
830 | | |
831 | 0 | msgpack_sbuffer_init(&mp_sbuf); |
832 | 0 | msgpack_packer_init(&mp_pck, &mp_sbuf, msgpack_sbuffer_write); |
833 | |
|
834 | 0 | ret = flb_ra_key_value_update(rp, map, in_key, in_val, &mp_pck); |
835 | 0 | if (ret < 0) { |
836 | 0 | msgpack_sbuffer_destroy(&mp_sbuf); |
837 | 0 | return -1; |
838 | 0 | } |
839 | 0 | *out_map = mp_sbuf.data; |
840 | 0 | *out_size = mp_sbuf.size; |
841 | |
|
842 | 0 | return 0; |
843 | 0 | } |
844 | | |
845 | | /** |
846 | | * Add key and/or value of the map using record accessor. |
847 | | * If key already exists, the API fails. |
848 | | * |
849 | | * @param ra the record accessor to specify key. |
850 | | * @param map the original map. |
851 | | * @param in_val the pointer to add val. |
852 | | * @param out_map the updated map. If the API fails, out_map will be NULL. |
853 | | * |
854 | | * @return result of the API. 0:success, -1:fail |
855 | | */ |
856 | | |
857 | | int flb_ra_append_kv_pair(struct flb_record_accessor *ra, msgpack_object map, |
858 | | void **out_map, size_t *out_size, |
859 | | msgpack_object *in_val) |
860 | 0 | { |
861 | 0 | struct flb_ra_parser *rp; |
862 | 0 | msgpack_packer mp_pck; |
863 | 0 | msgpack_sbuffer mp_sbuf; |
864 | 0 | int ret; |
865 | |
|
866 | 0 | msgpack_object *s_key = NULL; |
867 | 0 | msgpack_object *o_key = NULL; |
868 | 0 | msgpack_object *o_val = NULL; |
869 | |
|
870 | 0 | if (in_val == NULL) { |
871 | | /* no key and value. nothing to do */ |
872 | 0 | flb_error("%s: no value", __FUNCTION__); |
873 | 0 | return -1; |
874 | 0 | } |
875 | 0 | else if (ra == NULL || out_map == NULL|| out_size == NULL) { |
876 | | /* invalid input */ |
877 | 0 | flb_error("%s: invalid input", __FUNCTION__); |
878 | 0 | return -1; |
879 | 0 | } |
880 | | |
881 | 0 | flb_ra_get_kv_pair(ra, map, &s_key, &o_key, &o_val); |
882 | 0 | if (o_key != NULL && o_val != NULL) { |
883 | | /* key and value already exist */ |
884 | 0 | flb_error("%s: already exist", __FUNCTION__); |
885 | 0 | return -1; |
886 | 0 | } |
887 | | |
888 | 0 | rp = get_ra_parser(ra); |
889 | 0 | if (rp == NULL || rp->key == NULL) { |
890 | 0 | return -1; |
891 | 0 | } |
892 | | |
893 | 0 | msgpack_sbuffer_init(&mp_sbuf); |
894 | 0 | msgpack_packer_init(&mp_pck, &mp_sbuf, msgpack_sbuffer_write); |
895 | |
|
896 | 0 | ret = flb_ra_key_value_append(rp, map, in_val, &mp_pck); |
897 | 0 | if (ret < 0) { |
898 | 0 | msgpack_sbuffer_destroy(&mp_sbuf); |
899 | 0 | return -1; |
900 | 0 | } |
901 | | |
902 | 0 | *out_map = mp_sbuf.data; |
903 | 0 | *out_size = mp_sbuf.size; |
904 | |
|
905 | 0 | return 0; |
906 | 0 | } |