QUESTION

Is there a way to run tests on a rule and see what’s printed to stdout?

ANSWER

Yes!

To do this, you will need to redirect the stdout stream and leverage the alert_context function in your detection. You can use a global variable to pass the print messages on from rule to alert_context. This works for testing and production stdout capture. See the example below.

from io import StringIO
import sys

# Use a global
stored_stdout = None

def rule(event):
    # pylint: disable=global-statement
    global stored_stdout

    # Save stdout for later
    old_stdout = sys.stdout

    # Instead of writing to stdout, we'll capture and put data in result instead
    result = StringIO()
    sys.stdout = result

    # Regular printing
    print("message: {}".format(event.get("message")))
    print("log_type: {}".format(event.get("p_log_type")))

    # Put stdout back where it belongs
    sys.stdout = old_stdout
    result_string = result.getvalue()
    
    # Set the global variable to hold captured stdout data
    stored_stdout = result_string

    # This rule always returns true
    return True

def alert_context(event):
    global stored_stdout
    return {"stored_stdout": stored_stdout}