Skip to content

Commit

Permalink
Merge branch 'main' into fix/incident-overview
Browse files Browse the repository at this point in the history
  • Loading branch information
talboren authored Feb 13, 2025
2 parents a731ac5 + c6173cb commit 54cc7fd
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 1 deletion.
2 changes: 1 addition & 1 deletion keep/api/tasks/process_event_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def __internal_prepartion(
logger.exception(
"failed to parse source",
extra={
"alert": alert.dict(),
"alert": alerts,
},
)
raise
Expand Down
102 changes: 102 additions & 0 deletions keep/providers/mailgun_provider/mailgun_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,108 @@ def validate_config(self):
def dispose(self):
pass

@staticmethod
def parse_event_raw_body(raw_body: bytes | dict) -> dict:
"""
Parse the raw body of a Mailgun webhook event and create an ingestable dict.
Args:
raw_body (bytes | dict): The raw body from the webhook
Returns:
dict: Parsed event data in a format compatible with _format_alert
"""
if not isinstance(raw_body, bytes):
return raw_body

logging.getLogger(__name__).info("Parsing Mail Body")
try:
# Use latin1 as it can handle any byte sequence
content = raw_body.decode("latin1", errors="replace")
parsed_data = {}

# Try to find body-plain content
if 'Content-Disposition: form-data; name="body-plain"' in content:
logging.getLogger(__name__).info("Mail Body Found")
# Extract body-plain content
parts = content.split(
'Content-Disposition: form-data; name="body-plain"'
)
if len(parts) > 1:
body_content = parts[1].split("\r\n\r\n", 1)[1].split("\r\n--")[0]

# Convert the alert format to Mailgun expected format
parsed_data = {
"subject": "", # Will be populated below
"from": "", # Will be populated from Source
"stripped-text": "", # Will be populated from message content
"timestamp": "", # Will be populated from Opened
}

# Parse the content line by line
for line in body_content.strip().split("\r\n"):
if ":" in line:
key, value = line.split(":", 1)
key = key.strip()
value = value.strip()

# Map the fields to what _format_alert expects
if key == "Summary":
parsed_data["subject"] = value
elif key == "Source":
parsed_data["from"] = value
elif key in ["Alert Status", "Severity"]:
parsed_data[key.lower()] = value
elif key == "Opened":
# Convert the date format to timestamp
try:
dt = datetime.datetime.strptime(
value, "%d %b %Y %H:%M UTC"
)
parsed_data["timestamp"] = str(dt.timestamp())
except ValueError:
parsed_data["timestamp"] = str(
datetime.datetime.now().timestamp()
)

# Combine relevant fields for the message
message_parts = []
for key in [
"Summary",
"Alert Category",
"Service Test",
"Severity",
"Alert Status",
]:
if key in body_content:
for line in body_content.split("\r\n"):
if line.startswith(key + ":"):
message_parts.append(line)

parsed_data["stripped-text"] = "\n".join(message_parts)

# Store the full original content
parsed_data["raw_content"] = body_content
logging.getLogger(__name__).info(
"Mail Body Parsed", extra={"parsed_data": parsed_data}
)
return parsed_data
logging.getLogger(__name__).info("Mail Body Not Found")
return {
"subject": "Unknown Alert",
"from": "system",
"stripped-text": content,
}

except Exception as e:
logging.getLogger(__name__).exception(f"Error parsing webhook body: {e}")
return {
"subject": "Error Processing Alert",
"from": "system",
"stripped-text": "Error processing the alert content",
"timestamp": str(datetime.datetime.now().timestamp()),
}

def setup_webhook(
self, tenant_id: str, keep_api_url: str, api_key: str, setup_alerts: bool = True
) -> dict[str, str]:
Expand Down

0 comments on commit 54cc7fd

Please sign in to comment.