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

[Alerting] add a framework-provided mustache template variable that lists all the available variables and their values #75601

Closed
pmuellr opened this issue Aug 20, 2020 · 3 comments · Fixed by #85903
Assignees
Labels
discuss Feature:Alerting Team:ResponseOps Label for the ResponseOps team (formerly the Cases and Alerting teams)

Comments

@pmuellr
Copy link
Member

pmuellr commented Aug 20, 2020

For KIbana alerts, when you create actions to be executed when the alert is triggered, the parameters of the alert can be replaced with "context variables" provided by the application. You can see these in the alert flyout, here - the small red-outlined button will display the larger list of variables shown in the large red-outlined button:

image

It's difficult to keep this list up-to-date with the alerts, and in some cases may be impossible, as the alert can make variables available dynamically.

It would be nice to have one of these "context variables" that actually showed you ALL of the context variables, so you could use it an alert to see what all the values were, while crafting your actions.

Here's a quick hack that illustrates what we could do. The set of variables we pass to mustache to fill in the action parameter template is returned here, for the index threshold alert:

Mustache has a couple of ways of allowing functions to be used in the variables object - you can either pass a named function in the object, and it will be invoked when accessed, or you can make use of toString() to produce a nicer version of your object than what Mustache would typically provide. Eg, if you pass {{context}} as an action parameter, the result will be [object Object].

Here's a replacement for that last line above, which adds a toString() to the context variable itself, which returns a JSON version of itself:

  const actionContext: ActionContext = { ...baseContext, title, message };
  actionContext.toString = () => JSON.stringify(actionContext);
  return actionContext;

