DiagnoseSyslogCollector
Diagnoses why the syslog collector on a specified Broker VM is failing by checking broker status and collection_auditing logs.
python · Core
Source
import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 def diagnose_syslog_collector(broker_vm_name: str, timeframe: str) -> CommandResults: """ Diagnoses why the syslog collector on a specified Broker VM is failing. This function performs the following checks: 1. Calls core-list-brokers to get broker information 2. Checks if the Syslog Collector app is present and has "Active" status 3. If collector is valid, queries collection_auditing for errors/warnings using core-xql-generic-query-platform Args: broker_vm_name (str): The name of the Broker VM to diagnose. timeframe (str): Timeframe for error checking (default: "24 hours") Returns: CommandResults: Object containing the diagnostic results. """ default_limit = 10 demisto.debug(f"Starting syslog collector diagnosis for broker: {broker_vm_name}") # Get basic broker information broker_result = demisto.executeCommand("core-list-brokers", {"broker_vm_names": broker_vm_name}) if is_error(broker_result) or not broker_result or not isinstance(broker_result, list): if is_error(broker_result): demisto.debug(f"Error retrieving broker information: {get_error(broker_result)}") raise DemistoException("Failed to retrieve broker information: Internal Error.") broker_data_list = broker_result[0].get("Contents", []) if not broker_data_list or not isinstance(broker_data_list, list): raise DemistoException(f"Broker VM '{broker_vm_name}' not found") broker_data = broker_data_list[0] demisto.debug(f"Found broker data: {broker_data}") # Check if Syslog Collector app exists and is active apps = broker_data.get("APPS", []) syslog_collector = None for app in apps: if app.get("display_name") == "Syslog Collector": syslog_collector = app break # Build diagnosis report diagnosis_report = [] if not syslog_collector: status = "ERROR" diagnosis_report.append(f"The Syslog Collector app is not configured on broker '{broker_vm_name}'") else: collector_status = syslog_collector.get("status", "").lower() if collector_status != "active": status = "ERROR" diagnosis_report.append(f"Syslog Collector status is '{collector_status}' (expected 'active')") # Extract additional information from the reasons field reasons = syslog_collector.get("reasons", {}) if reasons: errors = reasons.get("errors", []) warnings = reasons.get("warnings", []) # Add errors to diagnosis report for error in errors: if error: diagnosis_report.append(f"[ERROR] {error}") # Add warnings to diagnosis report for warning in warnings: if warning: diagnosis_report.append(f"[WARNING] {warning}") else: # Step 3: Collector is active, check for errors in collection_auditing demisto.debug("Syslog Collector is active, checking for errors in collection_auditing") xql_query = f""" dataset = collection_auditing | filter collector_type = "Syslog Collector" and _broker_device_name = "{broker_vm_name}" and classification in ("ERROR", "WARNING") | fields _time, classification, description | limit {default_limit} """ try: # Call core-xql-generic-query-platform xql_args = { "query": xql_query, "timeframe": timeframe, "wait_for_results": "true", } demisto.debug(f"Executing XQL query with args: {xql_args}") xql_result = demisto.executeCommand("core-xql-generic-query-platform", xql_args) demisto.debug(f"XQL query result: {xql_result}") if is_error(xql_result) or not xql_result or not isinstance(xql_result, list) or len(xql_result) == 0: if is_error(xql_result): demisto.debug(f"XQL query failed: {get_error(xql_result)}") raise DemistoException("Failed to execute XQL query") xql_outputs = xql_result[0].get("Contents", {}) demisto.debug(f"XQL outputs: {xql_outputs}") query_status = xql_outputs.get("status") errors_found = xql_outputs.get("results", []) demisto.debug(f"XQL Query finished with status={query_status}, found {len(errors_found)} Syslog errors.") if query_status == "SUCCESS": if errors_found: status = "WARNING" # Deduplicate errors by description seen_descriptions = set() for error in errors_found: error_desc = error.get("description", "") if error_desc and error_desc not in seen_descriptions: seen_descriptions.add(error_desc) classification = error.get("classification", "UNKNOWN") timestamp = error.get("_time", "") diagnosis_report.append(f"[{timestamp}][{classification}] {error_desc}") else: status = "HEALTHY" diagnosis_report.append(f"Syslog Collector is active with no errors in the last {timeframe}") else: status = "ERROR" error_details = xql_outputs.get("error_details") raise DemistoException(error_details) except Exception as e: raise DemistoException(f"Internal error while trying to query collection_auditing. {str(e)}") # Final output with only status and diagnosis_report diagnostics = { "status": status, "diagnosis_report": diagnosis_report, } readable_output = tableToMarkdown( f"Syslog Collector Diagnostics for {broker_vm_name}", diagnostics, headerTransform=string_to_table_header, ) return CommandResults( readable_output=readable_output, outputs_prefix="Core.SyslogCollectorDiagnostics", outputs_key_field="status", outputs=diagnostics, ) def main(): args = demisto.args() broker_vm_name = args.get("broker_vm_name") timeframe = args.get("timeframe", "24 hours") if not broker_vm_name: return_error("Broker VM name is required for diagnosing the syslog collector.") try: return_results(diagnose_syslog_collector(broker_vm_name, timeframe)) except Exception as e: error_msg = str(e) if str(e) else repr(e) demisto.error(f"DiagnoseSyslogCollector script failed: {error_msg}\n{traceback.format_exc()}") return_error(f"Failed to execute DiagnoseSyslogCollector script.\nError: {error_msg}") if __name__ in ("__main__", "__builtin__", "builtins"): main()