1313# See the License for the specific language governing permissions and
1414# limitations under the License.
1515#
16- import json
1716from contextvars import ContextVar
1817from typing import (
1918 List ,
3433
3534from dataclasses import dataclass , asdict , field
3635
37- from starlette .datastructures import URL
3836from starlette .middleware .base import BaseHTTPMiddleware , RequestResponseEndpoint
3937from starlette .requests import Request
4038
5553from sqlglot import expressions
5654from mcp .server .auth .middleware .auth_context import get_access_token
5755from mcp .server .auth .provider import AccessToken
56+ from dremioai .metrics .tool_metrics import invocation_counter , invocation_duration
5857
5958logger = log .logger (__name__ )
6059
@@ -158,6 +157,23 @@ async def _impl(self, *args: P.args, **kw: P.kwargs) -> T:
158157 return _impl
159158
160159
160+ def with_metrics (fn : Callable [P , Awaitable [T ]]) -> Callable [P , Awaitable [T ]]:
161+ @functools .wraps (fn )
162+ async def _impl (self , * args : P .args , ** kw : P .kwargs ) -> T :
163+ project_id = None
164+ if dremio := settings .instance ().dremio :
165+ project_id = dremio .project_id
166+ invocation_counter .labels (
167+ project_id = project_id , tool = self .__class__ .__name__
168+ ).inc ()
169+ with invocation_duration .labels (
170+ project_id = project_id , tool = self .__class__ .__name__
171+ ).time ():
172+ return await fn (self , * args , ** kw )
173+
174+ return _impl
175+
176+
161177def _get_class_var_hints (tool : Tools , name : str ) -> bool :
162178 if class_var := get_type_hints (tool , include_extras = True ).get (name ):
163179 if cls_args := get_args (class_var ):
@@ -193,6 +209,7 @@ def group_by(self, df, by):
193209 return df .groupby (by ).size ().reset_index (name = "count" ).to_dict (orient = "records" )
194210
195211 @secured
212+ @with_metrics
196213 async def invoke (self ) -> Dict [str , Any ]:
197214 """Get the stats and details of failed or canceled jobs executed in the Dremio cluster in the past 7 days
198215 along with a split by job type
@@ -303,6 +320,7 @@ def ensure_query_allowed(s: str):
303320 )
304321
305322 @secured
323+ @with_metrics
306324 async def invoke (self , s : str ) -> Dict [str , Union [List [Dict [Any , Any ]] | str ]]:
307325 """Run a SELECT sql query on the Dremio cluster and return the results.
308326 Ensure that SQL keywords like 'day', 'month', 'count', 'table' etc are enclosed in double quotes
@@ -328,6 +346,7 @@ class BuildUsageReport(Tools):
328346 project_id_required : ClassVar [Annotated [bool , True ]]
329347
330348 @secured
349+ @with_metrics
331350 async def invoke (
332351 self , by : Optional [Literal ["PROJECT" , "ENGINE" ]] = "ENGINE"
333352 ) -> Dict [str , Any ]:
@@ -391,6 +410,7 @@ class GetSchemaOfTable(Tools):
391410 For : ClassVar [Annotated [ToolType , ToolType .FOR_SELF | ToolType .FOR_DATA_PATTERNS ]]
392411
393412 @secured
413+ @with_metrics
394414 async def invoke (self , table_name : Union [str | List [str ]]) -> Dict [str , Any ]:
395415 """Gets the schema of the given table.
396416
@@ -416,6 +436,7 @@ class GetTableOrViewLineage(Tools):
416436 For : ClassVar [Annotated [ToolType , ToolType .FOR_SELF | ToolType .FOR_DATA_PATTERNS ]]
417437
418438 @secured
439+ @with_metrics
419440 async def invoke (self , table_name : Union [str , List [str ]]) -> Dict [str , Any ]:
420441 """Finds the lineage of a table or view in the Dremio cluster
421442
@@ -437,6 +458,7 @@ class SearchTableAndViews(Tools):
437458 ]
438459
439460 @secured
461+ @with_metrics
440462 async def invoke (self , query : str ) -> Dict [str , Any ]:
441463 """Runs a semantic search on the Dremio cluster to find tables and views that match the query.
442464
0 commit comments