Skip to content

Commit

Permalink
Log events for function calls (#8395)
Browse files Browse the repository at this point in the history
This will let us collect statistics about function usage.

Note that I would've preferred the function ID to go into the `obj_id`
field, but function IDs are strings, and the field is numeric.
  • Loading branch information
SpecLad committed Sep 4, 2024
1 parent f2a5ec3 commit d80a574
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 6 deletions.
4 changes: 4 additions & 0 deletions changelog.d/20240903_155336_roman_function_events.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
### Added

- Added analytics events for function calls
(<https://github.com/cvat-ai/cvat/pull/8395>)
1 change: 1 addition & 0 deletions cvat/apps/events/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class EventScopes:
"annotations": ["create", "update", "delete"],
"label": ["create", "update", "delete"],
"dataset": ["export", "import"],
"function": ["call"],
}

@classmethod
Expand Down
20 changes: 20 additions & 0 deletions cvat/apps/events/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,26 @@ def handle_dataset_import(
) -> None:
handle_dataset_io(instance, "import", format_name=format_name, cloud_storage_id=cloud_storage_id)

def handle_function_call(
function_id: str,
target: Union[Task, Job],
**payload_fields,
) -> None:
record_server_event(
scope=event_scope("call", "function"),
request_id=request_id(),
project_id=project_id(target),
task_id=task_id(target),
job_id=job_id(target),
user_id=user_id(),
user_name=user_name(),
user_email=user_email(),
payload={
"function": {"id": function_id},
**payload_fields,
},
)

def handle_rq_exception(rq_job, exc_type, exc_value, tb):
oid = rq_job.meta.get(RQJobMetaField.ORG_ID, None)
oslug = rq_job.meta.get(RQJobMetaField.ORG_SLUG, None)
Expand Down
29 changes: 23 additions & 6 deletions cvat/apps/lambda_manager/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import numpy as np
import requests
import rq
from cvat.apps.events.handlers import handle_function_call
from cvat.apps.lambda_manager.signals import interactive_function_call_signal
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist, ValidationError
Expand Down Expand Up @@ -131,6 +132,12 @@ def _invoke_directly(self, func, payload):
return response

class LambdaFunction:
FRAME_PARAMETERS = (
('frame', 'frame'),
('frame0', 'start frame'),
('frame1', 'end frame'),
)

def __init__(self, gateway, data):
# ID of the function (e.g. omz.public.yolo-v3)
self.id = data['metadata']['name']
Expand Down Expand Up @@ -372,11 +379,7 @@ def validate_attributes_mapping(attributes_mapping, model_attributes, db_attribu
data_start_frame = task_data.start_frame
step = task_data.get_frame_step()

for key, desc in (
('frame', 'frame'),
('frame0', 'start frame'),
('frame1', 'end frame'),
):
for key, desc in self.FRAME_PARAMETERS:
if key not in data:
continue

Expand Down Expand Up @@ -1083,14 +1086,26 @@ def call(self, request, func_id):
gateway = LambdaGateway()
lambda_func = gateway.get(func_id)

return lambda_func.invoke(
response = lambda_func.invoke(
db_task,
request.data, # TODO: better to add validation via serializer for these data
db_job=job,
is_interactive=True,
request=request
)

handle_function_call(func_id, db_task,
category="interactive",
parameters={
param_name: param_value
for param_name, _ in LambdaFunction.FRAME_PARAMETERS
for param_value in [request.data.get(param_name)]
if param_value is not None
},
)

return response

@extend_schema(tags=['lambda'])
@extend_schema_view(
retrieve=extend_schema(
Expand Down Expand Up @@ -1182,6 +1197,8 @@ def create(self, request):
rq_job = queue.enqueue(lambda_func, threshold, task, quality,
mapping, cleanup, conv_mask_to_poly, max_distance, request, job=job)

handle_function_call(function, job or task, category="batch")

response_serializer = FunctionCallSerializer(rq_job.to_dict())
return response_serializer.data

Expand Down
2 changes: 2 additions & 0 deletions site/content/en/docs/administration/advanced/analytics.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ Server events:

- `export:dataset`, `import:dataset`

- `call:function`

Client events:

- `load:cvat`
Expand Down

0 comments on commit d80a574

Please sign in to comment.