-
Notifications
You must be signed in to change notification settings - Fork 0
feat: refactor instrumentations to use span/mode utils + add sampling #18
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
Merged
Merged
Changes from 4 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
08afc47
refactor wsgi + redis
sohankshirsagar 085c1de
refactored psycopg and psycopg2
sohankshirsagar 7d13f11
refactor django
sohankshirsagar 1507e10
refactored fastapi
sohankshirsagar e2c37ac
fix sampling
sohankshirsagar ec5c8f6
fix lint
sohankshirsagar df3d3d3
fix formatting
sohankshirsagar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,4 +39,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and guidelines. | |
|
|
||
| ## License | ||
|
|
||
| MIT | ||
| Apache License 2.0 | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,147 @@ | ||
| """Mode utilities for handling RECORD and REPLAY mode logic. | ||
|
|
||
| This module provides utilities that abstract common mode-handling patterns, | ||
| matching the Node SDK's modeUtils.ts. These utilities help instrumentations | ||
| decide how to handle requests based on the SDK mode and app state. | ||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import logging | ||
| from typing import TYPE_CHECKING, Callable, TypeVar | ||
|
|
||
| from opentelemetry.trace import SpanKind as OTelSpanKind | ||
|
|
||
| if TYPE_CHECKING: | ||
| from .tracing.span_utils import SpanInfo | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
| T = TypeVar("T") | ||
|
|
||
| # Type aliases for handler functions | ||
| OriginalFunctionCall = Callable[[], T] | ||
| RecordModeHandler = Callable[[bool], T] # (is_pre_app_start: bool) -> T | ||
| ReplayModeHandler = Callable[[], T] | ||
| NoOpRequestHandler = Callable[[], T] | ||
|
|
||
|
|
||
| def handle_record_mode( | ||
| original_function_call: OriginalFunctionCall[T], | ||
| record_mode_handler: RecordModeHandler[T], | ||
| span_kind: OTelSpanKind, | ||
| ) -> T: | ||
| """Handle RECORD mode logic for instrumentations. | ||
|
|
||
| This utility abstracts the common record mode pattern of checking for | ||
| current span context and deciding whether to execute record mode logic | ||
| or just call the original function. | ||
|
|
||
| Decision logic: | ||
| - If app NOT ready -> call record_mode_handler(is_pre_app_start=True) | ||
| - If no span context AND not SERVER span, OR span was pre-app-start -> call original_function_call() (skip) | ||
| - Otherwise -> call record_mode_handler(is_pre_app_start=False) | ||
|
|
||
| Args: | ||
| original_function_call: Function that calls the original function when no span context exists | ||
| record_mode_handler: Function that handles record mode logic; receives is_pre_app_start flag | ||
| span_kind: The kind of span being created (determines if this is a server request) | ||
|
|
||
| Returns: | ||
| Result from either original_function_call or record_mode_handler | ||
| """ | ||
| from .drift_sdk import TuskDrift | ||
| from .tracing.span_utils import SpanUtils | ||
|
|
||
| try: | ||
| sdk = TuskDrift.get_instance() | ||
|
sohankshirsagar marked this conversation as resolved.
|
||
| is_app_ready = sdk.is_app_ready() | ||
| current_span_info = SpanUtils.get_current_span_info() | ||
| except Exception as e: | ||
| logger.error(f"ModeUtils error checking app readiness or getting current span info: {e}") | ||
| return original_function_call() | ||
|
|
||
| if not is_app_ready: | ||
| # App not ready - record with is_pre_app_start=True | ||
| return record_mode_handler(True) | ||
|
|
||
| # App is ready - check span context | ||
| is_server_span = span_kind == OTelSpanKind.SERVER | ||
|
|
||
| if (not current_span_info and not is_server_span) or ( | ||
| current_span_info and current_span_info.is_pre_app_start | ||
| ): | ||
| # No span context and not a server request, OR within a pre-app-start span | ||
| # Skip recording - call original function | ||
| return original_function_call() | ||
|
|
||
| # App ready with valid span context - record with is_pre_app_start=False | ||
| return record_mode_handler(False) | ||
|
|
||
|
|
||
| def handle_replay_mode( | ||
| replay_mode_handler: ReplayModeHandler[T], | ||
| no_op_request_handler: NoOpRequestHandler[T], | ||
| is_server_request: bool, | ||
| ) -> T: | ||
| """Handle REPLAY mode logic for instrumentations. | ||
|
|
||
| This utility abstracts the common replay mode pattern of checking if | ||
| the request is a background request. | ||
|
|
||
| Decision logic: | ||
| - If background request (app ready + no parent span + not server request) -> call no_op_request_handler() | ||
| - Otherwise -> call replay_mode_handler() | ||
|
|
||
| Background requests are requests that happen after app startup but outside | ||
| of any trace context (health checks, background jobs, etc.). In REPLAY mode, | ||
| these should return dummy responses instead of querying for mocks. | ||
|
|
||
| Args: | ||
| replay_mode_handler: Function that handles normal replay mode logic (fetches mocks) | ||
| no_op_request_handler: Function that returns a dummy/no-op response for background requests | ||
| is_server_request: True if this is a SERVER span (inbound HTTP request) | ||
|
|
||
| Returns: | ||
| Result from either no_op_request_handler or replay_mode_handler | ||
| """ | ||
| from .drift_sdk import TuskDrift | ||
| from .tracing.span_utils import SpanUtils | ||
|
|
||
| sdk = TuskDrift.get_instance() | ||
| is_app_ready = sdk.is_app_ready() | ||
| current_span_info = SpanUtils.get_current_span_info() | ||
|
|
||
| # Background request: App is ready + not within a trace (no parent span) + not a server request | ||
| if is_app_ready and not current_span_info and not is_server_request: | ||
| logger.debug("[ModeUtils] Handling no-op request") | ||
| return no_op_request_handler() | ||
|
|
||
| return replay_mode_handler() | ||
|
|
||
|
|
||
| def is_background_request(is_server_request: bool = False) -> bool: | ||
| """Check if the current request is a background request. | ||
|
|
||
| A background request is one that: | ||
| - Happens after app is ready (not pre-app-start) | ||
| - Has no parent span context (not within an existing trace) | ||
| - Is not a server request (not an incoming HTTP request that starts a new trace) | ||
|
|
||
| Background requests should typically be handled with no-op/dummy responses | ||
| in REPLAY mode since they were never recorded. | ||
|
|
||
| Args: | ||
| is_server_request: True if this is a SERVER span type | ||
|
|
||
| Returns: | ||
| True if this is a background request, False otherwise | ||
| """ | ||
| from .drift_sdk import TuskDrift | ||
| from .tracing.span_utils import SpanUtils | ||
|
|
||
| sdk = TuskDrift.get_instance() | ||
| is_app_ready = sdk.is_app_ready() | ||
| current_span_info = SpanUtils.get_current_span_info() | ||
|
|
||
| return is_app_ready and not current_span_info and not is_server_request | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.