Skip to content

Commit ee654ea

Browse files
committed
out_cloudwatch_logs: increase MAX_EVENT_LEN to 1MB with tests
Increase MAX_EVENT_LEN from 262,118 bytes (256 KiB) to 1,000,000 bytes (1 MB) to better align with AWS CloudWatch's documented maximum event size of 1,048,576 bytes (1 MiB). The 1 MB limit provides a ~4.6% safety margin to account for JSON encoding overhead. Testing confirmed messages up to 1,048,546 bytes (encoding to 1,048,586 bytes) succeed, though we use a conservative limit for production safety. Add runtime tests to validate the new limit: - event_size_near_limit: Validates events just under 1MB are accepted - event_size_at_aws_max: Validates events near AWS max are truncated - event_truncation_with_backslash: Validates backslash handling at truncation boundary Signed-off-by: Shelby Hagman <[email protected]>
1 parent 4f8c50b commit ee654ea

File tree

2 files changed

+145
-2
lines changed

2 files changed

+145
-2
lines changed

plugins/out_cloudwatch_logs/cloudwatch_api.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,17 @@
4343
/* Maximum number of character limits including both the Attributes key and its value */
4444
#define ATTRIBUTES_MAX_LEN 300
4545

46-
/* 256KiB minus 26 bytes for the event */
47-
#define MAX_EVENT_LEN 262118
46+
/*
47+
* https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutLogEvents.html
48+
* AWS CloudWatch's documented maximum event size is 1,048,576 bytes (1 MiB),
49+
* including JSON encoding overhead (structure, escaping, etc.).
50+
*
51+
* Setting MAX_EVENT_LEN to 1,000,000 bytes (1 MB) provides a ~4.6% safety margin
52+
* to account for JSON encoding overhead and ensure reliable operation.
53+
* Testing confirmed messages up to 1,048,546 bytes (encoding to 1,048,586 bytes)
54+
* succeed, though we use a conservative limit for production safety.
55+
*/
56+
#define MAX_EVENT_LEN 1000000
4857

4958
/* Prefix used for entity fields only */
5059
#define AWS_ENTITY_PREFIX "aws_entity"

tests/runtime/out_cloudwatch.c

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
/* not a real error code, but tests that the code can respond to any error */
1010
#define ERROR_UNKNOWN "{\"__type\":\"UNKNOWN\"}"
1111

12+
/* MAX_EVENT_LEN from cloudwatch_api.h */
13+
#define MAX_EVENT_LEN 1000000
14+
1215
/* It writes a big JSON message (copied from TD test) */
1316
void flb_test_cloudwatch_success(void)
1417
{
@@ -393,6 +396,134 @@ void flb_test_cloudwatch_error_put_retention_policy(void)
393396
flb_destroy(ctx);
394397
}
395398

399+
/* Helper function to create a large JSON message of specified size */
400+
static char* create_large_json_message(size_t target_size)
401+
{
402+
char *json;
403+
size_t i;
404+
size_t data_size;
405+
406+
/* Account for JSON structure: {"message":"..."} = 15 chars + data */
407+
if (target_size < 20) {
408+
target_size = 20;
409+
}
410+
411+
json = flb_malloc(target_size + 1);
412+
if (!json) {
413+
return NULL;
414+
}
415+
416+
/* Start JSON object */
417+
strcpy(json, "{\"message\":\"");
418+
data_size = target_size - 15; /* Subtract JSON structure overhead */
419+
420+
/* Fill with 'A' characters */
421+
for (i = 0; i < data_size; i++) {
422+
json[12 + i] = 'A';
423+
}
424+
425+
/* Close JSON object */
426+
strcpy(json + 12 + data_size, "\"}");
427+
json[target_size] = '\0';
428+
429+
return json;
430+
}
431+
432+
/* Helper to setup and run a CloudWatch test with custom JSON data */
433+
static void run_cloudwatch_test_with_data(char *data, size_t data_len)
434+
{
435+
int ret;
436+
flb_ctx_t *ctx;
437+
int in_ffd;
438+
int out_ffd;
439+
440+
setenv("FLB_CLOUDWATCH_PLUGIN_UNDER_TEST", "true", 1);
441+
442+
ctx = flb_create();
443+
444+
in_ffd = flb_input(ctx, (char *) "lib", NULL);
445+
TEST_CHECK(in_ffd >= 0);
446+
flb_input_set(ctx, in_ffd, "tag", "test", NULL);
447+
448+
out_ffd = flb_output(ctx, (char *) "cloudwatch_logs", NULL);
449+
TEST_CHECK(out_ffd >= 0);
450+
flb_output_set(ctx, out_ffd, "match", "test", NULL);
451+
flb_output_set(ctx, out_ffd, "region", "us-west-2", NULL);
452+
flb_output_set(ctx, out_ffd, "log_group_name", "fluent", NULL);
453+
flb_output_set(ctx, out_ffd, "log_stream_prefix", "from-fluent-", NULL);
454+
flb_output_set(ctx, out_ffd, "auto_create_group", "On", NULL);
455+
flb_output_set(ctx, out_ffd, "net.keepalive", "Off", NULL);
456+
flb_output_set(ctx, out_ffd, "Retry_Limit", "1", NULL);
457+
458+
ret = flb_start(ctx);
459+
TEST_CHECK(ret == 0);
460+
461+
if (data) {
462+
flb_lib_push(ctx, in_ffd, data, data_len);
463+
}
464+
465+
sleep(2);
466+
flb_stop(ctx);
467+
flb_destroy(ctx);
468+
}
469+
470+
/* Test event size just under the limit (should succeed) */
471+
void flb_test_cloudwatch_event_size_near_limit(void)
472+
{
473+
char *large_json;
474+
475+
/* Create message just under MAX_EVENT_LEN (999,000 bytes) */
476+
large_json = create_large_json_message(999000);
477+
TEST_CHECK(large_json != NULL);
478+
479+
if (large_json) {
480+
run_cloudwatch_test_with_data(large_json, strlen(large_json));
481+
flb_free(large_json);
482+
}
483+
}
484+
485+
/* Test event size at AWS maximum (should be truncated to MAX_EVENT_LEN) */
486+
void flb_test_cloudwatch_event_size_at_aws_max(void)
487+
{
488+
char *large_json;
489+
490+
/* Create message near AWS max (1,048,576 bytes) */
491+
large_json = create_large_json_message(1048500);
492+
TEST_CHECK(large_json != NULL);
493+
494+
if (large_json) {
495+
run_cloudwatch_test_with_data(large_json, strlen(large_json));
496+
flb_free(large_json);
497+
}
498+
}
499+
500+
/* Test event with trailing backslash at truncation boundary */
501+
void flb_test_cloudwatch_event_truncation_with_backslash(void)
502+
{
503+
char *large_json;
504+
size_t i;
505+
506+
/* Create message with backslashes near the truncation point */
507+
large_json = flb_malloc(1000100);
508+
TEST_CHECK(large_json != NULL);
509+
510+
if (large_json) {
511+
strcpy(large_json, "{\"message\":\"");
512+
/* Fill with pattern that includes backslashes */
513+
for (i = 0; i < 999980; i++) {
514+
if (i % 100 == 99) {
515+
large_json[12 + i] = '\\';
516+
} else {
517+
large_json[12 + i] = 'A';
518+
}
519+
}
520+
strcpy(large_json + 12 + 999980, "\"}");
521+
522+
run_cloudwatch_test_with_data(large_json, strlen(large_json));
523+
flb_free(large_json);
524+
}
525+
}
526+
396527
/* Test list */
397528
TEST_LIST = {
398529
{"success", flb_test_cloudwatch_success },
@@ -405,5 +536,8 @@ TEST_LIST = {
405536
{"put_retention_policy_success", flb_test_cloudwatch_put_retention_policy_success },
406537
{"already_exists_create_group_put_retention_policy", flb_test_cloudwatch_already_exists_create_group_put_retention_policy },
407538
{"error_put_retention_policy", flb_test_cloudwatch_error_put_retention_policy },
539+
{"event_size_near_limit", flb_test_cloudwatch_event_size_near_limit },
540+
{"event_size_at_aws_max", flb_test_cloudwatch_event_size_at_aws_max },
541+
{"event_truncation_with_backslash", flb_test_cloudwatch_event_truncation_with_backslash },
408542
{NULL, NULL}
409543
};

0 commit comments

Comments
 (0)