holmesgpt 0.14.0a0__py3-none-any.whl → 0.14.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 holmesgpt might be problematic. Click here for more details.
- holmes/__init__.py +1 -1
- holmes/clients/robusta_client.py +15 -4
- holmes/common/env_vars.py +8 -1
- holmes/config.py +66 -139
- holmes/core/investigation.py +1 -2
- holmes/core/llm.py +295 -52
- holmes/core/models.py +2 -0
- holmes/core/safeguards.py +4 -4
- holmes/core/supabase_dal.py +14 -8
- holmes/core/tool_calling_llm.py +110 -102
- holmes/core/tools.py +260 -25
- holmes/core/tools_utils/data_types.py +81 -0
- holmes/core/tools_utils/tool_context_window_limiter.py +33 -0
- holmes/core/tools_utils/tool_executor.py +2 -2
- holmes/core/toolset_manager.py +150 -3
- holmes/core/transformers/__init__.py +23 -0
- holmes/core/transformers/base.py +62 -0
- holmes/core/transformers/llm_summarize.py +174 -0
- holmes/core/transformers/registry.py +122 -0
- holmes/core/transformers/transformer.py +31 -0
- holmes/main.py +5 -0
- holmes/plugins/prompts/_fetch_logs.jinja2 +10 -1
- holmes/plugins/toolsets/aks-node-health.yaml +46 -0
- holmes/plugins/toolsets/aks.yaml +64 -0
- holmes/plugins/toolsets/atlas_mongodb/mongodb_atlas.py +17 -15
- holmes/plugins/toolsets/azure_sql/tools/analyze_connection_failures.py +8 -4
- holmes/plugins/toolsets/azure_sql/tools/analyze_database_connections.py +7 -3
- holmes/plugins/toolsets/azure_sql/tools/analyze_database_health_status.py +3 -3
- holmes/plugins/toolsets/azure_sql/tools/analyze_database_performance.py +3 -3
- holmes/plugins/toolsets/azure_sql/tools/analyze_database_storage.py +7 -3
- holmes/plugins/toolsets/azure_sql/tools/get_active_alerts.py +4 -4
- holmes/plugins/toolsets/azure_sql/tools/get_slow_queries.py +7 -3
- holmes/plugins/toolsets/azure_sql/tools/get_top_cpu_queries.py +7 -3
- holmes/plugins/toolsets/azure_sql/tools/get_top_data_io_queries.py +7 -3
- holmes/plugins/toolsets/azure_sql/tools/get_top_log_io_queries.py +7 -3
- holmes/plugins/toolsets/bash/bash_toolset.py +6 -6
- holmes/plugins/toolsets/bash/common/bash.py +7 -7
- holmes/plugins/toolsets/coralogix/toolset_coralogix_logs.py +5 -3
- holmes/plugins/toolsets/datadog/datadog_api.py +490 -24
- holmes/plugins/toolsets/datadog/datadog_logs_instructions.jinja2 +21 -10
- holmes/plugins/toolsets/datadog/toolset_datadog_general.py +344 -205
- holmes/plugins/toolsets/datadog/toolset_datadog_logs.py +189 -17
- holmes/plugins/toolsets/datadog/toolset_datadog_metrics.py +95 -30
- holmes/plugins/toolsets/datadog/toolset_datadog_rds.py +10 -10
- holmes/plugins/toolsets/datadog/toolset_datadog_traces.py +20 -20
- holmes/plugins/toolsets/git.py +21 -21
- holmes/plugins/toolsets/grafana/common.py +2 -2
- holmes/plugins/toolsets/grafana/toolset_grafana.py +4 -4
- holmes/plugins/toolsets/grafana/toolset_grafana_loki.py +5 -4
- holmes/plugins/toolsets/grafana/toolset_grafana_tempo.jinja2 +123 -23
- holmes/plugins/toolsets/grafana/toolset_grafana_tempo.py +165 -307
- holmes/plugins/toolsets/internet/internet.py +3 -3
- holmes/plugins/toolsets/internet/notion.py +3 -3
- holmes/plugins/toolsets/investigator/core_investigation.py +3 -3
- holmes/plugins/toolsets/kafka.py +18 -18
- holmes/plugins/toolsets/kubernetes.yaml +58 -0
- holmes/plugins/toolsets/kubernetes_logs.py +6 -6
- holmes/plugins/toolsets/kubernetes_logs.yaml +32 -0
- holmes/plugins/toolsets/logging_utils/logging_api.py +1 -1
- holmes/plugins/toolsets/mcp/toolset_mcp.py +4 -4
- holmes/plugins/toolsets/newrelic.py +5 -5
- holmes/plugins/toolsets/opensearch/opensearch.py +5 -5
- holmes/plugins/toolsets/opensearch/opensearch_logs.py +7 -7
- holmes/plugins/toolsets/opensearch/opensearch_traces.py +10 -10
- holmes/plugins/toolsets/prometheus/prometheus.py +841 -351
- holmes/plugins/toolsets/prometheus/prometheus_instructions.jinja2 +39 -2
- holmes/plugins/toolsets/prometheus/utils.py +28 -0
- holmes/plugins/toolsets/rabbitmq/toolset_rabbitmq.py +6 -4
- holmes/plugins/toolsets/robusta/robusta.py +10 -10
- holmes/plugins/toolsets/runbook/runbook_fetcher.py +4 -4
- holmes/plugins/toolsets/servicenow/servicenow.py +6 -6
- holmes/plugins/toolsets/utils.py +88 -0
- holmes/utils/config_utils.py +91 -0
- holmes/utils/env.py +7 -0
- holmes/utils/holmes_status.py +2 -1
- holmes/utils/sentry_helper.py +41 -0
- holmes/utils/stream.py +9 -0
- {holmesgpt-0.14.0a0.dist-info → holmesgpt-0.14.1.dist-info}/METADATA +10 -14
- {holmesgpt-0.14.0a0.dist-info → holmesgpt-0.14.1.dist-info}/RECORD +82 -72
- {holmesgpt-0.14.0a0.dist-info → holmesgpt-0.14.1.dist-info}/LICENSE.txt +0 -0
- {holmesgpt-0.14.0a0.dist-info → holmesgpt-0.14.1.dist-info}/WHEEL +0 -0
- {holmesgpt-0.14.0a0.dist-info → holmesgpt-0.14.1.dist-info}/entry_points.txt +0 -0
|
@@ -3,33 +3,34 @@ from typing import Any, Dict, Tuple, cast, List
|
|
|
3
3
|
|
|
4
4
|
import yaml # type: ignore
|
|
5
5
|
|
|
6
|
-
from holmes.common.env_vars import load_bool
|
|
6
|
+
from holmes.common.env_vars import load_bool, MAX_GRAPH_POINTS
|
|
7
7
|
from holmes.core.tools import (
|
|
8
8
|
StructuredToolResult,
|
|
9
9
|
Tool,
|
|
10
10
|
ToolParameter,
|
|
11
|
-
|
|
11
|
+
StructuredToolResultStatus,
|
|
12
12
|
)
|
|
13
|
+
from holmes.plugins.toolsets.consts import STANDARD_END_DATETIME_TOOL_PARAM_DESCRIPTION
|
|
13
14
|
from holmes.plugins.toolsets.grafana.base_grafana_toolset import BaseGrafanaToolset
|
|
14
15
|
from holmes.plugins.toolsets.grafana.common import (
|
|
15
16
|
GrafanaTempoConfig,
|
|
16
17
|
)
|
|
17
18
|
from holmes.plugins.toolsets.grafana.grafana_tempo_api import GrafanaTempoAPI
|
|
18
19
|
from holmes.plugins.toolsets.logging_utils.logging_api import (
|
|
19
|
-
|
|
20
|
+
DEFAULT_GRAPH_TIME_SPAN_SECONDS,
|
|
20
21
|
)
|
|
21
22
|
from holmes.plugins.toolsets.utils import (
|
|
22
23
|
toolset_name_for_one_liner,
|
|
23
24
|
process_timestamps_to_int,
|
|
25
|
+
standard_start_datetime_tool_param_description,
|
|
26
|
+
adjust_step_for_max_points,
|
|
27
|
+
seconds_to_duration_string,
|
|
28
|
+
duration_string_to_seconds,
|
|
24
29
|
)
|
|
25
30
|
|
|
26
31
|
TEMPO_LABELS_ADD_PREFIX = load_bool("TEMPO_LABELS_ADD_PREFIX", True)
|
|
27
32
|
TEMPO_API_USE_POST = False # Use GET method for direct API mapping
|
|
28
33
|
|
|
29
|
-
ONE_HOUR_IN_SECONDS = 3600
|
|
30
|
-
DEFAULT_TRACES_TIME_SPAN_SECONDS = DEFAULT_TIME_SPAN_SECONDS # 7 days
|
|
31
|
-
DEFAULT_TAGS_TIME_SPAN_SECONDS = 8 * ONE_HOUR_IN_SECONDS # 8 hours
|
|
32
|
-
|
|
33
34
|
|
|
34
35
|
class BaseGrafanaTempoToolset(BaseGrafanaToolset):
|
|
35
36
|
config_class = GrafanaTempoConfig
|
|
@@ -109,213 +110,19 @@ class BaseGrafanaTempoToolset(BaseGrafanaToolset):
|
|
|
109
110
|
|
|
110
111
|
return filters
|
|
111
112
|
|
|
112
|
-
|
|
113
|
-
def
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
# class GetTempoTraces(Tool):
|
|
122
|
-
# def __init__(self, toolset: BaseGrafanaTempoToolset):
|
|
123
|
-
# super().__init__(
|
|
124
|
-
# name="fetch_tempo_traces",
|
|
125
|
-
# description="""Lists Tempo traces. At least one of `service_name`, `pod_name` or `deployment_name` argument is required.""",
|
|
126
|
-
# parameters={
|
|
127
|
-
# "min_duration": ToolParameter(
|
|
128
|
-
# description="The minimum duration of traces to fetch, e.g., '5s' for 5 seconds.",
|
|
129
|
-
# type="string",
|
|
130
|
-
# required=True,
|
|
131
|
-
# ),
|
|
132
|
-
# "service_name": ToolParameter(
|
|
133
|
-
# description="Filter traces by service name",
|
|
134
|
-
# type="string",
|
|
135
|
-
# required=False,
|
|
136
|
-
# ),
|
|
137
|
-
# "pod_name": ToolParameter(
|
|
138
|
-
# description="Filter traces by pod name",
|
|
139
|
-
# type="string",
|
|
140
|
-
# required=False,
|
|
141
|
-
# ),
|
|
142
|
-
# "namespace_name": ToolParameter(
|
|
143
|
-
# description="Filter traces by namespace",
|
|
144
|
-
# type="string",
|
|
145
|
-
# required=False,
|
|
146
|
-
# ),
|
|
147
|
-
# "deployment_name": ToolParameter(
|
|
148
|
-
# description="Filter traces by deployment name",
|
|
149
|
-
# type="string",
|
|
150
|
-
# required=False,
|
|
151
|
-
# ),
|
|
152
|
-
# "node_name": ToolParameter(
|
|
153
|
-
# description="Filter traces by node",
|
|
154
|
-
# type="string",
|
|
155
|
-
# required=False,
|
|
156
|
-
# ),
|
|
157
|
-
# "start_datetime": ToolParameter(
|
|
158
|
-
# description=f"The beginning time boundary for the trace search period. String in RFC3339 format. If a negative integer, the number of seconds relative to the end_timestamp. Defaults to -{DEFAULT_TRACES_TIME_SPAN_SECONDS}",
|
|
159
|
-
# type="string",
|
|
160
|
-
# required=False,
|
|
161
|
-
# ),
|
|
162
|
-
# "end_datetime": ToolParameter(
|
|
163
|
-
# description="The ending time boundary for the trace search period. String in RFC3339 format. Defaults to NOW().",
|
|
164
|
-
# type="string",
|
|
165
|
-
# required=False,
|
|
166
|
-
# ),
|
|
167
|
-
# "limit": ToolParameter(
|
|
168
|
-
# description="Maximum number of traces to return. Defaults to 50",
|
|
169
|
-
# type="string",
|
|
170
|
-
# required=False,
|
|
171
|
-
# ),
|
|
172
|
-
# "sort": ToolParameter(
|
|
173
|
-
# description="One of 'descending', 'ascending' or 'none' for no sorting. Defaults to descending",
|
|
174
|
-
# type="string",
|
|
175
|
-
# required=False,
|
|
176
|
-
# ),
|
|
177
|
-
# },
|
|
178
|
-
# )
|
|
179
|
-
# self._toolset = toolset
|
|
180
|
-
#
|
|
181
|
-
# def _invoke(self, params: Dict, user_approved: bool = False) -> StructuredToolResult:
|
|
182
|
-
# # Create API instance
|
|
183
|
-
# api = GrafanaTempoAPI(self._toolset.grafana_config, use_post=TEMPO_API_USE_POST)
|
|
184
|
-
#
|
|
185
|
-
# invalid_params_error = validate_params(
|
|
186
|
-
# params, ["service_name", "pod_name", "deployment_name"]
|
|
187
|
-
# )
|
|
188
|
-
# if invalid_params_error:
|
|
189
|
-
# return StructuredToolResult(
|
|
190
|
-
# status=ToolResultStatus.ERROR,
|
|
191
|
-
# error=invalid_params_error,
|
|
192
|
-
# params=params,
|
|
193
|
-
# )
|
|
194
|
-
#
|
|
195
|
-
# start, end = process_timestamps_to_int(
|
|
196
|
-
# params.get("start_datetime"),
|
|
197
|
-
# params.get("end_datetime"),
|
|
198
|
-
# default_time_span_seconds=DEFAULT_TRACES_TIME_SPAN_SECONDS,
|
|
199
|
-
# )
|
|
200
|
-
#
|
|
201
|
-
# filters = self._toolset.build_k8s_filters(params, use_exact_match=True)
|
|
202
|
-
#
|
|
203
|
-
# filters.append(f'duration>{get_param_or_raise(params, "min_duration")}')
|
|
204
|
-
#
|
|
205
|
-
# query = " && ".join(filters)
|
|
206
|
-
# query = f"{{{query}}}"
|
|
207
|
-
#
|
|
208
|
-
# traces = api.search_traces_by_query(
|
|
209
|
-
# q=query,
|
|
210
|
-
# start=start,
|
|
211
|
-
# end=end,
|
|
212
|
-
# limit=params.get("limit", 50),
|
|
213
|
-
# )
|
|
214
|
-
# return StructuredToolResult(
|
|
215
|
-
# status=ToolResultStatus.SUCCESS,
|
|
216
|
-
# data=format_traces_list(traces),
|
|
217
|
-
# params=params,
|
|
218
|
-
# invocation=query,
|
|
219
|
-
# )
|
|
220
|
-
#
|
|
221
|
-
# def get_parameterized_one_liner(self, params: Dict) -> str:
|
|
222
|
-
# return f"{toolset_name_for_one_liner(self._toolset.name)}: Fetched Tempo Traces (min_duration={params.get('min_duration')})"
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
# class GetTempoTags(Tool):
|
|
226
|
-
# def __init__(self, toolset: BaseGrafanaTempoToolset):
|
|
227
|
-
# super().__init__(
|
|
228
|
-
# name="fetch_tempo_tags",
|
|
229
|
-
# description="List the tags available in Tempo",
|
|
230
|
-
# parameters={
|
|
231
|
-
# "start_datetime": ToolParameter(
|
|
232
|
-
# description=f"The beginning time boundary for the search period. String in RFC3339 format. If a negative integer, the number of seconds relative to the end_timestamp. Defaults to -{DEFAULT_TAGS_TIME_SPAN_SECONDS}",
|
|
233
|
-
# type="string",
|
|
234
|
-
# required=False,
|
|
235
|
-
# ),
|
|
236
|
-
# "end_datetime": ToolParameter(
|
|
237
|
-
# description="The ending time boundary for the search period. String in RFC3339 format. Defaults to NOW().",
|
|
238
|
-
# type="string",
|
|
239
|
-
# required=False,
|
|
240
|
-
# ),
|
|
241
|
-
# },
|
|
242
|
-
# )
|
|
243
|
-
# self._toolset = toolset
|
|
244
|
-
#
|
|
245
|
-
# def _invoke(self, params: Dict, user_approved: bool = False) -> StructuredToolResult:
|
|
246
|
-
# # Create API instance
|
|
247
|
-
# api = GrafanaTempoAPI(self._toolset.grafana_config, use_post=TEMPO_API_USE_POST)
|
|
248
|
-
#
|
|
249
|
-
# start, end = process_timestamps_to_int(
|
|
250
|
-
# start=params.get("start_datetime"),
|
|
251
|
-
# end=params.get("end_datetime"),
|
|
252
|
-
# default_time_span_seconds=DEFAULT_TAGS_TIME_SPAN_SECONDS,
|
|
253
|
-
# )
|
|
254
|
-
#
|
|
255
|
-
# try:
|
|
256
|
-
# data = api.search_tag_names_v2(start=start, end=end)
|
|
257
|
-
# return StructuredToolResult(
|
|
258
|
-
# status=ToolResultStatus.SUCCESS,
|
|
259
|
-
# data=yaml.dump(data.get("scopes")),
|
|
260
|
-
# params=params,
|
|
261
|
-
# )
|
|
262
|
-
# except Exception as e:
|
|
263
|
-
# return StructuredToolResult(
|
|
264
|
-
# status=ToolResultStatus.ERROR,
|
|
265
|
-
# error=f"Failed to retrieve tags: {str(e)}",
|
|
266
|
-
# params=params,
|
|
267
|
-
# )
|
|
268
|
-
#
|
|
269
|
-
# def get_parameterized_one_liner(self, params: Dict) -> str:
|
|
270
|
-
# return f"{toolset_name_for_one_liner(self._toolset.name)}: Fetched Tempo tags"
|
|
271
|
-
#
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
# class GetTempoTraceById(Tool):
|
|
275
|
-
# def __init__(self, toolset: BaseGrafanaTempoToolset):
|
|
276
|
-
# super().__init__(
|
|
277
|
-
# name="fetch_tempo_trace_by_id",
|
|
278
|
-
# description="""Retrieves detailed information about a Tempo trace using its trace ID. Use this to investigate a trace.""",
|
|
279
|
-
# parameters={
|
|
280
|
-
# "trace_id": ToolParameter(
|
|
281
|
-
# description="The unique trace ID to fetch.",
|
|
282
|
-
# type="string",
|
|
283
|
-
# required=True,
|
|
284
|
-
# ),
|
|
285
|
-
# },
|
|
286
|
-
# )
|
|
287
|
-
# self._toolset = toolset
|
|
288
|
-
#
|
|
289
|
-
# def _invoke(self, params: Dict, user_approved: bool = False) -> StructuredToolResult:
|
|
290
|
-
# # Create API instance
|
|
291
|
-
# api = GrafanaTempoAPI(self._toolset.grafana_config, use_post=TEMPO_API_USE_POST)
|
|
292
|
-
#
|
|
293
|
-
# labels_mapping = self._toolset.grafana_config.labels
|
|
294
|
-
# labels = list(labels_mapping.model_dump().values())
|
|
295
|
-
#
|
|
296
|
-
# # Get raw trace data
|
|
297
|
-
# trace_data = api.query_trace_by_id_v2(
|
|
298
|
-
# trace_id=get_param_or_raise(params, "trace_id")
|
|
299
|
-
# )
|
|
300
|
-
#
|
|
301
|
-
# # Process the trace data (new API returns raw data)
|
|
302
|
-
# formatted_trace = process_trace(trace_data, labels)
|
|
303
|
-
#
|
|
304
|
-
# return StructuredToolResult(
|
|
305
|
-
# status=ToolResultStatus.SUCCESS,
|
|
306
|
-
# data=formatted_trace,
|
|
307
|
-
# params=params,
|
|
308
|
-
# )
|
|
309
|
-
#
|
|
310
|
-
# def get_parameterized_one_liner(self, params: Dict) -> str:
|
|
311
|
-
# return f"{toolset_name_for_one_liner(self._toolset.name)}: Fetched Tempo Trace (trace_id={params.get('trace_id')})"
|
|
312
|
-
#
|
|
113
|
+
@staticmethod
|
|
114
|
+
def adjust_start_end_time(params: Dict) -> Tuple[int, int]:
|
|
115
|
+
return process_timestamps_to_int(
|
|
116
|
+
start=params.get("start"),
|
|
117
|
+
end=params.get("end"),
|
|
118
|
+
default_time_span_seconds=DEFAULT_GRAPH_TIME_SPAN_SECONDS,
|
|
119
|
+
)
|
|
313
120
|
|
|
314
121
|
|
|
315
122
|
class FetchTracesSimpleComparison(Tool):
|
|
316
123
|
def __init__(self, toolset: BaseGrafanaTempoToolset):
|
|
317
124
|
super().__init__(
|
|
318
|
-
name="
|
|
125
|
+
name="tempo_fetch_traces_comparative_sample",
|
|
319
126
|
description="""Fetches statistics and representative samples of fast, slow, and typical traces for performance analysis. Requires either a `base_query` OR at least one of `service_name`, `pod_name`, `namespace_name`, `deployment_name`, `node_name`.
|
|
320
127
|
|
|
321
128
|
Important: call this tool first when investigating performance issues via traces. This tool provides comprehensive analysis for identifying patterns.
|
|
@@ -351,7 +158,11 @@ Examples:
|
|
|
351
158
|
required=False,
|
|
352
159
|
),
|
|
353
160
|
"base_query": ToolParameter(
|
|
354
|
-
description=
|
|
161
|
+
description=(
|
|
162
|
+
"Custom TraceQL filter. Supports span/resource attributes, "
|
|
163
|
+
"duration, and aggregates (count(), avg(), min(), max(), sum()). "
|
|
164
|
+
"Examples: '{span.http.status_code>=400}', '{duration>100ms}'"
|
|
165
|
+
),
|
|
355
166
|
type="string",
|
|
356
167
|
required=False,
|
|
357
168
|
),
|
|
@@ -360,13 +171,15 @@ Examples:
|
|
|
360
171
|
type="integer",
|
|
361
172
|
required=False,
|
|
362
173
|
),
|
|
363
|
-
"
|
|
364
|
-
description=
|
|
174
|
+
"start": ToolParameter(
|
|
175
|
+
description=standard_start_datetime_tool_param_description(
|
|
176
|
+
DEFAULT_GRAPH_TIME_SPAN_SECONDS
|
|
177
|
+
),
|
|
365
178
|
type="string",
|
|
366
179
|
required=False,
|
|
367
180
|
),
|
|
368
|
-
"
|
|
369
|
-
description=
|
|
181
|
+
"end": ToolParameter(
|
|
182
|
+
description=STANDARD_END_DATETIME_TOOL_PARAM_DESCRIPTION,
|
|
370
183
|
type="string",
|
|
371
184
|
required=False,
|
|
372
185
|
),
|
|
@@ -374,6 +187,14 @@ Examples:
|
|
|
374
187
|
)
|
|
375
188
|
self._toolset = toolset
|
|
376
189
|
|
|
190
|
+
@staticmethod
|
|
191
|
+
def validate_params(params: Dict[str, Any], expected_params: List[str]):
|
|
192
|
+
for param in expected_params:
|
|
193
|
+
if param in params and params[param] not in (None, "", [], {}):
|
|
194
|
+
return None
|
|
195
|
+
|
|
196
|
+
return f"At least one of the following argument is expected but none were set: {expected_params}"
|
|
197
|
+
|
|
377
198
|
def _invoke(
|
|
378
199
|
self, params: dict, user_approved: bool = False
|
|
379
200
|
) -> StructuredToolResult:
|
|
@@ -386,7 +207,7 @@ Examples:
|
|
|
386
207
|
filters = self._toolset.build_k8s_filters(params, use_exact_match=False)
|
|
387
208
|
|
|
388
209
|
# Validate that at least one parameter was provided
|
|
389
|
-
invalid_params_error = validate_params(
|
|
210
|
+
invalid_params_error = FetchTracesSimpleComparison.validate_params(
|
|
390
211
|
params,
|
|
391
212
|
[
|
|
392
213
|
"service_name",
|
|
@@ -398,7 +219,7 @@ Examples:
|
|
|
398
219
|
)
|
|
399
220
|
if invalid_params_error:
|
|
400
221
|
return StructuredToolResult(
|
|
401
|
-
status=
|
|
222
|
+
status=StructuredToolResultStatus.ERROR,
|
|
402
223
|
error=invalid_params_error,
|
|
403
224
|
params=params,
|
|
404
225
|
)
|
|
@@ -407,11 +228,7 @@ Examples:
|
|
|
407
228
|
|
|
408
229
|
sample_count = params.get("sample_count", 3)
|
|
409
230
|
|
|
410
|
-
start, end =
|
|
411
|
-
params.get("start_datetime"),
|
|
412
|
-
params.get("end_datetime"),
|
|
413
|
-
default_time_span_seconds=DEFAULT_TRACES_TIME_SPAN_SECONDS,
|
|
414
|
-
)
|
|
231
|
+
start, end = BaseGrafanaTempoToolset.adjust_start_end_time(params)
|
|
415
232
|
|
|
416
233
|
# Create API instance
|
|
417
234
|
api = GrafanaTempoAPI(
|
|
@@ -441,7 +258,7 @@ Examples:
|
|
|
441
258
|
traces = all_traces_response.get("traces", [])
|
|
442
259
|
if not traces:
|
|
443
260
|
return StructuredToolResult(
|
|
444
|
-
status=
|
|
261
|
+
status=StructuredToolResultStatus.SUCCESS,
|
|
445
262
|
data="No traces found matching the query",
|
|
446
263
|
params=params,
|
|
447
264
|
)
|
|
@@ -518,14 +335,14 @@ Examples:
|
|
|
518
335
|
|
|
519
336
|
# Return as YAML for readability
|
|
520
337
|
return StructuredToolResult(
|
|
521
|
-
status=
|
|
338
|
+
status=StructuredToolResultStatus.SUCCESS,
|
|
522
339
|
data=yaml.dump(result, default_flow_style=False, sort_keys=False),
|
|
523
340
|
params=params,
|
|
524
341
|
)
|
|
525
342
|
|
|
526
343
|
except Exception as e:
|
|
527
344
|
return StructuredToolResult(
|
|
528
|
-
status=
|
|
345
|
+
status=StructuredToolResultStatus.ERROR,
|
|
529
346
|
error=f"Error fetching traces: {str(e)}",
|
|
530
347
|
params=params,
|
|
531
348
|
)
|
|
@@ -534,21 +351,39 @@ Examples:
|
|
|
534
351
|
return f"{toolset_name_for_one_liner(self._toolset.name)}: Simple Tempo Traces Comparison"
|
|
535
352
|
|
|
536
353
|
|
|
537
|
-
# New tools matching GrafanaTempoAPI methods
|
|
538
|
-
|
|
539
|
-
|
|
540
354
|
class SearchTracesByQuery(Tool):
|
|
541
355
|
def __init__(self, toolset: BaseGrafanaTempoToolset):
|
|
542
356
|
super().__init__(
|
|
543
|
-
name="
|
|
357
|
+
name="tempo_search_traces_by_query",
|
|
544
358
|
description=(
|
|
545
359
|
"Search for traces using TraceQL query language. "
|
|
546
|
-
"Uses the Tempo API endpoint: GET /api/search with 'q' parameter
|
|
547
|
-
|
|
360
|
+
"Uses the Tempo API endpoint: GET /api/search with 'q' parameter.\n\n"
|
|
361
|
+
"TraceQL can select traces based on:\n"
|
|
362
|
+
"- Span and resource attributes\n"
|
|
363
|
+
"- Timing and duration\n"
|
|
364
|
+
"- Aggregate functions:\n"
|
|
365
|
+
" • count() - Count number of spans\n"
|
|
366
|
+
" • avg(attribute) - Calculate average\n"
|
|
367
|
+
" • min(attribute) - Find minimum value\n"
|
|
368
|
+
" • max(attribute) - Find maximum value\n"
|
|
369
|
+
" • sum(attribute) - Sum values\n\n"
|
|
370
|
+
"Examples:\n"
|
|
371
|
+
'- Specific operation: {resource.service.name = "frontend" && name = "POST /api/orders"}\n'
|
|
372
|
+
'- Error traces: {resource.service.name="frontend" && name = "POST /api/orders" && status = error}\n'
|
|
373
|
+
'- HTTP errors: {resource.service.name="frontend" && name = "POST /api/orders" && span.http.status_code >= 500}\n'
|
|
374
|
+
'- Multi-service: {span.service.name="frontend" && name = "GET /api/products/{id}"} && {span.db.system="postgresql"}\n'
|
|
375
|
+
"- With aggregates: { status = error } | by(resource.service.name) | count() > 1"
|
|
548
376
|
),
|
|
549
377
|
parameters={
|
|
550
378
|
"q": ToolParameter(
|
|
551
|
-
description=
|
|
379
|
+
description=(
|
|
380
|
+
"TraceQL query. Supports filtering by span/resource attributes, "
|
|
381
|
+
"duration, and aggregate functions (count(), avg(), min(), max(), sum()). "
|
|
382
|
+
"Examples: '{resource.service.name = \"frontend\"}', "
|
|
383
|
+
'\'{resource.service.name="frontend" && name = "POST /api/orders" && status = error}\', '
|
|
384
|
+
'\'{resource.service.name="frontend" && name = "POST /api/orders" && span.http.status_code >= 500}\', '
|
|
385
|
+
"'{} | count() > 10'"
|
|
386
|
+
),
|
|
552
387
|
type="string",
|
|
553
388
|
required=True,
|
|
554
389
|
),
|
|
@@ -558,13 +393,15 @@ class SearchTracesByQuery(Tool):
|
|
|
558
393
|
required=False,
|
|
559
394
|
),
|
|
560
395
|
"start": ToolParameter(
|
|
561
|
-
description=
|
|
562
|
-
|
|
396
|
+
description=standard_start_datetime_tool_param_description(
|
|
397
|
+
DEFAULT_GRAPH_TIME_SPAN_SECONDS
|
|
398
|
+
),
|
|
399
|
+
type="string",
|
|
563
400
|
required=False,
|
|
564
401
|
),
|
|
565
402
|
"end": ToolParameter(
|
|
566
|
-
description=
|
|
567
|
-
type="
|
|
403
|
+
description=STANDARD_END_DATETIME_TOOL_PARAM_DESCRIPTION,
|
|
404
|
+
type="string",
|
|
568
405
|
required=False,
|
|
569
406
|
),
|
|
570
407
|
"spss": ToolParameter(
|
|
@@ -581,22 +418,24 @@ class SearchTracesByQuery(Tool):
|
|
|
581
418
|
) -> StructuredToolResult:
|
|
582
419
|
api = GrafanaTempoAPI(self._toolset.grafana_config, use_post=TEMPO_API_USE_POST)
|
|
583
420
|
|
|
421
|
+
start, end = BaseGrafanaTempoToolset.adjust_start_end_time(params)
|
|
422
|
+
|
|
584
423
|
try:
|
|
585
424
|
result = api.search_traces_by_query(
|
|
586
425
|
q=params["q"],
|
|
587
426
|
limit=params.get("limit"),
|
|
588
|
-
start=
|
|
589
|
-
end=
|
|
427
|
+
start=start,
|
|
428
|
+
end=end,
|
|
590
429
|
spss=params.get("spss"),
|
|
591
430
|
)
|
|
592
431
|
return StructuredToolResult(
|
|
593
|
-
status=
|
|
432
|
+
status=StructuredToolResultStatus.SUCCESS,
|
|
594
433
|
data=yaml.dump(result, default_flow_style=False),
|
|
595
434
|
params=params,
|
|
596
435
|
)
|
|
597
436
|
except Exception as e:
|
|
598
437
|
return StructuredToolResult(
|
|
599
|
-
status=
|
|
438
|
+
status=StructuredToolResultStatus.ERROR,
|
|
600
439
|
error=str(e),
|
|
601
440
|
params=params,
|
|
602
441
|
)
|
|
@@ -608,15 +447,15 @@ class SearchTracesByQuery(Tool):
|
|
|
608
447
|
class SearchTracesByTags(Tool):
|
|
609
448
|
def __init__(self, toolset: BaseGrafanaTempoToolset):
|
|
610
449
|
super().__init__(
|
|
611
|
-
name="
|
|
450
|
+
name="tempo_search_traces_by_tags",
|
|
612
451
|
description=(
|
|
613
452
|
"Search for traces using logfmt-encoded tags. "
|
|
614
453
|
"Uses the Tempo API endpoint: GET /api/search with 'tags' parameter. "
|
|
615
|
-
'Example:
|
|
454
|
+
'Example: service.name="api" http.status_code="500"'
|
|
616
455
|
),
|
|
617
456
|
parameters={
|
|
618
457
|
"tags": ToolParameter(
|
|
619
|
-
description='Logfmt-encoded span/process attributes (e.g., \'
|
|
458
|
+
description='Logfmt-encoded span/process attributes (e.g., \'service.name="api" http.status_code="500"\')',
|
|
620
459
|
type="string",
|
|
621
460
|
required=True,
|
|
622
461
|
),
|
|
@@ -636,13 +475,15 @@ class SearchTracesByTags(Tool):
|
|
|
636
475
|
required=False,
|
|
637
476
|
),
|
|
638
477
|
"start": ToolParameter(
|
|
639
|
-
description=
|
|
640
|
-
|
|
478
|
+
description=standard_start_datetime_tool_param_description(
|
|
479
|
+
DEFAULT_GRAPH_TIME_SPAN_SECONDS
|
|
480
|
+
),
|
|
481
|
+
type="string",
|
|
641
482
|
required=False,
|
|
642
483
|
),
|
|
643
484
|
"end": ToolParameter(
|
|
644
|
-
description=
|
|
645
|
-
type="
|
|
485
|
+
description=STANDARD_END_DATETIME_TOOL_PARAM_DESCRIPTION,
|
|
486
|
+
type="string",
|
|
646
487
|
required=False,
|
|
647
488
|
),
|
|
648
489
|
"spss": ToolParameter(
|
|
@@ -659,24 +500,26 @@ class SearchTracesByTags(Tool):
|
|
|
659
500
|
) -> StructuredToolResult:
|
|
660
501
|
api = GrafanaTempoAPI(self._toolset.grafana_config, use_post=TEMPO_API_USE_POST)
|
|
661
502
|
|
|
503
|
+
start, end = BaseGrafanaTempoToolset.adjust_start_end_time(params)
|
|
504
|
+
|
|
662
505
|
try:
|
|
663
506
|
result = api.search_traces_by_tags(
|
|
664
507
|
tags=params["tags"],
|
|
665
508
|
min_duration=params.get("min_duration"),
|
|
666
509
|
max_duration=params.get("max_duration"),
|
|
667
510
|
limit=params.get("limit"),
|
|
668
|
-
start=
|
|
669
|
-
end=
|
|
511
|
+
start=start,
|
|
512
|
+
end=end,
|
|
670
513
|
spss=params.get("spss"),
|
|
671
514
|
)
|
|
672
515
|
return StructuredToolResult(
|
|
673
|
-
status=
|
|
516
|
+
status=StructuredToolResultStatus.SUCCESS,
|
|
674
517
|
data=yaml.dump(result, default_flow_style=False),
|
|
675
518
|
params=params,
|
|
676
519
|
)
|
|
677
520
|
except Exception as e:
|
|
678
521
|
return StructuredToolResult(
|
|
679
|
-
status=
|
|
522
|
+
status=StructuredToolResultStatus.ERROR,
|
|
680
523
|
error=str(e),
|
|
681
524
|
params=params,
|
|
682
525
|
)
|
|
@@ -688,7 +531,7 @@ class SearchTracesByTags(Tool):
|
|
|
688
531
|
class QueryTraceById(Tool):
|
|
689
532
|
def __init__(self, toolset: BaseGrafanaTempoToolset):
|
|
690
533
|
super().__init__(
|
|
691
|
-
name="
|
|
534
|
+
name="tempo_query_trace_by_id",
|
|
692
535
|
description=(
|
|
693
536
|
"Retrieve detailed trace information by trace ID. "
|
|
694
537
|
"Uses the Tempo API endpoint: GET /api/v2/traces/{trace_id}. "
|
|
@@ -701,13 +544,15 @@ class QueryTraceById(Tool):
|
|
|
701
544
|
required=True,
|
|
702
545
|
),
|
|
703
546
|
"start": ToolParameter(
|
|
704
|
-
description=
|
|
705
|
-
|
|
547
|
+
description=standard_start_datetime_tool_param_description(
|
|
548
|
+
DEFAULT_GRAPH_TIME_SPAN_SECONDS
|
|
549
|
+
),
|
|
550
|
+
type="string",
|
|
706
551
|
required=False,
|
|
707
552
|
),
|
|
708
553
|
"end": ToolParameter(
|
|
709
|
-
description=
|
|
710
|
-
type="
|
|
554
|
+
description=STANDARD_END_DATETIME_TOOL_PARAM_DESCRIPTION,
|
|
555
|
+
type="string",
|
|
711
556
|
required=False,
|
|
712
557
|
),
|
|
713
558
|
},
|
|
@@ -719,22 +564,24 @@ class QueryTraceById(Tool):
|
|
|
719
564
|
) -> StructuredToolResult:
|
|
720
565
|
api = GrafanaTempoAPI(self._toolset.grafana_config, use_post=TEMPO_API_USE_POST)
|
|
721
566
|
|
|
567
|
+
start, end = BaseGrafanaTempoToolset.adjust_start_end_time(params)
|
|
568
|
+
|
|
722
569
|
try:
|
|
723
570
|
trace_data = api.query_trace_by_id_v2(
|
|
724
571
|
trace_id=params["trace_id"],
|
|
725
|
-
start=
|
|
726
|
-
end=
|
|
572
|
+
start=start,
|
|
573
|
+
end=end,
|
|
727
574
|
)
|
|
728
575
|
|
|
729
576
|
# Return raw trace data as YAML for readability
|
|
730
577
|
return StructuredToolResult(
|
|
731
|
-
status=
|
|
578
|
+
status=StructuredToolResultStatus.SUCCESS,
|
|
732
579
|
data=yaml.dump(trace_data, default_flow_style=False),
|
|
733
580
|
params=params,
|
|
734
581
|
)
|
|
735
582
|
except Exception as e:
|
|
736
583
|
return StructuredToolResult(
|
|
737
|
-
status=
|
|
584
|
+
status=StructuredToolResultStatus.ERROR,
|
|
738
585
|
error=str(e),
|
|
739
586
|
params=params,
|
|
740
587
|
)
|
|
@@ -746,7 +593,7 @@ class QueryTraceById(Tool):
|
|
|
746
593
|
class SearchTagNames(Tool):
|
|
747
594
|
def __init__(self, toolset: BaseGrafanaTempoToolset):
|
|
748
595
|
super().__init__(
|
|
749
|
-
name="
|
|
596
|
+
name="tempo_search_tag_names",
|
|
750
597
|
description=(
|
|
751
598
|
"Discover available tag names across traces. "
|
|
752
599
|
"Uses the Tempo API endpoint: GET /api/v2/search/tags. "
|
|
@@ -764,13 +611,15 @@ class SearchTagNames(Tool):
|
|
|
764
611
|
required=False,
|
|
765
612
|
),
|
|
766
613
|
"start": ToolParameter(
|
|
767
|
-
description=
|
|
768
|
-
|
|
614
|
+
description=standard_start_datetime_tool_param_description(
|
|
615
|
+
DEFAULT_GRAPH_TIME_SPAN_SECONDS
|
|
616
|
+
),
|
|
617
|
+
type="string",
|
|
769
618
|
required=False,
|
|
770
619
|
),
|
|
771
620
|
"end": ToolParameter(
|
|
772
|
-
description=
|
|
773
|
-
type="
|
|
621
|
+
description=STANDARD_END_DATETIME_TOOL_PARAM_DESCRIPTION,
|
|
622
|
+
type="string",
|
|
774
623
|
required=False,
|
|
775
624
|
),
|
|
776
625
|
"limit": ToolParameter(
|
|
@@ -792,23 +641,25 @@ class SearchTagNames(Tool):
|
|
|
792
641
|
) -> StructuredToolResult:
|
|
793
642
|
api = GrafanaTempoAPI(self._toolset.grafana_config, use_post=TEMPO_API_USE_POST)
|
|
794
643
|
|
|
644
|
+
start, end = BaseGrafanaTempoToolset.adjust_start_end_time(params)
|
|
645
|
+
|
|
795
646
|
try:
|
|
796
647
|
result = api.search_tag_names_v2(
|
|
797
648
|
scope=params.get("scope"),
|
|
798
649
|
q=params.get("q"),
|
|
799
|
-
start=
|
|
800
|
-
end=
|
|
650
|
+
start=start,
|
|
651
|
+
end=end,
|
|
801
652
|
limit=params.get("limit"),
|
|
802
653
|
max_stale_values=params.get("max_stale_values"),
|
|
803
654
|
)
|
|
804
655
|
return StructuredToolResult(
|
|
805
|
-
status=
|
|
656
|
+
status=StructuredToolResultStatus.SUCCESS,
|
|
806
657
|
data=yaml.dump(result, default_flow_style=False),
|
|
807
658
|
params=params,
|
|
808
659
|
)
|
|
809
660
|
except Exception as e:
|
|
810
661
|
return StructuredToolResult(
|
|
811
|
-
status=
|
|
662
|
+
status=StructuredToolResultStatus.ERROR,
|
|
812
663
|
error=str(e),
|
|
813
664
|
params=params,
|
|
814
665
|
)
|
|
@@ -820,7 +671,7 @@ class SearchTagNames(Tool):
|
|
|
820
671
|
class SearchTagValues(Tool):
|
|
821
672
|
def __init__(self, toolset: BaseGrafanaTempoToolset):
|
|
822
673
|
super().__init__(
|
|
823
|
-
name="
|
|
674
|
+
name="tempo_search_tag_values",
|
|
824
675
|
description=(
|
|
825
676
|
"Get all values for a specific tag. "
|
|
826
677
|
"Uses the Tempo API endpoint: GET /api/v2/search/tag/{tag}/values. "
|
|
@@ -838,13 +689,15 @@ class SearchTagValues(Tool):
|
|
|
838
689
|
required=False,
|
|
839
690
|
),
|
|
840
691
|
"start": ToolParameter(
|
|
841
|
-
description=
|
|
842
|
-
|
|
692
|
+
description=standard_start_datetime_tool_param_description(
|
|
693
|
+
DEFAULT_GRAPH_TIME_SPAN_SECONDS
|
|
694
|
+
),
|
|
695
|
+
type="string",
|
|
843
696
|
required=False,
|
|
844
697
|
),
|
|
845
698
|
"end": ToolParameter(
|
|
846
|
-
description=
|
|
847
|
-
type="
|
|
699
|
+
description=STANDARD_END_DATETIME_TOOL_PARAM_DESCRIPTION,
|
|
700
|
+
type="string",
|
|
848
701
|
required=False,
|
|
849
702
|
),
|
|
850
703
|
"limit": ToolParameter(
|
|
@@ -866,23 +719,25 @@ class SearchTagValues(Tool):
|
|
|
866
719
|
) -> StructuredToolResult:
|
|
867
720
|
api = GrafanaTempoAPI(self._toolset.grafana_config, use_post=TEMPO_API_USE_POST)
|
|
868
721
|
|
|
722
|
+
start, end = BaseGrafanaTempoToolset.adjust_start_end_time(params)
|
|
723
|
+
|
|
869
724
|
try:
|
|
870
725
|
result = api.search_tag_values_v2(
|
|
871
726
|
tag=params["tag"],
|
|
872
727
|
q=params.get("q"),
|
|
873
|
-
start=
|
|
874
|
-
end=
|
|
728
|
+
start=start,
|
|
729
|
+
end=end,
|
|
875
730
|
limit=params.get("limit"),
|
|
876
731
|
max_stale_values=params.get("max_stale_values"),
|
|
877
732
|
)
|
|
878
733
|
return StructuredToolResult(
|
|
879
|
-
status=
|
|
734
|
+
status=StructuredToolResultStatus.SUCCESS,
|
|
880
735
|
data=yaml.dump(result, default_flow_style=False),
|
|
881
736
|
params=params,
|
|
882
737
|
)
|
|
883
738
|
except Exception as e:
|
|
884
739
|
return StructuredToolResult(
|
|
885
|
-
status=
|
|
740
|
+
status=StructuredToolResultStatus.ERROR,
|
|
886
741
|
error=str(e),
|
|
887
742
|
params=params,
|
|
888
743
|
)
|
|
@@ -894,7 +749,7 @@ class SearchTagValues(Tool):
|
|
|
894
749
|
class QueryMetricsInstant(Tool):
|
|
895
750
|
def __init__(self, toolset: BaseGrafanaTempoToolset):
|
|
896
751
|
super().__init__(
|
|
897
|
-
name="
|
|
752
|
+
name="tempo_query_metrics_instant",
|
|
898
753
|
description=(
|
|
899
754
|
"Compute a single TraceQL metric value across time range. "
|
|
900
755
|
"Uses the Tempo API endpoint: GET /api/metrics/query. "
|
|
@@ -924,17 +779,14 @@ class QueryMetricsInstant(Tool):
|
|
|
924
779
|
required=True,
|
|
925
780
|
),
|
|
926
781
|
"start": ToolParameter(
|
|
927
|
-
description=
|
|
782
|
+
description=standard_start_datetime_tool_param_description(
|
|
783
|
+
DEFAULT_GRAPH_TIME_SPAN_SECONDS
|
|
784
|
+
),
|
|
928
785
|
type="string",
|
|
929
786
|
required=False,
|
|
930
787
|
),
|
|
931
788
|
"end": ToolParameter(
|
|
932
|
-
description=
|
|
933
|
-
type="string",
|
|
934
|
-
required=False,
|
|
935
|
-
),
|
|
936
|
-
"since": ToolParameter(
|
|
937
|
-
description="Duration string (e.g., '1h', '30m')",
|
|
789
|
+
description=STANDARD_END_DATETIME_TOOL_PARAM_DESCRIPTION,
|
|
938
790
|
type="string",
|
|
939
791
|
required=False,
|
|
940
792
|
),
|
|
@@ -947,21 +799,22 @@ class QueryMetricsInstant(Tool):
|
|
|
947
799
|
) -> StructuredToolResult:
|
|
948
800
|
api = GrafanaTempoAPI(self._toolset.grafana_config, use_post=TEMPO_API_USE_POST)
|
|
949
801
|
|
|
802
|
+
start, end = BaseGrafanaTempoToolset.adjust_start_end_time(params)
|
|
803
|
+
|
|
950
804
|
try:
|
|
951
805
|
result = api.query_metrics_instant(
|
|
952
806
|
q=params["q"],
|
|
953
|
-
start=
|
|
954
|
-
end=
|
|
955
|
-
since=params.get("since"),
|
|
807
|
+
start=start,
|
|
808
|
+
end=end,
|
|
956
809
|
)
|
|
957
810
|
return StructuredToolResult(
|
|
958
|
-
status=
|
|
811
|
+
status=StructuredToolResultStatus.SUCCESS,
|
|
959
812
|
data=yaml.dump(result, default_flow_style=False),
|
|
960
813
|
params=params,
|
|
961
814
|
)
|
|
962
815
|
except Exception as e:
|
|
963
816
|
return StructuredToolResult(
|
|
964
|
-
status=
|
|
817
|
+
status=StructuredToolResultStatus.ERROR,
|
|
965
818
|
error=str(e),
|
|
966
819
|
params=params,
|
|
967
820
|
)
|
|
@@ -975,7 +828,7 @@ class QueryMetricsInstant(Tool):
|
|
|
975
828
|
class QueryMetricsRange(Tool):
|
|
976
829
|
def __init__(self, toolset: BaseGrafanaTempoToolset):
|
|
977
830
|
super().__init__(
|
|
978
|
-
name="
|
|
831
|
+
name="tempo_query_metrics_range",
|
|
979
832
|
description=(
|
|
980
833
|
"Get time series data from TraceQL metrics queries. "
|
|
981
834
|
"Uses the Tempo API endpoint: GET /api/metrics/query_range. "
|
|
@@ -1007,17 +860,14 @@ class QueryMetricsRange(Tool):
|
|
|
1007
860
|
required=False,
|
|
1008
861
|
),
|
|
1009
862
|
"start": ToolParameter(
|
|
1010
|
-
description=
|
|
863
|
+
description=standard_start_datetime_tool_param_description(
|
|
864
|
+
DEFAULT_GRAPH_TIME_SPAN_SECONDS
|
|
865
|
+
),
|
|
1011
866
|
type="string",
|
|
1012
867
|
required=False,
|
|
1013
868
|
),
|
|
1014
869
|
"end": ToolParameter(
|
|
1015
|
-
description=
|
|
1016
|
-
type="string",
|
|
1017
|
-
required=False,
|
|
1018
|
-
),
|
|
1019
|
-
"since": ToolParameter(
|
|
1020
|
-
description="Duration string (e.g., '3h', '1d')",
|
|
870
|
+
description=STANDARD_END_DATETIME_TOOL_PARAM_DESCRIPTION,
|
|
1021
871
|
type="string",
|
|
1022
872
|
required=False,
|
|
1023
873
|
),
|
|
@@ -1035,23 +885,34 @@ class QueryMetricsRange(Tool):
|
|
|
1035
885
|
) -> StructuredToolResult:
|
|
1036
886
|
api = GrafanaTempoAPI(self._toolset.grafana_config, use_post=TEMPO_API_USE_POST)
|
|
1037
887
|
|
|
888
|
+
start, end = BaseGrafanaTempoToolset.adjust_start_end_time(params)
|
|
889
|
+
|
|
890
|
+
# Calculate appropriate step
|
|
891
|
+
step_param = params.get("step")
|
|
892
|
+
step_seconds = duration_string_to_seconds(step_param) if step_param else None
|
|
893
|
+
adjusted_step = adjust_step_for_max_points(
|
|
894
|
+
end - start,
|
|
895
|
+
int(MAX_GRAPH_POINTS),
|
|
896
|
+
step_seconds,
|
|
897
|
+
)
|
|
898
|
+
step = seconds_to_duration_string(adjusted_step)
|
|
899
|
+
|
|
1038
900
|
try:
|
|
1039
901
|
result = api.query_metrics_range(
|
|
1040
902
|
q=params["q"],
|
|
1041
|
-
step=
|
|
1042
|
-
start=
|
|
1043
|
-
end=
|
|
1044
|
-
since=params.get("since"),
|
|
903
|
+
step=step,
|
|
904
|
+
start=start,
|
|
905
|
+
end=end,
|
|
1045
906
|
exemplars=params.get("exemplars"),
|
|
1046
907
|
)
|
|
1047
908
|
return StructuredToolResult(
|
|
1048
|
-
status=
|
|
909
|
+
status=StructuredToolResultStatus.SUCCESS,
|
|
1049
910
|
data=yaml.dump(result, default_flow_style=False),
|
|
1050
911
|
params=params,
|
|
1051
912
|
)
|
|
1052
913
|
except Exception as e:
|
|
1053
914
|
return StructuredToolResult(
|
|
1054
|
-
status=
|
|
915
|
+
status=StructuredToolResultStatus.ERROR,
|
|
1055
916
|
error=str(e),
|
|
1056
917
|
params=params,
|
|
1057
918
|
)
|
|
@@ -1069,9 +930,6 @@ class GrafanaTempoToolset(BaseGrafanaTempoToolset):
|
|
|
1069
930
|
docs_url="https://holmesgpt.dev/data-sources/builtin-toolsets/grafanatempo/",
|
|
1070
931
|
tools=[
|
|
1071
932
|
FetchTracesSimpleComparison(self),
|
|
1072
|
-
# GetTempoTraces(self),
|
|
1073
|
-
# GetTempoTraceById(self),
|
|
1074
|
-
# GetTempoTags(self),
|
|
1075
933
|
SearchTracesByQuery(self),
|
|
1076
934
|
SearchTracesByTags(self),
|
|
1077
935
|
QueryTraceById(self),
|