|
38 | 38 |
|
39 | 39 | #include <fluent-bit/flb_base64.h> |
40 | 40 | #include <fluent-bit/aws/flb_aws_compress.h> |
| 41 | +#include <fluent-bit/aws/flb_aws_aggregation.h> |
41 | 42 |
|
42 | 43 | #include <monkey/mk_core.h> |
43 | 44 | #include <msgpack.h> |
|
53 | 54 |
|
54 | 55 | #define ERR_CODE_SERVICE_UNAVAILABLE "ServiceUnavailableException" |
55 | 56 |
|
| 57 | +/* Forward declarations */ |
| 58 | +static int send_log_events(struct flb_firehose *ctx, struct flush *buf); |
| 59 | + |
56 | 60 | static struct flb_aws_header put_record_batch_header = { |
57 | 61 | .key = "X-Amz-Target", |
58 | 62 | .key_len = 12, |
@@ -141,6 +145,29 @@ static int end_put_payload(struct flb_firehose *ctx, struct flush *buf, |
141 | 145 | } |
142 | 146 |
|
143 | 147 |
|
| 148 | +/* |
| 149 | + * Process event with simple aggregation (Firehose version) |
| 150 | + * Uses shared aggregation implementation |
| 151 | + */ |
| 152 | +static int process_event_simple_aggregation(struct flb_firehose *ctx, struct flush *buf, |
| 153 | + const msgpack_object *obj, struct flb_time *tms, |
| 154 | + struct flb_config *config) |
| 155 | +{ |
| 156 | + return flb_aws_aggregation_process_event(&buf->agg_buf, |
| 157 | + buf->tmp_buf, |
| 158 | + buf->tmp_buf_size, |
| 159 | + &buf->tmp_buf_offset, |
| 160 | + obj, |
| 161 | + tms, |
| 162 | + config, |
| 163 | + ctx->ins, |
| 164 | + ctx->delivery_stream, |
| 165 | + ctx->log_key, |
| 166 | + ctx->time_key, |
| 167 | + ctx->time_key_format, |
| 168 | + MAX_EVENT_SIZE); |
| 169 | +} |
| 170 | + |
144 | 171 | /* |
145 | 172 | * Processes the msgpack object |
146 | 173 | * -1 = failure, record not added |
@@ -356,6 +383,102 @@ static void reset_flush_buf(struct flb_firehose *ctx, struct flush *buf) { |
356 | 383 | buf->data_size += strlen(ctx->delivery_stream); |
357 | 384 | } |
358 | 385 |
|
| 386 | +/* Finalize and send aggregated record */ |
| 387 | +static int send_aggregated_record(struct flb_firehose *ctx, struct flush *buf) { |
| 388 | + int ret; |
| 389 | + size_t agg_size; |
| 390 | + size_t b64_len; |
| 391 | + struct firehose_event *event; |
| 392 | + void *compressed_tmp_buf; |
| 393 | + size_t compressed_size; |
| 394 | + |
| 395 | + /* Finalize the aggregated record */ |
| 396 | + ret = flb_aws_aggregation_finalize(&buf->agg_buf, 1, &agg_size); |
| 397 | + if (ret < 0) { |
| 398 | + /* No data to finalize */ |
| 399 | + return 0; |
| 400 | + } |
| 401 | + |
| 402 | + /* Handle compression if enabled */ |
| 403 | + if (ctx->compression != FLB_AWS_COMPRESS_NONE) { |
| 404 | + ret = flb_aws_compression_b64_truncate_compress(ctx->compression, |
| 405 | + MAX_B64_EVENT_SIZE, |
| 406 | + buf->agg_buf.agg_buf, |
| 407 | + agg_size, |
| 408 | + &compressed_tmp_buf, |
| 409 | + &compressed_size); |
| 410 | + if (ret == -1) { |
| 411 | + flb_plg_error(ctx->ins, "Unable to compress aggregated record, discarding, %s", |
| 412 | + ctx->delivery_stream); |
| 413 | + flb_aws_aggregation_reset(&buf->agg_buf); |
| 414 | + return 0; |
| 415 | + } |
| 416 | + |
| 417 | + /* Ensure event_buf is large enough */ |
| 418 | + if (buf->event_buf == NULL || buf->event_buf_size < compressed_size) { |
| 419 | + flb_free(buf->event_buf); |
| 420 | + buf->event_buf = compressed_tmp_buf; |
| 421 | + buf->event_buf_size = compressed_size; |
| 422 | + compressed_tmp_buf = NULL; |
| 423 | + } else { |
| 424 | + memcpy(buf->event_buf, compressed_tmp_buf, compressed_size); |
| 425 | + flb_free(compressed_tmp_buf); |
| 426 | + } |
| 427 | + agg_size = compressed_size; |
| 428 | + } |
| 429 | + else { |
| 430 | + /* Base64 encode the aggregated record */ |
| 431 | + size_t size = (agg_size * 1.5) + 4; |
| 432 | + if (buf->event_buf == NULL || buf->event_buf_size < size) { |
| 433 | + flb_free(buf->event_buf); |
| 434 | + buf->event_buf = flb_malloc(size); |
| 435 | + buf->event_buf_size = size; |
| 436 | + if (buf->event_buf == NULL) { |
| 437 | + flb_errno(); |
| 438 | + return -1; |
| 439 | + } |
| 440 | + } |
| 441 | + |
| 442 | + ret = flb_base64_encode((unsigned char *) buf->event_buf, size, &b64_len, |
| 443 | + (unsigned char *) buf->agg_buf.agg_buf, agg_size); |
| 444 | + if (ret != 0) { |
| 445 | + flb_errno(); |
| 446 | + return -1; |
| 447 | + } |
| 448 | + agg_size = b64_len; |
| 449 | + } |
| 450 | + |
| 451 | + /* Copy to tmp_buf for sending */ |
| 452 | + if (buf->tmp_buf_size < agg_size) { |
| 453 | + flb_plg_error(ctx->ins, "Aggregated record too large for buffer"); |
| 454 | + flb_aws_aggregation_reset(&buf->agg_buf); |
| 455 | + return 0; |
| 456 | + } |
| 457 | + |
| 458 | + memcpy(buf->tmp_buf, buf->event_buf, agg_size); |
| 459 | + |
| 460 | + /* Create event record */ |
| 461 | + event = &buf->events[0]; |
| 462 | + event->json = buf->tmp_buf; |
| 463 | + event->len = agg_size; |
| 464 | + event->timestamp.tv_sec = 0; |
| 465 | + event->timestamp.tv_nsec = 0; |
| 466 | + buf->event_index = 1; |
| 467 | + |
| 468 | + /* Calculate data_size for the payload */ |
| 469 | + buf->data_size = PUT_RECORD_BATCH_HEADER_LEN + PUT_RECORD_BATCH_FOOTER_LEN; |
| 470 | + buf->data_size += strlen(ctx->delivery_stream); |
| 471 | + buf->data_size += agg_size + PUT_RECORD_BATCH_PER_RECORD_LEN; |
| 472 | + |
| 473 | + /* Send the aggregated record */ |
| 474 | + ret = send_log_events(ctx, buf); |
| 475 | + |
| 476 | + /* Reset aggregation buffer */ |
| 477 | + flb_aws_aggregation_reset(&buf->agg_buf); |
| 478 | + |
| 479 | + return ret; |
| 480 | +} |
| 481 | + |
359 | 482 | /* constructs a put payload, and then sends */ |
360 | 483 | static int send_log_events(struct flb_firehose *ctx, struct flush *buf) { |
361 | 484 | int ret; |
@@ -445,6 +568,38 @@ static int add_event(struct flb_firehose *ctx, struct flush *buf, |
445 | 568 | reset_flush_buf(ctx, buf); |
446 | 569 | } |
447 | 570 |
|
| 571 | + /* Use simple aggregation if enabled */ |
| 572 | + if (ctx->simple_aggregation) { |
| 573 | +retry_add_event_agg: |
| 574 | + retry_add = FLB_FALSE; |
| 575 | + ret = process_event_simple_aggregation(ctx, buf, obj, tms, config); |
| 576 | + if (ret < 0) { |
| 577 | + return -1; |
| 578 | + } |
| 579 | + else if (ret == 1) { |
| 580 | + /* Buffer full - send aggregated record and retry */ |
| 581 | + ret = send_aggregated_record(ctx, buf); |
| 582 | + reset_flush_buf(ctx, buf); |
| 583 | + if (ret < 0) { |
| 584 | + return -1; |
| 585 | + } |
| 586 | + retry_add = FLB_TRUE; |
| 587 | + } |
| 588 | + else if (ret == 2) { |
| 589 | + /* Discard this record */ |
| 590 | + flb_plg_warn(ctx->ins, "Discarding large or unprocessable record, %s", |
| 591 | + ctx->delivery_stream); |
| 592 | + return 0; |
| 593 | + } |
| 594 | + |
| 595 | + if (retry_add == FLB_TRUE) { |
| 596 | + goto retry_add_event_agg; |
| 597 | + } |
| 598 | + |
| 599 | + return 0; |
| 600 | + } |
| 601 | + |
| 602 | + /* Normal processing without aggregation */ |
448 | 603 | retry_add_event: |
449 | 604 | retry_add = FLB_FALSE; |
450 | 605 | ret = process_event(ctx, buf, obj, tms, config); |
@@ -603,7 +758,13 @@ int process_and_send_records(struct flb_firehose *ctx, struct flush *buf, |
603 | 758 | flb_log_event_decoder_destroy(&log_decoder); |
604 | 759 |
|
605 | 760 | /* send any remaining events */ |
606 | | - ret = send_log_events(ctx, buf); |
| 761 | + if (ctx->simple_aggregation) { |
| 762 | + /* Send any remaining aggregated data */ |
| 763 | + ret = send_aggregated_record(ctx, buf); |
| 764 | + } |
| 765 | + else { |
| 766 | + ret = send_log_events(ctx, buf); |
| 767 | + } |
607 | 768 | reset_flush_buf(ctx, buf); |
608 | 769 |
|
609 | 770 | if (ret < 0) { |
@@ -953,6 +1114,9 @@ int put_record_batch(struct flb_firehose *ctx, struct flush *buf, |
953 | 1114 | void flush_destroy(struct flush *buf) |
954 | 1115 | { |
955 | 1116 | if (buf) { |
| 1117 | + if (buf->agg_buf_initialized) { |
| 1118 | + flb_aws_aggregation_destroy(&buf->agg_buf); |
| 1119 | + } |
956 | 1120 | flb_free(buf->tmp_buf); |
957 | 1121 | flb_free(buf->out_buf); |
958 | 1122 | flb_free(buf->events); |
|
0 commit comments