Creating Findings


Playbooks should use the Findings API to display output. They should not send output directly to Slack or other destinations.

By using the Findings API, your playbook will support Slack, MSTeams, and other sinks.

Basic Usage

Playbooks can call event.add_enrichment to add to the playbook's output. For example:

def test_playbook(event: ExecutionBaseEvent):
                "This is a *markdown* message. Here are some movie characters:"
                [["Han Solo", "Star Wars"], ["Paul Atreides", "Dune"]],
                ["name", "movie"],

When playbooks finish running, their output is sent to the configured sinks. Here is output for the above example:

Core Concepts

The Findings API has four important concepts:


An event, like a Prometheus alert or a deployment update.


Details about a Finding, like the labels for a Prometheus alert or a deployment's YAML before and after the update.


A visual element, like a paragraph, an image, or a table.


A destination Findings are sent to, like Slack, MSTeams, Kafka topics

Here is an example showing the above concepts:

digraph {

  node [ fontname="Handlee"
  subgraph cluster_finding {

      label=<Finding<BR /><BR /><I><FONT POINT-SIZE="9">HighCPU Alert</FONT></I>>;

      subgraph cluster_enrichment1 {
          label=<Enrichment<BR /><BR /><I><FONT POINT-SIZE="9">Prometheus Labels</FONT></I>>;
          block1 [
              label = <TableBlock<BR /><BR /><I><FONT POINT-SIZE="9">pod=my-pod<BR />namespace=default</FONT></I>>;

      subgraph cluster_enrichment2 {
          label=<Enrichment<BR /><BR /><I><FONT POINT-SIZE="9">CPU Profile Result</FONT></I>>;
          block2 [
              label = <MarkdownBlock<BR /><BR /><I><FONT POINT-SIZE="9">Explanation</FONT></I>>;
          block3 [
              label = <FileBlock<BR /><BR /><I><FONT POINT-SIZE="9">Profiler Result</FONT></I>>;

      slack_sink [
          label = <Slack Sink>;
      msteams_sink [
          label = <MSTeams Sink>;
      more_sinks [
          label = <...>;

  block2 -> slack_sink, more_sinks, msteams_sink [ltail=cluster_finding minlen=2];

Advanced Usage

It is possible to customize a findings name, override the default finding for events, and more.

But we haven't documented it yet. Please consult the source code.

class Finding(title, aggregation_key, severity=FindingSeverity.INFO, source=FindingSource.NONE, description=None, subject=<robusta.core.reporting.base.FindingSubject object>, finding_type=FindingType.ISSUE, failure=True, creation_date=None, fingerprint=None, starts_at=None, ends_at=None, add_silence_url=False, silence_labels=None)[source]

A Finding represents an event that should be sent to sinks.

property attribute_map: Dict[str, str]
Return type

Dict[str, str]

get_investigate_uri(account_id, cluster_name=None)[source]
add_enrichment(enrichment_blocks, annotations=None, suppress_warning=False)[source]
get_prometheus_silence_url(account_id, cluster_name)[source]
Return type


Block Types

Every Block represents a different type of visual data. Here are the possible Blocks:

MarkdownBlock(text[, dedent])

A Block of Markdown

FileBlock(filename, contents)

A file of any type.


A visual separator between other blocks


Text formatted as a header


A list of items, nicely formatted

TableBlock(rows[, headers, ...])

Table display of a list of lists.

KubernetesFieldsBlock(k8s_obj, fields[, ...])

A nicely formatted Kubernetes objects, with a subset of the fields shown

KubernetesDiffBlock(interesting_diffs, old, ...)

A diff between two versions of a Kubernetes object


Json data


A set of buttons that allows callbacks from the sink - for example, a button in Slack that will trigger another action when clicked


Not all block types are supported by all sinks. If an unsupported block arrives at a sink, it will be ignored


class MarkdownBlock(text, dedent=False)[source]

A Block of Markdown

  • text (str) -- one or more paragraphs of Markdown markup

  • dedent (bool) -- if True, remove common indentation so that you can use multi-line docstrings.

A simple example:

MarkdownBlock("Hi, *I'm bold* and _I'm italic_")

Things can get hairy when using writing content across multiple lines:

    "# This is a header \n\n"
    "And this is a paragraph. "
    "Same paragraph. A new string on each line prevents Python from adding newlines."

For convenience, use strip_whitespace=True and multiline strings:

    Due to strip_whitespace=True this is all one
    paragraph despite indentation and newlines.
    """, strip_whitespace=True)
class FileBlock(filename, contents)[source]

A file of any type. Used for images, log files, binary files, and more.

  • filename (str) -- the file's name

  • contents (bytes) -- the file's contents


FileBlock("test.txt", "this is the file's contents")
class DividerBlock(**data)[source]

A visual separator between other blocks

Create a new model by parsing and validating input data from keyword arguments.

Raises ValidationError if the input data cannot be parsed to form a valid model.

class HeaderBlock(text)[source]

Text formatted as a header


text (str) -- the header

class ListBlock(items)[source]

A list of items, nicely formatted


items (List[str]) -- a list of strings

class TableBlock(rows, headers=(), column_renderers={}, table_name='')[source]

Table display of a list of lists.

Note: Wider tables appears as a file attachment on Slack, because they aren't rendered properly inline

  • rows (List[List]) -- a list of rows. each row is a list of columns

  • headers (Sequence[str]) -- names of each column

class KubernetesFieldsBlock(k8s_obj, fields, explanations={})[source]

A nicely formatted Kubernetes objects, with a subset of the fields shown

  • k8s_obj (HikaruDocumentBase) -- a kubernetes object

  • fields (List[str]) -- a list of fields to display. for example ["", "metadata.namespace"]

  • explanations (Dict[str, str]) -- an explanation for each field. for example {"": "the pods name"}

class KubernetesDiffBlock(interesting_diffs, old, new, name, namespace=None)[source]

A diff between two versions of a Kubernetes object

  • interesting_diffs (List[DiffDetail]) -- parts of the diff to emphasize - some sinks will only show these to save space

  • old (Optional[HikaruDocumentBase]) -- the old version of the object

  • new (Optional[HikaruDocumentBase]) -- the new version of the object

class JsonBlock(json_str)[source]

Json data


json_str (str) -- json as a string

class CallbackBlock(choices)[source]

A set of buttons that allows callbacks from the sink - for example, a button in Slack that will trigger another action when clicked


choices (Dict[str, CallbackChoice]) -- a dict mapping between each the text on each button to the action it triggers