opentelemetry-instrumentation-vertexai 2.0b0__py3-none-any.whl → 2.1b0__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 opentelemetry-instrumentation-vertexai might be problematic. Click here for more details.
- opentelemetry/instrumentation/vertexai/__init__.py +101 -24
- opentelemetry/instrumentation/vertexai/events.py +18 -16
- opentelemetry/instrumentation/vertexai/patch.py +257 -28
- opentelemetry/instrumentation/vertexai/utils.py +136 -21
- opentelemetry/instrumentation/vertexai/version.py +1 -1
- {opentelemetry_instrumentation_vertexai-2.0b0.dist-info → opentelemetry_instrumentation_vertexai-2.1b0.dist-info}/METADATA +6 -6
- opentelemetry_instrumentation_vertexai-2.1b0.dist-info/RECORD +12 -0
- opentelemetry_instrumentation_vertexai-2.0b0.dist-info/RECORD +0 -12
- {opentelemetry_instrumentation_vertexai-2.0b0.dist-info → opentelemetry_instrumentation_vertexai-2.1b0.dist-info}/WHEEL +0 -0
- {opentelemetry_instrumentation_vertexai-2.0b0.dist-info → opentelemetry_instrumentation_vertexai-2.1b0.dist-info}/entry_points.txt +0 -0
- {opentelemetry_instrumentation_vertexai-2.0b0.dist-info → opentelemetry_instrumentation_vertexai-2.1b0.dist-info}/licenses/LICENSE +0 -0
|
@@ -39,58 +39,135 @@ API
|
|
|
39
39
|
---
|
|
40
40
|
"""
|
|
41
41
|
|
|
42
|
+
from __future__ import annotations
|
|
43
|
+
|
|
42
44
|
from typing import Any, Collection
|
|
43
45
|
|
|
44
46
|
from wrapt import (
|
|
45
47
|
wrap_function_wrapper, # type: ignore[reportUnknownVariableType]
|
|
46
48
|
)
|
|
47
49
|
|
|
48
|
-
from opentelemetry.
|
|
50
|
+
from opentelemetry._logs import get_logger
|
|
51
|
+
from opentelemetry.instrumentation._semconv import (
|
|
52
|
+
_OpenTelemetrySemanticConventionStability,
|
|
53
|
+
_OpenTelemetryStabilitySignalType,
|
|
54
|
+
_StabilityMode,
|
|
55
|
+
)
|
|
49
56
|
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
|
57
|
+
from opentelemetry.instrumentation.utils import unwrap
|
|
50
58
|
from opentelemetry.instrumentation.vertexai.package import _instruments
|
|
51
|
-
from opentelemetry.instrumentation.vertexai.patch import
|
|
52
|
-
generate_content_create,
|
|
53
|
-
)
|
|
59
|
+
from opentelemetry.instrumentation.vertexai.patch import MethodWrappers
|
|
54
60
|
from opentelemetry.instrumentation.vertexai.utils import is_content_enabled
|
|
55
61
|
from opentelemetry.semconv.schemas import Schemas
|
|
56
62
|
from opentelemetry.trace import get_tracer
|
|
63
|
+
from opentelemetry.util.genai.completion_hook import load_completion_hook
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _methods_to_wrap(
|
|
67
|
+
method_wrappers: MethodWrappers,
|
|
68
|
+
):
|
|
69
|
+
# This import is very slow, do it lazily in case instrument() is not called
|
|
70
|
+
# pylint: disable=import-outside-toplevel
|
|
71
|
+
from google.cloud.aiplatform_v1.services.prediction_service import (
|
|
72
|
+
async_client,
|
|
73
|
+
client,
|
|
74
|
+
)
|
|
75
|
+
from google.cloud.aiplatform_v1beta1.services.prediction_service import (
|
|
76
|
+
async_client as async_client_v1beta1,
|
|
77
|
+
)
|
|
78
|
+
from google.cloud.aiplatform_v1beta1.services.prediction_service import (
|
|
79
|
+
client as client_v1beta1,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
for client_class in (
|
|
83
|
+
client.PredictionServiceClient,
|
|
84
|
+
client_v1beta1.PredictionServiceClient,
|
|
85
|
+
):
|
|
86
|
+
yield (
|
|
87
|
+
client_class,
|
|
88
|
+
client_class.generate_content.__name__, # type: ignore[reportUnknownMemberType]
|
|
89
|
+
method_wrappers.generate_content,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
for client_class in (
|
|
93
|
+
async_client.PredictionServiceAsyncClient,
|
|
94
|
+
async_client_v1beta1.PredictionServiceAsyncClient,
|
|
95
|
+
):
|
|
96
|
+
yield (
|
|
97
|
+
client_class,
|
|
98
|
+
client_class.generate_content.__name__, # type: ignore[reportUnknownMemberType]
|
|
99
|
+
method_wrappers.agenerate_content,
|
|
100
|
+
)
|
|
57
101
|
|
|
58
102
|
|
|
59
103
|
class VertexAIInstrumentor(BaseInstrumentor):
|
|
104
|
+
def __init__(self) -> None:
|
|
105
|
+
super().__init__()
|
|
106
|
+
self._methods_to_unwrap: list[tuple[Any, str]] = []
|
|
107
|
+
|
|
60
108
|
def instrumentation_dependencies(self) -> Collection[str]:
|
|
61
109
|
return _instruments
|
|
62
110
|
|
|
63
111
|
def _instrument(self, **kwargs: Any):
|
|
64
112
|
"""Enable VertexAI instrumentation."""
|
|
113
|
+
completion_hook = (
|
|
114
|
+
kwargs.get("completion_hook") or load_completion_hook()
|
|
115
|
+
)
|
|
116
|
+
sem_conv_opt_in_mode = _OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(
|
|
117
|
+
_OpenTelemetryStabilitySignalType.GEN_AI,
|
|
118
|
+
)
|
|
65
119
|
tracer_provider = kwargs.get("tracer_provider")
|
|
120
|
+
schema = (
|
|
121
|
+
Schemas.V1_28_0.value
|
|
122
|
+
if sem_conv_opt_in_mode == _StabilityMode.DEFAULT
|
|
123
|
+
else Schemas.V1_36_0.value
|
|
124
|
+
)
|
|
66
125
|
tracer = get_tracer(
|
|
67
126
|
__name__,
|
|
68
127
|
"",
|
|
69
128
|
tracer_provider,
|
|
70
|
-
schema_url=
|
|
129
|
+
schema_url=schema,
|
|
71
130
|
)
|
|
72
|
-
|
|
73
|
-
|
|
131
|
+
logger_provider = kwargs.get("logger_provider")
|
|
132
|
+
logger = get_logger(
|
|
74
133
|
__name__,
|
|
75
134
|
"",
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
wrap_function_wrapper(
|
|
81
|
-
module="google.cloud.aiplatform_v1beta1.services.prediction_service.client",
|
|
82
|
-
name="PredictionServiceClient.generate_content",
|
|
83
|
-
wrapper=generate_content_create(
|
|
84
|
-
tracer, event_logger, is_content_enabled()
|
|
85
|
-
),
|
|
135
|
+
logger_provider=logger_provider,
|
|
136
|
+
schema_url=schema,
|
|
86
137
|
)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
name="PredictionServiceClient.generate_content",
|
|
90
|
-
wrapper=generate_content_create(
|
|
91
|
-
tracer, event_logger, is_content_enabled()
|
|
92
|
-
),
|
|
138
|
+
sem_conv_opt_in_mode = _OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(
|
|
139
|
+
_OpenTelemetryStabilitySignalType.GEN_AI,
|
|
93
140
|
)
|
|
141
|
+
if sem_conv_opt_in_mode == _StabilityMode.DEFAULT:
|
|
142
|
+
# Type checker now knows sem_conv_opt_in_mode is a Literal[_StabilityMode.DEFAULT]
|
|
143
|
+
method_wrappers = MethodWrappers(
|
|
144
|
+
tracer,
|
|
145
|
+
logger,
|
|
146
|
+
is_content_enabled(sem_conv_opt_in_mode),
|
|
147
|
+
sem_conv_opt_in_mode,
|
|
148
|
+
completion_hook,
|
|
149
|
+
)
|
|
150
|
+
elif sem_conv_opt_in_mode == _StabilityMode.GEN_AI_LATEST_EXPERIMENTAL:
|
|
151
|
+
# Type checker now knows it's the other literal
|
|
152
|
+
method_wrappers = MethodWrappers(
|
|
153
|
+
tracer,
|
|
154
|
+
logger,
|
|
155
|
+
is_content_enabled(sem_conv_opt_in_mode),
|
|
156
|
+
sem_conv_opt_in_mode,
|
|
157
|
+
completion_hook,
|
|
158
|
+
)
|
|
159
|
+
else:
|
|
160
|
+
raise RuntimeError(f"{sem_conv_opt_in_mode} mode not supported")
|
|
161
|
+
for client_class, method_name, wrapper in _methods_to_wrap(
|
|
162
|
+
method_wrappers
|
|
163
|
+
):
|
|
164
|
+
wrap_function_wrapper(
|
|
165
|
+
client_class,
|
|
166
|
+
name=method_name,
|
|
167
|
+
wrapper=wrapper,
|
|
168
|
+
)
|
|
169
|
+
self._methods_to_unwrap.append((client_class, method_name))
|
|
94
170
|
|
|
95
171
|
def _uninstrument(self, **kwargs: Any) -> None:
|
|
96
|
-
|
|
172
|
+
for client_class, method_name in self._methods_to_unwrap:
|
|
173
|
+
unwrap(client_class, method_name)
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
# type: ignore[reportUnknownDeprecated]
|
|
16
|
+
|
|
15
17
|
"""
|
|
16
18
|
Factories for event types described in
|
|
17
19
|
https://github.com/open-telemetry/semantic-conventions/blob/main/docs/gen-ai/gen-ai-events.md#system-event.
|
|
@@ -25,7 +27,7 @@ from __future__ import annotations
|
|
|
25
27
|
from dataclasses import asdict, dataclass
|
|
26
28
|
from typing import Any, Iterable, Literal
|
|
27
29
|
|
|
28
|
-
from opentelemetry.
|
|
30
|
+
from opentelemetry._logs import LogRecord
|
|
29
31
|
from opentelemetry.semconv._incubating.attributes import gen_ai_attributes
|
|
30
32
|
from opentelemetry.util.types import AnyValue
|
|
31
33
|
|
|
@@ -34,7 +36,7 @@ def user_event(
|
|
|
34
36
|
*,
|
|
35
37
|
role: str = "user",
|
|
36
38
|
content: AnyValue = None,
|
|
37
|
-
) ->
|
|
39
|
+
) -> LogRecord:
|
|
38
40
|
"""Creates a User event
|
|
39
41
|
https://github.com/open-telemetry/semantic-conventions/blob/v1.28.0/docs/gen-ai/gen-ai-events.md#user-event
|
|
40
42
|
"""
|
|
@@ -43,8 +45,8 @@ def user_event(
|
|
|
43
45
|
}
|
|
44
46
|
if content is not None:
|
|
45
47
|
body["content"] = content
|
|
46
|
-
return
|
|
47
|
-
|
|
48
|
+
return LogRecord(
|
|
49
|
+
event_name="gen_ai.user.message",
|
|
48
50
|
attributes={
|
|
49
51
|
gen_ai_attributes.GEN_AI_SYSTEM: gen_ai_attributes.GenAiSystemValues.VERTEX_AI.value,
|
|
50
52
|
},
|
|
@@ -56,7 +58,7 @@ def assistant_event(
|
|
|
56
58
|
*,
|
|
57
59
|
role: str = "assistant",
|
|
58
60
|
content: AnyValue = None,
|
|
59
|
-
) ->
|
|
61
|
+
) -> LogRecord:
|
|
60
62
|
"""Creates an Assistant event
|
|
61
63
|
https://github.com/open-telemetry/semantic-conventions/blob/v1.28.0/docs/gen-ai/gen-ai-events.md#assistant-event
|
|
62
64
|
"""
|
|
@@ -65,8 +67,8 @@ def assistant_event(
|
|
|
65
67
|
}
|
|
66
68
|
if content is not None:
|
|
67
69
|
body["content"] = content
|
|
68
|
-
return
|
|
69
|
-
|
|
70
|
+
return LogRecord(
|
|
71
|
+
event_name="gen_ai.assistant.message",
|
|
70
72
|
attributes={
|
|
71
73
|
gen_ai_attributes.GEN_AI_SYSTEM: gen_ai_attributes.GenAiSystemValues.VERTEX_AI.value,
|
|
72
74
|
},
|
|
@@ -78,7 +80,7 @@ def system_event(
|
|
|
78
80
|
*,
|
|
79
81
|
role: str = "system",
|
|
80
82
|
content: AnyValue = None,
|
|
81
|
-
) ->
|
|
83
|
+
) -> LogRecord:
|
|
82
84
|
"""Creates a System event
|
|
83
85
|
https://github.com/open-telemetry/semantic-conventions/blob/v1.28.0/docs/gen-ai/gen-ai-events.md#system-event
|
|
84
86
|
"""
|
|
@@ -87,8 +89,8 @@ def system_event(
|
|
|
87
89
|
}
|
|
88
90
|
if content is not None:
|
|
89
91
|
body["content"] = content
|
|
90
|
-
return
|
|
91
|
-
|
|
92
|
+
return LogRecord(
|
|
93
|
+
event_name="gen_ai.system.message",
|
|
92
94
|
attributes={
|
|
93
95
|
gen_ai_attributes.GEN_AI_SYSTEM: gen_ai_attributes.GenAiSystemValues.VERTEX_AI.value,
|
|
94
96
|
},
|
|
@@ -101,7 +103,7 @@ def tool_event(
|
|
|
101
103
|
role: str | None,
|
|
102
104
|
id_: str,
|
|
103
105
|
content: AnyValue = None,
|
|
104
|
-
) ->
|
|
106
|
+
) -> LogRecord:
|
|
105
107
|
"""Creates a Tool message event
|
|
106
108
|
https://github.com/open-telemetry/semantic-conventions/blob/v1.28.0/docs/gen-ai/gen-ai-events.md#event-gen_aitoolmessage
|
|
107
109
|
"""
|
|
@@ -114,8 +116,8 @@ def tool_event(
|
|
|
114
116
|
}
|
|
115
117
|
if content is not None:
|
|
116
118
|
body["content"] = content
|
|
117
|
-
return
|
|
118
|
-
|
|
119
|
+
return LogRecord(
|
|
120
|
+
event_name="gen_ai.tool.message",
|
|
119
121
|
attributes={
|
|
120
122
|
gen_ai_attributes.GEN_AI_SYSTEM: gen_ai_attributes.GenAiSystemValues.VERTEX_AI.value,
|
|
121
123
|
},
|
|
@@ -156,7 +158,7 @@ def choice_event(
|
|
|
156
158
|
index: int,
|
|
157
159
|
message: ChoiceMessage,
|
|
158
160
|
tool_calls: Iterable[ChoiceToolCall] = (),
|
|
159
|
-
) ->
|
|
161
|
+
) -> LogRecord:
|
|
160
162
|
"""Creates a choice event, which describes the Gen AI response message.
|
|
161
163
|
https://github.com/open-telemetry/semantic-conventions/blob/v1.28.0/docs/gen-ai/gen-ai-events.md#event-gen_aichoice
|
|
162
164
|
"""
|
|
@@ -172,8 +174,8 @@ def choice_event(
|
|
|
172
174
|
if tool_calls_list:
|
|
173
175
|
body["tool_calls"] = tool_calls_list
|
|
174
176
|
|
|
175
|
-
return
|
|
176
|
-
|
|
177
|
+
return LogRecord(
|
|
178
|
+
event_name="gen_ai.choice",
|
|
177
179
|
attributes={
|
|
178
180
|
gen_ai_attributes.GEN_AI_SYSTEM: gen_ai_attributes.GenAiSystemValues.VERTEX_AI.value,
|
|
179
181
|
},
|
|
@@ -14,16 +14,28 @@
|
|
|
14
14
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
|
+
from contextlib import contextmanager
|
|
18
|
+
from dataclasses import asdict
|
|
17
19
|
from typing import (
|
|
18
20
|
TYPE_CHECKING,
|
|
19
21
|
Any,
|
|
22
|
+
Awaitable,
|
|
20
23
|
Callable,
|
|
24
|
+
Literal,
|
|
21
25
|
MutableSequence,
|
|
26
|
+
Union,
|
|
27
|
+
cast,
|
|
28
|
+
overload,
|
|
22
29
|
)
|
|
23
30
|
|
|
24
|
-
from opentelemetry.
|
|
31
|
+
from opentelemetry._logs import Logger, LogRecord
|
|
32
|
+
from opentelemetry.instrumentation._semconv import (
|
|
33
|
+
_StabilityMode,
|
|
34
|
+
)
|
|
25
35
|
from opentelemetry.instrumentation.vertexai.utils import (
|
|
26
36
|
GenerateContentParams,
|
|
37
|
+
_map_finish_reason,
|
|
38
|
+
convert_content_to_message_parts,
|
|
27
39
|
get_genai_request_attributes,
|
|
28
40
|
get_genai_response_attributes,
|
|
29
41
|
get_server_attributes,
|
|
@@ -31,7 +43,17 @@ from opentelemetry.instrumentation.vertexai.utils import (
|
|
|
31
43
|
request_to_events,
|
|
32
44
|
response_to_events,
|
|
33
45
|
)
|
|
46
|
+
from opentelemetry.semconv._incubating.attributes import (
|
|
47
|
+
gen_ai_attributes as GenAI,
|
|
48
|
+
)
|
|
34
49
|
from opentelemetry.trace import SpanKind, Tracer
|
|
50
|
+
from opentelemetry.util.genai.completion_hook import CompletionHook
|
|
51
|
+
from opentelemetry.util.genai.types import (
|
|
52
|
+
ContentCapturingMode,
|
|
53
|
+
InputMessage,
|
|
54
|
+
OutputMessage,
|
|
55
|
+
)
|
|
56
|
+
from opentelemetry.util.genai.utils import gen_ai_json_dumps
|
|
35
57
|
|
|
36
58
|
if TYPE_CHECKING:
|
|
37
59
|
from google.cloud.aiplatform_v1.services.prediction_service import client
|
|
@@ -87,17 +109,148 @@ def _extract_params(
|
|
|
87
109
|
)
|
|
88
110
|
|
|
89
111
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
112
|
+
# For details about GEN_AI_LATEST_EXPERIMENTAL stability mode see
|
|
113
|
+
# https://github.com/open-telemetry/semantic-conventions/blob/v1.37.0/docs/gen-ai/gen-ai-agent-spans.md?plain=1#L18-L37
|
|
114
|
+
class MethodWrappers:
|
|
115
|
+
@overload
|
|
116
|
+
def __init__(
|
|
117
|
+
self,
|
|
118
|
+
tracer: Tracer,
|
|
119
|
+
logger: Logger,
|
|
120
|
+
capture_content: ContentCapturingMode,
|
|
121
|
+
sem_conv_opt_in_mode: Literal[
|
|
122
|
+
_StabilityMode.GEN_AI_LATEST_EXPERIMENTAL
|
|
123
|
+
],
|
|
124
|
+
completion_hook: CompletionHook,
|
|
125
|
+
) -> None: ...
|
|
94
126
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
127
|
+
@overload
|
|
128
|
+
def __init__(
|
|
129
|
+
self,
|
|
130
|
+
tracer: Tracer,
|
|
131
|
+
logger: Logger,
|
|
132
|
+
capture_content: bool,
|
|
133
|
+
sem_conv_opt_in_mode: Literal[_StabilityMode.DEFAULT],
|
|
134
|
+
completion_hook: CompletionHook,
|
|
135
|
+
) -> None: ...
|
|
136
|
+
|
|
137
|
+
def __init__(
|
|
138
|
+
self,
|
|
139
|
+
tracer: Tracer,
|
|
140
|
+
logger: Logger,
|
|
141
|
+
capture_content: Union[bool, ContentCapturingMode],
|
|
142
|
+
sem_conv_opt_in_mode: Union[
|
|
143
|
+
Literal[_StabilityMode.DEFAULT],
|
|
144
|
+
Literal[_StabilityMode.GEN_AI_LATEST_EXPERIMENTAL],
|
|
100
145
|
],
|
|
146
|
+
completion_hook: CompletionHook,
|
|
147
|
+
) -> None:
|
|
148
|
+
self.tracer = tracer
|
|
149
|
+
self.logger = logger
|
|
150
|
+
self.capture_content = capture_content
|
|
151
|
+
self.sem_conv_opt_in_mode = sem_conv_opt_in_mode
|
|
152
|
+
self.completion_hook = completion_hook
|
|
153
|
+
|
|
154
|
+
@contextmanager
|
|
155
|
+
def _with_new_instrumentation(
|
|
156
|
+
self,
|
|
157
|
+
capture_content: ContentCapturingMode,
|
|
158
|
+
instance: client.PredictionServiceClient
|
|
159
|
+
| client_v1beta1.PredictionServiceClient,
|
|
160
|
+
args: Any,
|
|
161
|
+
kwargs: Any,
|
|
162
|
+
):
|
|
163
|
+
params = _extract_params(*args, **kwargs)
|
|
164
|
+
request_attributes = get_genai_request_attributes(True, params)
|
|
165
|
+
with self.tracer.start_as_current_span(
|
|
166
|
+
name=f"{GenAI.GenAiOperationNameValues.CHAT.value} {request_attributes.get(GenAI.GEN_AI_REQUEST_MODEL, '')}".strip(),
|
|
167
|
+
kind=SpanKind.CLIENT,
|
|
168
|
+
) as span:
|
|
169
|
+
|
|
170
|
+
def handle_response(
|
|
171
|
+
response: prediction_service.GenerateContentResponse
|
|
172
|
+
| prediction_service_v1beta1.GenerateContentResponse
|
|
173
|
+
| None,
|
|
174
|
+
) -> None:
|
|
175
|
+
event = LogRecord(
|
|
176
|
+
event_name="gen_ai.client.inference.operation.details",
|
|
177
|
+
)
|
|
178
|
+
attributes = (
|
|
179
|
+
get_server_attributes(instance.api_endpoint) # type: ignore[reportUnknownMemberType]
|
|
180
|
+
| request_attributes
|
|
181
|
+
| get_genai_response_attributes(response)
|
|
182
|
+
)
|
|
183
|
+
system_instructions, inputs, outputs = [], [], []
|
|
184
|
+
if params.system_instruction:
|
|
185
|
+
system_instructions = convert_content_to_message_parts(
|
|
186
|
+
params.system_instruction
|
|
187
|
+
)
|
|
188
|
+
if params.contents:
|
|
189
|
+
inputs = [
|
|
190
|
+
InputMessage(
|
|
191
|
+
role=content.role,
|
|
192
|
+
parts=convert_content_to_message_parts(content),
|
|
193
|
+
)
|
|
194
|
+
for content in params.contents
|
|
195
|
+
]
|
|
196
|
+
if response:
|
|
197
|
+
outputs = [
|
|
198
|
+
OutputMessage(
|
|
199
|
+
finish_reason=_map_finish_reason(
|
|
200
|
+
candidate.finish_reason
|
|
201
|
+
),
|
|
202
|
+
role=candidate.content.role,
|
|
203
|
+
parts=convert_content_to_message_parts(
|
|
204
|
+
candidate.content
|
|
205
|
+
),
|
|
206
|
+
)
|
|
207
|
+
for candidate in response.candidates
|
|
208
|
+
]
|
|
209
|
+
self.completion_hook.on_completion(
|
|
210
|
+
inputs=inputs,
|
|
211
|
+
outputs=outputs,
|
|
212
|
+
system_instruction=system_instructions,
|
|
213
|
+
span=span,
|
|
214
|
+
log_record=event,
|
|
215
|
+
)
|
|
216
|
+
content_attributes = {
|
|
217
|
+
k: [asdict(x) for x in v]
|
|
218
|
+
for k, v in [
|
|
219
|
+
(
|
|
220
|
+
GenAI.GEN_AI_SYSTEM_INSTRUCTIONS,
|
|
221
|
+
system_instructions,
|
|
222
|
+
),
|
|
223
|
+
(GenAI.GEN_AI_INPUT_MESSAGES, inputs),
|
|
224
|
+
(GenAI.GEN_AI_OUTPUT_MESSAGES, outputs),
|
|
225
|
+
]
|
|
226
|
+
if v
|
|
227
|
+
}
|
|
228
|
+
if span.is_recording():
|
|
229
|
+
span.set_attributes(attributes)
|
|
230
|
+
if capture_content in (
|
|
231
|
+
ContentCapturingMode.SPAN_AND_EVENT,
|
|
232
|
+
ContentCapturingMode.SPAN_ONLY,
|
|
233
|
+
):
|
|
234
|
+
span.set_attributes(
|
|
235
|
+
{
|
|
236
|
+
k: gen_ai_json_dumps(v)
|
|
237
|
+
for k, v in content_attributes.items()
|
|
238
|
+
}
|
|
239
|
+
)
|
|
240
|
+
event.attributes = attributes
|
|
241
|
+
if capture_content in (
|
|
242
|
+
ContentCapturingMode.SPAN_AND_EVENT,
|
|
243
|
+
ContentCapturingMode.EVENT_ONLY,
|
|
244
|
+
):
|
|
245
|
+
event.attributes |= content_attributes
|
|
246
|
+
self.logger.emit(event)
|
|
247
|
+
|
|
248
|
+
yield handle_response
|
|
249
|
+
|
|
250
|
+
@contextmanager
|
|
251
|
+
def _with_default_instrumentation(
|
|
252
|
+
self,
|
|
253
|
+
capture_content: bool,
|
|
101
254
|
instance: client.PredictionServiceClient
|
|
102
255
|
| client_v1beta1.PredictionServiceClient,
|
|
103
256
|
args: Any,
|
|
@@ -106,12 +259,13 @@ def generate_content_create(
|
|
|
106
259
|
params = _extract_params(*args, **kwargs)
|
|
107
260
|
api_endpoint: str = instance.api_endpoint # type: ignore[reportUnknownMemberType]
|
|
108
261
|
span_attributes = {
|
|
109
|
-
**get_genai_request_attributes(params),
|
|
262
|
+
**get_genai_request_attributes(False, params),
|
|
110
263
|
**get_server_attributes(api_endpoint),
|
|
111
264
|
}
|
|
112
265
|
|
|
113
266
|
span_name = get_span_name(span_attributes)
|
|
114
|
-
|
|
267
|
+
|
|
268
|
+
with self.tracer.start_as_current_span(
|
|
115
269
|
name=span_name,
|
|
116
270
|
kind=SpanKind.CLIENT,
|
|
117
271
|
attributes=span_attributes,
|
|
@@ -119,24 +273,99 @@ def generate_content_create(
|
|
|
119
273
|
for event in request_to_events(
|
|
120
274
|
params=params, capture_content=capture_content
|
|
121
275
|
):
|
|
122
|
-
|
|
276
|
+
self.logger.emit(event)
|
|
123
277
|
|
|
124
278
|
# TODO: set error.type attribute
|
|
125
279
|
# https://github.com/open-telemetry/semantic-conventions/blob/main/docs/gen-ai/gen-ai-spans.md
|
|
126
|
-
response = wrapped(*args, **kwargs)
|
|
127
|
-
# TODO: handle streaming
|
|
128
|
-
# if is_streaming(kwargs):
|
|
129
|
-
# return StreamWrapper(
|
|
130
|
-
# result, span, event_logger, capture_content
|
|
131
|
-
# )
|
|
132
|
-
|
|
133
|
-
if span.is_recording():
|
|
134
|
-
span.set_attributes(get_genai_response_attributes(response))
|
|
135
|
-
for event in response_to_events(
|
|
136
|
-
response=response, capture_content=capture_content
|
|
137
|
-
):
|
|
138
|
-
event_logger.emit(event)
|
|
139
280
|
|
|
140
|
-
|
|
281
|
+
def handle_response(
|
|
282
|
+
response: prediction_service.GenerateContentResponse
|
|
283
|
+
| prediction_service_v1beta1.GenerateContentResponse,
|
|
284
|
+
) -> None:
|
|
285
|
+
if span.is_recording():
|
|
286
|
+
# When streaming, this is called multiple times so attributes would be
|
|
287
|
+
# overwritten. In practice, it looks the API only returns the interesting
|
|
288
|
+
# attributes on the last streamed response. However, I couldn't find
|
|
289
|
+
# documentation for this and setting attributes shouldn't be too expensive.
|
|
290
|
+
span.set_attributes(
|
|
291
|
+
get_genai_response_attributes(response)
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
for event in response_to_events(
|
|
295
|
+
response=response, capture_content=capture_content
|
|
296
|
+
):
|
|
297
|
+
self.logger.emit(event)
|
|
298
|
+
|
|
299
|
+
yield handle_response
|
|
300
|
+
|
|
301
|
+
def generate_content(
|
|
302
|
+
self,
|
|
303
|
+
wrapped: Callable[
|
|
304
|
+
...,
|
|
305
|
+
prediction_service.GenerateContentResponse
|
|
306
|
+
| prediction_service_v1beta1.GenerateContentResponse,
|
|
307
|
+
],
|
|
308
|
+
instance: client.PredictionServiceClient
|
|
309
|
+
| client_v1beta1.PredictionServiceClient,
|
|
310
|
+
args: Any,
|
|
311
|
+
kwargs: Any,
|
|
312
|
+
) -> (
|
|
313
|
+
prediction_service.GenerateContentResponse
|
|
314
|
+
| prediction_service_v1beta1.GenerateContentResponse
|
|
315
|
+
):
|
|
316
|
+
if self.sem_conv_opt_in_mode == _StabilityMode.DEFAULT:
|
|
317
|
+
capture_content_bool = cast(bool, self.capture_content)
|
|
318
|
+
with self._with_default_instrumentation(
|
|
319
|
+
capture_content_bool, instance, args, kwargs
|
|
320
|
+
) as handle_response:
|
|
321
|
+
response = wrapped(*args, **kwargs)
|
|
322
|
+
handle_response(response)
|
|
323
|
+
return response
|
|
324
|
+
else:
|
|
325
|
+
capture_content = cast(ContentCapturingMode, self.capture_content)
|
|
326
|
+
with self._with_new_instrumentation(
|
|
327
|
+
capture_content, instance, args, kwargs
|
|
328
|
+
) as handle_response:
|
|
329
|
+
response = None
|
|
330
|
+
try:
|
|
331
|
+
response = wrapped(*args, **kwargs)
|
|
332
|
+
return response
|
|
333
|
+
finally:
|
|
334
|
+
handle_response(response)
|
|
141
335
|
|
|
142
|
-
|
|
336
|
+
async def agenerate_content(
|
|
337
|
+
self,
|
|
338
|
+
wrapped: Callable[
|
|
339
|
+
...,
|
|
340
|
+
Awaitable[
|
|
341
|
+
prediction_service.GenerateContentResponse
|
|
342
|
+
| prediction_service_v1beta1.GenerateContentResponse
|
|
343
|
+
],
|
|
344
|
+
],
|
|
345
|
+
instance: client.PredictionServiceClient
|
|
346
|
+
| client_v1beta1.PredictionServiceClient,
|
|
347
|
+
args: Any,
|
|
348
|
+
kwargs: Any,
|
|
349
|
+
) -> (
|
|
350
|
+
prediction_service.GenerateContentResponse
|
|
351
|
+
| prediction_service_v1beta1.GenerateContentResponse
|
|
352
|
+
):
|
|
353
|
+
if self.sem_conv_opt_in_mode == _StabilityMode.DEFAULT:
|
|
354
|
+
capture_content_bool = cast(bool, self.capture_content)
|
|
355
|
+
with self._with_default_instrumentation(
|
|
356
|
+
capture_content_bool, instance, args, kwargs
|
|
357
|
+
) as handle_response:
|
|
358
|
+
response = await wrapped(*args, **kwargs)
|
|
359
|
+
handle_response(response)
|
|
360
|
+
return response
|
|
361
|
+
else:
|
|
362
|
+
capture_content = cast(ContentCapturingMode, self.capture_content)
|
|
363
|
+
with self._with_new_instrumentation(
|
|
364
|
+
capture_content, instance, args, kwargs
|
|
365
|
+
) as handle_response:
|
|
366
|
+
response = None
|
|
367
|
+
try:
|
|
368
|
+
response = await wrapped(*args, **kwargs)
|
|
369
|
+
return response
|
|
370
|
+
finally:
|
|
371
|
+
handle_response(response)
|
|
@@ -12,27 +12,35 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
# type: ignore[reportUnknownDeprecated]
|
|
16
|
+
|
|
15
17
|
from __future__ import annotations
|
|
16
18
|
|
|
19
|
+
import logging
|
|
17
20
|
import re
|
|
18
21
|
from dataclasses import dataclass
|
|
19
22
|
from os import environ
|
|
20
23
|
from typing import (
|
|
21
24
|
TYPE_CHECKING,
|
|
22
25
|
Iterable,
|
|
26
|
+
Literal,
|
|
23
27
|
Mapping,
|
|
24
28
|
Sequence,
|
|
29
|
+
Union,
|
|
25
30
|
cast,
|
|
31
|
+
overload,
|
|
26
32
|
)
|
|
27
33
|
from urllib.parse import urlparse
|
|
28
34
|
|
|
29
35
|
from google.protobuf import json_format
|
|
30
36
|
|
|
31
|
-
from opentelemetry.
|
|
37
|
+
from opentelemetry._logs import LogRecord
|
|
38
|
+
from opentelemetry.instrumentation._semconv import (
|
|
39
|
+
_StabilityMode,
|
|
40
|
+
)
|
|
32
41
|
from opentelemetry.instrumentation.vertexai.events import (
|
|
33
42
|
ChoiceMessage,
|
|
34
43
|
ChoiceToolCall,
|
|
35
|
-
FinishReason,
|
|
36
44
|
assistant_event,
|
|
37
45
|
choice_event,
|
|
38
46
|
system_event,
|
|
@@ -43,6 +51,15 @@ from opentelemetry.semconv._incubating.attributes import (
|
|
|
43
51
|
gen_ai_attributes as GenAIAttributes,
|
|
44
52
|
)
|
|
45
53
|
from opentelemetry.semconv.attributes import server_attributes
|
|
54
|
+
from opentelemetry.util.genai.types import (
|
|
55
|
+
ContentCapturingMode,
|
|
56
|
+
FinishReason,
|
|
57
|
+
MessagePart,
|
|
58
|
+
Text,
|
|
59
|
+
ToolCall,
|
|
60
|
+
ToolCallResponse,
|
|
61
|
+
)
|
|
62
|
+
from opentelemetry.util.genai.utils import get_content_capturing_mode
|
|
46
63
|
from opentelemetry.util.types import AnyValue, AttributeValue
|
|
47
64
|
|
|
48
65
|
if TYPE_CHECKING:
|
|
@@ -103,7 +120,8 @@ def get_server_attributes(
|
|
|
103
120
|
}
|
|
104
121
|
|
|
105
122
|
|
|
106
|
-
def get_genai_request_attributes(
|
|
123
|
+
def get_genai_request_attributes( # pylint: disable=too-many-branches
|
|
124
|
+
use_latest_semconvs: bool,
|
|
107
125
|
params: GenerateContentParams,
|
|
108
126
|
operation_name: GenAIAttributes.GenAiOperationNameValues = GenAIAttributes.GenAiOperationNameValues.CHAT,
|
|
109
127
|
):
|
|
@@ -111,9 +129,12 @@ def get_genai_request_attributes(
|
|
|
111
129
|
generation_config = params.generation_config
|
|
112
130
|
attributes: dict[str, AttributeValue] = {
|
|
113
131
|
GenAIAttributes.GEN_AI_OPERATION_NAME: operation_name.value,
|
|
114
|
-
GenAIAttributes.GEN_AI_SYSTEM: GenAIAttributes.GenAiSystemValues.VERTEX_AI.value,
|
|
115
132
|
GenAIAttributes.GEN_AI_REQUEST_MODEL: model,
|
|
116
133
|
}
|
|
134
|
+
if not use_latest_semconvs:
|
|
135
|
+
attributes[GenAIAttributes.GEN_AI_SYSTEM] = (
|
|
136
|
+
GenAIAttributes.GenAiSystemValues.VERTEX_AI.value
|
|
137
|
+
)
|
|
117
138
|
|
|
118
139
|
if not generation_config:
|
|
119
140
|
return attributes
|
|
@@ -125,6 +146,8 @@ def get_genai_request_attributes(
|
|
|
125
146
|
generation_config.temperature
|
|
126
147
|
)
|
|
127
148
|
if "top_p" in generation_config:
|
|
149
|
+
# There is also a top_k parameter ( The maximum number of tokens to consider when sampling.),
|
|
150
|
+
# but no semconv yet exists for it.
|
|
128
151
|
attributes[GenAIAttributes.GEN_AI_REQUEST_TOP_P] = (
|
|
129
152
|
generation_config.top_p
|
|
130
153
|
)
|
|
@@ -140,30 +163,43 @@ def get_genai_request_attributes(
|
|
|
140
163
|
attributes[GenAIAttributes.GEN_AI_REQUEST_FREQUENCY_PENALTY] = (
|
|
141
164
|
generation_config.frequency_penalty
|
|
142
165
|
)
|
|
143
|
-
# Uncomment once GEN_AI_REQUEST_SEED is released in 1.30
|
|
144
|
-
# https://github.com/open-telemetry/semantic-conventions/pull/1710
|
|
145
|
-
# if "seed" in generation_config:
|
|
146
|
-
# attributes[GenAIAttributes.GEN_AI_REQUEST_SEED] = (
|
|
147
|
-
# generation_config.seed
|
|
148
|
-
# )
|
|
149
166
|
if "stop_sequences" in generation_config:
|
|
150
167
|
attributes[GenAIAttributes.GEN_AI_REQUEST_STOP_SEQUENCES] = (
|
|
151
168
|
generation_config.stop_sequences
|
|
152
169
|
)
|
|
170
|
+
if use_latest_semconvs:
|
|
171
|
+
if "seed" in generation_config:
|
|
172
|
+
attributes[GenAIAttributes.GEN_AI_REQUEST_SEED] = (
|
|
173
|
+
generation_config.seed
|
|
174
|
+
)
|
|
175
|
+
if "candidate_count" in generation_config:
|
|
176
|
+
attributes[GenAIAttributes.GEN_AI_REQUEST_CHOICE_COUNT] = (
|
|
177
|
+
generation_config.candidate_count
|
|
178
|
+
)
|
|
179
|
+
if "response_mime_type" in generation_config:
|
|
180
|
+
if generation_config.response_mime_type == "text/plain":
|
|
181
|
+
attributes[GenAIAttributes.GEN_AI_OUTPUT_TYPE] = "text"
|
|
182
|
+
elif generation_config.response_mime_type == "application/json":
|
|
183
|
+
attributes[GenAIAttributes.GEN_AI_OUTPUT_TYPE] = "json"
|
|
184
|
+
else:
|
|
185
|
+
attributes[GenAIAttributes.GEN_AI_OUTPUT_TYPE] = (
|
|
186
|
+
generation_config.response_mime_type
|
|
187
|
+
)
|
|
153
188
|
|
|
154
189
|
return attributes
|
|
155
190
|
|
|
156
191
|
|
|
157
192
|
def get_genai_response_attributes(
|
|
158
193
|
response: prediction_service.GenerateContentResponse
|
|
159
|
-
| prediction_service_v1beta1.GenerateContentResponse
|
|
194
|
+
| prediction_service_v1beta1.GenerateContentResponse
|
|
195
|
+
| None,
|
|
160
196
|
) -> dict[str, AttributeValue]:
|
|
197
|
+
if not response:
|
|
198
|
+
return {}
|
|
161
199
|
finish_reasons: list[str] = [
|
|
162
200
|
_map_finish_reason(candidate.finish_reason)
|
|
163
201
|
for candidate in response.candidates
|
|
164
202
|
]
|
|
165
|
-
# TODO: add gen_ai.response.id once available in the python client
|
|
166
|
-
# https://github.com/open-telemetry/opentelemetry-python-contrib/issues/3246
|
|
167
203
|
return {
|
|
168
204
|
GenAIAttributes.GEN_AI_RESPONSE_MODEL: response.model_version,
|
|
169
205
|
GenAIAttributes.GEN_AI_RESPONSE_FINISH_REASONS: finish_reasons,
|
|
@@ -186,12 +222,29 @@ OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT = (
|
|
|
186
222
|
)
|
|
187
223
|
|
|
188
224
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
225
|
+
@overload
|
|
226
|
+
def is_content_enabled(
|
|
227
|
+
mode: Literal[_StabilityMode.GEN_AI_LATEST_EXPERIMENTAL],
|
|
228
|
+
) -> ContentCapturingMode: ...
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
@overload
|
|
232
|
+
def is_content_enabled(mode: Literal[_StabilityMode.DEFAULT]) -> bool: ...
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def is_content_enabled(
|
|
236
|
+
mode: Union[
|
|
237
|
+
Literal[_StabilityMode.DEFAULT],
|
|
238
|
+
Literal[_StabilityMode.GEN_AI_LATEST_EXPERIMENTAL],
|
|
239
|
+
],
|
|
240
|
+
) -> Union[bool, ContentCapturingMode]:
|
|
241
|
+
if mode == _StabilityMode.DEFAULT:
|
|
242
|
+
capture_content = environ.get(
|
|
243
|
+
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT, "false"
|
|
244
|
+
)
|
|
193
245
|
|
|
194
|
-
|
|
246
|
+
return capture_content.lower() == "true"
|
|
247
|
+
return get_content_capturing_mode()
|
|
195
248
|
|
|
196
249
|
|
|
197
250
|
def get_span_name(span_attributes: Mapping[str, AttributeValue]) -> str:
|
|
@@ -204,7 +257,7 @@ def get_span_name(span_attributes: Mapping[str, AttributeValue]) -> str:
|
|
|
204
257
|
|
|
205
258
|
def request_to_events(
|
|
206
259
|
*, params: GenerateContentParams, capture_content: bool
|
|
207
|
-
) -> Iterable[
|
|
260
|
+
) -> Iterable[LogRecord]:
|
|
208
261
|
# System message
|
|
209
262
|
if params.system_instruction:
|
|
210
263
|
request_content = _parts_to_any_value(
|
|
@@ -256,12 +309,72 @@ def request_to_events(
|
|
|
256
309
|
yield user_event(role=content.role, content=request_content)
|
|
257
310
|
|
|
258
311
|
|
|
312
|
+
@dataclass
|
|
313
|
+
class BlobPart:
|
|
314
|
+
data: bytes
|
|
315
|
+
mime_type: str
|
|
316
|
+
type: Literal["blob"] = "blob"
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
@dataclass
|
|
320
|
+
class FileDataPart:
|
|
321
|
+
mime_type: str
|
|
322
|
+
uri: str
|
|
323
|
+
type: Literal["file_data"] = "file_data"
|
|
324
|
+
|
|
325
|
+
class Config:
|
|
326
|
+
extra = "allow"
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def convert_content_to_message_parts(
|
|
330
|
+
content: content.Content | content_v1beta1.Content,
|
|
331
|
+
) -> list[MessagePart]:
|
|
332
|
+
parts: MessagePart = []
|
|
333
|
+
for idx, part in enumerate(content.parts):
|
|
334
|
+
if "function_response" in part:
|
|
335
|
+
part = part.function_response
|
|
336
|
+
parts.append(
|
|
337
|
+
ToolCallResponse(
|
|
338
|
+
id=f"{part.name}_{idx}",
|
|
339
|
+
response=json_format.MessageToDict(part._pb.response), # type: ignore[reportUnknownMemberType]
|
|
340
|
+
)
|
|
341
|
+
)
|
|
342
|
+
elif "function_call" in part:
|
|
343
|
+
part = part.function_call
|
|
344
|
+
parts.append(
|
|
345
|
+
ToolCall(
|
|
346
|
+
id=f"{part.name}_{idx}",
|
|
347
|
+
name=part.name,
|
|
348
|
+
arguments=json_format.MessageToDict(
|
|
349
|
+
part._pb.args, # type: ignore[reportUnknownMemberType]
|
|
350
|
+
),
|
|
351
|
+
)
|
|
352
|
+
)
|
|
353
|
+
elif "text" in part:
|
|
354
|
+
parts.append(Text(content=part.text))
|
|
355
|
+
elif "inline_data" in part:
|
|
356
|
+
part = part.inline_data
|
|
357
|
+
parts.append(
|
|
358
|
+
BlobPart(mime_type=part.mime_type or "", data=part.data or b"")
|
|
359
|
+
)
|
|
360
|
+
elif "file_data" in part:
|
|
361
|
+
part = part.file_data
|
|
362
|
+
parts.append(
|
|
363
|
+
FileDataPart(
|
|
364
|
+
mime_type=part.mime_type or "", uri=part.file_uri or ""
|
|
365
|
+
)
|
|
366
|
+
)
|
|
367
|
+
else:
|
|
368
|
+
logging.warning("Unknown part dropped from telemetry %s", part)
|
|
369
|
+
return parts
|
|
370
|
+
|
|
371
|
+
|
|
259
372
|
def response_to_events(
|
|
260
373
|
*,
|
|
261
374
|
response: prediction_service.GenerateContentResponse
|
|
262
375
|
| prediction_service_v1beta1.GenerateContentResponse,
|
|
263
376
|
capture_content: bool,
|
|
264
|
-
) -> Iterable[
|
|
377
|
+
) -> Iterable[LogRecord]:
|
|
265
378
|
for candidate in response.candidates:
|
|
266
379
|
tool_calls = _extract_tool_calls(
|
|
267
380
|
candidate=candidate, capture_content=capture_content
|
|
@@ -319,7 +432,9 @@ def _parts_to_any_value(
|
|
|
319
432
|
return [
|
|
320
433
|
cast(
|
|
321
434
|
"dict[str, AnyValue]",
|
|
322
|
-
type(part).to_dict(
|
|
435
|
+
type(part).to_dict( # type: ignore[reportUnknownMemberType]
|
|
436
|
+
part, always_print_fields_with_no_presence=False
|
|
437
|
+
),
|
|
323
438
|
)
|
|
324
439
|
for part in parts
|
|
325
440
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opentelemetry-instrumentation-vertexai
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1b0
|
|
4
4
|
Summary: OpenTelemetry Official VertexAI instrumentation
|
|
5
5
|
Project-URL: Homepage, https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation-genai/opentelemetry-instrumentation-vertexai
|
|
6
6
|
Project-URL: Repository, https://github.com/open-telemetry/opentelemetry-python-contrib
|
|
@@ -12,15 +12,15 @@ Classifier: Intended Audience :: Developers
|
|
|
12
12
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
13
|
Classifier: Programming Language :: Python
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.9
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.10
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
-
Requires-Python: >=3.
|
|
21
|
-
Requires-Dist: opentelemetry-api~=1.
|
|
22
|
-
Requires-Dist: opentelemetry-instrumentation~=0.
|
|
23
|
-
Requires-Dist: opentelemetry-semantic-conventions~=0.
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Requires-Dist: opentelemetry-api~=1.37
|
|
21
|
+
Requires-Dist: opentelemetry-instrumentation~=0.58b0
|
|
22
|
+
Requires-Dist: opentelemetry-semantic-conventions~=0.58b0
|
|
23
|
+
Requires-Dist: opentelemetry-util-genai<0.3b0,>=0.2b0
|
|
24
24
|
Provides-Extra: instruments
|
|
25
25
|
Requires-Dist: google-cloud-aiplatform>=1.64; extra == 'instruments'
|
|
26
26
|
Description-Content-Type: text/x-rst
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
opentelemetry/instrumentation/vertexai/__init__.py,sha256=h2ikRd_hLXscLwbacyfCY5fdFYH76iMxkHHr8r1AeCU,6010
|
|
2
|
+
opentelemetry/instrumentation/vertexai/events.py,sha256=EHp1uqJ-vMKJ5jVxRgHNyboN51JUYEPcXcT3yV5rcRE,5274
|
|
3
|
+
opentelemetry/instrumentation/vertexai/package.py,sha256=CFLAAZb6L_fDNfJgpW-cXjhiQjwGLAuxhdAjMNt3jPM,638
|
|
4
|
+
opentelemetry/instrumentation/vertexai/patch.py,sha256=_YZpMo14k-ccy8VcNbl9rG7VsztLorcS12an6e8wJx8,13543
|
|
5
|
+
opentelemetry/instrumentation/vertexai/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
opentelemetry/instrumentation/vertexai/utils.py,sha256=CxOypyBGjpuaKX4lijomyGBupiViC_TpYHgiCTR2nGE,15001
|
|
7
|
+
opentelemetry/instrumentation/vertexai/version.py,sha256=tlQVIB6SsAnJ7uZmREAk0QDaATSCgbgYwdtY4G8GX9M,607
|
|
8
|
+
opentelemetry_instrumentation_vertexai-2.1b0.dist-info/METADATA,sha256=tXZDreIfz0gB64b5zYAdufFr3WdjRL6hB_1k4ynrrL4,3946
|
|
9
|
+
opentelemetry_instrumentation_vertexai-2.1b0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
10
|
+
opentelemetry_instrumentation_vertexai-2.1b0.dist-info/entry_points.txt,sha256=aAbxWr7zIDuYms-m-ea5GEV2rqyx7xPT8FWr2umrCmU,100
|
|
11
|
+
opentelemetry_instrumentation_vertexai-2.1b0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
12
|
+
opentelemetry_instrumentation_vertexai-2.1b0.dist-info/RECORD,,
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
opentelemetry/instrumentation/vertexai/__init__.py,sha256=DrASu5cA6RjJU9fX6z-T4Oi_DfG5bmZi49mX4D7k_us,3188
|
|
2
|
-
opentelemetry/instrumentation/vertexai/events.py,sha256=0PlFioS1I_hnvelEwFAOMxwiLBQqQpq9ADSZa8yxF_c,5161
|
|
3
|
-
opentelemetry/instrumentation/vertexai/package.py,sha256=CFLAAZb6L_fDNfJgpW-cXjhiQjwGLAuxhdAjMNt3jPM,638
|
|
4
|
-
opentelemetry/instrumentation/vertexai/patch.py,sha256=UIgMrsT4Qhr6bFRUn2vca_ntQgR7MGUMRlVZEsgMvDA,4769
|
|
5
|
-
opentelemetry/instrumentation/vertexai/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
opentelemetry/instrumentation/vertexai/utils.py,sha256=CJwxZIH-9CmnCcbc9TXsG9W59NaJdU_cHDVTdK-6jCU,11546
|
|
7
|
-
opentelemetry/instrumentation/vertexai/version.py,sha256=3DvzQveBD-YdMIJDP5YIVXzqInnizLBgk8mSkEdl7CA,607
|
|
8
|
-
opentelemetry_instrumentation_vertexai-2.0b0.dist-info/METADATA,sha256=G6fPgJcQPWVvSTSeD1oC-ssN6V7_Rql_30B1Q3BaW3I,3942
|
|
9
|
-
opentelemetry_instrumentation_vertexai-2.0b0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
10
|
-
opentelemetry_instrumentation_vertexai-2.0b0.dist-info/entry_points.txt,sha256=aAbxWr7zIDuYms-m-ea5GEV2rqyx7xPT8FWr2umrCmU,100
|
|
11
|
-
opentelemetry_instrumentation_vertexai-2.0b0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
12
|
-
opentelemetry_instrumentation_vertexai-2.0b0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|