mcp-instana 0.1.0__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.
- mcp_instana-0.1.1.dist-info/METADATA +908 -0
- mcp_instana-0.1.1.dist-info/RECORD +30 -0
- {mcp_instana-0.1.0.dist-info → mcp_instana-0.1.1.dist-info}/WHEEL +1 -1
- mcp_instana-0.1.1.dist-info/entry_points.txt +4 -0
- mcp_instana-0.1.0.dist-info/LICENSE → mcp_instana-0.1.1.dist-info/licenses/LICENSE.md +3 -3
- src/application/__init__.py +1 -0
- src/{client/application_alert_config_mcp_tools.py → application/application_alert_config.py} +251 -273
- src/application/application_analyze.py +415 -0
- src/application/application_catalog.py +153 -0
- src/{client/application_metrics_mcp_tools.py → application/application_metrics.py} +107 -129
- src/{client/application_resources_mcp_tools.py → application/application_resources.py} +128 -150
- src/application/application_settings.py +1135 -0
- src/application/application_topology.py +107 -0
- src/core/__init__.py +1 -0
- src/core/server.py +436 -0
- src/core/utils.py +213 -0
- src/event/__init__.py +1 -0
- src/{client/events_mcp_tools.py → event/events_tools.py} +128 -136
- src/infrastructure/__init__.py +1 -0
- src/{client/infrastructure_analyze_mcp_tools.py → infrastructure/infrastructure_analyze.py} +200 -203
- src/{client/infrastructure_catalog_mcp_tools.py → infrastructure/infrastructure_catalog.py} +194 -264
- src/infrastructure/infrastructure_metrics.py +167 -0
- src/{client/infrastructure_resources_mcp_tools.py → infrastructure/infrastructure_resources.py} +192 -223
- src/{client/infrastructure_topology_mcp_tools.py → infrastructure/infrastructure_topology.py} +105 -106
- src/log/__init__.py +1 -0
- src/log/log_alert_configuration.py +331 -0
- src/prompts/mcp_prompts.py +900 -0
- src/prompts/prompt_loader.py +29 -0
- src/prompts/prompt_registry.json +21 -0
- mcp_instana-0.1.0.dist-info/METADATA +0 -649
- mcp_instana-0.1.0.dist-info/RECORD +0 -19
- mcp_instana-0.1.0.dist-info/entry_points.txt +0 -3
- src/client/What is the sum of queue depth for all q +0 -55
- src/client/instana_client_base.py +0 -93
- src/client/log_alert_configuration_mcp_tools.py +0 -316
- src/client/show the top 5 services with the highest +0 -28
- src/mcp_server.py +0 -343
|
@@ -4,71 +4,50 @@ Application Metrics MCP Tools Module
|
|
|
4
4
|
This module provides application metrics-specific MCP tools for Instana monitoring.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
import
|
|
8
|
-
import traceback
|
|
9
|
-
from typing import Dict, Any, Optional, List, Union
|
|
7
|
+
import logging
|
|
10
8
|
from datetime import datetime
|
|
9
|
+
from typing import Any, Dict, List, Optional
|
|
11
10
|
|
|
12
11
|
# Import the necessary classes from the SDK
|
|
13
12
|
try:
|
|
14
13
|
from instana_client.api.application_metrics_api import ApplicationMetricsApi
|
|
15
|
-
from instana_client.api_client import ApiClient
|
|
16
|
-
from instana_client.configuration import Configuration
|
|
17
14
|
from instana_client.models.get_application_metrics import GetApplicationMetrics
|
|
18
15
|
from instana_client.models.get_applications import GetApplications
|
|
19
16
|
from instana_client.models.get_endpoints import GetEndpoints
|
|
20
17
|
from instana_client.models.get_services import GetServices
|
|
21
18
|
except ImportError as e:
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
import logging
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
logger.error(f"Error importing Instana SDK: {e}", exc_info=True)
|
|
24
22
|
raise
|
|
25
23
|
|
|
26
|
-
from .
|
|
24
|
+
from src.core.utils import BaseInstanaClient, register_as_tool, with_header_auth
|
|
27
25
|
|
|
28
|
-
#
|
|
29
|
-
|
|
30
|
-
"""Print debug information to stderr instead of stdout"""
|
|
31
|
-
print(*args, file=sys.stderr, **kwargs)
|
|
26
|
+
# Configure logger for this module
|
|
27
|
+
logger = logging.getLogger(__name__)
|
|
32
28
|
|
|
33
29
|
class ApplicationMetricsMCPTools(BaseInstanaClient):
|
|
34
30
|
"""Tools for application metrics in Instana MCP."""
|
|
35
|
-
|
|
31
|
+
|
|
36
32
|
def __init__(self, read_token: str, base_url: str):
|
|
37
33
|
"""Initialize the Application Metrics MCP tools client."""
|
|
38
34
|
super().__init__(read_token=read_token, base_url=base_url)
|
|
39
|
-
|
|
40
|
-
try:
|
|
41
|
-
|
|
42
|
-
# Configure the API client with the correct base URL and authentication
|
|
43
|
-
configuration = Configuration()
|
|
44
|
-
configuration.host = base_url
|
|
45
|
-
configuration.api_key['ApiKeyAuth'] = read_token
|
|
46
|
-
configuration.api_key_prefix['ApiKeyAuth'] = 'apiToken'
|
|
47
|
-
|
|
48
|
-
# Create an API client with this configuration
|
|
49
|
-
api_client = ApiClient(configuration=configuration)
|
|
50
|
-
|
|
51
|
-
# Initialize the Instana SDK's ApplicationMetricsApi with our configured client
|
|
52
|
-
self.metrics_api = ApplicationMetricsApi(api_client=api_client)
|
|
53
|
-
except Exception as e:
|
|
54
|
-
debug_print(f"Error initializing ApplicationMetricsApi: {e}")
|
|
55
|
-
traceback.print_exc(file=sys.stderr)
|
|
56
|
-
raise
|
|
57
|
-
|
|
35
|
+
|
|
58
36
|
@register_as_tool
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
37
|
+
@with_header_auth(ApplicationMetricsApi)
|
|
38
|
+
async def get_application_data_metrics_v2(self,
|
|
39
|
+
metrics: Optional[List[Dict[str, Any]]] = None,
|
|
40
|
+
time_frame: Optional[Dict[str, int]] = None,
|
|
41
|
+
application_id: Optional[str] = None,
|
|
42
|
+
service_id: Optional[str] = None,
|
|
43
|
+
endpoint_id: Optional[str] = None,
|
|
44
|
+
ctx=None, api_client=None) -> Dict[str, Any]:
|
|
66
45
|
"""
|
|
67
46
|
Get application data metrics using the v2 API.
|
|
68
|
-
|
|
47
|
+
|
|
69
48
|
This API endpoint retrieves one or more supported aggregations of metrics for a combination of entities.
|
|
70
49
|
For example, retrieve MEAN aggregation of latency metric for an Endpoint, Service, and Application.
|
|
71
|
-
|
|
50
|
+
|
|
72
51
|
Args:
|
|
73
52
|
metrics: List of metrics to retrieve with their aggregations
|
|
74
53
|
Example: [{"metric": "latency", "aggregation": "MEAN"}]
|
|
@@ -78,13 +57,13 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
|
|
|
78
57
|
service_id: ID of the service to get metrics for (optional)
|
|
79
58
|
endpoint_id: ID of the endpoint to get metrics for (optional)
|
|
80
59
|
ctx: The MCP context (optional)
|
|
81
|
-
|
|
60
|
+
|
|
82
61
|
Returns:
|
|
83
62
|
Dictionary containing metrics data or error information
|
|
84
63
|
"""
|
|
85
64
|
try:
|
|
86
|
-
|
|
87
|
-
|
|
65
|
+
logger.debug(f"get_application_data_metrics_v2 called with application_id={application_id}, service_id={service_id}, endpoint_id={endpoint_id}")
|
|
66
|
+
|
|
88
67
|
# Set default time range if not provided
|
|
89
68
|
if not time_frame:
|
|
90
69
|
to_time = int(datetime.now().timestamp() * 1000)
|
|
@@ -93,7 +72,7 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
|
|
|
93
72
|
"from": from_time,
|
|
94
73
|
"to": to_time
|
|
95
74
|
}
|
|
96
|
-
|
|
75
|
+
|
|
97
76
|
# Set default metrics if not provided
|
|
98
77
|
if not metrics:
|
|
99
78
|
metrics = [
|
|
@@ -102,13 +81,13 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
|
|
|
102
81
|
"aggregation": "MEAN"
|
|
103
82
|
}
|
|
104
83
|
]
|
|
105
|
-
|
|
84
|
+
|
|
106
85
|
# Create the request body
|
|
107
86
|
request_body = {
|
|
108
87
|
"metrics": metrics,
|
|
109
88
|
"timeFrame": time_frame
|
|
110
89
|
}
|
|
111
|
-
|
|
90
|
+
|
|
112
91
|
# Add entity IDs if provided
|
|
113
92
|
if application_id:
|
|
114
93
|
request_body["applicationId"] = application_id
|
|
@@ -116,41 +95,41 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
|
|
|
116
95
|
request_body["serviceId"] = service_id
|
|
117
96
|
if endpoint_id:
|
|
118
97
|
request_body["endpointId"] = endpoint_id
|
|
119
|
-
|
|
98
|
+
|
|
120
99
|
# Create the GetApplicationMetrics object
|
|
121
100
|
get_app_metrics = GetApplicationMetrics(**request_body)
|
|
122
|
-
|
|
101
|
+
|
|
123
102
|
# Call the get_application_data_metrics_v2 method from the SDK
|
|
124
|
-
result =
|
|
103
|
+
result = api_client.get_application_data_metrics_v2(
|
|
125
104
|
get_application_metrics=get_app_metrics
|
|
126
105
|
)
|
|
127
|
-
|
|
106
|
+
|
|
128
107
|
# Convert the result to a dictionary
|
|
129
108
|
if hasattr(result, 'to_dict'):
|
|
130
109
|
result_dict = result.to_dict()
|
|
131
110
|
else:
|
|
132
111
|
# If it's already a dict or another format, use it as is
|
|
133
112
|
result_dict = result
|
|
134
|
-
|
|
135
|
-
|
|
113
|
+
|
|
114
|
+
logger.debug(f"Result from get_application_data_metrics_v2: {result_dict}")
|
|
136
115
|
return result_dict
|
|
137
116
|
except Exception as e:
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
117
|
+
logger.error(f"Error in get_application_data_metrics_v2: {e}", exc_info=True)
|
|
118
|
+
return {"error": f"Failed to get application data metrics: {e!s}"}
|
|
119
|
+
|
|
142
120
|
@register_as_tool
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
121
|
+
@with_header_auth(ApplicationMetricsApi)
|
|
122
|
+
async def get_application_metrics(self,
|
|
123
|
+
application_ids: Optional[List[str]] = None,
|
|
124
|
+
metrics: Optional[List[Dict[str, str]]] = None,
|
|
125
|
+
time_frame: Optional[Dict[str, int]] = None,
|
|
126
|
+
fill_time_series: Optional[bool] = True,
|
|
127
|
+
ctx=None, api_client=None) -> Dict[str, Any]:
|
|
149
128
|
"""
|
|
150
129
|
Get metrics for specific applications.
|
|
151
|
-
|
|
130
|
+
|
|
152
131
|
This API endpoint retrieves one or more supported aggregations of metrics for an Application Perspective.
|
|
153
|
-
|
|
132
|
+
|
|
154
133
|
Args:
|
|
155
134
|
application_ids: List of application IDs to get metrics for
|
|
156
135
|
metrics: List of metrics to retrieve with their aggregations
|
|
@@ -159,13 +138,13 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
|
|
|
159
138
|
Example: {"from": 1617994800000, "to": 1618081200000}
|
|
160
139
|
fill_time_series: Whether to fill missing data points with timestamp and value 0
|
|
161
140
|
ctx: The MCP context (optional)
|
|
162
|
-
|
|
141
|
+
|
|
163
142
|
Returns:
|
|
164
143
|
Dictionary containing application metrics data or error information
|
|
165
144
|
"""
|
|
166
145
|
try:
|
|
167
|
-
|
|
168
|
-
|
|
146
|
+
logger.debug(f"get_application_metrics called with application_ids={application_ids}")
|
|
147
|
+
|
|
169
148
|
# Set default time range if not provided
|
|
170
149
|
if not time_frame:
|
|
171
150
|
to_time = int(datetime.now().timestamp() * 1000)
|
|
@@ -174,7 +153,7 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
|
|
|
174
153
|
"from": from_time,
|
|
175
154
|
"to": to_time
|
|
176
155
|
}
|
|
177
|
-
|
|
156
|
+
|
|
178
157
|
# Set default metrics if not provided
|
|
179
158
|
if not metrics:
|
|
180
159
|
metrics = [
|
|
@@ -183,52 +162,52 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
|
|
|
183
162
|
"aggregation": "MEAN"
|
|
184
163
|
}
|
|
185
164
|
]
|
|
186
|
-
|
|
165
|
+
|
|
187
166
|
# Create the request body
|
|
188
167
|
request_body = {
|
|
189
168
|
"metrics": metrics,
|
|
190
169
|
"timeFrame": time_frame
|
|
191
170
|
}
|
|
192
|
-
|
|
171
|
+
|
|
193
172
|
# Add application IDs if provided
|
|
194
173
|
if application_ids:
|
|
195
174
|
request_body["applicationIds"] = application_ids
|
|
196
|
-
|
|
175
|
+
|
|
197
176
|
# Create the GetApplications object
|
|
198
177
|
get_applications = GetApplications(**request_body)
|
|
199
|
-
|
|
178
|
+
|
|
200
179
|
# Call the get_application_metrics method from the SDK
|
|
201
|
-
result =
|
|
180
|
+
result = api_client.get_application_metrics(
|
|
202
181
|
fill_time_series=fill_time_series,
|
|
203
182
|
get_applications=get_applications
|
|
204
183
|
)
|
|
205
|
-
|
|
184
|
+
|
|
206
185
|
# Convert the result to a dictionary
|
|
207
186
|
if hasattr(result, 'to_dict'):
|
|
208
187
|
result_dict = result.to_dict()
|
|
209
188
|
else:
|
|
210
189
|
# If it's already a dict or another format, use it as is
|
|
211
190
|
result_dict = result
|
|
212
|
-
|
|
213
|
-
|
|
191
|
+
|
|
192
|
+
logger.debug(f"Result from get_application_metrics: {result_dict}")
|
|
214
193
|
return result_dict
|
|
215
194
|
except Exception as e:
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
195
|
+
logger.error(f"Error in get_application_metrics: {e}", exc_info=True)
|
|
196
|
+
return {"error": f"Failed to get application metrics: {e!s}"}
|
|
197
|
+
|
|
220
198
|
@register_as_tool
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
199
|
+
@with_header_auth(ApplicationMetricsApi)
|
|
200
|
+
async def get_endpoints_metrics(self,
|
|
201
|
+
endpoint_ids: Optional[List[str]] = None,
|
|
202
|
+
metrics: Optional[List[Dict[str, str]]] = None,
|
|
203
|
+
time_frame: Optional[Dict[str, int]] = None,
|
|
204
|
+
fill_time_series: Optional[bool] = True,
|
|
205
|
+
ctx=None, api_client=None) -> Dict[str, Any]:
|
|
227
206
|
"""
|
|
228
207
|
Get metrics for specific endpoints.
|
|
229
|
-
|
|
208
|
+
|
|
230
209
|
This API endpoint retrieves one or more supported aggregations of metrics for an Endpoint.
|
|
231
|
-
|
|
210
|
+
|
|
232
211
|
Args:
|
|
233
212
|
endpoint_ids: List of endpoint IDs to get metrics for
|
|
234
213
|
metrics: List of metrics to retrieve with their aggregations
|
|
@@ -237,13 +216,13 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
|
|
|
237
216
|
Example: {"from": 1617994800000, "to": 1618081200000}
|
|
238
217
|
fill_time_series: Whether to fill missing data points with timestamp and value 0
|
|
239
218
|
ctx: The MCP context (optional)
|
|
240
|
-
|
|
219
|
+
|
|
241
220
|
Returns:
|
|
242
221
|
Dictionary containing endpoint metrics data or error information
|
|
243
222
|
"""
|
|
244
223
|
try:
|
|
245
|
-
|
|
246
|
-
|
|
224
|
+
logger.debug(f"get_endpoints_metrics called with endpoint_ids={endpoint_ids}")
|
|
225
|
+
|
|
247
226
|
# Set default time range if not provided
|
|
248
227
|
if not time_frame:
|
|
249
228
|
to_time = int(datetime.now().timestamp() * 1000)
|
|
@@ -252,7 +231,7 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
|
|
|
252
231
|
"from": from_time,
|
|
253
232
|
"to": to_time
|
|
254
233
|
}
|
|
255
|
-
|
|
234
|
+
|
|
256
235
|
# Set default metrics if not provided
|
|
257
236
|
if not metrics:
|
|
258
237
|
metrics = [
|
|
@@ -261,53 +240,53 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
|
|
|
261
240
|
"aggregation": "MEAN"
|
|
262
241
|
}
|
|
263
242
|
]
|
|
264
|
-
|
|
243
|
+
|
|
265
244
|
# Create the request body
|
|
266
245
|
request_body = {
|
|
267
246
|
"metrics": metrics,
|
|
268
247
|
"timeFrame": time_frame
|
|
269
248
|
}
|
|
270
|
-
|
|
249
|
+
|
|
271
250
|
# Add endpoint IDs if provided
|
|
272
251
|
if endpoint_ids:
|
|
273
252
|
request_body["endpointIds"] = endpoint_ids
|
|
274
|
-
|
|
253
|
+
|
|
275
254
|
# Create the GetEndpoints object
|
|
276
255
|
get_endpoints = GetEndpoints(**request_body)
|
|
277
|
-
|
|
256
|
+
|
|
278
257
|
# Call the get_endpoints_metrics method from the SDK
|
|
279
|
-
result =
|
|
258
|
+
result = api_client.get_endpoints_metrics(
|
|
280
259
|
fill_time_series=fill_time_series,
|
|
281
260
|
get_endpoints=get_endpoints
|
|
282
261
|
)
|
|
283
|
-
|
|
262
|
+
|
|
284
263
|
# Convert the result to a dictionary
|
|
285
264
|
if hasattr(result, 'to_dict'):
|
|
286
265
|
result_dict = result.to_dict()
|
|
287
266
|
else:
|
|
288
267
|
# If it's already a dict or another format, use it as is
|
|
289
268
|
result_dict = result
|
|
290
|
-
|
|
291
|
-
|
|
269
|
+
|
|
270
|
+
logger.debug(f"Result from get_endpoints_metrics: {result_dict}")
|
|
292
271
|
return result_dict
|
|
293
272
|
except Exception as e:
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
273
|
+
logger.error(f"Error in get_endpoints_metrics: {e}", exc_info=True)
|
|
274
|
+
return {"error": f"Failed to get endpoints metrics: {e!s}"}
|
|
275
|
+
|
|
298
276
|
@register_as_tool
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
277
|
+
@with_header_auth(ApplicationMetricsApi)
|
|
278
|
+
async def get_services_metrics(self,
|
|
279
|
+
service_ids: Optional[List[str]] = None,
|
|
280
|
+
metrics: Optional[List[Dict[str, str]]] = None,
|
|
281
|
+
time_frame: Optional[Dict[str, int]] = None,
|
|
282
|
+
fill_time_series: Optional[bool] = True,
|
|
283
|
+
include_snapshot_ids: Optional[bool] = False,
|
|
284
|
+
ctx=None, api_client=None) -> Dict[str, Any]:
|
|
306
285
|
"""
|
|
307
286
|
Get metrics for specific services.
|
|
308
|
-
|
|
287
|
+
|
|
309
288
|
This API endpoint retrieves one or more supported aggregations of metrics for a Service.
|
|
310
|
-
|
|
289
|
+
|
|
311
290
|
Args:
|
|
312
291
|
service_ids: List of service IDs to get metrics for
|
|
313
292
|
metrics: List of metrics to retrieve with their aggregations
|
|
@@ -317,13 +296,13 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
|
|
|
317
296
|
fill_time_series: Whether to fill missing data points with timestamp and value 0
|
|
318
297
|
include_snapshot_ids: Whether to include snapshot IDs in the results
|
|
319
298
|
ctx: The MCP context (optional)
|
|
320
|
-
|
|
299
|
+
|
|
321
300
|
Returns:
|
|
322
301
|
Dictionary containing service metrics data or error information
|
|
323
302
|
"""
|
|
324
303
|
try:
|
|
325
|
-
|
|
326
|
-
|
|
304
|
+
logger.debug(f"get_services_metrics called with service_ids={service_ids}")
|
|
305
|
+
|
|
327
306
|
# Set default time range if not provided
|
|
328
307
|
if not time_frame:
|
|
329
308
|
to_time = int(datetime.now().timestamp() * 1000)
|
|
@@ -332,7 +311,7 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
|
|
|
332
311
|
"from": from_time,
|
|
333
312
|
"to": to_time
|
|
334
313
|
}
|
|
335
|
-
|
|
314
|
+
|
|
336
315
|
# Set default metrics if not provided
|
|
337
316
|
if not metrics:
|
|
338
317
|
metrics = [
|
|
@@ -341,37 +320,36 @@ class ApplicationMetricsMCPTools(BaseInstanaClient):
|
|
|
341
320
|
"aggregation": "MEAN"
|
|
342
321
|
}
|
|
343
322
|
]
|
|
344
|
-
|
|
323
|
+
|
|
345
324
|
# Create the request body
|
|
346
325
|
request_body = {
|
|
347
326
|
"metrics": metrics,
|
|
348
327
|
"timeFrame": time_frame
|
|
349
328
|
}
|
|
350
|
-
|
|
329
|
+
|
|
351
330
|
# Add service IDs if provided
|
|
352
331
|
if service_ids:
|
|
353
332
|
request_body["serviceIds"] = service_ids
|
|
354
|
-
|
|
333
|
+
|
|
355
334
|
# Create the GetServices object
|
|
356
335
|
get_services = GetServices(**request_body)
|
|
357
|
-
|
|
336
|
+
|
|
358
337
|
# Call the get_services_metrics method from the SDK
|
|
359
|
-
result =
|
|
338
|
+
result = api_client.get_services_metrics(
|
|
360
339
|
fill_time_series=fill_time_series,
|
|
361
340
|
include_snapshot_ids=include_snapshot_ids,
|
|
362
341
|
get_services=get_services
|
|
363
342
|
)
|
|
364
|
-
|
|
343
|
+
|
|
365
344
|
# Convert the result to a dictionary
|
|
366
345
|
if hasattr(result, 'to_dict'):
|
|
367
346
|
result_dict = result.to_dict()
|
|
368
347
|
else:
|
|
369
348
|
# If it's already a dict or another format, use it as is
|
|
370
349
|
result_dict = result
|
|
371
|
-
|
|
372
|
-
|
|
350
|
+
|
|
351
|
+
logger.debug(f"Result from get_services_metrics: {result_dict}")
|
|
373
352
|
return result_dict
|
|
374
353
|
except Exception as e:
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
return {"error": f"Failed to get services metrics: {str(e)}"}
|
|
354
|
+
logger.error(f"Error in get_services_metrics: {e}", exc_info=True)
|
|
355
|
+
return {"error": f"Failed to get services metrics: {e!s}"}
|