-
Notifications
You must be signed in to change notification settings - Fork 432
[chore] Add warnings when instrumentation is used before initialization #3177
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…ed before ag.init()
|
@astandrik is attempting to deploy a commit to the agenta projects Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements a warning mechanism to alert users when instrumented functions are called before ag.init() is invoked. The implementation adds pre-initialization checks across all four function types (sync, async, sync generator, async generator) that emit a one-time RuntimeWarning to guide users toward correct SDK initialization.
Key Changes
- Added
_is_tracing_initialized()helper to check if the Agenta SDK tracing is properly initialized - Implemented
_warn_instrumentation_before_init_once()that emits a one-time warning with clear guidance when tracing is not initialized - Integrated early-return logic into all four instrumentation wrappers to gracefully handle pre-init calls
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| sdk/agenta/sdk/decorators/tracing.py | Adds initialization checking logic, warning mechanism, and early-return behavior for all four function types when tracing is not initialized |
| sdk/tests/unit/test_tracing_decorators.py | Adds test class with 3 tests covering sync functions, async functions, and sync generators to verify warning behavior |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| async def test_async_generator_warns_once_and_still_executes(self, recwarn): | ||
| @instrument() | ||
| async def gen(): | ||
| yield "a" | ||
| await asyncio.sleep(0.001) | ||
| yield "b" | ||
|
|
||
| first = [] | ||
| async for item in gen(): | ||
| first.append(item) | ||
| assert first == ["a", "b"] | ||
|
|
||
| second = [] | ||
| async for item in gen(): | ||
| second.append(item) | ||
| assert second == ["a", "b"] | ||
|
|
||
| runtime_warnings = [ | ||
| w for w in recwarn if issubclass(w.category, RuntimeWarning) | ||
| ] | ||
| assert len(runtime_warnings) == 1 |
Copilot
AI
Dec 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test validates the number of warnings but doesn't check the warning message content like the sync function test does (lines 711-713). Consider adding similar assertions to verify the warning message contains "called before ag.init()" and "Fix: call ag.init()" for consistency and completeness.
| is_sync_generator = isgeneratorfunction(handler) | ||
| is_async_generator = isasyncgenfunction(handler) | ||
|
|
||
| handler_name = f"{getattr(handler, '__module__', '<unknown>')}.{getattr(handler, '__qualname__', getattr(handler, '__name__', '<unknown>'))}" |
Copilot
AI
Dec 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line exceeds typical line length conventions (appears to be ~140+ characters). Consider breaking it into multiple lines for better readability. For example, compute qualname separately first, then construct the full handler_name.
| handler_name = f"{getattr(handler, '__module__', '<unknown>')}.{getattr(handler, '__qualname__', getattr(handler, '__name__', '<unknown>'))}" | |
| qualname = getattr(handler, '__qualname__', getattr(handler, '__name__', '<unknown>')) | |
| handler_name = f"{getattr(handler, '__module__', '<unknown>')}.{qualname}" |
|
|
||
| log = get_module_logger(__name__) | ||
|
|
||
| _PREINIT_INSTRUMENTATION_WARNING_EMITTED = False |
Copilot
AI
Dec 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The global variable _PREINIT_INSTRUMENTATION_WARNING_EMITTED is not thread-safe. In a multi-threaded environment, multiple threads could simultaneously check if the warning has been emitted (line 56), both see False, and both proceed to emit the warning. This could result in multiple warnings being emitted instead of just one. Consider using a threading lock or thread-local storage to ensure thread-safety.
| async def test_async_function_warns_once_and_still_executes(self, recwarn): | ||
| @instrument() | ||
| async def mul(x, y): | ||
| await asyncio.sleep(0.001) | ||
| return x * y | ||
|
|
||
| assert await mul(2, 3) == 6 | ||
| assert await mul(3, 4) == 12 | ||
|
|
||
| runtime_warnings = [ | ||
| w for w in recwarn if issubclass(w.category, RuntimeWarning) | ||
| ] | ||
| assert len(runtime_warnings) == 1 |
Copilot
AI
Dec 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test validates the number of warnings but doesn't check the warning message content like the sync function test does (lines 711-713). Consider adding similar assertions to verify the warning message contains "called before ag.init()" and "Fix: call ag.init()" for consistency and completeness.
mmabrouk
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @astandrik for the PR!
I have tested it and it works fine.
It feels to me that the solution is a bit too verbose, however I don't have a solution to make it simpler.
I asked @junaway for a review, he knows that part of the code best and he can judge.
Closes #3171