Skip to content

Commit b67b9b0

Browse files
committed
Add temporary support for aiplatform.googleapis.com/ReasoningEngine monitored resource in logging exporter
1 parent c9ae87a commit b67b9b0

File tree

4 files changed

+198
-9
lines changed

4 files changed

+198
-9
lines changed

opentelemetry-exporter-gcp-logging/src/opentelemetry/exporter/cloud_logging/__init__.py

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ def _convert_any_value_to_string(value: Any) -> str:
147147

148148
# Be careful not to mutate original body. Make copies of anything that needs to change.
149149
def _sanitized_body(
150-
body: Mapping[str, AnyValue]
150+
body: Mapping[str, AnyValue],
151151
) -> MutableMapping[str, AnyValue]:
152152
new_body: MutableMapping[str, AnyValue] = {}
153153
for key, value in body.items():
@@ -212,6 +212,46 @@ def is_log_id_valid(log_id: str) -> bool:
212212
)
213213

214214

215+
def _get_monitored_resource(
216+
resource: Optional[Resource],
217+
) -> MonitoredResource | None:
218+
if not resource:
219+
return None
220+
221+
# TODO: Remove temporary special case for Vertex Agent Engine
222+
# https://github.com/GoogleCloudPlatform/opentelemetry-operations-python/issues/444
223+
cloud_resource_id = resource.attributes.get("cloud.resource_id")
224+
if isinstance(cloud_resource_id, str) and (
225+
match := re.match(
226+
r"//aiplatform\.googleapis\.com/projects/(?P<project_id>[^/]+)"
227+
r"/locations/(?P<location>[^/]+)"
228+
r"/reasoningEngines/(?P<agent_engine_id>[^/]+)",
229+
cloud_resource_id,
230+
)
231+
):
232+
project_id = match.group("project_id")
233+
location = match.group("location")
234+
agent_engine_id = match.group("agent_engine_id")
235+
# https://cloud.google.com/monitoring/api/resources#tag_aiplatform.googleapis.com/ReasoningEngine
236+
return MonitoredResource(
237+
type="aiplatform.googleapis.com/ReasoningEngine",
238+
labels={
239+
"resource_container": project_id,
240+
"location": location,
241+
"reasoning_engine_id": agent_engine_id,
242+
},
243+
)
244+
245+
monitored_resource_data = get_monitored_resource(resource)
246+
if not monitored_resource_data:
247+
return None
248+
249+
return MonitoredResource(
250+
type=monitored_resource_data.type,
251+
labels=monitored_resource_data.labels,
252+
)
253+
254+
215255
class CloudLoggingExporter(LogExporter):
216256
def __init__(
217257
self,
@@ -302,14 +342,10 @@ def export(self, batch: Sequence[LogData]):
302342
else:
303343
ts.FromDatetime(now)
304344
log_entry.timestamp = ts
305-
monitored_resource_data = get_monitored_resource(
306-
log_record.resource or Resource({})
307-
)
308-
if monitored_resource_data:
309-
log_entry.resource = MonitoredResource(
310-
type=monitored_resource_data.type,
311-
labels=monitored_resource_data.labels,
312-
)
345+
if monitored_resource := _get_monitored_resource(
346+
log_record.resource
347+
):
348+
log_entry.resource = monitored_resource
313349
log_entry.trace_sampled = (
314350
log_record.trace_flags is not None
315351
and log_record.trace_flags.sampled
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
[
2+
{
3+
"entries": [
4+
{
5+
"logName": "projects/fakeproject/logs/test",
6+
"resource": {
7+
"labels": {
8+
"location": "europe-west3",
9+
"reasoning_engine_id": "8477639270431981568",
10+
"resource_container": "some-project123-321"
11+
},
12+
"type": "aiplatform.googleapis.com/ReasoningEngine"
13+
},
14+
"textPayload": "valid agent engine",
15+
"timestamp": "2025-01-15T21:25:10.997977393Z"
16+
},
17+
{
18+
"logName": "projects/fakeproject/logs/test",
19+
"resource": {
20+
"labels": {
21+
"location": "global",
22+
"namespace": "",
23+
"node_id": ""
24+
},
25+
"type": "generic_node"
26+
},
27+
"textPayload": "invalid 1",
28+
"timestamp": "2025-01-15T21:25:10.997977393Z"
29+
},
30+
{
31+
"logName": "projects/fakeproject/logs/test",
32+
"resource": {
33+
"labels": {
34+
"location": "global",
35+
"namespace": "",
36+
"node_id": ""
37+
},
38+
"type": "generic_node"
39+
},
40+
"textPayload": "invalid 2",
41+
"timestamp": "2025-01-15T21:25:10.997977393Z"
42+
},
43+
{
44+
"logName": "projects/fakeproject/logs/test",
45+
"resource": {
46+
"labels": {
47+
"location": "global",
48+
"namespace": "",
49+
"node_id": ""
50+
},
51+
"type": "generic_node"
52+
},
53+
"textPayload": "invalid 3",
54+
"timestamp": "2025-01-15T21:25:10.997977393Z"
55+
}
56+
],
57+
"partialSuccess": true
58+
}
59+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
[
2+
{
3+
"logging.googleapis.com/labels": {},
4+
"logging.googleapis.com/spanId": "",
5+
"logging.googleapis.com/trace": "",
6+
"logging.googleapis.com/trace_sampled": false,
7+
"message": "valid agent engine",
8+
"severity": "DEFAULT",
9+
"time": "2025-01-15T21:25:10.997977393Z"
10+
},
11+
{
12+
"logging.googleapis.com/labels": {},
13+
"logging.googleapis.com/spanId": "",
14+
"logging.googleapis.com/trace": "",
15+
"logging.googleapis.com/trace_sampled": false,
16+
"message": "invalid 1",
17+
"severity": "DEFAULT",
18+
"time": "2025-01-15T21:25:10.997977393Z"
19+
},
20+
{
21+
"logging.googleapis.com/labels": {},
22+
"logging.googleapis.com/spanId": "",
23+
"logging.googleapis.com/trace": "",
24+
"logging.googleapis.com/trace_sampled": false,
25+
"message": "invalid 2",
26+
"severity": "DEFAULT",
27+
"time": "2025-01-15T21:25:10.997977393Z"
28+
},
29+
{
30+
"logging.googleapis.com/labels": {},
31+
"logging.googleapis.com/spanId": "",
32+
"logging.googleapis.com/trace": "",
33+
"logging.googleapis.com/trace_sampled": false,
34+
"message": "invalid 3",
35+
"severity": "DEFAULT",
36+
"time": "2025-01-15T21:25:10.997977393Z"
37+
}
38+
]

opentelemetry-exporter-gcp-logging/tests/test_cloud_logging.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,62 @@ def test_user_agent(cloudloggingfake: CloudLoggingFake) -> None:
165165
)
166166

167167

168+
def test_agent_engine_monitored_resources(
169+
export_and_assert_snapshot: ExportAndAssertSnapshot,
170+
) -> None:
171+
log_data = [
172+
LogData(
173+
log_record=LogRecord(
174+
body="valid agent engine",
175+
timestamp=1736976310997977393,
176+
resource=Resource(
177+
{
178+
"cloud.resource_id": "//aiplatform.googleapis.com/projects/some-project123-321/locations/europe-west3/reasoningEngines/8477639270431981568"
179+
}
180+
),
181+
),
182+
instrumentation_scope=InstrumentationScope("test"),
183+
),
184+
LogData(
185+
log_record=LogRecord(
186+
body="invalid 1",
187+
timestamp=1736976310997977393,
188+
resource=Resource(
189+
{
190+
"cloud.resource_id": "//aiplatform.googleapis.com/locations/europe-west3/reasoningEngines/8477639270431981568"
191+
}
192+
),
193+
),
194+
instrumentation_scope=InstrumentationScope("test"),
195+
),
196+
LogData(
197+
log_record=LogRecord(
198+
body="invalid 2",
199+
timestamp=1736976310997977393,
200+
resource=Resource(
201+
{
202+
"cloud.resource_id": "//aiplatform.googleapis.com/projects/some-project123-321/locations/europe-west3/reasoningEngines//8477639270431981568"
203+
}
204+
),
205+
),
206+
instrumentation_scope=InstrumentationScope("test"),
207+
),
208+
LogData(
209+
log_record=LogRecord(
210+
body="invalid 3",
211+
timestamp=1736976310997977393,
212+
resource=Resource(
213+
{
214+
"cloud.resource_id": "aiplatform.googleapis.com/projects/some-project123-321/locations/europe-west3/reasoningEngines//8477639270431981568"
215+
}
216+
),
217+
),
218+
instrumentation_scope=InstrumentationScope("test"),
219+
),
220+
]
221+
export_and_assert_snapshot(log_data)
222+
223+
168224
def test_convert_otlp_dict_body(
169225
export_and_assert_snapshot: ExportAndAssertSnapshot,
170226
) -> None:

0 commit comments

Comments
 (0)