///|
fn demo_series() -> Array[@model.Series] {
[
@model.Series::new(
"http_requests_total",
@model.LabelSet::new([("job", "api"), ("instance", "api-1")]),
[
{ timestamp: 0.0, value: 10.0, },
{ timestamp: 60000.0, value: 20.0, },
{ timestamp: 120000.0, value: 35.0, },
{ timestamp: 180000.0, value: 55.0, },
{ timestamp: 240000.0, value: 80.0, },
{ timestamp: 300000.0, value: 110.0, },
],
),
@model.Series::new(
"http_requests_total",
@model.LabelSet::new([("job", "api"), ("instance", "api-2")]),
[
{ timestamp: 0.0, value: 5.0, },
{ timestamp: 60000.0, value: 9.0, },
{ timestamp: 120000.0, value: 15.0, },
{ timestamp: 180000.0, value: 23.0, },
{ timestamp: 240000.0, value: 32.0, },
{ timestamp: 300000.0, value: 44.0, },
],
),
]
}
///|
fn print_help() -> Unit {
println("MoonPromQL")
println("")
println("Usage:")
println(" moon run cmd/moonpromql -- eval [--at ]")
println(
" moon run cmd/moonpromql -- eval-json [--at ]",
)
println(" moon run cmd/moonpromql -- parse ")
println(" moon run cmd/moonpromql -- demo")
println("")
println("Examples:")
println(
" moon run cmd/moonpromql -- eval \"sum by (job) (rate(http_requests_total[5m]))\" --at 300000",
)
println(
" moon run cmd/moonpromql -- eval \"http_requests_total{instance=\\\"api-1\\\"}\" --at 300000",
)
}
///|
fn parse_timestamp(value : String) -> Double raise @model.PromqlError {
@string.parse_double(value) catch {
_ => raise @model.EvalError("invalid --at timestamp `\{value}`")
}
}
///|
fn run_eval(query : String, eval_time : Double) -> Unit {
let context = @eval.EvalContext::new(demo_series(), eval_time)
let result = @eval.query(query, context) catch {
error => {
println("error: \{error}")
abort("query failed")
}
}
println(result.to_string())
}
///|
fn run_eval_json(
query : String,
series_json : String,
eval_time : Double,
) -> Unit {
let series = @adapters_json.parse_series(series_json) catch {
error => {
println("error: \{error}")
abort("query failed")
}
}
let context = @eval.EvalContext::new(series, eval_time)
let result = @eval.query(query, context) catch {
error => {
println("error: \{error}")
abort("query failed")
}
}
println(result.to_string())
}
///|
fn run_parse(query : String) -> Unit {
let expression = @parser.parse(query) catch {
error => {
println("error: \{error}")
abort("query failed")
}
}
let kind = match expression {
@ast.Number(_) => "number"
@ast.StringLiteral(_) => "string"
@ast.Selector(_) => "selector"
@ast.Call(_, _) => "function call"
@ast.Aggregate(_, _, _, _) => "aggregation"
@ast.Unary(_, _) => "unary expression"
@ast.Binary(_, _, _, _, _) => "binary expression"
}
println("parsed \{kind}")
}
///|
fn main {
let args = @env.args()
if args.length() < 2 {
print_help()
return
}
match args[1] {
"help" | "--help" | "-h" => print_help()
"demo" => run_eval("rate(http_requests_total[5m])", 300000.0)
"parse" =>
if args.length() < 3 {
abort("error: parse requires a query")
} else {
run_parse(args[2])
}
"eval" =>
if args.length() < 3 {
abort("error: eval requires a query")
} else {
let mut eval_time = 300000.0
if args.length() >= 5 && args[3] == "--at" {
eval_time = parse_timestamp(args[4]) catch {
error => {
println("error: \{error}")
abort("query failed")
}
}
}
run_eval(args[2], eval_time)
}
"eval-json" =>
if args.length() < 4 {
abort("error: eval-json requires a query and a JSON series fixture")
} else {
let mut eval_time = 300000.0
if args.length() >= 6 && args[4] == "--at" {
eval_time = parse_timestamp(args[5]) catch {
error => {
println("error: \{error}")
abort("query failed")
}
}
}
run_eval_json(args[2], args[3], eval_time)
}
_ => abort("error: unknown command; use --help")
}
}