Skip to content

fix: flush buffered OTEL logs - #2772

Merged
EItanya merged 1 commit into
kagent-dev:mainfrom
yashrajshuklaaa:fix/flush-otel-logger-provider
Sep 26, 2026
Merged

EItanya merged 1 commit into
kagent-dev:mainfrom
yashrajshuklaaa:fix/flush-otel-logger-provider

Conversation

@yashrajshuklaaa

Copy link
Copy Markdown
Contributor

What

Fix ForceFlush() so it flushes both the tracer and logger providers.

Why

GenAI audit logs are buffered by the OTEL batch log processor. When an Agent Substrate actor checkpoints right after the A2A response closes, those buffered logs can be left behind and never exported.

Changes

  • Flush the global LoggerProvider in ForceFlush().
  • Keep tracer flushing working as before.
  • Use the same timeout for both providers.
  • Added a regression test to make sure buffered logs are exported, even when the request context is already cancelled.
  • Updated the related comment from spans to telemetry.

Validation

  • go test ./adk/pkg/telemetry ./adk/pkg/a2a/server
  • go build ./adk/pkg/telemetry ./adk/pkg/a2a/server

All passed.

Fixes #2759

@github-actions github-actions Bot added the bug Something isn't working label Sep 9, 2026
@EItanya

EItanya commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

@krisztianfekete

@krisztianfekete krisztianfekete 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.

Thanks for the PR! Would you mind also fixing this on the Python side, address the comments and add test coverage for both runtimes and both signals?

Comment thread go/adk/pkg/telemetry/tracing.go Outdated
return
}

flushCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), flushTimeout())

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.

Can we give each provider its own budget, or flush logs first?

Comment thread go/adk/pkg/telemetry/tracing.go Outdated
// session's last message).
// Uses its own detached timeout because the request context is typically
// already canceled by the time deferred cleanup runs. The timeout defaults to
// 3s and is configurable via KAGENT_TRACE_FLUSH_TIMEOUT_MS.

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.

We probably want to rename this now that it covers both traces and logs.

@yashrajshuklaaa
yashrajshuklaaa requested a review from a team as a code owner September 10, 2026 16:04
@yashrajshuklaaa

Copy link
Copy Markdown
Contributor Author

@krisztianfekete Thanks for the review. I’ve addressed the comments and updated the PR. fix now covers both Go and Python, flushing logs first while keeping a shared timeout budget. also added test coverage for both logs and traces in both runtimes and renamed the timeout setting to KAGENT_TELEMETRY_FLUSH_TIMEOUT_MS
Validation is passing locally and the changes are pushed to the PR.

Comment thread go/adk/pkg/telemetry/tracing.go Outdated
Comment thread go/adk/pkg/telemetry/tracing.go Outdated
Comment thread python/packages/kagent-core/tests/test_tracing_configure.py Outdated
@yashrajshuklaaa

Copy link
Copy Markdown
Contributor Author

@mesutoezdil resolved all comments :) PTAL

@yashrajshuklaaa

Copy link
Copy Markdown
Contributor Author

@krisztianfekete pls review this

Comment on lines 310 to 313

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.

This is nested under if tracing_enabled, so with OTEL_LOGGING_ENABLED=true and tracing off the new log flush is never called. Can you move out of the tracing branch?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed. the post-response flush hook now installs when tracing_enabled or metrics_enabled or logging_enabled. Added test_configure_installs_post_response_flush_with_logs_only to cover the logs-only case.

Comment thread go/pkg/tracing/tracing.go Outdated
Comment on lines +106 to +109
flushCtx, cancel := context.WithTimeout(
context.WithoutCancel(ctx),
flushTimeout(),
)

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.

Both implementations share this one deadline, while Python splits the budget with remaining_millis, can you please match the two?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Matched now. each provider in Go gets its own full FlushTimeout, the same way Python already passed the full timeout_millis to each provider's force_flush individually. No more shared/split deadline in either runtime.

Comment thread go/pkg/tracing/tracing.go Outdated

func flushTimeout() time.Duration {
if value := strings.TrimSpace(os.Getenv("KAGENT_TRACE_FLUSH_TIMEOUT_MS")); value != "" {
if value := strings.TrimSpace(os.Getenv("KAGENT_TELEMETRY_FLUSH_TIMEOUT_MS")); value != "" {

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.

The rename drops any existing KAGENT_TRACE_FLUSH_TIMEOUT_MS override to the 3s default with no warning. Can we keep the old name as a fallback for a release and log a notice for the rename?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Moot after the rebase. the telemetry refactor removed the configurable timeout env var entirely in favor of a fixed constant so there's no override or fallback to preserve on either name.

@yashrajshuklaaa
yashrajshuklaaa force-pushed the fix/flush-otel-logger-provider branch from 8d34cf6 to c70733d Compare September 25, 2026 01:19
@yashrajshuklaaa

Copy link
Copy Markdown
Contributor Author

@krisztianfekete all review comments have been addressed. PTAL : )

@krisztianfekete krisztianfekete 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.

Thanks for sticking with this, one last rebase needed. #2929 merged after your push and changed Providers.ForceFlush.

On the Go side, let's keep main's version and only add the logger. Drop the per-provider flush and use the one shared timeout. Flush logs first, then tracer, then meter, and include p.logger == nil in the early return.

Python changes should be fine after the rebase.

@yashrajshuklaaa
yashrajshuklaaa force-pushed the fix/flush-otel-logger-provider branch from c70733d to b6eb9b7 Compare September 25, 2026 20:16
@yashrajshuklaaa

Copy link
Copy Markdown
Contributor Author

Thanks for sticking with this, one last rebase needed. #2929 merged after your push and changed Providers.ForceFlush.

On the Go side, let's keep main's version and only add the logger. Drop the per-provider flush and use the one shared timeout. Flush logs first, then tracer, then meter, and include p.logger == nil in the early return.

Python changes should be fine after the rebase.

Rebased onto main after #2929. Kept the flushRecordKey/WithFlushRecord skip-on-failure logic and single shared FlushTimeout, dropped the per-provider timeout split, and added the logger flush on top, keeping the logs to tracer to meter order via errors.Join. Also added p.logger == nil to the early-return check. Go and Python tests all passing on my end, PTAL 🙂

Comment thread go/pkg/telemetry/telemetry.go Outdated
Comment on lines +169 to +171
flush := func(f func(context.Context) error) error {
return f(ctx)
}

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.

This wrapper does nothing now, please call p.logger.ForceFlush(ctx) and the others directly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done :)

Signed-off-by: Yashraj Shukla <shuklayashraj68@gmail.com>
@yashrajshuklaaa
yashrajshuklaaa force-pushed the fix/flush-otel-logger-provider branch from b6eb9b7 to f6f0e0e Compare September 25, 2026 20:33
@EItanya
EItanya added this pull request to the merge queue Sep 26, 2026
Merged via the queue into kagent-dev:main with commit 271c72e Sep 26, 2026
29 checks passed
@yashrajshuklaaa

Copy link
Copy Markdown
Contributor Author

thanks @krisztianfekete @EItanya 🎉☺️

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ForceFlush never flushes the LoggerProvider, so GenAI audit records are silently dropped when the Actor checkpoints

4 participants