Skip to content

[FLINK-40452] Cap exception fetching by size instead of line count - #1194

Open
mbalassi wants to merge 1 commit into
apache:mainfrom
mbalassi:flink-40452
Open

mbalassi wants to merge 1 commit into
apache:mainfrom
mbalassi:flink-40452

Conversation

@mbalassi

@mbalassi mbalassi commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

JobStatusObserver capped JobManager exception text in K8s events byline count (stacktrace.split("\n"), keep first N lines). A single unbroken line of any size produces one array element, so it bypassed the cap entirely and could fill the operator heap.

Approach

  • Replaced events.exceptions.stacktrace-lines (line count, default 5)
    with events.exceptions.stacktrace.max.length (character count, default
    2048 — matches the two existing sibling options
    exception.stacktrace.max.length / exception.field.max.length; no
    config in the repo defaults to 4096, so 2048 was kept rather than
    raised).
  • Replaced the truncation itself: stacktrace.length() >
    maxStackTraceLength + bounded substring, instead of splitting on \n.
    Also removes an unbounded 3-4x string-copy chain downstream of the old
    cap.
  • Old option removed outright (no value-preserving migration exists
    between line-count and character-count semantics).
  • Added a regression test (5000-char single line, no newlines) and
    updated existing tests, generated config docs, and hand-written
    event-format docs (both locales).

Testing

Updated existing unit test and added a new test to explicitly cover the bug scenario reported in FlINK-40452.


Was generative AI tooling used to co-author this PR?
  • Yes (please specify the tool below)

Generated-by: Claude Code (Opus 5)

@mbalassi
mbalassi requested a review from rmetzger August 26, 2026 15:05

@Dennis-Mircea Dennis-Mircea left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also took a closer look at JobStatusObserver and I see that the recordJobErrorIfPresent method is not covered by this feature, and currently it can emit event messages of any size. I'd say will great to extend the max length support for this method as well.

Additionally, the observeJobManagerExceptions has a TODO in place as of now which brings into light another hot spot for this max cap feature. Currently, the history of exceptions is being retrieved via REST and can have a big size as well, so I'd say it is worth considering fixing that place as well and to wrap everything at once for JobStatusObserver.

operatorConfig.get(KubernetesOperatorConfigOptions.OPERATOR_EVENT_EXCEPTION_LIMIT);
int reportedExceptionEventsMaxStackTraceLength =
operatorConfig.get(
KubernetesOperatorConfigOptions.OPERATOR_EVENT_EXCEPTION_STACKTRACE_LINES);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't be better/safer to first deprecate this option that was introduced as part of 1.12.0 operator release and remove it in further releases?

public static final ConfigOption<Integer> OPERATOR_EVENT_EXCEPTION_STACKTRACE_LINES =
operatorConfig("events.exceptions.stacktrace-lines")
public static final ConfigOption<Integer> OPERATOR_EVENT_EXCEPTION_STACKTRACE_MAX_LENGTH =
operatorConfig("events.exceptions.stacktrace.max.length")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say it's good to add a defensive support for negative values, and maybe consider -1 value as unlimited length.

@spuru9 spuru9 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM post the addressing the comments from Dennis.

@mbalassi Can you take a look at them.

.append(stacktrace.length() - maxStackTraceLength)
.append(" more characters)");
} else {
eventMessage.append(stacktrace);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit optional: we can simply this to

          if (stacktrace != null && !stacktrace.isBlank()) {                                                                                                                                                     
              getSubstringWithMaxLength(stacktrace, maxStackTraceLength).ifPresent(eventMessage::append);                                                                                                        
              if (stacktrace.length() > maxStackTraceLength) {                                                                                                                                                   
                  eventMessage                                                                                                                                                                                   
                          .append("... (")                                                                                                                                                                       
                          .append(stacktrace.length() - maxStackTraceLength)                                                                                                                                     
                          .append(" more characters)");                                                                                                                                                          
              }                                                                                                                                                                                                  
          }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants