Structured template properties with Templatable
The behavior described in this document may change without notice.
To learn the basics of alert templates, see use templates.
ThirdEye alert templates support variables and properties.
At execution time, variables in a template are replaced by their properties value.
In an alert configuration json, a variable looks like "${var}"
and properties are defined
in templateProperties
.
By default, variables only work in String
fields, and properties are expected to be String
.
But any type of field, like a list or a map, can be templatized. This is possible with the so-called structured template properties.
Behavior
Structured template properties are enabled with the Templatable
Class. A Templatable<T>
, with T
being any type,
makes the field behave like a Union[T, String]
, where the string can only be written as a variable, in format "${var}"
.
An example of a structured template property is rcaExcludedDimensions
in startree-threshold template.
The field is a Templatable<List<String>>
. The field is set as a String:
"rcaExcludedDimensions": "${rcaExcludedDimensions}",
and the property is set as a List:
"defaultProperties": {
"rcaExcludedDimensions": [],
When the template is saved, the String value is accepted.
At runtime the string is replaced by the list.
Making a field compatible with structured properties
Even if all fields could be made Templatable
, it was decided that fields should be made Templatable on a per-need basis.
Don't make String
fields Templatable
, this is not necessary: Templatable<String>
= Union[String, String]
= String
.
Plan node Spec fields
There is nothing to do.
The values of the params
map of alert nodes are templatable.
Class extending AbstractSpec
to parse the params
map don't have to implement templatable.
Templatable is resolved internally and a Map<String, Object>
is passed when mapping params
to the Spec
.
This is implemented here.
Other fields
Wrap the field you want to make compatible with structured properties with Templatable
. Most likely, you'll have to update a DTO
and an API
class. Then update the code that uses this field.
An example PR can be found here.
The implementation is such that wrapping a field with Templatable
will not break the existing entities in the database. See Serialization and Deserialization.
Capabilities
- Multiple level of nested Templatable fields is supported
- Passing the
Templatable
structure directly for deserialization is not supported. Eg for acomponent
of typeTemplatable<Map<Int, Int>>
Such json is not validValid jsons are:"component": {"templatedValue": "${var}", "value": {1:2, 3:4}}
or"component": "${var}"
"component": {1:2, 3:4}
This behavior ensures the Templatable truly behaves like a union at the serialization level:
it is not possible to set the String
value and the T
value of the Templatable
at the same time.
Implementation
Original PR is here.
Serialization and Deserialization
A custom jackson (de)serialization mechanism is used to get the Union-like behavior.
The implementing class are ApiTemplatableSerializer and ApiTemplatableDeserializer.
You should not have to use these class directly. Use ThirdEyeSerialization helpers.
In most context (API level, API json reading/writing, persistence level), you should use ThirdEyeSerialization.newObjectMapper
to get an ObjectMapper
.
If you need a jackson.databind.Module
with the custom (de)serializations, use ThirdEyeSerialization.TEMPLATABLE
.
Applying structured properties
Applying structured template properties is implemented in TemplateEngineTemplatableSerializer
.
It exploits the recursive visitor pattern of jackson serialization to make the implementation easy, but it's an internal detail and this serialization should not be exposed nor used elsewhere.