docs/en/guides/mal-extension.md
MAL (Meter Analysis Language) supports custom extension functions callable from scripts using the
namespace::method() syntax. Extensions are discovered at startup via Java ServiceLoader, requiring
no changes to the MAL compiler or grammar.
MalFunctionExtensionCreate a class that implements the SPI interface and add static methods annotated with @MALContextFunction:
package com.example;
import org.apache.skywalking.oap.meter.analyzer.v2.dsl.SampleFamily;
import org.apache.skywalking.oap.meter.analyzer.v2.spi.MALContextFunction;
import org.apache.skywalking.oap.meter.analyzer.v2.spi.MalFunctionExtension;
public class MyExtension implements MalFunctionExtension {
@Override
public String name() {
return "myext"; // namespace used in MAL scripts
}
@MALContextFunction
public static SampleFamily scale(SampleFamily sf, double factor) {
return sf.multiply(Double.valueOf(factor));
}
@MALContextFunction
public static SampleFamily filterByTag(SampleFamily sf, String key, String value) {
return sf.tagEqual(key, value);
}
}
Create the file META-INF/services/org.apache.skywalking.oap.meter.analyzer.v2.spi.MalFunctionExtension:
com.example.MyExtension
metricsRules:
- name: scaled_metric
exp: metric.sum(['svc']).myext::scale(2.0)
- name: filtered_metric
exp: metric.myext::filterByTag("env", "prod").sum(['svc'])
staticSampleFamily (auto-bound to the current chain value in the expression)SampleFamilyIllegalArgumentException at startupIllegalArgumentException at startupIllegalArgumentException at startup| Java Type | MAL Argument | Example |
|---|---|---|
String | String literal | "value" |
double | Number literal | 2.0 |
float | Number literal | 3.0 |
long | Number literal | 100 |
int | Number literal | 10 |
List<String> | String list | ["tag1", "tag2"] |
Only List<String> is supported for list parameters. Other generic list types (e.g., List<Integer>)
are rejected at startup.
The MAL compiler generates direct static method calls at compile time — no reflection at runtime.
Each metric gets a named variable (e.g., _metric), and extension calls are emitted as static calls
on the variable:
For metric.sum(['svc']).myext::scale(2.0):
SampleFamily _metric = ((SampleFamily) samples.getOrDefault("metric", SampleFamily.EMPTY));
_metric = _metric.sum(java.util.Arrays.asList(new String[]{"svc"}));
_metric = com.example.MyExtension.scale(_metric, 2.0);
return _metric;
The compiler validates at expression compilation time:
SampleFamily first parameter)Any validation failure results in a compilation error with a clear message.