Multi-Cloud Manager provides unified log management across Azure and GCP. Query logs using native query languages (KQL for Azure, LQL for GCP), export to CSV, and analyze log data to troubleshoot issues and gain insights.
Query VM heartbeat data to verify connectivity and health:
# From log_analytics.py:335-340Heartbeat| where Computer == 'vm-name'| top 500 by TimeGenerated desc| project TimeGenerated, Computer, Category, OSType, OSName, Version, ResourceId
# From log_analytics.py:324-333Perf| where Computer == 'vm-name'| where CounterName == '% Processor Time' or CounterName == 'Available MBytes Memory'| where InstanceName == '_Total' or InstanceName == 'Memory' or InstanceName == 'total'| summarize AverageValue = avg(CounterValue) by TimeGenerated, CounterName| order by TimeGenerated desc| top 500 by TimeGenerated
Key Counters:
% Processor Time: CPU utilization percentage
Available MBytes Memory: Available physical memory
# From log_analytics.py:384-401POST /api/azure/vm/{vm_name}/logs/queryContent-Type: application/json{ "workspaceGuid": "12345678-1234-1234-1234-123456789abc", "kqlQuery": "Heartbeat | where Computer == 'vm-name' | top 10 by TimeGenerated desc"}
Security validation:
# From log_analytics.py:396-401dangerous_keywords = ['delete', 'update', 'modify', 'insert', 'drop']if any(keyword in kql_query.lower() for keyword in dangerous_keywords): return jsonify({"error": "Zapytanie zawiera niedozwolone słowa kluczowe"}), 400if f"Computer == '{vm_id}'" not in kql_query: return jsonify({"error": f"Zapytanie musi zawierać filtr 'where Computer == \"{vm_id}\"'"}), 400
All queries must filter by the specific VM to prevent unauthorized data access.
# From containermonitor.py:196-201ContainerInstanceLog_CL| where ContainerGroup_s == 'container-group-name'| top 500 by TimeGenerated desc
Validation ensures container-specific filtering:
# From containermonitor.py:252-253if f"ContainerGroup_s == '{container_group_name}'" not in kql_query: return jsonify({"error": "Zapytanie musi zawierać filtr container-specific"}), 400
# From vmmonitor.py:306-376POST /api/gcp/vm/{project_id}/{instance_id}/logs/queryContent-Type: application/json{ "lqlQuery": "resource.type=\"gce_instance\" resource.labels.instance_id=\"1234567890\" severity>=ERROR"}
Common LQL Filters:
# Filter by resource type and instanceresource.type="gce_instance"resource.labels.instance_id="1234567890"# Filter by severityseverity>=ERRORseverity=INFO# Filter by timestamptimestamp>="2024-01-15T00:00:00Z"# Filter by log namelogName="projects/my-project/logs/syslog"
Required filters:
# From vmmonitor.py:324-326instance_filter = f'resource.labels.instance_id="{instance_id}"'if instance_filter not in lql_query: return jsonify({"error": f"Zapytanie LQL musi zawierać filtr: {instance_filter}"}), 400
# From containermonitor.py:192-255POST /api/gcp/container/{project_id}/{service_name}/logs/queryContent-Type: application/json{ "lqlQuery": "resource.type=\"cloud_run_revision\" resource.labels.service_name=\"my-service\" severity>=WARNING"}
Required filter:
# From containermonitor.py:208-210service_filter = f'resource.labels.service_name="{container_name}"'if service_filter not in lql_query: return jsonify({"error": "Zapytanie LQL musi zawierać filtr service_name"}), 400
GET /api/gcp/container/{container_name}/logs/export?workspaceGuid={guid}&hours=1&type=container
# From containermonitor.py:177-235query = f"""ContainerInstanceLog_CL| where ContainerGroup_s == '{container_group_name}'| top 500 by TimeGenerated desc"""response = client.query_workspace( workspace_id=workspace_guid, query=query, timespan=timedelta(hours=timespan_hours))
Syslog| where Computer == 'vm-name'| where SeverityLevel == "err" or SeverityLevel == "crit"| project TimeGenerated, Facility, SeverityLevel, SyslogMessage| order by TimeGenerated desc