Skip to content

Commit

Permalink
feat: added rollbar provider (#1177)
Browse files Browse the repository at this point in the history
Co-authored-by: Tal <[email protected]>
  • Loading branch information
ezhil56x and talboren authored May 16, 2024
1 parent 680f057 commit 0f06d07
Show file tree
Hide file tree
Showing 5 changed files with 256 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ Workflow triggers can either be executed manually when an alert is activated or
<img width=32 height=32 src="https://github.com/keephq/keep/blob/main/keep-ui/public/icons/statuscake-icon.png?raw=true"/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<img width=32 height=32 src="https://github.com/keephq/keep/blob/main/keep-ui/public/icons/uptimekuma-icon.png?raw=true"/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<img width=32 height=32 src="https://github.com/keephq/keep/blob/main/keep-ui/public/icons/rollbar-icon.png?raw=true"/>
</p>
<h3 align="center">Ticketing tools</h2>
<p align="center">
Expand Down
1 change: 1 addition & 0 deletions docs/mint.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
"providers/documentation/pushover-provider",
"providers/documentation/redmine-provider",
"providers/documentation/resend-provider",
"providers/documentation/rollbar-provider",
"providers/documentation/sentry-provider",
"providers/documentation/signalfx-provider",
"providers/documentation/signl4-provider",
Expand Down
23 changes: 23 additions & 0 deletions docs/providers/documentation/rollbar-provider.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
title: 'Rollbar'
sidebarTitle: 'Rollbar Provider'
description: 'Rollbar provides real-time error tracking and debugging tools for developers.'
---

## Authentication Parameters

The Rollbar provider requires the following authentication parameters:

- `rollbarAccessToken` - Project Access Token is used to authenticate the Rollbar API requests.

## Connecting with the Provider

1. Create an account on [Rollbar](https://rollbar.com/).
2. After logging in, navigate to the project you want to connect with and go to the project settings.
3. Under Setup, go to Project Access Tokens and create new token with read and write scopes.
4. Copy the generated token.
5. This will be used as the `rollbarAccessToken` parameter in the provider configuration.

## Usefull Links

- [Rollbar](https://rollbar.com/)
Binary file added keep-ui/public/icons/rollbar-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
230 changes: 230 additions & 0 deletions keep/providers/rollbar_provider/rollbar_provider.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
"""
RollbarProvider is a class that allows to install webhooks and get alerts in Rollbar.
"""

import dataclasses
import pydantic

import datetime
import requests

from typing import List, Optional
from urllib.parse import urljoin

from keep.api.models.alert import AlertDto, AlertSeverity
from keep.contextmanager.contextmanager import ContextManager
from keep.providers.base.base_provider import BaseProvider
from keep.providers.models.provider_config import ProviderConfig, ProviderScope

@pydantic.dataclasses.dataclass
class RollbarProviderAuthConfig:
"""
RollbarProviderAuthConfig is a class that allows to authenticate in Rollbar.
"""
rollbarAccessToken: str = dataclasses.field(
metadata={
"required": True,
"description": "Project Access Token",
"sensitive": True,
},
default=None,
)

class RollbarProvider(BaseProvider):
PROVIDER_DISPLAY_NAME = "Rollbar"
PROVIDER_TAGS = ["alert"]

PROVIDER_SCOPES = [
ProviderScope(
name="authenticated",
description="User is Authenticated",
),
]

SEVERITIES_MAP = {
"warning": AlertSeverity.WARNING,
"error": AlertSeverity.HIGH,
"info": AlertSeverity.INFO,
"critical": AlertSeverity.CRITICAL,
"debug": AlertSeverity.LOW
}

def __init__(
self, context_manager: ContextManager, provider_id: str, config: ProviderConfig
):
super().__init__(context_manager, provider_id, config)

def dispose(self):
pass

def validate_config(self):
"""
Validate the configuration of the provider.
"""
self.authentication_config = RollbarProviderAuthConfig(
**self.config.authentication
)

def __get_url(self, path: str):
"""
Get the URL for the request.
"""
return urljoin("https://api.rollbar.com/api/1/", path)

def __get_headers(self):
"""
Get the headers for the request.
"""
return {
"X-Rollbar-Access-Token": self.authentication_config.rollbarAccessToken,
"accept": "application/json; charset=utf-8",
"content-type": "application/json"
}

def validate_scopes(self) -> dict[str, bool | str]:
"""
Validate the scopes of the provider.
"""
try:
response = requests.get(self.__get_url("items"), headers=self.__get_headers())
if response.status_code == 200:
scopes = {
"authenticated": True
}
else:
self.logger.error("Unable to read projects from Rollbar, statusCode: %s", response.status_code)
scopes = {
"authenticated": f"Unable to read projects from Rollbar, statusCode: {response.status_code}"
}

except Exception as e:
self.logger.error("Error validating scopes for Rollbar: %s", e)
scopes = {
"authenticated": f"Error validating scopes for Rollbar: {e}"
}

return scopes

def __get_occurences(self) -> List[AlertDto]:
try:
response = requests.get(self.__get_url("instances"), headers=self.__get_headers())

if not response.ok:
self.logger.error("Failed to get occurrences from Rollbar: %s", response.json())
raise Exception("Could not get occurrences from Rollbar")

return [AlertDto(
id=alert["id"],
name=alert["project_id"],
environment=alert["data"]["environment"],
event_id=alert["data"]["uuid"],
language=alert["data"]["language"],
message=alert["data"]["body"]["message"]["body"],
host=alert["data"]["server"]["host"],
pid=alert["data"]["server"]["pid"],
severity=RollbarProvider.SEVERITIES_MAP[alert["data"]["level"]],
lastReceived=datetime.datetime.fromtimestamp(alert["timestamp"]).isoformat(),
) for alert in response.json()["result"]["instances"]]

except Exception as e:
self.logger.error("Error getting occurrences from Rollbar: %s", e)
raise Exception(f"Error getting occurrences from Rollbar: {e}")

def _get_alerts(self) -> List[AlertDto]:
alerts = []
try:
self.logger.info("Collecting alerts (occurrences) from Rollbar")
occurences_alert = self.__get_occurences()
alerts.extend(occurences_alert)
except Exception as e:
self.logger.error("Error getting occurrences from Rollbar: %s", e)

return alerts

@staticmethod
def _format_alert(
event: dict,
provider_instance: Optional["RollbarProvider"] = None,
) -> AlertDto:
item_data = event['data']['item']
occurrence_data = event['data']['occurrence']
return AlertDto(
id=str(item_data['id']),
name=event['event_name'],
severity=RollbarProvider.SEVERITIES_MAP[occurrence_data["level"]],
lastReceived=datetime.datetime.fromtimestamp(item_data['last_occurrence_timestamp']).isoformat(),
environment=item_data['environment'],
service='Rollbar',
source=[occurrence_data['framework']],
url=event['data']['url'],
message=occurrence_data['body']['message']['body'],
description=item_data['title'],
event_id=str(occurrence_data['uuid']),
labels={'level': item_data['level']},
fingerprint=item_data['hash'],
)

def setup_webhook(self, tenant_id: str, keep_api_url: str, api_key: str, setup_alerts: bool = True):
self.logger.info("Setting up webhook for Rollbar")
self.logger.info("Enabling Webhook in Rollbar")
try:
response = requests.put(
self.__get_url("notifications/webhook"),
headers=self.__get_headers(),
json={
"enabled": True,
"url": f"{keep_api_url}?api_key={api_key}",
}
)

if response.ok:
response = requests.post(
self.__get_url("notifications/webhook/rules"),
headers=self.__get_headers(),
json={
{
"trigger": "occurrence",
}
}
)
if response.ok:
self.logger.info("Created occurrence rule in Rollbar")
else:
self.logger.error("Failed to enable webhook in Rollbar: %s", response.json())
raise Exception("Failed to enable webhook in Rollbar")

self.logger.info("Webhook enabled in Rollbar")
except Exception as e:
self.logger.error("Error setting up webhook for Rollbar: %s", e)
raise Exception(f"Error setting up webhook for Rollbar: {e}")

if __name__ == "__main__":
import logging

logging.basicConfig(level=logging.DEBUG, handlers=[logging.StreamHandler()])
context_manager = ContextManager(
tenant_id="singletenant",
workflow_id="test",
)

import os

rollbar_host = os.environ.get("ROLLBAR_HOST")

if rollbar_host is None:
raise Exception("ROLLBAR_HOST is not set")

config = ProviderConfig(
description="Rollbar Provider",
authentication={
"rollbarAccessToken": rollbar_host,
},
)

provider = RollbarProvider(
context_manager,
provider_id="rollbar",
config=config,
)

provider._get_alerts()

0 comments on commit 0f06d07

Please sign in to comment.