Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BugSnag 🐛 #157

Merged
merged 3 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions config.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ credentials:
key: MY_API_KEY
ssl: False

error_reporting:
- name: bugsnag
api_key: API_KEY

sources:
# This section defines each of the input sources for ThreatIngestor.
# Define as many as you want. ThreatIngestor maintains a "state" for each of
Expand Down
13 changes: 13 additions & 0 deletions docs/extras.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@ Extras

There are a few extra tools included alongside ThreatIngestor, that didn't quite make sense as sources or operators.

BugSnag
-------

BugSnag monitoring is a valuable tool to have when running in daemon mode. Adding it is extremely simple and the only requirement is to have an API key.

Here's an example to include in your ``config.yml``:

.. code-block:: yaml

error_reporting:
- name: bugsnag
api_key: API_KEY

Quick Webapp
------------

Expand Down
65 changes: 0 additions & 65 deletions tests/test_operators_twitter.py

This file was deleted.

48 changes: 47 additions & 1 deletion threatingestor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,30 @@
logger.info("Notifiers is not installed.")
notifiers = None

try:
import bugsnag
bugsnag_imported = True
except ImportError:
logger.info("BugSnag is not installed.")
bugsnag_imported = False

import threatingestor.config
import threatingestor.state
import threatingestor.exceptions
import threatingestor.whitelist

BUGSNAG_ACTIVE = False

def bugsnag_notification(msg=None, metadata=None) -> None:
"""
Monitor your code with BugSnag

You can include a additional information with the `metadata` paramater.
"""

if bugsnag_imported:
bugsnag.notify(Exception(msg), metadata={"ThreatIngestor" : metadata})

class Ingestor:
"""ThreatIngestor main work logic.

Expand All @@ -35,6 +54,7 @@ def __init__(self, config_file):

# Configure logging with optional notifiers.
logger.configure(**self.config.logging())

try:
logger.level("NOTIFY", no=35, color="<yellow>", icon="\U0001F514")
except TypeError:
Expand All @@ -61,13 +81,28 @@ def __init__(self, config_file):
logger.exception("Couldn't initialize statsd client; bad config?")
sys.exit(1)

# Configure BugSnag
if bugsnag_imported:
for service in self.config.error_reporting():
if service['name'] == "bugsnag":
if service['api_key']:
bugsnag.configure(api_key=service['api_key'])
logger.debug("BugSnag configured")
BUGSNAG_ACTIVE = True

break

# Load state DB.
try:
logger.debug(f"Opening state database '{self.config.state_path()}'")
self.statedb = threatingestor.state.State(self.config.state_path())
except (OSError, IOError, threatingestor.exceptions.IngestorError):
# Error loading state DB.
logger.exception("Error reading state database")

if BUGSNAG_ACTIVE:
bugsnag_notification("Error reading state database")

sys.exit(1)

# Instantiate plugins.
Expand All @@ -84,8 +119,11 @@ def __init__(self, config_file):
self.whitelist = threatingestor.whitelist.Whitelist(self.config.whitelists())

except (TypeError, ConnectionError, threatingestor.exceptions.PluginError):
logger.warning("Twitter config format has recently changed. See https://github.com/InQuest/ThreatIngestor/releases/tag/v1.0.0b5")
logger.exception("Error initializing plugins")

if BUGSNAG_ACTIVE:
bugsnag_notification("Error initializing plugins")

sys.exit(1)

def _is_whitelisted(self, artifact) -> bool:
Expand Down Expand Up @@ -122,6 +160,10 @@ def run_once(self):
except Exception:
self.statsd.incr(f'error.source.{source}')
logger.exception(f"Unknown error in source '{source}'")

if BUGSNAG_ACTIVE:
bugsnag_notification(f"Unknown error in source '{source}'")

continue

# Save the source state.
Expand All @@ -144,6 +186,10 @@ def run_once(self):
except Exception:
self.statsd.incr(f'error.operator.{operator}')
logger.exception(f"Unknown error in operator '{operator}'")

if BUGSNAG_ACTIVE:
bugsnag_notification(f"Unknown error in operator '{operator}'")

continue

# Record stats and update the summary.
Expand Down
5 changes: 5 additions & 0 deletions threatingestor/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ def logging(self):
return self.config.get('logging', {})


def error_reporting(self):
"""Returns error_reporting config dictionary."""
return self.config['error_reporting']


def credentials(self, credential_name):
"""Return a dictionary with the specified credentials."""
for credential in self.config['credentials']:
Expand Down
54 changes: 0 additions & 54 deletions threatingestor/operators/twitter.py

This file was deleted.