With this code, the result of using {{context}} will no longer be [object Object], but will be the following (I've split lines for readability):

{
  "date": "2020-08-20T20:03:36.378Z",
  "group": "host-1",
  "value": 0.800000011920929,
  "title": "alert es-apm-sys-sim threshold group host-1 exceeded threshold",
  "message": "alert es-apm-sys-sim threshold group host-1 value 0.800000011920929 exceeded threshold avg(system.cpu.total.norm.pct) > 0.8 over 5s on 2020-08-20T20:03:36.378Z"
}

Sort of seems we should provide some top-level variable, that would include all the other top-level variables (all the alert* variables, the params, context, and state objects, etc), as a flattened list (in the case of context variables being objects with properties themselves), with a fixed name, that we make available for all the templating uses.

I'm not expecting this would be used in a "real" alert, but while creating your alerts to see what variables are available. Perhaps an appropriate name for this "variable" would be variables or such.

@pmuellr pmuellr added Feature:Alerting Team:ResponseOps Label for the ResponseOps team (formerly the Cases and Alerting teams) labels Aug 20, 2020
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-alerting-services (Team:Alerting Services)

@pmuellr
Copy link
Member Author

pmuellr commented Nov 24, 2020

There's an implementation of this in not-yet-merged-ATM PR #83919, since I was already in that code and this was easy enough to add.

pmuellr added a commit to pmuellr/kibana that referenced this issue Dec 8, 2020
resolves elastic#79371
resolves elastic#75601
resolves elastic#62928

In this PR, we allow action types to determine how to escape the
variables used in their parameters, when rendered as mustache
templates.  Prior to this, action parameters were recursively
rendered as mustache templates using the default mustache
templating, by the alerts library.  The default mustache
templating used html escaping.

Action types opt-in to the new capability via a new optional
method in the action type, `renderParameterTemplates()`.  If not
provided, the previous recursive rendering is done, but now with
no escaping at all.

For elastic#75601, added toString() methods to mustache object variables
which allow them to be used in a template and expanded to
JSON, for experimentation / discovery of context variables.

For elastic#62928, changed the mustache template rendering to be
replaced with the error message, if an error occurred,
so at least you can now see that an error occurred.  Useful
to diagnose problems with invalid mustache templates.
@pmuellr
Copy link
Member Author

pmuellr commented Dec 8, 2020

I had some code this in PR #83919 for a while, but am taking it out as that PR is getting too big. I'll keep a branch of that though, and do a follow-on PR for this.

For reference, here's the code for it:

import { isPlainObject } from 'lodash';

type Variables = Record<string, unknown>;

// return variables cloned, with a toString() added to objects
function augmentObjectVariables(variables: Variables): Variables {
  const result = JSON.parse(JSON.stringify(variables));
  addToStringDeep(result);
  return result;
}

function addToStringDeep(object: unknown): void {
  // for objects, add a toString method, and then walk
  if (isNonNullObject(object)) {
    if (!object.hasOwnProperty('toString')) {
      object.toString = () => JSON.stringify(object);
    }
    Object.values(object).forEach((value) => addToStringDeep(value));
  }

  // walk arrays, but don't add a toString() as mustache already does something
  if (Array.isArray(object)) {
    object.forEach((element) => addToStringDeep(element));
    return;
  }
}

function isNonNullObject(object: unknown): object is Record<string, unknown> {
  if (object == null) return false;
  if (typeof object !== 'object') return false;
  if (!isPlainObject(object)) return false;
  return true;
}

Here's a test for it:

  describe('augmented object variables', () => {
    const deepVariables = {
      a: 1,
      b: { c: 2, d: [3, 4] },
      e: [5, { f: 6, g: 7 }],
    };
    expect(renderMustacheObject({ x: '{{a}} - {{b}} -- {{e}} ' }, deepVariables))
      .toMatchInlineSnapshot(`
      Object {
        "x": "1 - {\\"c\\":2,\\"d\\":[3,4]} -- 5,{\\"f\\":6,\\"g\\":7} ",
      }
    `);

    const expected = '1 - {"c":2,"d":[3,4]} -- 5,{"f":6,"g":7}';
    expect(renderMustacheString('{{a}} - {{b}} -- {{e}}', deepVariables, 'none')).toEqual(expected);
  });

pmuellr added a commit to pmuellr/kibana that referenced this issue Dec 14, 2020
resolves elastic#75601

Previously, if a context variable that is an object is referenced in a
mustache template used as an action parameter, the resulting variable
expansion will be `[Object object]`.  In this PR, we change this so that
the expansion is a JSON representation of the object.

This is primarily for diagnostic purposes, so that customers can see
all the context variables available, and their values, while testing
testing their alerting actions.
pmuellr added a commit to pmuellr/kibana that referenced this issue Dec 15, 2020
resolves elastic#75601

Previously, if a context variable that is an object is referenced in a
mustache template used as an action parameter, the resulting variable
expansion will be `[Object object]`.  In this PR, we change this so that
the expansion is a JSON representation of the object.

This is primarily for diagnostic purposes, so that customers can see
all the context variables available, and their values, while testing
testing their alerting actions.
pmuellr added a commit that referenced this issue Dec 15, 2020
resolves #75601

Previously, if a context variable that is an object is referenced in a
mustache template used as an action parameter, the resulting variable
expansion will be `[Object object]`.  In this PR, we change this so that
the expansion is a JSON representation of the object.

This is primarily for diagnostic purposes, so that customers can see
all the context variables available, and their values, while testing
testing their alerting actions.
pmuellr added a commit to pmuellr/kibana that referenced this issue Dec 15, 2020
resolves elastic#75601

Previously, if a context variable that is an object is referenced in a
mustache template used as an action parameter, the resulting variable
expansion will be `[Object object]`.  In this PR, we change this so that
the expansion is a JSON representation of the object.

This is primarily for diagnostic purposes, so that customers can see
all the context variables available, and their values, while testing
testing their alerting actions.
pmuellr added a commit that referenced this issue Dec 16, 2020
resolves #75601

Previously, if a context variable that is an object is referenced in a
mustache template used as an action parameter, the resulting variable
expansion will be `[Object object]`.  In this PR, we change this so that
the expansion is a JSON representation of the object.

This is primarily for diagnostic purposes, so that customers can see
all the context variables available, and their values, while testing
testing their alerting actions.
@kobelb kobelb added the needs-team Issues missing a team label label Jan 31, 2022
@botelastic botelastic bot removed the needs-team Issues missing a team label label Jan 31, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discuss Feature:Alerting Team:ResponseOps Label for the ResponseOps team (formerly the Cases and Alerting teams)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants