diff --git a/drdroid_debug_toolkit/core/integrations/source_api_processors/render_api_processor.py b/drdroid_debug_toolkit/core/integrations/source_api_processors/render_api_processor.py index 13fe930..ac78b9e 100644 --- a/drdroid_debug_toolkit/core/integrations/source_api_processors/render_api_processor.py +++ b/drdroid_debug_toolkit/core/integrations/source_api_processors/render_api_processor.py @@ -66,7 +66,9 @@ def get_service(self, service_id): logger.error(f"Error getting service {service_id}: {e}") raise Exception(f"Failed to get service: {e}") - def fetch_logs(self, service_id, start_time=None, end_time=None, limit=None): + def fetch_logs(self, service_id, start_time=None, end_time=None, limit=None, + instance=None, host=None, status_code=None, method=None, + task=None, task_run=None, level=None, type=None, text=None, path=None): """Fetch logs for a specific service.""" try: # First, get the service details to extract the ownerId @@ -110,6 +112,28 @@ def fetch_logs(self, service_id, start_time=None, end_time=None, limit=None): if limit: params['limit'] = limit + # Add filter parameters (arrays are passed as lists, requests handles them correctly) + if instance: + params['instance'] = instance if isinstance(instance, list) else [instance] + if host: + params['host'] = host if isinstance(host, list) else [host] + if status_code: + params['statusCode'] = status_code if isinstance(status_code, list) else [status_code] + if method: + params['method'] = method if isinstance(method, list) else [method] + if task: + params['task'] = task if isinstance(task, list) else [task] + if task_run: + params['taskRun'] = task_run if isinstance(task_run, list) else [task_run] + if level: + params['level'] = level if isinstance(level, list) else [level] + if type: + params['type'] = type if isinstance(type, list) else [type] + if text: + params['text'] = text if isinstance(text, list) else [text] + if path: + params['path'] = path if isinstance(path, list) else [path] + response = requests.get(url, headers=self.headers, params=params) response.raise_for_status() return response.json() diff --git a/drdroid_debug_toolkit/core/integrations/source_managers/render_source_manager.py b/drdroid_debug_toolkit/core/integrations/source_managers/render_source_manager.py index 4aa2bbb..1a49626 100644 --- a/drdroid_debug_toolkit/core/integrations/source_managers/render_source_manager.py +++ b/drdroid_debug_toolkit/core/integrations/source_managers/render_source_manager.py @@ -114,10 +114,70 @@ def __init__(self): is_optional=True), FormField(key_name=StringValue(value="limit"), display_name=StringValue(value="Limit"), - description=StringValue(value='Maximum number of log entries to fetch (optional)'), + description=StringValue(value='Maximum number of log entries to fetch (1-100, optional, defaults to 20)'), data_type=LiteralType.LONG, form_field_type=FormFieldType.TEXT_FT, is_optional=True), + FormField(key_name=StringValue(value="instance"), + display_name=StringValue(value="Instance"), + description=StringValue(value='Filter logs by instance ID(s) - array of strings'), + data_type=LiteralType.STRING, + form_field_type=FormFieldType.STRING_ARRAY_FT, + is_optional=True), + FormField(key_name=StringValue(value="host"), + display_name=StringValue(value="Host"), + description=StringValue(value='Filter request logs by host - supports wildcards and regex'), + data_type=LiteralType.STRING, + form_field_type=FormFieldType.STRING_ARRAY_FT, + is_optional=True), + FormField(key_name=StringValue(value="status_code"), + display_name=StringValue(value="Status Code"), + description=StringValue(value='Filter request logs by status code - supports wildcards and regex'), + data_type=LiteralType.STRING, + form_field_type=FormFieldType.STRING_ARRAY_FT, + is_optional=True), + FormField(key_name=StringValue(value="method"), + display_name=StringValue(value="Method"), + description=StringValue(value='Filter request logs by HTTP method (GET, POST, etc.)'), + data_type=LiteralType.STRING, + form_field_type=FormFieldType.STRING_ARRAY_FT, + is_optional=True), + FormField(key_name=StringValue(value="task"), + display_name=StringValue(value="Task"), + description=StringValue(value='Filter logs by task(s)'), + data_type=LiteralType.STRING, + form_field_type=FormFieldType.STRING_ARRAY_FT, + is_optional=True), + FormField(key_name=StringValue(value="task_run"), + display_name=StringValue(value="Task Run"), + description=StringValue(value='Filter logs by task run ID(s)'), + data_type=LiteralType.STRING, + form_field_type=FormFieldType.STRING_ARRAY_FT, + is_optional=True), + FormField(key_name=StringValue(value="level"), + display_name=StringValue(value="Level"), + description=StringValue(value='Filter logs by severity level - supports wildcards and regex'), + data_type=LiteralType.STRING, + form_field_type=FormFieldType.STRING_ARRAY_FT, + is_optional=True), + FormField(key_name=StringValue(value="type"), + display_name=StringValue(value="Type"), + description=StringValue(value='Filter logs by type (app, request, build, etc.)'), + data_type=LiteralType.STRING, + form_field_type=FormFieldType.STRING_ARRAY_FT, + is_optional=True), + FormField(key_name=StringValue(value="text"), + display_name=StringValue(value="Text"), + description=StringValue(value='Filter by log text content - supports wildcards and regex'), + data_type=LiteralType.STRING, + form_field_type=FormFieldType.STRING_ARRAY_FT, + is_optional=True), + FormField(key_name=StringValue(value="path"), + display_name=StringValue(value="Path"), + description=StringValue(value='Filter request logs by path - supports wildcards and regex'), + data_type=LiteralType.STRING, + form_field_type=FormFieldType.STRING_ARRAY_FT, + is_optional=True), ] }, } @@ -367,8 +427,24 @@ def fetch_logs(self, time_range: TimeRange, render_task: Render, connector_proto end_time = task_data.end_time.value if task_data.end_time else None limit = task_data.limit.value if task_data.limit else None + # Extract filter parameters (repeated string fields) + instance = list(task_data.instance) if task_data.instance else None + host = list(task_data.host) if task_data.host else None + status_code = list(task_data.status_code) if task_data.status_code else None + method = list(task_data.method) if task_data.method else None + task = list(task_data.task) if task_data.task else None + task_run = list(task_data.task_run) if task_data.task_run else None + level = list(task_data.level) if task_data.level else None + type = list(task_data.type) if task_data.type else None + text = list(task_data.text) if task_data.text else None + path = list(task_data.path) if task_data.path else None + api_processor = self._get_api_processor(connector_proto) - result = api_processor.fetch_logs(service_id, start_time, end_time, limit) + result = api_processor.fetch_logs( + service_id, start_time, end_time, limit, + instance=instance, host=host, status_code=status_code, method=method, + task=task, task_run=task_run, level=level, type=type, text=text, path=path + ) # Convert result to protobuf struct result_struct = Struct() diff --git a/drdroid_debug_toolkit/core/protos/playbooks/source_task_definitions/render_task.proto b/drdroid_debug_toolkit/core/protos/playbooks/source_task_definitions/render_task.proto index 95d0524..33399cc 100644 --- a/drdroid_debug_toolkit/core/protos/playbooks/source_task_definitions/render_task.proto +++ b/drdroid_debug_toolkit/core/protos/playbooks/source_task_definitions/render_task.proto @@ -26,6 +26,16 @@ message Render { google.protobuf.StringValue start_time = 2; google.protobuf.StringValue end_time = 3; google.protobuf.Int64Value limit = 4; + repeated string instance = 5; + repeated string host = 6; + repeated string status_code = 7; + repeated string method = 8; + repeated string task = 9; + repeated string task_run = 10; + repeated string level = 11; + repeated string type = 12; + repeated string text = 13; + repeated string path = 14; } enum TaskType { diff --git a/drdroid_debug_toolkit/core/protos/playbooks/source_task_definitions/render_task_pb2.py b/drdroid_debug_toolkit/core/protos/playbooks/source_task_definitions/render_task_pb2.py index 5d31e09..2c2854a 100644 --- a/drdroid_debug_toolkit/core/protos/playbooks/source_task_definitions/render_task_pb2.py +++ b/drdroid_debug_toolkit/core/protos/playbooks/source_task_definitions/render_task_pb2.py @@ -25,7 +25,7 @@ from google.protobuf import wrappers_pb2 as google_dot_protobuf_dot_wrappers__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n?core/protos/playbooks/source_task_definitions/render_task.proto\x12\x15\x63ore.protos.playbooks\x1a\x1egoogle/protobuf/wrappers.proto\"\x81\x08\n\x06Render\x12\x34\n\x04type\x18\x01 \x01(\x0e\x32&.core.protos.playbooks.Render.TaskType\x12\x41\n\x0clist_deploys\x18\x02 \x01(\x0b\x32).core.protos.playbooks.Render.ListDeploysH\x00\x12=\n\nget_deploy\x18\x03 \x01(\x0b\x32\'.core.protos.playbooks.Render.GetDeployH\x00\x12\x43\n\rlist_services\x18\x04 \x01(\x0b\x32*.core.protos.playbooks.Render.ListServicesH\x00\x12?\n\x0bget_service\x18\x05 \x01(\x0b\x32(.core.protos.playbooks.Render.GetServiceH\x00\x12=\n\nfetch_logs\x18\x06 \x01(\x0b\x32\'.core.protos.playbooks.Render.FetchLogsH\x00\x1a?\n\x0bListDeploys\x12\x30\n\nservice_id\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x1an\n\tGetDeploy\x12\x30\n\nservice_id\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12/\n\tdeploy_id\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x1a\x44\n\x0cListServices\x12\x34\n\x10include_previews\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.BoolValue\x1a>\n\nGetService\x12\x30\n\nservice_id\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x1a\xcb\x01\n\tFetchLogs\x12\x30\n\nservice_id\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x30\n\nstart_time\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12.\n\x08\x65nd_time\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12*\n\x05limit\x18\x04 \x01(\x0b\x32\x1b.google.protobuf.Int64Value\"m\n\x08TaskType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x10\n\x0cLIST_DEPLOYS\x10\x01\x12\x0e\n\nGET_DEPLOY\x10\x02\x12\x11\n\rLIST_SERVICES\x10\x03\x12\x0f\n\x0bGET_SERVICE\x10\x04\x12\x0e\n\nFETCH_LOGS\x10\x05\x42\x06\n\x04taskb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n?core/protos/playbooks/source_task_definitions/render_task.proto\x12\x15\x63ore.protos.playbooks\x1a\x1egoogle/protobuf/wrappers.proto\"\x9f\t\n\x06Render\x12\x34\n\x04type\x18\x01 \x01(\x0e\x32&.core.protos.playbooks.Render.TaskType\x12\x41\n\x0clist_deploys\x18\x02 \x01(\x0b\x32).core.protos.playbooks.Render.ListDeploysH\x00\x12=\n\nget_deploy\x18\x03 \x01(\x0b\x32\'.core.protos.playbooks.Render.GetDeployH\x00\x12\x43\n\rlist_services\x18\x04 \x01(\x0b\x32*.core.protos.playbooks.Render.ListServicesH\x00\x12?\n\x0bget_service\x18\x05 \x01(\x0b\x32(.core.protos.playbooks.Render.GetServiceH\x00\x12=\n\nfetch_logs\x18\x06 \x01(\x0b\x32\'.core.protos.playbooks.Render.FetchLogsH\x00\x1a?\n\x0bListDeploys\x12\x30\n\nservice_id\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x1an\n\tGetDeploy\x12\x30\n\nservice_id\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12/\n\tdeploy_id\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x1a\x44\n\x0cListServices\x12\x34\n\x10include_previews\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.BoolValue\x1a>\n\nGetService\x12\x30\n\nservice_id\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x1a\xe9\x02\n\tFetchLogs\x12\x30\n\nservice_id\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x30\n\nstart_time\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12.\n\x08\x65nd_time\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12*\n\x05limit\x18\x04 \x01(\x0b\x32\x1b.google.protobuf.Int64Value\x12\x10\n\x08instance\x18\x05 \x03(\t\x12\x0c\n\x04host\x18\x06 \x03(\t\x12\x13\n\x0bstatus_code\x18\x07 \x03(\t\x12\x0e\n\x06method\x18\x08 \x03(\t\x12\x0c\n\x04task\x18\t \x03(\t\x12\x10\n\x08task_run\x18\n \x03(\t\x12\r\n\x05level\x18\x0b \x03(\t\x12\x0c\n\x04type\x18\x0c \x03(\t\x12\x0c\n\x04text\x18\r \x03(\t\x12\x0c\n\x04path\x18\x0e \x03(\t\"m\n\x08TaskType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x10\n\x0cLIST_DEPLOYS\x10\x01\x12\x0e\n\nGET_DEPLOY\x10\x02\x12\x11\n\rLIST_SERVICES\x10\x03\x12\x0f\n\x0bGET_SERVICE\x10\x04\x12\x0e\n\nFETCH_LOGS\x10\x05\x42\x06\n\x04taskb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -33,7 +33,7 @@ if not _descriptor._USE_C_DESCRIPTORS: DESCRIPTOR._loaded_options = None _globals['_RENDER']._serialized_start=123 - _globals['_RENDER']._serialized_end=1148 + _globals['_RENDER']._serialized_end=1306 _globals['_RENDER_LISTDEPLOYS']._serialized_start=514 _globals['_RENDER_LISTDEPLOYS']._serialized_end=577 _globals['_RENDER_GETDEPLOY']._serialized_start=579 @@ -43,7 +43,7 @@ _globals['_RENDER_GETSERVICE']._serialized_start=761 _globals['_RENDER_GETSERVICE']._serialized_end=823 _globals['_RENDER_FETCHLOGS']._serialized_start=826 - _globals['_RENDER_FETCHLOGS']._serialized_end=1029 - _globals['_RENDER_TASKTYPE']._serialized_start=1031 - _globals['_RENDER_TASKTYPE']._serialized_end=1140 + _globals['_RENDER_FETCHLOGS']._serialized_end=1187 + _globals['_RENDER_TASKTYPE']._serialized_start=1189 + _globals['_RENDER_TASKTYPE']._serialized_end=1298 # @@protoc_insertion_point(module_scope) diff --git a/drdroid_debug_toolkit/core/protos/playbooks/source_task_definitions/render_task_pb2.pyi b/drdroid_debug_toolkit/core/protos/playbooks/source_task_definitions/render_task_pb2.pyi index e8d74d1..bb1cad8 100644 --- a/drdroid_debug_toolkit/core/protos/playbooks/source_task_definitions/render_task_pb2.pyi +++ b/drdroid_debug_toolkit/core/protos/playbooks/source_task_definitions/render_task_pb2.pyi @@ -3,7 +3,9 @@ isort:skip_file """ import builtins +import collections.abc import google.protobuf.descriptor +import google.protobuf.internal.containers import google.protobuf.internal.enum_type_wrapper import google.protobuf.message import google.protobuf.wrappers_pb2 @@ -114,6 +116,16 @@ class Render(google.protobuf.message.Message): START_TIME_FIELD_NUMBER: builtins.int END_TIME_FIELD_NUMBER: builtins.int LIMIT_FIELD_NUMBER: builtins.int + INSTANCE_FIELD_NUMBER: builtins.int + HOST_FIELD_NUMBER: builtins.int + STATUS_CODE_FIELD_NUMBER: builtins.int + METHOD_FIELD_NUMBER: builtins.int + TASK_FIELD_NUMBER: builtins.int + TASK_RUN_FIELD_NUMBER: builtins.int + LEVEL_FIELD_NUMBER: builtins.int + TYPE_FIELD_NUMBER: builtins.int + TEXT_FIELD_NUMBER: builtins.int + PATH_FIELD_NUMBER: builtins.int @property def service_id(self) -> google.protobuf.wrappers_pb2.StringValue: ... @property @@ -122,6 +134,26 @@ class Render(google.protobuf.message.Message): def end_time(self) -> google.protobuf.wrappers_pb2.StringValue: ... @property def limit(self) -> google.protobuf.wrappers_pb2.Int64Value: ... + @property + def instance(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ... + @property + def host(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ... + @property + def status_code(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ... + @property + def method(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ... + @property + def task(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ... + @property + def task_run(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ... + @property + def level(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ... + @property + def type(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ... + @property + def text(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ... + @property + def path(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ... def __init__( self, *, @@ -129,9 +161,19 @@ class Render(google.protobuf.message.Message): start_time: google.protobuf.wrappers_pb2.StringValue | None = ..., end_time: google.protobuf.wrappers_pb2.StringValue | None = ..., limit: google.protobuf.wrappers_pb2.Int64Value | None = ..., + instance: collections.abc.Iterable[builtins.str] | None = ..., + host: collections.abc.Iterable[builtins.str] | None = ..., + status_code: collections.abc.Iterable[builtins.str] | None = ..., + method: collections.abc.Iterable[builtins.str] | None = ..., + task: collections.abc.Iterable[builtins.str] | None = ..., + task_run: collections.abc.Iterable[builtins.str] | None = ..., + level: collections.abc.Iterable[builtins.str] | None = ..., + type: collections.abc.Iterable[builtins.str] | None = ..., + text: collections.abc.Iterable[builtins.str] | None = ..., + path: collections.abc.Iterable[builtins.str] | None = ..., ) -> None: ... def HasField(self, field_name: typing_extensions.Literal["end_time", b"end_time", "limit", b"limit", "service_id", b"service_id", "start_time", b"start_time"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["end_time", b"end_time", "limit", b"limit", "service_id", b"service_id", "start_time", b"start_time"]) -> None: ... + def ClearField(self, field_name: typing_extensions.Literal["end_time", b"end_time", "host", b"host", "instance", b"instance", "level", b"level", "limit", b"limit", "method", b"method", "path", b"path", "service_id", b"service_id", "start_time", b"start_time", "status_code", b"status_code", "task", b"task", "task_run", b"task_run", "text", b"text", "type", b"type"]) -> None: ... TYPE_FIELD_NUMBER: builtins.int LIST_DEPLOYS_FIELD_NUMBER: builtins.int