JMTE Templating

Java Minimal Template Engine (JMTE) is a lightweight yet versatile formatting engine used by some components in Graylog for text outputs. When Graylog needs to insert message data into a text string — such as an alert notification body, a decorator display value, or an archive path — it uses JMTE to evaluate the template and produce the final output.

This article explains how JMTE works and when to apply it, so you can write effective templates for the areas of Graylog that support templated output.

Hint: This article includes a revised subset of the documentation found at the Java Minimal Template Engine GitHub project.

Prerequisites

Before proceeding, ensure that the following prerequisites are met:

  • You should be familiar with the Graylog message fields or event attributes that you want to use in your templates, such as event timestamps, source information, or message backlog fields, before you begin writing JMTE expressions.

Highlights

The following highlights provide a summary of the key takeaways from this article:

  • Identify Graylog entities and components that support JMTE templates.

  • Create basic JMTE expressions using delimiters and dot notation.

  • Use formatting, conditional expressions, loops, separators, and escaping in JMTE templates.

JMTE Application Areas

Graylog uses JMTE in numerous entities and components throughout the user interface. The template engine lets you create replacement expressions that insert text from log messages into other content, such as notifications, event procedures, and search decorators.

The complete list of places where JMTE can be applied follows:

  • Archives (Enterprise > Archives).

    • Defines the archive path template.

  • Alerts (Alerts > Notifications).

    • Email:Multiple fields.

    • HTTP:Body Template field.

    • PagerDuty:Event Title, Incident Key, and Key Prefix fields.

    • Scripts:Script parameters and environment variables.

    • Slack:Custom Message and Channel fields.

  • Data adapters (System > Lookup Tables > Data Adapters).

    • Sets the HTTP JSONPath data adapter Lookup URL field.

  • Decorators (System > Configuration > Decorators).

    • Customizes display value of messages on the Search page.

  • Event definitions (Alerts > Event Definitions).

    • Creates an event summary template.

    • Creates custom fields template.

  • Event procedures (Enterprise > Security > Event Procedures).

    • Creates event procedure definitions.

    • Creates event procedure step definitions.

Typically, you can use the full template language as described below to enhance output in most of these areas. However, some instances, such as the archive path, are limited in scope based on the specific use.

Basic Expressions

A basic JMTE expression consists of a variable enclosed in delimiters. At run time, the variable, representing the source material you want to expose, is replaced in the output.

To create a replacement expression, use these delimiters:

  • ${ for the start of an expression.

  • } for the end of an expression.

The simplest form of an expression is to expand an entry from your source to a string. For example, the expression ${AccountType} might expand to User for a given entry in a log.

To access a certain property or field, you can use the dot (.) notation to navigate to it. For example, if you are defining an email notification, you could include the following in the Body Template:

"Event occurred at ${event.timestamp}"

When the event is triggered, the timestamp is pulled from the event details and inserted in the string.

Datetime Formatting

To format datetime output, use: date(<format>). A valid date format must be provided in place of <format>. Valid characters in that format can be found in the JodaTime documentation.

For example, use the following code to format the variable event_timestamp with the format yyyy-MM-dd HH:mm:ss:

${event_timestamp;date(yyyy-MM-dd HH:mm:ss)}

Conditional Expressions

Display text or expand an expression only when certain conditions hold true. JMTE provides a conditional statement to do so:

${if <condition>}

  <text displayed if condition holds>

${else}

  <text displayed if condition does not hold>

${end}

In the above example, replace the sections in angle brackets (< >) with your specific content. The text displayed after the if or else statement can consist of multiple lines.

The else section is optional, and the whole conditional block is terminated by the end expression. Specific conditions can be negated using the ! operator. You can also compare items to a string constant using the = operator.

Conditional expressions can be nested. However, you cannot use logical operators (that is, AND or OR) to combine conditions within a single if expression.

The condition can be any object. Conditions evaluate using these rules:

  • If the object is null, or if calling toString on the object returns the empty string or false, the condition evaluates to false.

  • If the object is a Boolean, the condition evaluates to the value of that Boolean.

  • If the object is a map, a collection, an array, or any data type that is iterable, the condition evaluates to true if it contains any elements and false if it does not.

  • Otherwise, the condition evaluates to true.

For example, in the following code, which you might use as part of an email alert, the text in the if section displays only if an alert has backlog messages:

${if backlog}

 --- [Backlog] ------------------------------------

  Last messages accounting for this alert:

  ${foreach backlog message}

    ${message}

  ${end}

${end}

This example also uses the foreach statement (described below) to display each of the backlog messages.

Conditional Shortcut

You can use a shortcut for the following common conditional statement. This shortcut works by supplying a default constant value that is used in case the variable is undefined. You specify the default value in brackets. For example:

${address(unknown)}

is equivalent to:

${if address}${address}${else}unknown${end}

Loop Expressions

If you want to expand all elements of a container, you can use the foreach expression:

${foreach backlog message}

 ${message}

${end}

In this example, the variable message is set to each element of the container, and the body (that is, anything you include between the foreach expression and the end expression) is expanded for each item in the container. As with conditional expressions, you can include multiple lines within the loop.

The container must be an array or map of objects. If the container is a map, the loop iterates over its entry set and the items become objects whose fields can be accessed using the dot notation mentioned earlier.

Special Variables

To change the way an item in a container is displayed based on its position, use special variables. A common use case is alternating formatting for table rows, depending on whether the row number is even or odd.

The available special variables are:

  • first

  • last

  • odd

  • even

  • index

Special variables are suffixed by an underscore, _, followed by the name of the item variable. For example, in a foreach loop that has message as the item name, using a special variable would create first_message, as shown in the following code:

${foreach backlog message}

  ${if first_message}

    <strong>${message}</strong>

  ${else}

    ${message}

  ${end}

${end}

In this example, the first message is displayed with bold (<strong>) formatting while all other items are displayed with plain text.

Separators

When displaying a list of items, you can add a separator between each item. You can use special variables for this, as shown in the previous section, or use the simpler separator syntax shown below:foreach

${foreach container item , }${item}${end}

For the code above, if the container includes three items, the formatted output looks like this:

item1, item2, item3

Reserved Characters

If you want to expose the characters or character sequences that are reserved in JMTE code, you need to escape them by using a backslash, \. You can escape the backslash itself by adding a second backslash.

For example:

  • \${ outputs ${.

  • \} outputs }.

  • \\ outputs \.

Further Reading

Explore the following additional resources and recommended readings to expand your knowledge on related topics: