monocle-apptrace 0.0.1__py3-none-any.whl → 0.1.1__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.
Potentially problematic release.
This version of monocle-apptrace might be problematic. Click here for more details.
- monocle_apptrace/README.md +52 -28
- monocle_apptrace/__init__.py +0 -2
- monocle_apptrace/constants.py +22 -0
- monocle_apptrace/exporters/file_exporter.py +63 -0
- monocle_apptrace/haystack/__init__.py +5 -24
- monocle_apptrace/haystack/wrap_node.py +1 -1
- monocle_apptrace/haystack/wrap_openai.py +1 -9
- monocle_apptrace/haystack/wrap_pipeline.py +22 -9
- monocle_apptrace/instrumentor.py +29 -32
- monocle_apptrace/langchain/__init__.py +5 -94
- monocle_apptrace/llamaindex/__init__.py +7 -63
- monocle_apptrace/metamodel/README.md +47 -0
- monocle_apptrace/metamodel/entities/README.md +54 -0
- monocle_apptrace/metamodel/entities/entity_types.json +157 -0
- monocle_apptrace/metamodel/entities/entity_types.py +51 -0
- monocle_apptrace/metamodel/maps/haystack_methods.json +25 -0
- monocle_apptrace/metamodel/maps/lang_chain_methods.json +106 -0
- monocle_apptrace/metamodel/maps/llama_index_methods.json +70 -0
- monocle_apptrace/metamodel/spans/README.md +121 -0
- monocle_apptrace/metamodel/spans/span_example.json +140 -0
- monocle_apptrace/metamodel/spans/span_format.json +55 -0
- monocle_apptrace/utils.py +56 -16
- monocle_apptrace/wrap_common.py +143 -46
- monocle_apptrace/wrapper.py +3 -3
- monocle_apptrace-0.1.1.dist-info/METADATA +111 -0
- monocle_apptrace-0.1.1.dist-info/RECORD +29 -0
- monocle_apptrace-0.0.1.dist-info/METADATA +0 -76
- monocle_apptrace-0.0.1.dist-info/RECORD +0 -17
- {monocle_apptrace-0.0.1.dist-info → monocle_apptrace-0.1.1.dist-info}/WHEEL +0 -0
- {monocle_apptrace-0.0.1.dist-info → monocle_apptrace-0.1.1.dist-info}/licenses/LICENSE +0 -0
- {monocle_apptrace-0.0.1.dist-info → monocle_apptrace-0.1.1.dist-info}/licenses/NOTICE +0 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "llamaindex.retrieve",
|
|
3
|
+
"context": {
|
|
4
|
+
"trace_id": "0x93cd0bf865b3ffcc3cf9c075dc3e3797",
|
|
5
|
+
"span_id": "0x5d3f839e900bda24",
|
|
6
|
+
"trace_state": "[]"
|
|
7
|
+
},
|
|
8
|
+
"kind": "SpanKind.CLIENT",
|
|
9
|
+
"parent_id": "0x7a63d63e42ccac60",
|
|
10
|
+
"start_time": "2024-09-09T14:38:45.237182Z",
|
|
11
|
+
"end_time": "2024-09-09T14:38:45.620112Z",
|
|
12
|
+
"status": {
|
|
13
|
+
"status_code": "OK"
|
|
14
|
+
},
|
|
15
|
+
"attributes": {
|
|
16
|
+
"span.type": "Retrieval",
|
|
17
|
+
"entity.count": 2,
|
|
18
|
+
"entity.1.name": "ChromaVectorStore",
|
|
19
|
+
"entity.1.type": "vectorstore.chroma",
|
|
20
|
+
"entity.1.embedding-model-name": "BAAI/bge-small-en-v1.5",
|
|
21
|
+
"entity.2.name": "BAAI/bge-small-en-v1.5",
|
|
22
|
+
"entity.2.type": "model.embedding",
|
|
23
|
+
"entity.2.model_name": "BAAI/bge-small-en-v1.5"
|
|
24
|
+
},
|
|
25
|
+
"events": [
|
|
26
|
+
{
|
|
27
|
+
"name": "data.input",
|
|
28
|
+
"timestamp": "timestamp",
|
|
29
|
+
"attributes": {
|
|
30
|
+
"context_input": "question: What is an americano?"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "data.output",
|
|
35
|
+
"timestamp": "timestamp",
|
|
36
|
+
"attributes": {
|
|
37
|
+
"context_output": "Coffee is a hot drink made from the roasted and ground seeds (coffee beans) of a tropical shrub\nA latte consists of one or more shots of espresso, served in a glass (or sometimes a cup), into which hot steamed milk is added\nAmericano is a type of coffee drink prepared by diluting an espresso shot with hot water at a 1:3 to 1:4 ratio, resulting in a drink that retains the complex flavors of espresso, but in a lighter way"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
],
|
|
42
|
+
"links": [],
|
|
43
|
+
"resource": {
|
|
44
|
+
"attributes": {
|
|
45
|
+
"service.name": "coffee-bot"
|
|
46
|
+
},
|
|
47
|
+
"schema_url": ""
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "llamaindex.openai",
|
|
52
|
+
"context": {
|
|
53
|
+
"trace_id": "0x93cd0bf865b3ffcc3cf9c075dc3e3797",
|
|
54
|
+
"span_id": "0x8b6363e1937a4d7b",
|
|
55
|
+
"trace_state": "[]"
|
|
56
|
+
},
|
|
57
|
+
"kind": "SpanKind.CLIENT",
|
|
58
|
+
"parent_id": "0x7a63d63e42ccac60",
|
|
59
|
+
"start_time": "2024-09-09T14:38:45.622174Z",
|
|
60
|
+
"end_time": "2024-09-09T14:38:46.514120Z",
|
|
61
|
+
"status": {
|
|
62
|
+
"status_code": "OK"
|
|
63
|
+
},
|
|
64
|
+
"attributes": {
|
|
65
|
+
"span.type": "inference",
|
|
66
|
+
"entity.count": 2,
|
|
67
|
+
"entity.1.name": "AzureOpenAI",
|
|
68
|
+
"entity.1.type": "inference.azure_oai",
|
|
69
|
+
"entity.1.provider_name": "openai.azure.com",
|
|
70
|
+
"entity.1.deployment": "kshitiz-gpt",
|
|
71
|
+
"entity.1.inference_endpoint": "https://okahu-openai-dev.openai.azure.com/",
|
|
72
|
+
|
|
73
|
+
"entity.2.name": "gpt-35-turbo",
|
|
74
|
+
"entity.2.type": "model.llm",
|
|
75
|
+
"entity.2.model_name": "gpt-35-turbo"
|
|
76
|
+
},
|
|
77
|
+
"events": [
|
|
78
|
+
{
|
|
79
|
+
"name": "data.input",
|
|
80
|
+
"timestamp": "timestamp",
|
|
81
|
+
"attributes": {
|
|
82
|
+
"question": "What is an americano?",
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"name": "data.output",
|
|
87
|
+
"timestamp": "timestamp",
|
|
88
|
+
"attributes": {
|
|
89
|
+
"response": "An americano is a type of coffee drink that is made by diluting an espresso shot with hot water at a 1:3 to 1:4 ratio, resulting in a drink that retains the complex flavors of espresso, but in a lighter way.",
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"name": "metadata",
|
|
94
|
+
"timestamp": "timestamp",
|
|
95
|
+
"attributes": {
|
|
96
|
+
"temperature": 0.1,
|
|
97
|
+
"completion_tokens": 52,
|
|
98
|
+
"prompt_tokens": 233,
|
|
99
|
+
"total_tokens": 285
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
],
|
|
103
|
+
"links": [],
|
|
104
|
+
"resource": {
|
|
105
|
+
"attributes": {
|
|
106
|
+
"service.name": "coffee-bot"
|
|
107
|
+
},
|
|
108
|
+
"schema_url": ""
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
{
|
|
112
|
+
"name": "llamaindex.query",
|
|
113
|
+
"context": {
|
|
114
|
+
"trace_id": "0x93cd0bf865b3ffcc3cf9c075dc3e3797",
|
|
115
|
+
"span_id": "0x7a63d63e42ccac60",
|
|
116
|
+
"trace_state": "[]"
|
|
117
|
+
},
|
|
118
|
+
"kind": "SpanKind.CLIENT",
|
|
119
|
+
"parent_id": null,
|
|
120
|
+
"start_time": "2024-09-09T14:38:45.236627Z",
|
|
121
|
+
"end_time": "2024-09-09T14:38:46.514442Z",
|
|
122
|
+
"status": {
|
|
123
|
+
"status_code": "OK"
|
|
124
|
+
},
|
|
125
|
+
"attributes": {
|
|
126
|
+
"span.type": "workflow",
|
|
127
|
+
"entity.count": 1,
|
|
128
|
+
"entity.1.name": "coffee-bot",
|
|
129
|
+
"entity.1.type": "workflow.llama_index"
|
|
130
|
+
},
|
|
131
|
+
"events": [
|
|
132
|
+
],
|
|
133
|
+
"links": [],
|
|
134
|
+
"resource": {
|
|
135
|
+
"attributes": {
|
|
136
|
+
"service.name": "coffee-bot"
|
|
137
|
+
},
|
|
138
|
+
"schema_url": ""
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "span-name",
|
|
3
|
+
"context": {
|
|
4
|
+
"trace_id": "trace-id",
|
|
5
|
+
"span_id": "span-id",
|
|
6
|
+
"trace_state": "[]"
|
|
7
|
+
},
|
|
8
|
+
"kind": "SpanKind.CLIENT",
|
|
9
|
+
"parent_id": "parent-id or None (for root span)",
|
|
10
|
+
"start_time": "UTC timestamp",
|
|
11
|
+
"end_time": "UTC timestamp",
|
|
12
|
+
"status": {
|
|
13
|
+
"status_code": "OK or Error"
|
|
14
|
+
},
|
|
15
|
+
"attributes": {
|
|
16
|
+
"description": "List of AI component entities used in this span, eg Model, Inference hosting service. Needs to be one of the supported entity types.",
|
|
17
|
+
|
|
18
|
+
"span.type": "Monocle-span-type",
|
|
19
|
+
"entity.count": "count-of-entities",
|
|
20
|
+
|
|
21
|
+
"entity.<index>.name": "Monocle-Entity-name",
|
|
22
|
+
"entity.<index>.type": "Monocle-Entity-Type",
|
|
23
|
+
"entity.<index>.<attribute>": "Value"
|
|
24
|
+
},
|
|
25
|
+
"events" : [
|
|
26
|
+
{
|
|
27
|
+
"name": "data.input",
|
|
28
|
+
"timestamp": "UTC timestamp",
|
|
29
|
+
"attributes": {
|
|
30
|
+
"input_attribute": "value"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "data.output",
|
|
35
|
+
"timestamp": "UTC timestamp",
|
|
36
|
+
"attributes": {
|
|
37
|
+
"output_attribute": "value"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"name": "metadata",
|
|
42
|
+
"timestamp": "UTC timestamp",
|
|
43
|
+
"attributes": {
|
|
44
|
+
"metadata_attribute": "value"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
"links": [],
|
|
49
|
+
"resource": {
|
|
50
|
+
"attributes": {
|
|
51
|
+
"service.name": "top-workflow-name"
|
|
52
|
+
},
|
|
53
|
+
"schema_url": ""
|
|
54
|
+
}
|
|
55
|
+
}
|
monocle_apptrace/utils.py
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
1
|
import logging
|
|
4
|
-
|
|
2
|
+
import json
|
|
3
|
+
from importlib import import_module
|
|
4
|
+
import os
|
|
5
|
+
from opentelemetry.trace import Span
|
|
6
|
+
from monocle_apptrace.constants import azure_service_map, aws_service_map
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
exception_logger = None
|
|
8
|
+
embedding_model_context = {}
|
|
8
9
|
|
|
9
10
|
def set_span_attribute(span, name, value):
|
|
10
11
|
if value is not None:
|
|
11
12
|
if value != "":
|
|
12
13
|
span.set_attribute(name, value)
|
|
13
|
-
return
|
|
14
|
-
|
|
15
14
|
|
|
16
15
|
def dont_throw(func):
|
|
17
16
|
"""
|
|
@@ -22,15 +21,12 @@ def dont_throw(func):
|
|
|
22
21
|
"""
|
|
23
22
|
# Obtain a logger specific to the function's module
|
|
24
23
|
logger = logging.getLogger(func.__module__)
|
|
25
|
-
|
|
24
|
+
# pylint: disable=inconsistent-return-statements
|
|
26
25
|
def wrapper(*args, **kwargs):
|
|
27
26
|
try:
|
|
28
27
|
return func(*args, **kwargs)
|
|
29
|
-
except Exception as
|
|
30
|
-
logger.warning("Failed to execute %s, error: %s", func.__name__, str(
|
|
31
|
-
if Config.exception_logger:
|
|
32
|
-
Config.exception_logger(e)
|
|
33
|
-
|
|
28
|
+
except Exception as ex:
|
|
29
|
+
logger.warning("Failed to execute %s, error: %s", func.__name__, str(ex))
|
|
34
30
|
return wrapper
|
|
35
31
|
|
|
36
32
|
def with_tracer_wrapper(func):
|
|
@@ -44,10 +40,54 @@ def with_tracer_wrapper(func):
|
|
|
44
40
|
|
|
45
41
|
return _with_tracer
|
|
46
42
|
|
|
47
|
-
def resolve_from_alias(
|
|
43
|
+
def resolve_from_alias(my_map, alias):
|
|
48
44
|
"""Find a alias that is not none from list of aliases"""
|
|
49
45
|
|
|
50
46
|
for i in alias:
|
|
51
|
-
if i in
|
|
52
|
-
return
|
|
47
|
+
if i in my_map.keys():
|
|
48
|
+
return my_map[i]
|
|
53
49
|
return None
|
|
50
|
+
|
|
51
|
+
def load_wrapper_from_config(config_file_path: str, module_name: str = None):
|
|
52
|
+
wrapper_methods = []
|
|
53
|
+
with open(config_file_path, encoding='UTF-8') as config_file:
|
|
54
|
+
json_data = json.load(config_file)
|
|
55
|
+
wrapper_methods = json_data["wrapper_methods"]
|
|
56
|
+
for wrapper_method in wrapper_methods:
|
|
57
|
+
wrapper_method["wrapper"] = get_wrapper_method(
|
|
58
|
+
wrapper_method["wrapper_package"], wrapper_method["wrapper_method"])
|
|
59
|
+
if "span_name_getter_method" in wrapper_method :
|
|
60
|
+
wrapper_method["span_name_getter"] = get_wrapper_method(
|
|
61
|
+
wrapper_method["span_name_getter_package"],
|
|
62
|
+
wrapper_method["span_name_getter_method"])
|
|
63
|
+
return wrapper_methods
|
|
64
|
+
|
|
65
|
+
def get_wrapper_method(package_name: str, method_name: str):
|
|
66
|
+
wrapper_module = import_module("monocle_apptrace." + package_name)
|
|
67
|
+
return getattr(wrapper_module, method_name)
|
|
68
|
+
|
|
69
|
+
def update_span_with_infra_name(span: Span, span_key: str):
|
|
70
|
+
for key,val in azure_service_map.items():
|
|
71
|
+
if key in os.environ:
|
|
72
|
+
span.set_attribute(span_key, val)
|
|
73
|
+
for key,val in aws_service_map.items():
|
|
74
|
+
if key in os.environ:
|
|
75
|
+
span.set_attribute(span_key, val)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def set_embedding_model(model_name: str):
|
|
79
|
+
"""
|
|
80
|
+
Sets the embedding model in the global context.
|
|
81
|
+
|
|
82
|
+
@param model_name: The name of the embedding model to set
|
|
83
|
+
"""
|
|
84
|
+
embedding_model_context['embedding_model'] = model_name
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def get_embedding_model() -> str:
|
|
88
|
+
"""
|
|
89
|
+
Retrieves the embedding model from the global context.
|
|
90
|
+
|
|
91
|
+
@return: The name of the embedding model, or 'unknown' if not set
|
|
92
|
+
"""
|
|
93
|
+
return embedding_model_context.get('embedding_model', 'unknown')
|
monocle_apptrace/wrap_common.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
#pylint: disable=protected-access
|
|
1
2
|
import logging
|
|
2
3
|
import os
|
|
4
|
+
from urllib.parse import urlparse
|
|
3
5
|
|
|
4
6
|
from opentelemetry.trace import Span, Tracer
|
|
5
|
-
|
|
6
|
-
from monocle_apptrace.utils import resolve_from_alias, with_tracer_wrapper
|
|
7
|
+
from monocle_apptrace.utils import resolve_from_alias, update_span_with_infra_name, with_tracer_wrapper, get_embedding_model
|
|
7
8
|
|
|
8
9
|
logger = logging.getLogger(__name__)
|
|
9
10
|
WORKFLOW_TYPE_KEY = "workflow_type"
|
|
@@ -14,7 +15,12 @@ PROMPT_OUTPUT_KEY = "output"
|
|
|
14
15
|
QUERY = "question"
|
|
15
16
|
RESPONSE = "response"
|
|
16
17
|
TAGS = "tags"
|
|
17
|
-
|
|
18
|
+
SESSION_PROPERTIES_KEY = "session"
|
|
19
|
+
INFRA_SERVICE_KEY = "infra_service_name"
|
|
20
|
+
TYPE = "type"
|
|
21
|
+
PROVIDER = "provider_name"
|
|
22
|
+
EMBEDDING_MODEL = "embedding_model"
|
|
23
|
+
VECTOR_STORE = 'vector_store'
|
|
18
24
|
|
|
19
25
|
|
|
20
26
|
WORKFLOW_TYPE_MAP = {
|
|
@@ -23,6 +29,24 @@ WORKFLOW_TYPE_MAP = {
|
|
|
23
29
|
"haystack": "workflow.haystack"
|
|
24
30
|
}
|
|
25
31
|
|
|
32
|
+
framework_vector_store_mapping = {
|
|
33
|
+
'langchain_core.retrievers': lambda instance: {
|
|
34
|
+
'provider': instance.tags[0],
|
|
35
|
+
'embedding_model': instance.tags[1],
|
|
36
|
+
'type': VECTOR_STORE,
|
|
37
|
+
},
|
|
38
|
+
'llama_index.core.indices.base_retriever': lambda instance: {
|
|
39
|
+
'provider': type(instance._vector_store).__name__,
|
|
40
|
+
'embedding_model': instance._embed_model.model_name,
|
|
41
|
+
'type': VECTOR_STORE,
|
|
42
|
+
},
|
|
43
|
+
'haystack.components.retrievers': lambda instance: {
|
|
44
|
+
'provider': instance.__dict__.get("document_store").__class__.__name__,
|
|
45
|
+
'embedding_model': get_embedding_model(),
|
|
46
|
+
'type': VECTOR_STORE,
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
|
|
26
50
|
@with_tracer_wrapper
|
|
27
51
|
def task_wrapper(tracer: Tracer, to_wrap, wrapped, instance, args, kwargs):
|
|
28
52
|
"""Instruments and calls every function defined in TO_WRAP."""
|
|
@@ -37,29 +61,39 @@ def task_wrapper(tracer: Tracer, to_wrap, wrapped, instance, args, kwargs):
|
|
|
37
61
|
name = to_wrap.get("span_name")
|
|
38
62
|
else:
|
|
39
63
|
name = f"langchain.task.{instance.__class__.__name__}"
|
|
40
|
-
kind = to_wrap.get("kind")
|
|
41
64
|
|
|
42
65
|
with tracer.start_as_current_span(name) as span:
|
|
43
|
-
|
|
44
|
-
update_span_with_prompt_input(to_wrap=to_wrap, wrapped_args=args, span=span)
|
|
45
|
-
|
|
46
|
-
#capture the tags attribute of the instance if present, else ignore
|
|
47
|
-
try:
|
|
48
|
-
span.set_attribute(TAGS, getattr(instance, TAGS))
|
|
49
|
-
except AttributeError:
|
|
50
|
-
pass
|
|
51
|
-
update_span_with_context_input(to_wrap=to_wrap, wrapped_args=args, span=span)
|
|
66
|
+
pre_task_processing(to_wrap, instance, args, span)
|
|
52
67
|
return_value = wrapped(*args, **kwargs)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if is_root_span(span):
|
|
56
|
-
workflow_name = span.resource.attributes.get("service.name")
|
|
57
|
-
span.set_attribute("workflow_name",workflow_name)
|
|
58
|
-
update_span_with_prompt_output(to_wrap=to_wrap, wrapped_args=return_value, span=span)
|
|
59
|
-
update_workflow_type(to_wrap, span)
|
|
68
|
+
post_task_processing(to_wrap, span, return_value)
|
|
60
69
|
|
|
61
70
|
return return_value
|
|
62
71
|
|
|
72
|
+
def post_task_processing(to_wrap, span, return_value):
|
|
73
|
+
update_span_with_context_output(to_wrap=to_wrap, return_value=return_value, span=span)
|
|
74
|
+
|
|
75
|
+
if is_root_span(span):
|
|
76
|
+
workflow_name = span.resource.attributes.get("service.name")
|
|
77
|
+
span.set_attribute("workflow_name",workflow_name)
|
|
78
|
+
update_span_with_prompt_output(to_wrap=to_wrap, wrapped_args=return_value, span=span)
|
|
79
|
+
update_workflow_type(to_wrap, span)
|
|
80
|
+
|
|
81
|
+
def pre_task_processing(to_wrap, instance, args, span):
|
|
82
|
+
if is_root_span(span):
|
|
83
|
+
update_span_with_prompt_input(to_wrap=to_wrap, wrapped_args=args, span=span)
|
|
84
|
+
|
|
85
|
+
update_span_with_infra_name(span, INFRA_SERVICE_KEY)
|
|
86
|
+
|
|
87
|
+
#capture the tags attribute of the instance if present, else ignore
|
|
88
|
+
try:
|
|
89
|
+
update_tags(instance, span)
|
|
90
|
+
update_vectorstore_attributes(to_wrap, instance, span)
|
|
91
|
+
except AttributeError:
|
|
92
|
+
pass
|
|
93
|
+
update_span_with_context_input(to_wrap=to_wrap, wrapped_args=args, span=span)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
63
97
|
@with_tracer_wrapper
|
|
64
98
|
async def atask_wrapper(tracer, to_wrap, wrapped, instance, args, kwargs):
|
|
65
99
|
"""Instruments and calls every function defined in TO_WRAP."""
|
|
@@ -74,9 +108,10 @@ async def atask_wrapper(tracer, to_wrap, wrapped, instance, args, kwargs):
|
|
|
74
108
|
name = to_wrap.get("span_name")
|
|
75
109
|
else:
|
|
76
110
|
name = f"langchain.task.{instance.__class__.__name__}"
|
|
77
|
-
kind = to_wrap.get("kind")
|
|
78
111
|
with tracer.start_as_current_span(name) as span:
|
|
112
|
+
pre_task_processing(to_wrap, instance, args, span)
|
|
79
113
|
return_value = await wrapped(*args, **kwargs)
|
|
114
|
+
post_task_processing(to_wrap, span, return_value)
|
|
80
115
|
|
|
81
116
|
return return_value
|
|
82
117
|
|
|
@@ -86,7 +121,7 @@ async def allm_wrapper(tracer, to_wrap, wrapped, instance, args, kwargs):
|
|
|
86
121
|
if instance.__class__.__name__ in ("AgentExecutor"):
|
|
87
122
|
return wrapped(*args, **kwargs)
|
|
88
123
|
|
|
89
|
-
if to_wrap.get("span_name_getter"):
|
|
124
|
+
if callable(to_wrap.get("span_name_getter")):
|
|
90
125
|
name = to_wrap.get("span_name_getter")(instance)
|
|
91
126
|
|
|
92
127
|
elif hasattr(instance, "name") and instance.name:
|
|
@@ -95,11 +130,11 @@ async def allm_wrapper(tracer, to_wrap, wrapped, instance, args, kwargs):
|
|
|
95
130
|
name = to_wrap.get("span_name")
|
|
96
131
|
else:
|
|
97
132
|
name = f"langchain.task.{instance.__class__.__name__}"
|
|
98
|
-
kind = to_wrap.get("kind")
|
|
99
133
|
with tracer.start_as_current_span(name) as span:
|
|
100
134
|
update_llm_endpoint(curr_span= span, instance=instance)
|
|
101
135
|
|
|
102
136
|
return_value = await wrapped(*args, **kwargs)
|
|
137
|
+
update_span_from_llm_response(response = return_value, span = span)
|
|
103
138
|
|
|
104
139
|
return return_value
|
|
105
140
|
|
|
@@ -119,8 +154,9 @@ def llm_wrapper(tracer: Tracer, to_wrap, wrapped, instance, args, kwargs):
|
|
|
119
154
|
name = to_wrap.get("span_name")
|
|
120
155
|
else:
|
|
121
156
|
name = f"langchain.task.{instance.__class__.__name__}"
|
|
122
|
-
kind = to_wrap.get("kind")
|
|
123
157
|
with tracer.start_as_current_span(name) as span:
|
|
158
|
+
if 'haystack.components.retrievers' in to_wrap['package'] and 'haystack.retriever' in span.name:
|
|
159
|
+
update_vectorstore_attributes(to_wrap, instance, span)
|
|
124
160
|
update_llm_endpoint(curr_span= span, instance=instance)
|
|
125
161
|
|
|
126
162
|
return_value = wrapped(*args, **kwargs)
|
|
@@ -136,22 +172,45 @@ def update_llm_endpoint(curr_span: Span, instance):
|
|
|
136
172
|
if 'temperature' in instance.__dict__:
|
|
137
173
|
temp_val = instance.__dict__.get("temperature")
|
|
138
174
|
curr_span.set_attribute("temperature", temp_val)
|
|
139
|
-
|
|
140
|
-
model_name =
|
|
141
|
-
curr_span.set_attribute("
|
|
175
|
+
# handling for model name
|
|
176
|
+
model_name = resolve_from_alias(instance.__dict__ , ["model","model_name"])
|
|
177
|
+
curr_span.set_attribute("model_name", model_name)
|
|
178
|
+
set_provider_name(curr_span, instance)
|
|
142
179
|
# handling AzureOpenAI deployment
|
|
143
|
-
deployment_name =
|
|
180
|
+
deployment_name = resolve_from_alias(instance.__dict__ , [ "engine", "azure_deployment",
|
|
144
181
|
"deployment_name", "deployment_id", "deployment"])
|
|
145
182
|
curr_span.set_attribute("az_openai_deployment", deployment_name)
|
|
146
183
|
# handling the inference endpoint
|
|
147
184
|
inference_ep = resolve_from_alias(instance.__dict__,["azure_endpoint","api_base"])
|
|
148
185
|
curr_span.set_attribute("inference_endpoint",inference_ep)
|
|
149
186
|
|
|
187
|
+
def set_provider_name(curr_span, instance):
|
|
188
|
+
provider_url = ""
|
|
189
|
+
|
|
190
|
+
try :
|
|
191
|
+
if isinstance(instance.client._client.base_url.host, str) :
|
|
192
|
+
provider_url = instance. client._client.base_url.host
|
|
193
|
+
except:
|
|
194
|
+
pass
|
|
195
|
+
|
|
196
|
+
try :
|
|
197
|
+
if isinstance(instance.api_base, str):
|
|
198
|
+
provider_url = instance.api_base
|
|
199
|
+
except:
|
|
200
|
+
pass
|
|
201
|
+
|
|
202
|
+
try :
|
|
203
|
+
if len(provider_url) > 0:
|
|
204
|
+
parsed_provider_url = urlparse(provider_url)
|
|
205
|
+
curr_span.set_attribute("provider_name", parsed_provider_url.hostname or provider_url)
|
|
206
|
+
except:
|
|
207
|
+
pass
|
|
208
|
+
|
|
150
209
|
def is_root_span(curr_span: Span) -> bool:
|
|
151
|
-
return curr_span.parent
|
|
210
|
+
return curr_span.parent is None
|
|
152
211
|
|
|
153
212
|
def get_input_from_args(chain_args):
|
|
154
|
-
if len(chain_args) > 0 and
|
|
213
|
+
if len(chain_args) > 0 and isinstance(chain_args[0], str):
|
|
155
214
|
return chain_args[0]
|
|
156
215
|
return ""
|
|
157
216
|
|
|
@@ -166,15 +225,19 @@ def update_span_from_llm_response(response, span: Span):
|
|
|
166
225
|
span.set_attribute("total_tokens", token_usage.get("total_tokens"))
|
|
167
226
|
# extract token usage from llamaindex openai
|
|
168
227
|
if(response is not None and hasattr(response, "raw")):
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
228
|
+
try:
|
|
229
|
+
if response.raw is not None:
|
|
230
|
+
token_usage = response.raw.get("usage") if isinstance(response.raw, dict) else getattr(response.raw, "usage", None)
|
|
231
|
+
if token_usage is not None:
|
|
232
|
+
if getattr(token_usage, "completion_tokens", None):
|
|
233
|
+
span.set_attribute("completion_tokens", getattr(token_usage, "completion_tokens"))
|
|
234
|
+
if getattr(token_usage, "prompt_tokens", None):
|
|
235
|
+
span.set_attribute("prompt_tokens", getattr(token_usage, "prompt_tokens"))
|
|
236
|
+
if getattr(token_usage, "total_tokens", None):
|
|
237
|
+
span.set_attribute("total_tokens", getattr(token_usage, "total_tokens"))
|
|
238
|
+
except AttributeError:
|
|
239
|
+
token_usage = None
|
|
240
|
+
|
|
178
241
|
|
|
179
242
|
def update_workflow_type(to_wrap, span: Span):
|
|
180
243
|
package_name = to_wrap.get('package')
|
|
@@ -185,30 +248,64 @@ def update_workflow_type(to_wrap, span: Span):
|
|
|
185
248
|
|
|
186
249
|
def update_span_with_context_input(to_wrap, wrapped_args ,span: Span):
|
|
187
250
|
package_name: str = to_wrap.get('package')
|
|
188
|
-
if
|
|
251
|
+
if "langchain_core.retrievers" in package_name:
|
|
189
252
|
input_arg_text = wrapped_args[0]
|
|
190
253
|
span.add_event(CONTEXT_INPUT_KEY, {QUERY:input_arg_text})
|
|
191
|
-
if
|
|
254
|
+
if "llama_index.core.indices.base_retriever" in package_name:
|
|
192
255
|
input_arg_text = wrapped_args[0].query_str
|
|
193
256
|
span.add_event(CONTEXT_INPUT_KEY, {QUERY:input_arg_text})
|
|
194
257
|
|
|
195
258
|
def update_span_with_context_output(to_wrap, return_value ,span: Span):
|
|
196
259
|
package_name: str = to_wrap.get('package')
|
|
197
|
-
if
|
|
260
|
+
if "llama_index.core.indices.base_retriever" in package_name:
|
|
198
261
|
output_arg_text = return_value[0].text
|
|
199
262
|
span.add_event(CONTEXT_OUTPUT_KEY, {RESPONSE:output_arg_text})
|
|
200
263
|
|
|
201
264
|
def update_span_with_prompt_input(to_wrap, wrapped_args ,span: Span):
|
|
202
265
|
input_arg_text = wrapped_args[0]
|
|
203
|
-
|
|
266
|
+
|
|
204
267
|
if isinstance(input_arg_text, dict):
|
|
205
268
|
span.add_event(PROMPT_INPUT_KEY,input_arg_text)
|
|
206
|
-
else:
|
|
269
|
+
else:
|
|
207
270
|
span.add_event(PROMPT_INPUT_KEY,{QUERY:input_arg_text})
|
|
208
271
|
|
|
209
272
|
def update_span_with_prompt_output(to_wrap, wrapped_args ,span: Span):
|
|
210
273
|
package_name: str = to_wrap.get('package')
|
|
211
|
-
if
|
|
274
|
+
if isinstance(wrapped_args, str):
|
|
212
275
|
span.add_event(PROMPT_OUTPUT_KEY, {RESPONSE:wrapped_args})
|
|
213
|
-
if
|
|
276
|
+
if "llama_index.core.base.base_query_engine" in package_name:
|
|
214
277
|
span.add_event(PROMPT_OUTPUT_KEY, {RESPONSE:wrapped_args.response})
|
|
278
|
+
|
|
279
|
+
def update_tags(instance, span):
|
|
280
|
+
try:
|
|
281
|
+
# copy tags as is from langchain
|
|
282
|
+
span.set_attribute(TAGS, getattr(instance, TAGS))
|
|
283
|
+
except:
|
|
284
|
+
pass
|
|
285
|
+
try:
|
|
286
|
+
# extract embed model and vector store names for llamaindex
|
|
287
|
+
model_name = instance.retriever._embed_model.model_name
|
|
288
|
+
vector_store_name = type(instance.retriever._vector_store).__name__
|
|
289
|
+
span.set_attribute(TAGS, [model_name, vector_store_name])
|
|
290
|
+
except:
|
|
291
|
+
pass
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def update_vectorstore_attributes(to_wrap, instance, span):
|
|
295
|
+
"""
|
|
296
|
+
Updates the telemetry span attributes for vector store retrieval tasks.
|
|
297
|
+
"""
|
|
298
|
+
try:
|
|
299
|
+
package = to_wrap.get('package')
|
|
300
|
+
if package in framework_vector_store_mapping:
|
|
301
|
+
attributes = framework_vector_store_mapping[package](instance)
|
|
302
|
+
span._attributes.update({
|
|
303
|
+
TYPE: attributes['type'],
|
|
304
|
+
PROVIDER: attributes['provider'],
|
|
305
|
+
EMBEDDING_MODEL: attributes['embedding_model']
|
|
306
|
+
})
|
|
307
|
+
else:
|
|
308
|
+
logger.warning(f"Package '{package}' not recognized for vector store telemetry.")
|
|
309
|
+
|
|
310
|
+
except Exception as e:
|
|
311
|
+
logger.error(f"Error updating span attributes: {e}")
|
monocle_apptrace/wrapper.py
CHANGED
|
@@ -5,20 +5,20 @@ from monocle_apptrace.langchain import LANGCHAIN_METHODS
|
|
|
5
5
|
from monocle_apptrace.llamaindex import LLAMAINDEX_METHODS
|
|
6
6
|
from monocle_apptrace.wrap_common import task_wrapper
|
|
7
7
|
|
|
8
|
+
# pylint: disable=too-few-public-methods
|
|
8
9
|
class WrapperMethod:
|
|
9
10
|
def __init__(
|
|
10
11
|
self,
|
|
11
12
|
package: str,
|
|
12
|
-
|
|
13
|
+
object_name: str,
|
|
13
14
|
method: str,
|
|
14
15
|
span_name: str = None,
|
|
15
16
|
wrapper = task_wrapper
|
|
16
17
|
):
|
|
17
18
|
self.package = package
|
|
18
|
-
self.object =
|
|
19
|
+
self.object = object_name
|
|
19
20
|
self.method = method
|
|
20
21
|
self.span_name = span_name
|
|
21
22
|
self.wrapper = wrapper
|
|
22
23
|
|
|
23
24
|
INBUILT_METHODS_LIST = LANGCHAIN_METHODS + LLAMAINDEX_METHODS + HAYSTACK_METHODS
|
|
24
|
-
|