chore: import upstream snapshot with attribution
Test Browser Use CLI Install / uv pip install (ubuntu-latest) (push) Failing after 1s
Test Browser Use CLI Install / uvx browser-use from local wheel (push) Failing after 1s
Test Browser Use CLI Install / uvx browser-use[cli] from PyPI (push) Failing after 1s
package / pip-install-on-macos-latest-py-3.11 (push) Has been skipped
package / pip-install-on-macos-latest-py-3.13 (push) Has been skipped
package / pip-install-on-ubuntu-latest-py-3.11 (push) Has been skipped
package / pip-install-on-windows-latest-py-3.13 (push) Has been skipped
cloud_evals / trigger_cloud_eval_image_build (push) Failing after 1s
docker / build_publish_image (push) Failing after 1s
Test Browser Use CLI Install / browser-use skill sync (push) Failing after 1s
lint / code-style (push) Failing after 0s
lint / type-checker (push) Failing after 1s
package / pip-build (push) Failing after 1s
lint / syntax-errors (push) Failing after 3s
package / pip-install-on-ubuntu-latest-py-3.13 (push) Has been skipped
package / pip-install-on-windows-latest-py-3.11 (push) Has been skipped
test / ${{ matrix.test_filename }} (push) Has been skipped
test / evaluate-tasks (push) Has been skipped
test / setup-chromium (push) Failing after 2s
test / find_tests (push) Failing after 2s
Test Browser Use CLI Install / uv pip install (windows-latest) (push) Has been cancelled
Test Browser Use CLI Install / uv pip install (macos-latest) (push) Has been cancelled
Test Browser Use CLI Install / uv pip install (ubuntu-latest) (push) Failing after 1s
Test Browser Use CLI Install / uvx browser-use from local wheel (push) Failing after 1s
Test Browser Use CLI Install / uvx browser-use[cli] from PyPI (push) Failing after 1s
package / pip-install-on-macos-latest-py-3.11 (push) Has been skipped
package / pip-install-on-macos-latest-py-3.13 (push) Has been skipped
package / pip-install-on-ubuntu-latest-py-3.11 (push) Has been skipped
package / pip-install-on-windows-latest-py-3.13 (push) Has been skipped
cloud_evals / trigger_cloud_eval_image_build (push) Failing after 1s
docker / build_publish_image (push) Failing after 1s
Test Browser Use CLI Install / browser-use skill sync (push) Failing after 1s
lint / code-style (push) Failing after 0s
lint / type-checker (push) Failing after 1s
package / pip-build (push) Failing after 1s
lint / syntax-errors (push) Failing after 3s
package / pip-install-on-ubuntu-latest-py-3.13 (push) Has been skipped
package / pip-install-on-windows-latest-py-3.11 (push) Has been skipped
test / ${{ matrix.test_filename }} (push) Has been skipped
test / evaluate-tasks (push) Has been skipped
test / setup-chromium (push) Failing after 2s
test / find_tests (push) Failing after 2s
Test Browser Use CLI Install / uv pip install (windows-latest) (push) Has been cancelled
Test Browser Use CLI Install / uv pip install (macos-latest) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
# @file purpose: Observability module for browser-use that handles optional lmnr integration with debug mode support
|
||||
"""
|
||||
Observability module for browser-use
|
||||
|
||||
This module provides observability decorators that optionally integrate with lmnr (Laminar) for tracing.
|
||||
If lmnr is not installed, it provides no-op wrappers that accept the same parameters.
|
||||
|
||||
Features:
|
||||
- Optional lmnr integration - works with or without lmnr installed
|
||||
- Debug mode support - observe_debug only traces when in debug mode
|
||||
- Full parameter compatibility with lmnr observe decorator
|
||||
- No-op fallbacks when lmnr is unavailable
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
from collections.abc import Callable
|
||||
from functools import wraps
|
||||
from typing import Any, Literal, TypeVar, cast
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
# Type definitions
|
||||
F = TypeVar('F', bound=Callable[..., Any])
|
||||
|
||||
|
||||
# Check if we're in debug mode
|
||||
def _is_debug_mode() -> bool:
|
||||
"""Check if we're in debug mode based on environment variables or logging level."""
|
||||
|
||||
lmnr_debug_mode = os.getenv('LMNR_LOGGING_LEVEL', '').lower()
|
||||
if lmnr_debug_mode == 'debug':
|
||||
# logger.info('Debug mode is enabled for observability')
|
||||
return True
|
||||
# logger.info('Debug mode is disabled for observability')
|
||||
return False
|
||||
|
||||
|
||||
# Try to import lmnr observe
|
||||
_LMNR_AVAILABLE = False
|
||||
_lmnr_observe = None
|
||||
|
||||
try:
|
||||
from lmnr import observe as _lmnr_observe # type: ignore
|
||||
|
||||
if os.environ.get('BROWSER_USE_VERBOSE_OBSERVABILITY', 'false').lower() == 'true':
|
||||
logger.debug('Lmnr is available for observability')
|
||||
_LMNR_AVAILABLE = True
|
||||
except (ImportError, TypeError):
|
||||
if os.environ.get('BROWSER_USE_VERBOSE_OBSERVABILITY', 'false').lower() == 'true':
|
||||
logger.debug('Lmnr is not available for observability')
|
||||
_LMNR_AVAILABLE = False
|
||||
|
||||
|
||||
def _create_no_op_decorator(
|
||||
name: str | None = None,
|
||||
ignore_input: bool = False,
|
||||
ignore_output: bool = False,
|
||||
metadata: dict[str, Any] | None = None,
|
||||
**kwargs: Any,
|
||||
) -> Callable[[F], F]:
|
||||
"""Create a no-op decorator that accepts all lmnr observe parameters but does nothing."""
|
||||
import asyncio
|
||||
|
||||
def decorator(func: F) -> F:
|
||||
if asyncio.iscoroutinefunction(func):
|
||||
|
||||
@wraps(func)
|
||||
async def async_wrapper(*args, **kwargs):
|
||||
return await func(*args, **kwargs)
|
||||
|
||||
return cast(F, async_wrapper)
|
||||
else:
|
||||
|
||||
@wraps(func)
|
||||
def sync_wrapper(*args, **kwargs):
|
||||
return func(*args, **kwargs)
|
||||
|
||||
return cast(F, sync_wrapper)
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
def observe(
|
||||
name: str | None = None,
|
||||
ignore_input: bool = False,
|
||||
ignore_output: bool = False,
|
||||
metadata: dict[str, Any] | None = None,
|
||||
span_type: Literal['DEFAULT', 'LLM', 'TOOL'] = 'DEFAULT',
|
||||
**kwargs: Any,
|
||||
) -> Callable[[F], F]:
|
||||
"""
|
||||
Observability decorator that traces function execution when lmnr is available.
|
||||
|
||||
This decorator will use lmnr's observe decorator if lmnr is installed,
|
||||
otherwise it will be a no-op that accepts the same parameters.
|
||||
|
||||
Args:
|
||||
name: Name of the span/trace
|
||||
ignore_input: Whether to ignore function input parameters in tracing
|
||||
ignore_output: Whether to ignore function output in tracing
|
||||
metadata: Additional metadata to attach to the span
|
||||
**kwargs: Additional parameters passed to lmnr observe
|
||||
|
||||
Returns:
|
||||
Decorated function that may be traced depending on lmnr availability
|
||||
|
||||
Example:
|
||||
@observe(name="my_function", metadata={"version": "1.0"})
|
||||
def my_function(param1, param2):
|
||||
return param1 + param2
|
||||
"""
|
||||
kwargs = {
|
||||
'name': name,
|
||||
'ignore_input': ignore_input,
|
||||
'ignore_output': ignore_output,
|
||||
'metadata': metadata,
|
||||
'span_type': span_type,
|
||||
'tags': ['observe', 'observe_debug'], # important: tags need to be created on laminar first
|
||||
**kwargs,
|
||||
}
|
||||
|
||||
if _LMNR_AVAILABLE and _lmnr_observe:
|
||||
# Use the real lmnr observe decorator
|
||||
return cast(Callable[[F], F], _lmnr_observe(**kwargs))
|
||||
else:
|
||||
# Use no-op decorator
|
||||
return _create_no_op_decorator(**kwargs)
|
||||
|
||||
|
||||
def observe_debug(
|
||||
name: str | None = None,
|
||||
ignore_input: bool = False,
|
||||
ignore_output: bool = False,
|
||||
metadata: dict[str, Any] | None = None,
|
||||
span_type: Literal['DEFAULT', 'LLM', 'TOOL'] = 'DEFAULT',
|
||||
**kwargs: Any,
|
||||
) -> Callable[[F], F]:
|
||||
"""
|
||||
Debug-only observability decorator that only traces when in debug mode.
|
||||
|
||||
This decorator will use lmnr's observe decorator if both lmnr is installed
|
||||
AND we're in debug mode, otherwise it will be a no-op.
|
||||
|
||||
Debug mode is determined by:
|
||||
- DEBUG environment variable set to 1/true/yes/on
|
||||
- BROWSER_USE_DEBUG environment variable set to 1/true/yes/on
|
||||
- Root logging level set to DEBUG or lower
|
||||
|
||||
Args:
|
||||
name: Name of the span/trace
|
||||
ignore_input: Whether to ignore function input parameters in tracing
|
||||
ignore_output: Whether to ignore function output in tracing
|
||||
metadata: Additional metadata to attach to the span
|
||||
**kwargs: Additional parameters passed to lmnr observe
|
||||
|
||||
Returns:
|
||||
Decorated function that may be traced only in debug mode
|
||||
|
||||
Example:
|
||||
@observe_debug(ignore_input=True, ignore_output=True,name="debug_function", metadata={"debug": True})
|
||||
def debug_function(param1, param2):
|
||||
return param1 + param2
|
||||
"""
|
||||
kwargs = {
|
||||
'name': name,
|
||||
'ignore_input': ignore_input,
|
||||
'ignore_output': ignore_output,
|
||||
'metadata': metadata,
|
||||
'span_type': span_type,
|
||||
'tags': ['observe_debug'], # important: tags need to be created on laminar first
|
||||
**kwargs,
|
||||
}
|
||||
|
||||
if _LMNR_AVAILABLE and _lmnr_observe and _is_debug_mode():
|
||||
# Use the real lmnr observe decorator only in debug mode
|
||||
return cast(Callable[[F], F], _lmnr_observe(**kwargs))
|
||||
else:
|
||||
# Use no-op decorator (either not in debug mode or lmnr not available)
|
||||
return _create_no_op_decorator(**kwargs)
|
||||
|
||||
|
||||
# Convenience functions for checking availability and debug status
|
||||
def is_lmnr_available() -> bool:
|
||||
"""Check if lmnr is available for tracing."""
|
||||
return _LMNR_AVAILABLE
|
||||
|
||||
|
||||
def is_debug_mode() -> bool:
|
||||
"""Check if we're currently in debug mode."""
|
||||
return _is_debug_mode()
|
||||
|
||||
|
||||
def get_observability_status() -> dict[str, bool]:
|
||||
"""Get the current status of observability features."""
|
||||
return {
|
||||
'lmnr_available': _LMNR_AVAILABLE,
|
||||
'debug_mode': _is_debug_mode(),
|
||||
'observe_active': _LMNR_AVAILABLE,
|
||||
'observe_debug_active': _LMNR_AVAILABLE and _is_debug_mode(),
|
||||
}
|
||||
Reference in New Issue
Block a user