lmnr 0.4.65__py3-none-any.whl → 0.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lmnr/__init__.py +30 -0
- lmnr/openllmetry_sdk/__init__.py +4 -15
- lmnr/openllmetry_sdk/tracing/attributes.py +0 -1
- lmnr/openllmetry_sdk/tracing/tracing.py +24 -9
- lmnr/sdk/browser/browser_use_otel.py +11 -12
- lmnr/sdk/browser/playwright_otel.py +214 -229
- lmnr/sdk/browser/pw_utils.py +289 -0
- lmnr/sdk/browser/utils.py +18 -53
- lmnr/sdk/client/asynchronous/async_client.py +157 -0
- lmnr/sdk/client/asynchronous/resources/__init__.py +13 -0
- lmnr/sdk/client/asynchronous/resources/agent.py +215 -0
- lmnr/sdk/client/asynchronous/resources/base.py +32 -0
- lmnr/sdk/client/asynchronous/resources/browser_events.py +40 -0
- lmnr/sdk/client/asynchronous/resources/evals.py +64 -0
- lmnr/sdk/client/asynchronous/resources/pipeline.py +89 -0
- lmnr/sdk/client/asynchronous/resources/semantic_search.py +60 -0
- lmnr/sdk/client/synchronous/resources/__init__.py +7 -0
- lmnr/sdk/client/synchronous/resources/agent.py +209 -0
- lmnr/sdk/client/synchronous/resources/base.py +32 -0
- lmnr/sdk/client/synchronous/resources/browser_events.py +40 -0
- lmnr/sdk/client/synchronous/resources/evals.py +102 -0
- lmnr/sdk/client/synchronous/resources/pipeline.py +89 -0
- lmnr/sdk/client/synchronous/resources/semantic_search.py +60 -0
- lmnr/sdk/client/synchronous/sync_client.py +170 -0
- lmnr/sdk/datasets.py +7 -2
- lmnr/sdk/evaluations.py +53 -27
- lmnr/sdk/laminar.py +22 -175
- lmnr/sdk/types.py +121 -23
- lmnr/sdk/utils.py +10 -0
- lmnr/version.py +6 -6
- {lmnr-0.4.65.dist-info → lmnr-0.5.0.dist-info}/METADATA +88 -38
- lmnr-0.5.0.dist-info/RECORD +55 -0
- lmnr/sdk/client.py +0 -313
- lmnr-0.4.65.dist-info/RECORD +0 -39
- {lmnr-0.4.65.dist-info → lmnr-0.5.0.dist-info}/LICENSE +0 -0
- {lmnr-0.4.65.dist-info → lmnr-0.5.0.dist-info}/WHEEL +0 -0
- {lmnr-0.4.65.dist-info → lmnr-0.5.0.dist-info}/entry_points.txt +0 -0
@@ -1,28 +1,29 @@
|
|
1
|
-
import asyncio
|
2
1
|
import logging
|
3
|
-
import os
|
4
|
-
import threading
|
5
|
-
import time
|
6
2
|
import uuid
|
7
3
|
|
8
|
-
from lmnr.sdk.browser.
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
)
|
14
|
-
from lmnr.sdk.client import LaminarClient
|
15
|
-
from lmnr.version import PYTHON_VERSION, SDK_VERSION
|
4
|
+
from lmnr.sdk.browser.pw_utils import handle_navigation_async, handle_navigation_sync
|
5
|
+
from lmnr.sdk.browser.utils import with_tracer_and_client_wrapper
|
6
|
+
from lmnr.sdk.client.asynchronous.async_client import AsyncLaminarClient
|
7
|
+
from lmnr.sdk.client.synchronous.sync_client import LaminarClient
|
8
|
+
from lmnr.version import __version__
|
16
9
|
|
17
10
|
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
18
11
|
from opentelemetry.instrumentation.utils import unwrap
|
19
|
-
from opentelemetry.trace import
|
12
|
+
from opentelemetry.trace import (
|
13
|
+
get_tracer,
|
14
|
+
Tracer,
|
15
|
+
get_current_span,
|
16
|
+
Span,
|
17
|
+
INVALID_SPAN,
|
18
|
+
set_span_in_context,
|
19
|
+
)
|
20
|
+
from opentelemetry.context import get_current
|
20
21
|
from typing import Collection
|
21
22
|
from wrapt import wrap_function_wrapper
|
22
23
|
|
23
24
|
try:
|
24
|
-
from playwright.async_api import
|
25
|
-
from playwright.sync_api import
|
25
|
+
from playwright.async_api import Browser
|
26
|
+
from playwright.sync_api import Browser as SyncBrowser
|
26
27
|
except ImportError as e:
|
27
28
|
raise ImportError(
|
28
29
|
f"Attempted to import {__file__}, but it is designed "
|
@@ -34,241 +35,216 @@ except ImportError as e:
|
|
34
35
|
_instruments = ("playwright >= 1.9.0",)
|
35
36
|
logger = logging.getLogger(__name__)
|
36
37
|
|
37
|
-
|
38
|
-
{
|
39
|
-
"package": "playwright.sync_api",
|
40
|
-
"object": "BrowserContext",
|
41
|
-
"method": "new_page",
|
42
|
-
}
|
43
|
-
]
|
44
|
-
|
45
|
-
WRAPPED_METHODS_ASYNC = [
|
46
|
-
{
|
47
|
-
"package": "playwright.async_api",
|
48
|
-
"object": "BrowserContext",
|
49
|
-
"method": "new_page",
|
50
|
-
}
|
51
|
-
]
|
52
|
-
|
53
|
-
_original_new_page = None
|
54
|
-
_original_new_page_async = None
|
55
|
-
|
56
|
-
current_dir = os.path.dirname(os.path.abspath(__file__))
|
57
|
-
with open(os.path.join(current_dir, "rrweb", "rrweb.min.js"), "r") as f:
|
58
|
-
RRWEB_CONTENT = f"() => {{ {f.read()} }}"
|
59
|
-
|
60
|
-
|
61
|
-
async def send_events_async(page: Page, session_id: str, trace_id: str):
|
62
|
-
"""Fetch events from the page and send them to the server"""
|
63
|
-
try:
|
64
|
-
# Check if function exists first
|
65
|
-
has_function = await page.evaluate(
|
66
|
-
"""
|
67
|
-
() => typeof window.lmnrGetAndClearEvents === 'function'
|
68
|
-
"""
|
69
|
-
)
|
70
|
-
if not has_function:
|
71
|
-
return
|
72
|
-
|
73
|
-
events = await page.evaluate("window.lmnrGetAndClearEvents()")
|
74
|
-
if not events or len(events) == 0:
|
75
|
-
return
|
76
|
-
|
77
|
-
await LaminarClient.send_browser_events(
|
78
|
-
session_id, trace_id, events, f"python@{PYTHON_VERSION}"
|
79
|
-
)
|
80
|
-
|
81
|
-
except Exception as e:
|
82
|
-
logger.error(f"Error sending events: {e}")
|
83
|
-
|
84
|
-
|
85
|
-
def send_events_sync(page: SyncPage, session_id: str, trace_id: str):
|
86
|
-
"""Synchronous version of send_events"""
|
87
|
-
try:
|
88
|
-
# Check if function exists first
|
89
|
-
has_function = page.evaluate(
|
90
|
-
"""
|
91
|
-
() => typeof window.lmnrGetAndClearEvents === 'function'
|
92
|
-
"""
|
93
|
-
)
|
94
|
-
if not has_function:
|
95
|
-
return
|
96
|
-
|
97
|
-
events = page.evaluate("window.lmnrGetAndClearEvents()")
|
98
|
-
if not events or len(events) == 0:
|
99
|
-
return
|
100
|
-
|
101
|
-
LaminarClient.send_browser_events_sync(
|
102
|
-
session_id, trace_id, events, f"python@{PYTHON_VERSION}"
|
103
|
-
)
|
104
|
-
|
105
|
-
except Exception as e:
|
106
|
-
logger.error(f"Error sending events: {e}")
|
107
|
-
|
108
|
-
|
109
|
-
def inject_rrweb(page: SyncPage):
|
110
|
-
try:
|
111
|
-
page.wait_for_load_state("domcontentloaded")
|
112
|
-
|
113
|
-
# Wrap the evaluate call in a try-catch
|
114
|
-
try:
|
115
|
-
is_loaded = page.evaluate(
|
116
|
-
"""() => typeof window.lmnrRrweb !== 'undefined'"""
|
117
|
-
)
|
118
|
-
except Exception as e:
|
119
|
-
logger.debug(f"Failed to check if rrweb is loaded: {e}")
|
120
|
-
is_loaded = False
|
121
|
-
|
122
|
-
if not is_loaded:
|
123
|
-
|
124
|
-
def load_rrweb():
|
125
|
-
try:
|
126
|
-
page.evaluate(RRWEB_CONTENT)
|
127
|
-
page.wait_for_function(
|
128
|
-
"""(() => typeof window.lmnrRrweb !== 'undefined')""",
|
129
|
-
timeout=5000,
|
130
|
-
)
|
131
|
-
return True
|
132
|
-
except Exception as e:
|
133
|
-
logger.debug(f"Failed to load rrweb: {e}")
|
134
|
-
return False
|
135
|
-
|
136
|
-
if not retry_sync(
|
137
|
-
load_rrweb, delay=1, error_message="Failed to load rrweb"
|
138
|
-
):
|
139
|
-
return
|
140
|
-
|
141
|
-
try:
|
142
|
-
page.evaluate(INJECT_PLACEHOLDER)
|
143
|
-
except Exception as e:
|
144
|
-
logger.debug(f"Failed to inject rrweb placeholder: {e}")
|
145
|
-
|
146
|
-
except Exception as e:
|
147
|
-
logger.error(f"Error during rrweb injection: {e}")
|
148
|
-
|
149
|
-
|
150
|
-
async def inject_rrweb_async(page: Page):
|
151
|
-
try:
|
152
|
-
await page.wait_for_load_state("domcontentloaded")
|
153
|
-
|
154
|
-
# Wrap the evaluate call in a try-catch
|
155
|
-
try:
|
156
|
-
is_loaded = await page.evaluate(
|
157
|
-
"""() => typeof window.lmnrRrweb !== 'undefined'"""
|
158
|
-
)
|
159
|
-
except Exception as e:
|
160
|
-
logger.debug(f"Failed to check if rrweb is loaded: {e}")
|
161
|
-
is_loaded = False
|
162
|
-
|
163
|
-
if not is_loaded:
|
164
|
-
|
165
|
-
async def load_rrweb():
|
166
|
-
try:
|
167
|
-
await page.evaluate(RRWEB_CONTENT)
|
168
|
-
await page.wait_for_function(
|
169
|
-
"""(() => typeof window.lmnrRrweb !== 'undefined')""",
|
170
|
-
timeout=5000,
|
171
|
-
)
|
172
|
-
return True
|
173
|
-
except Exception as e:
|
174
|
-
logger.debug(f"Failed to load rrweb: {e}")
|
175
|
-
return False
|
176
|
-
|
177
|
-
if not await retry_async(
|
178
|
-
load_rrweb, delay=1, error_message="Failed to load rrweb"
|
179
|
-
):
|
180
|
-
return
|
181
|
-
|
182
|
-
try:
|
183
|
-
await page.evaluate(INJECT_PLACEHOLDER)
|
184
|
-
except Exception as e:
|
185
|
-
logger.debug(f"Failed to inject rrweb placeholder: {e}")
|
186
|
-
|
187
|
-
except Exception as e:
|
188
|
-
logger.error(f"Error during rrweb injection: {e}")
|
189
|
-
|
190
|
-
|
191
|
-
def handle_navigation(page: SyncPage, session_id: str, trace_id: str):
|
192
|
-
def on_load():
|
193
|
-
try:
|
194
|
-
inject_rrweb(page)
|
195
|
-
except Exception as e:
|
196
|
-
logger.error(f"Error in on_load handler: {e}")
|
197
|
-
|
198
|
-
page.on("load", on_load)
|
199
|
-
inject_rrweb(page)
|
200
|
-
|
201
|
-
def collection_loop():
|
202
|
-
while not page.is_closed(): # Stop when page closes
|
203
|
-
send_events_sync(page, session_id, trace_id)
|
204
|
-
time.sleep(2)
|
205
|
-
|
206
|
-
thread = threading.Thread(target=collection_loop, daemon=True)
|
207
|
-
thread.start()
|
38
|
+
_context_spans: dict[str, Span] = {}
|
208
39
|
|
209
40
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
except Exception as e:
|
215
|
-
logger.error(f"Error in on_load handler: {e}")
|
216
|
-
|
217
|
-
page.on("load", lambda: asyncio.create_task(on_load()))
|
218
|
-
await inject_rrweb_async(page)
|
219
|
-
|
220
|
-
async def collection_loop():
|
221
|
-
try:
|
222
|
-
while not page.is_closed(): # Stop when page closes
|
223
|
-
await send_events_async(page, session_id, trace_id)
|
224
|
-
await asyncio.sleep(2)
|
225
|
-
logger.info("Event collection stopped")
|
226
|
-
except Exception as e:
|
227
|
-
logger.error(f"Event collection stopped: {e}")
|
228
|
-
|
229
|
-
# Create and store task
|
230
|
-
task = asyncio.create_task(collection_loop())
|
231
|
-
|
232
|
-
# Clean up task when page closes
|
233
|
-
page.on("close", lambda: task.cancel())
|
234
|
-
|
235
|
-
|
236
|
-
@_with_tracer_wrapper
|
237
|
-
def _wrap(tracer: Tracer, to_wrap, wrapped, instance, args, kwargs):
|
41
|
+
@with_tracer_and_client_wrapper
|
42
|
+
def _wrap_new_page(
|
43
|
+
tracer: Tracer, client: LaminarClient, to_wrap, wrapped, instance, args, kwargs
|
44
|
+
):
|
238
45
|
with tracer.start_as_current_span(
|
239
|
-
f"
|
46
|
+
f"{to_wrap.get('object')}.{to_wrap.get('method')}"
|
240
47
|
) as span:
|
241
48
|
page = wrapped(*args, **kwargs)
|
242
49
|
session_id = str(uuid.uuid4().hex)
|
243
50
|
trace_id = format(get_current_span().get_span_context().trace_id, "032x")
|
244
51
|
span.set_attribute("lmnr.internal.has_browser_session", True)
|
245
|
-
|
52
|
+
handle_navigation_sync(page, session_id, trace_id, client)
|
246
53
|
return page
|
247
54
|
|
248
55
|
|
249
|
-
@
|
250
|
-
async def
|
56
|
+
@with_tracer_and_client_wrapper
|
57
|
+
async def _wrap_new_page_async(
|
58
|
+
tracer: Tracer, client: AsyncLaminarClient, to_wrap, wrapped, instance, args, kwargs
|
59
|
+
):
|
251
60
|
with tracer.start_as_current_span(
|
252
|
-
f"
|
61
|
+
f"{to_wrap.get('object')}.{to_wrap.get('method')}"
|
253
62
|
) as span:
|
254
63
|
page = await wrapped(*args, **kwargs)
|
255
64
|
session_id = str(uuid.uuid4().hex)
|
256
|
-
trace_id = format(
|
65
|
+
trace_id = format(span.get_span_context().trace_id, "032x")
|
257
66
|
span.set_attribute("lmnr.internal.has_browser_session", True)
|
258
|
-
await handle_navigation_async(page, session_id, trace_id)
|
67
|
+
await handle_navigation_async(page, session_id, trace_id, client)
|
259
68
|
return page
|
260
69
|
|
261
70
|
|
262
|
-
|
263
|
-
|
71
|
+
@with_tracer_and_client_wrapper
|
72
|
+
def _wrap_new_browser_sync(
|
73
|
+
tracer: Tracer, client: LaminarClient, to_wrap, wrapped, instance, args, kwargs
|
74
|
+
):
|
75
|
+
global _context_spans
|
76
|
+
browser: SyncBrowser = wrapped(*args, **kwargs)
|
77
|
+
session_id = str(uuid.uuid4().hex)
|
78
|
+
for context in browser.contexts:
|
79
|
+
span = get_current_span()
|
80
|
+
if span == INVALID_SPAN:
|
81
|
+
span = tracer.start_span(
|
82
|
+
name=f"{to_wrap.get('object')}.{to_wrap.get('method')}"
|
83
|
+
)
|
84
|
+
set_span_in_context(span, get_current())
|
85
|
+
_context_spans[id(context)] = span
|
86
|
+
span.set_attribute("lmnr.internal.has_browser_session", True)
|
87
|
+
for page in context.pages:
|
88
|
+
trace_id = format(span.get_span_context().trace_id, "032x")
|
89
|
+
handle_navigation_sync(page, session_id, trace_id, client)
|
90
|
+
return browser
|
91
|
+
|
92
|
+
|
93
|
+
@with_tracer_and_client_wrapper
|
94
|
+
async def _wrap_new_browser_async(
|
95
|
+
tracer: Tracer, client: AsyncLaminarClient, to_wrap, wrapped, instance, args, kwargs
|
96
|
+
):
|
97
|
+
global _context_spans
|
98
|
+
browser: Browser = await wrapped(*args, **kwargs)
|
99
|
+
session_id = str(uuid.uuid4().hex)
|
100
|
+
for context in browser.contexts:
|
101
|
+
span = get_current_span()
|
102
|
+
if span == INVALID_SPAN:
|
103
|
+
span = tracer.start_span(
|
104
|
+
name=f"{to_wrap.get('object')}.{to_wrap.get('method')}"
|
105
|
+
)
|
106
|
+
set_span_in_context(span, get_current())
|
107
|
+
_context_spans[id(context)] = span
|
108
|
+
span.set_attribute("lmnr.internal.has_browser_session", True)
|
109
|
+
for page in context.pages:
|
110
|
+
trace_id = format(span.get_span_context().trace_id, "032x")
|
111
|
+
await handle_navigation_async(page, session_id, trace_id, client)
|
112
|
+
return browser
|
113
|
+
|
114
|
+
|
115
|
+
@with_tracer_and_client_wrapper
|
116
|
+
def _wrap_close_browser_sync(
|
117
|
+
tracer: Tracer,
|
118
|
+
client: LaminarClient,
|
119
|
+
to_wrap,
|
120
|
+
wrapped,
|
121
|
+
instance: SyncBrowser,
|
122
|
+
args,
|
123
|
+
kwargs,
|
124
|
+
):
|
125
|
+
global _context_spans
|
126
|
+
for context in instance.contexts:
|
127
|
+
key = id(context)
|
128
|
+
span = _context_spans.get(key)
|
129
|
+
if span:
|
130
|
+
if span.is_recording():
|
131
|
+
span.end()
|
132
|
+
_context_spans.pop(key)
|
133
|
+
return wrapped(*args, **kwargs)
|
134
|
+
|
135
|
+
|
136
|
+
@with_tracer_and_client_wrapper
|
137
|
+
async def _wrap_close_browser_async(
|
138
|
+
tracer: Tracer,
|
139
|
+
client: AsyncLaminarClient,
|
140
|
+
to_wrap,
|
141
|
+
wrapped,
|
142
|
+
instance: Browser,
|
143
|
+
args,
|
144
|
+
kwargs,
|
145
|
+
):
|
146
|
+
global _context_spans
|
147
|
+
for context in instance.contexts:
|
148
|
+
key = id(context)
|
149
|
+
span = _context_spans.get(key)
|
150
|
+
if span:
|
151
|
+
if span.is_recording():
|
152
|
+
span.end()
|
153
|
+
_context_spans.pop(key)
|
154
|
+
return await wrapped(*args, **kwargs)
|
155
|
+
|
156
|
+
|
157
|
+
WRAPPED_METHODS = [
|
158
|
+
{
|
159
|
+
"package": "playwright.sync_api",
|
160
|
+
"object": "BrowserContext",
|
161
|
+
"method": "new_page",
|
162
|
+
"wrapper": _wrap_new_page,
|
163
|
+
},
|
164
|
+
{
|
165
|
+
"package": "playwright.sync_api",
|
166
|
+
"object": "Browser",
|
167
|
+
"method": "new_page",
|
168
|
+
"wrapper": _wrap_new_page,
|
169
|
+
},
|
170
|
+
{
|
171
|
+
"package": "playwright.sync_api",
|
172
|
+
"object": "BrowserType",
|
173
|
+
"method": "launch",
|
174
|
+
"wrapper": _wrap_new_browser_sync,
|
175
|
+
},
|
176
|
+
{
|
177
|
+
"package": "playwright.sync_api",
|
178
|
+
"object": "BrowserType",
|
179
|
+
"method": "connect",
|
180
|
+
"wrapper": _wrap_new_browser_sync,
|
181
|
+
},
|
182
|
+
{
|
183
|
+
"package": "playwright.sync_api",
|
184
|
+
"object": "BrowserType",
|
185
|
+
"method": "connect_over_cdp",
|
186
|
+
"wrapper": _wrap_new_browser_sync,
|
187
|
+
},
|
188
|
+
{
|
189
|
+
"package": "playwright.sync_api",
|
190
|
+
"object": "Browser",
|
191
|
+
"method": "close",
|
192
|
+
"wrapper": _wrap_close_browser_sync,
|
193
|
+
},
|
194
|
+
]
|
195
|
+
|
196
|
+
WRAPPED_METHODS_ASYNC = [
|
197
|
+
{
|
198
|
+
"package": "playwright.async_api",
|
199
|
+
"object": "BrowserContext",
|
200
|
+
"method": "new_page",
|
201
|
+
"wrapper": _wrap_new_page_async,
|
202
|
+
},
|
203
|
+
{
|
204
|
+
"package": "playwright.async_api",
|
205
|
+
"object": "Browser",
|
206
|
+
"method": "new_page",
|
207
|
+
"wrapper": _wrap_new_page_async,
|
208
|
+
},
|
209
|
+
{
|
210
|
+
"package": "playwright.async_api",
|
211
|
+
"object": "BrowserType",
|
212
|
+
"method": "launch",
|
213
|
+
"wrapper": _wrap_new_browser_async,
|
214
|
+
},
|
215
|
+
{
|
216
|
+
"package": "playwright.async_api",
|
217
|
+
"object": "BrowserType",
|
218
|
+
"method": "connect",
|
219
|
+
"wrapper": _wrap_new_browser_async,
|
220
|
+
},
|
221
|
+
{
|
222
|
+
"package": "playwright.async_api",
|
223
|
+
"object": "BrowserType",
|
224
|
+
"method": "connect_over_cdp",
|
225
|
+
"wrapper": _wrap_new_browser_async,
|
226
|
+
},
|
227
|
+
{
|
228
|
+
"package": "playwright.async_api",
|
229
|
+
"object": "Browser",
|
230
|
+
"method": "close",
|
231
|
+
"wrapper": _wrap_close_browser_async,
|
232
|
+
},
|
233
|
+
]
|
234
|
+
|
235
|
+
|
236
|
+
class PlaywrightInstrumentor(BaseInstrumentor):
|
237
|
+
def __init__(self, client: LaminarClient, async_client: AsyncLaminarClient):
|
264
238
|
super().__init__()
|
239
|
+
self.client = client
|
240
|
+
self.async_client = async_client
|
265
241
|
|
266
242
|
def instrumentation_dependencies(self) -> Collection[str]:
|
267
243
|
return _instruments
|
268
244
|
|
269
245
|
def _instrument(self, **kwargs):
|
270
246
|
tracer_provider = kwargs.get("tracer_provider")
|
271
|
-
tracer = get_tracer(__name__,
|
247
|
+
tracer = get_tracer(__name__, __version__, tracer_provider)
|
272
248
|
|
273
249
|
for wrapped_method in WRAPPED_METHODS:
|
274
250
|
wrap_package = wrapped_method.get("package")
|
@@ -278,14 +254,16 @@ class BrowserUseInstrumentor(BaseInstrumentor):
|
|
278
254
|
wrap_function_wrapper(
|
279
255
|
wrap_package,
|
280
256
|
f"{wrap_object}.{wrap_method}",
|
281
|
-
|
257
|
+
wrapped_method.get("wrapper")(
|
282
258
|
tracer,
|
259
|
+
self.client,
|
283
260
|
wrapped_method,
|
284
261
|
),
|
285
262
|
)
|
286
263
|
except ModuleNotFoundError:
|
287
|
-
pass # that's ok, we'
|
264
|
+
pass # that's ok, we don't want to fail if some module is missing
|
288
265
|
|
266
|
+
# Wrap async methods
|
289
267
|
for wrapped_method in WRAPPED_METHODS_ASYNC:
|
290
268
|
wrap_package = wrapped_method.get("package")
|
291
269
|
wrap_object = wrapped_method.get("object")
|
@@ -294,17 +272,24 @@ class BrowserUseInstrumentor(BaseInstrumentor):
|
|
294
272
|
wrap_function_wrapper(
|
295
273
|
wrap_package,
|
296
274
|
f"{wrap_object}.{wrap_method}",
|
297
|
-
|
275
|
+
wrapped_method.get("wrapper")(
|
298
276
|
tracer,
|
277
|
+
self.async_client,
|
299
278
|
wrapped_method,
|
300
279
|
),
|
301
280
|
)
|
302
281
|
except ModuleNotFoundError:
|
303
|
-
pass # that's ok, we'
|
282
|
+
pass # that's ok, we don't want to fail if some module is missing
|
304
283
|
|
305
284
|
def _uninstrument(self, **kwargs):
|
306
|
-
|
285
|
+
# Unwrap methods
|
286
|
+
global _context_spans
|
287
|
+
for wrapped_method in WRAPPED_METHODS + WRAPPED_METHODS_ASYNC:
|
307
288
|
wrap_package = wrapped_method.get("package")
|
308
289
|
wrap_object = wrapped_method.get("object")
|
309
290
|
wrap_method = wrapped_method.get("method")
|
310
291
|
unwrap(wrap_package, f"{wrap_object}.{wrap_method}")
|
292
|
+
for span in _context_spans.values():
|
293
|
+
if span.is_recording():
|
294
|
+
span.end()
|
295
|
+
_context_spans = {}
|