Creating Findings ################### Motivation -------------- 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: .. code-block:: python @action def test_playbook(event: ExecutionBaseEvent): event.add_enrichment( [ MarkdownBlock( "This is a *markdown* message. Here are some movie characters:" ), TableBlock( [["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: .. tab-set:: .. tab-item:: Slack .. image:: /images/basic-robusta-finding-slack.png :width: 700 Core Concepts ---------------------------- The Findings API has four important concepts: Finding An event, like a Prometheus alert or a deployment update. Enrichment Details about a Finding, like the labels for a Prometheus alert or a deployment's YAML before and after the update. Block A visual element, like a paragraph, an image, or a table. Sink A destination Findings are sent to, like Slack, MSTeams, Kafka topics Here is an example showing the above concepts: .. graphviz:: digraph { compound=true; rankdir=TB fixedsize=true; node [ fontname="Handlee" fixedsize=true width=2 height=1 ]; subgraph cluster_finding { label=
HighCPU Alert>; subgraph cluster_enrichment1 { label=
Prometheus Labels>; block1 [ label =
pod=my-pod
namespace=default
>; ] } subgraph cluster_enrichment2 { label=
CPU Profile Result>; rank=same; block2 [ label =
Explanation>; ] block3 [ label =
Profiler Result>; ] } } slack_sink [ label = ; ] msteams_sink [ label = ; ] 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. .. autoclass:: robusta.api.Finding :members: :undoc-members: Block Types ----------------------------- Every Block represents a different type of visual data. Here are the possible Blocks: .. module:: robusta.api .. autosummary:: MarkdownBlock FileBlock DividerBlock HeaderBlock ListBlock TableBlock KubernetesFieldsBlock KubernetesDiffBlock JsonBlock CallbackBlock .. note:: Not all block types are supported by all sinks. If an unsupported block arrives at a sink, it will be ignored Reference -------------- .. autoclass:: robusta.api.MarkdownBlock :no-members: A simple example: .. code-block:: python MarkdownBlock("Hi, *I'm bold* and _I'm italic_") Things can get hairy when using writing content across multiple lines: .. code-block:: python MarkdownBlock( "# 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: .. code-block:: python MarkdownBlock(""" Due to strip_whitespace=True this is all one paragraph despite indentation and newlines. """, strip_whitespace=True) .. autoclass:: robusta.api.FileBlock :no-members: Examples: .. code-block:: python FileBlock("test.txt", "this is the file's contents") .. autoclass:: robusta.api.DividerBlock :no-members: .. autoclass:: robusta.api.HeaderBlock :no-members: .. autoclass:: robusta.api.ListBlock :no-members: .. autoclass:: robusta.api.TableBlock :no-members: .. autoclass:: robusta.api.KubernetesFieldsBlock :no-members: .. autoclass:: robusta.api.KubernetesDiffBlock :no-members: .. autoclass:: robusta.api.JsonBlock :no-members: .. autoclass:: robusta.api.CallbackBlock :no-members: