-
Notifications
You must be signed in to change notification settings - Fork 25
langchain instrumentor PR #448
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?
Changes from 37 commits
1f549b0
9dab168
13944b3
31b875f
8475d99
4ecaf95
5d7d17d
142b99f
8a4e6d5
7a8c2dd
2b1e66f
e27abb0
54365b8
70dea80
b8b8636
ab44b5a
829a5c3
69a7873
354fdbb
da0c624
18e85bd
23e0f2c
d19e256
5d671b0
310024b
373afcb
a0f7622
8fea513
a606ec9
b347ff8
5578c2f
e325abf
3a08423
cadd51b
1071ac7
a7b929a
5ac2d75
b44a041
d38ade7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -82,6 +82,13 @@ dependencies = [ | |
"opentelemetry-instrumentation-urllib3 == 0.54b1", | ||
"opentelemetry-instrumentation-wsgi == 0.54b1", | ||
"opentelemetry-instrumentation-cassandra == 0.54b1", | ||
"langchain == 0.3.27", | ||
"langchain-core == 0.3.72", | ||
"langchain-aws == 0.2.15", | ||
"langchain-community == 0.3.27", | ||
"langgraph == 0.6.3", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For instrumentation libraries, we normally don't add dependencies for the library we're instrumenting directly. For example, see the pyproject.toml in the upstream instrumentor. The reason for this is because we only want to instrument a customer's library if they have it installed. Otherwise, our instrumentation logic will just not run. |
||
"pytest-asyncio == 0.21.0", | ||
"pytest-vcr == 1.0.2", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we should add these in the main dependencies since they are just for testing. For example, we don't like |
||
] | ||
|
||
[project.optional-dependencies] | ||
|
@@ -95,6 +102,9 @@ test = [] | |
[project.entry-points.opentelemetry_configurator] | ||
aws_configurator = "amazon.opentelemetry.distro.aws_opentelemetry_configurator:AwsOpenTelemetryConfigurator" | ||
|
||
[project.entry-points.opentelemetry_instrumentor] | ||
langchain = "amazon.opentelemetry.distro.opentelemetry.instrumentation.langchain_v2:LangChainInstrumentor" | ||
|
||
[project.entry-points.opentelemetry_distro] | ||
aws_distro = "amazon.opentelemetry.distro.aws_opentelemetry_distro:AwsOpenTelemetryDistro" | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
# pylint: disable=no-self-use | ||
|
||
from typing import Collection | ||
|
||
from wrapt import wrap_function_wrapper | ||
|
||
from amazon.opentelemetry.distro.opentelemetry.instrumentation.langchain_v2.callback_handler import ( | ||
OpenTelemetryCallbackHandler, | ||
) | ||
from amazon.opentelemetry.distro.opentelemetry.instrumentation.langchain_v2.version import __version__ | ||
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor | ||
from opentelemetry.instrumentation.utils import unwrap | ||
from opentelemetry.trace import get_tracer | ||
|
||
__all__ = ["OpenTelemetryCallbackHandler"] | ||
|
||
_instruments = ("langchain >= 0.1.0",) | ||
|
||
|
||
class LangChainInstrumentor(BaseInstrumentor): | ||
def __init__(self): | ||
super().__init__() | ||
self.handler = None # Initialize the handler attribute | ||
self._wrapped = [] | ||
|
||
def instrumentation_dependencies(self) -> Collection[str]: | ||
return _instruments | ||
|
||
def _instrument(self, **kwargs): | ||
tracer_provider = kwargs.get("tracer_provider") | ||
tracer = get_tracer(__name__, __version__, tracer_provider) | ||
|
||
otel_callback_handler = OpenTelemetryCallbackHandler(tracer) | ||
|
||
wrap_function_wrapper( | ||
module="langchain_core.callbacks", | ||
name="BaseCallbackManager.__init__", | ||
wrapper=_BaseCallbackManagerInitWrapper(otel_callback_handler), | ||
) | ||
|
||
def _uninstrument(self, **kwargs): | ||
unwrap("langchain_core.callbacks", "BaseCallbackManager.__init__") | ||
if hasattr(self, "_wrapped"): | ||
for module, name in self._wrapped: | ||
unwrap(module, name) | ||
self.handler = None | ||
|
||
|
||
class _BaseCallbackManagerInitWrapper: | ||
def __init__(self, callback_handler: "OpenTelemetryCallbackHandler"): | ||
self.callback_handler = callback_handler | ||
self._wrapped = [] | ||
|
||
def __call__( | ||
self, | ||
wrapped, | ||
instance, | ||
args, | ||
kwargs, | ||
) -> None: | ||
wrapped(*args, **kwargs) | ||
for handler in instance.inheritable_handlers: | ||
if isinstance(handler, OpenTelemetryCallbackHandler): | ||
return None | ||
|
||
instance.add_handler(self.callback_handler, True) | ||
return None |
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.
We should not need some of these dependencies here.
For example, why do we need
duckduckgo-search
?