|
4 | 4 | import os
|
5 | 5 | import json
|
6 | 6 | import time
|
| 7 | +import sys |
| 8 | +import inspect |
| 9 | +import functools |
7 | 10 | from typing import Collection
|
8 | 11 | from opentelemetry.instrumentation.ollama.config import Config
|
9 | 12 | from opentelemetry.instrumentation.ollama.utils import dont_throw
|
@@ -431,6 +434,22 @@ def is_metrics_collection_enabled() -> bool:
|
431 | 434 | return (os.getenv("TRACELOOP_METRICS_ENABLED") or "true").lower() == "true"
|
432 | 435 |
|
433 | 436 |
|
| 437 | +# Proxy class to dynamically call the latest ollama function implementations |
| 438 | +class InstrumentedFunction: |
| 439 | + """Proxy function that always invokes the latest ollama function implementation""" |
| 440 | + def __init__(self, func_name): |
| 441 | + self.func_name = func_name |
| 442 | + import ollama |
| 443 | + original = getattr(ollama, func_name) |
| 444 | + functools.update_wrapper(self, original) |
| 445 | + self.__wrapped__ = original |
| 446 | + |
| 447 | + def __call__(self, *args, **kwargs): |
| 448 | + import ollama |
| 449 | + actual_func = getattr(ollama, self.func_name) |
| 450 | + return actual_func(*args, **kwargs) |
| 451 | + |
| 452 | + |
434 | 453 | class OllamaInstrumentor(BaseInstrumentor):
|
435 | 454 | """An instrumentor for Ollama's client library."""
|
436 | 455 |
|
@@ -477,6 +496,27 @@ def _instrument(self, **kwargs):
|
477 | 496 | _wrap(tracer, token_histogram, duration_histogram, wrapped_method),
|
478 | 497 | )
|
479 | 498 |
|
| 499 | + # replace imported ollama functions in other modules |
| 500 | + try: |
| 501 | + # Iterate through all loaded modules to find modules that reference imported ollama functions |
| 502 | + for module_name, module in list(sys.modules.items()): |
| 503 | + if module_name != "ollama" and hasattr(module, "__dict__"): |
| 504 | + for attr_name, attr_value in list(module.__dict__.items()): |
| 505 | + for wrapped_method in WRAPPED_METHODS: |
| 506 | + method_name = wrapped_method.get("method") |
| 507 | + if ( |
| 508 | + attr_name == method_name |
| 509 | + and ( |
| 510 | + inspect.isfunction(attr_value) |
| 511 | + or inspect.ismethod(attr_value) |
| 512 | + ) |
| 513 | + and attr_value.__module__.startswith("ollama") |
| 514 | + ): |
| 515 | + module.__dict__[attr_name] = InstrumentedFunction(method_name) |
| 516 | + logger.debug(f"Replaced {method_name} in module {module_name}") |
| 517 | + except Exception as e: |
| 518 | + logger.warning(f"Error instrumenting imported ollama methods: {e}") |
| 519 | + |
480 | 520 | def _uninstrument(self, **kwargs):
|
481 | 521 | for wrapped_method in WRAPPED_METHODS:
|
482 | 522 | unwrap(
|
|
0 commit comments