Packages
caffeine_lang
5.4.4
6.3.1
6.3.0
6.2.2
6.2.1
6.2.0
6.1.2
6.1.1
6.1.0
6.0.0
5.6.0
5.5.0
5.4.4
5.4.3
5.4.2
5.4.1
5.4.0
5.3.0
5.2.0
5.1.1
5.1.0
5.0.12
5.0.11
5.0.10
5.0.8
5.0.7
5.0.6
5.0.5
5.0.4
5.0.1
5.0.0
4.10.0
4.9.0
4.8.3
4.8.2
4.8.1
4.8.0
4.7.9
4.7.8
4.7.7
4.7.6
4.7.5
4.6.7
4.6.6
4.6.5
4.6.4
4.6.3
4.6.2
4.6.0
4.5.1
4.5.0
4.4.4
4.4.3
4.4.1
4.4.0
4.3.7
4.3.6
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
1.0.2
1.0.1
0.1.0
0.0.24
0.0.23
0.0.22
0.0.21
0.0.20
0.0.19
0.0.18
0.0.17
0.0.16
0.0.15
0.0.14
0.0.13
0.0.12
0.0.11
0.0.10
0.0.9
0.0.8
0.0.7
0.0.6
0.0.5
0.0.4
0.0.2
0.0.1
A compiler for generating reliability artifacts from service expectation definitions.
Current section
Files
Jump to
Current section
Files
src/caffeine_lang@codegen@datadog.erl
-module(caffeine_lang@codegen@datadog).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/caffeine_lang/codegen/datadog.gleam").
-export([resolve_indicators/1, window_to_timeframe/1, ir_to_terraform_resource/1, generate_resources/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-file("src/caffeine_lang/codegen/datadog.gleam", 31).
?DOC(false).
-spec resolve_indicators(
caffeine_lang@linker@ir:intermediate_representation(caffeine_lang@linker@ir:deps_validated())
) -> {ok,
caffeine_lang@linker@ir:intermediate_representation(caffeine_lang@linker@ir:resolved())} |
{error, caffeine_lang@errors:compilation_error()}.
resolve_indicators(Ir) ->
gleam@result:'try'(
begin
_pipe = erlang:element(4, Ir),
_pipe@1 = gleam@list:find(
_pipe,
fun(Vt) -> erlang:element(2, Vt) =:= <<"indicators"/utf8>> end
),
gleam@result:replace_error(
_pipe@1,
caffeine_lang@errors:semantic_analysis_template_resolution_error(
<<<<"expectation '"/utf8,
(caffeine_lang@linker@ir:ir_to_identifier(Ir))/binary>>/binary,
"' - missing 'indicators' field in IR"/utf8>>
)
)
end,
fun(Indicators_value_tuple) ->
gleam@result:'try'(
begin
_pipe@2 = caffeine_lang@value:extract_string_dict(
erlang:element(4, Indicators_value_tuple)
),
gleam@result:map_error(
_pipe@2,
fun(_) ->
caffeine_lang@errors:semantic_analysis_template_resolution_error(
<<<<"expectation '"/utf8,
(caffeine_lang@linker@ir:ir_to_identifier(
Ir
))/binary>>/binary,
"' - failed to decode indicators"/utf8>>
)
end
)
end,
fun(Indicators_dict) ->
Identifier = caffeine_lang@linker@ir:ir_to_identifier(Ir),
gleam@result:'try'(
begin
_pipe@3 = Indicators_dict,
_pipe@4 = maps:to_list(_pipe@3),
gleam@list:try_map(
_pipe@4,
fun(Pair) ->
{Key, Indicator} = Pair,
gleam@result:map(
caffeine_lang@codegen@datadog_template:parse_and_resolve_query_template(
Indicator,
erlang:element(4, Ir),
Identifier
),
fun(Resolved) -> {Key, Resolved} end
)
end
)
end,
fun(Resolved_indicators) ->
Resolved_indicators_value = begin
_pipe@5 = Resolved_indicators,
_pipe@6 = gleam@list:map(
_pipe@5,
fun(Pair@1) ->
{erlang:element(1, Pair@1),
{string_value,
erlang:element(2, Pair@1)}}
end
),
_pipe@7 = maps:from_list(_pipe@6),
{dict_value, _pipe@7}
end,
New_indicators_value_tuple = {value_tuple,
<<"indicators"/utf8>>,
{collection_type,
{dict,
{primitive_type, string},
{primitive_type, string}}},
Resolved_indicators_value},
Evaluation_tuple_result = begin
_pipe@8 = erlang:element(4, Ir),
gleam@list:find(
_pipe@8,
fun(Vt@1) ->
erlang:element(2, Vt@1) =:= <<"evaluation"/utf8>>
end
)
end,
gleam@result:'try'(case Evaluation_tuple_result of
{error, _} ->
{ok, none};
{ok, Evaluation_tuple} ->
gleam@result:'try'(
begin
_pipe@9 = caffeine_lang@value:extract_string(
erlang:element(
4,
Evaluation_tuple
)
),
gleam@result:map_error(
_pipe@9,
fun(_) ->
caffeine_lang@errors:semantic_analysis_template_resolution_error(
<<<<"expectation '"/utf8,
(caffeine_lang@linker@ir:ir_to_identifier(
Ir
))/binary>>/binary,
"' - failed to decode 'evaluation' field as string"/utf8>>
)
end
)
end,
fun(Evaluation_string) ->
_pipe@10 = caffeine_lang@codegen@datadog_template:parse_and_resolve_query_template(
Evaluation_string,
erlang:element(4, Ir),
Identifier
),
gleam@result:map(
_pipe@10,
fun(Resolved_evaluation) ->
{some,
{value_tuple,
<<"evaluation"/utf8>>,
{primitive_type,
string},
{string_value,
Resolved_evaluation}}}
end
)
end
)
end, fun(Resolved_evaluation_tuple) ->
New_values = begin
_pipe@11 = erlang:element(4, Ir),
gleam@list:map(
_pipe@11,
fun(Vt@2) ->
case erlang:element(2, Vt@2) of
<<"indicators"/utf8>> ->
New_indicators_value_tuple;
<<"evaluation"/utf8>> ->
case Resolved_evaluation_tuple of
{some,
New_evaluation} ->
New_evaluation;
none ->
Vt@2
end;
_ ->
Vt@2
end
end
)
end,
Resolved_indicators_dict = begin
_pipe@12 = Resolved_indicators,
maps:from_list(_pipe@12)
end,
Resolved_eval = case Resolved_evaluation_tuple of
{some, Vt@3} ->
_pipe@13 = caffeine_lang@value:extract_string(
erlang:element(4, Vt@3)
),
gleam@option:from_result(_pipe@13);
none ->
erlang:element(
5,
erlang:element(5, Ir)
)
end,
New_ir = caffeine_lang@linker@ir:map_slo(
{intermediate_representation,
erlang:element(2, Ir),
erlang:element(3, Ir),
New_values,
erlang:element(5, Ir),
erlang:element(6, Ir)},
fun(Slo) ->
{slo_fields,
erlang:element(2, Slo),
Resolved_indicators_dict,
erlang:element(4, Slo),
Resolved_eval,
erlang:element(6, Slo),
erlang:element(7, Slo),
erlang:element(8, Slo),
erlang:element(9, Slo)}
end
),
{ok,
caffeine_lang@linker@ir:promote(New_ir)}
end)
end
)
end
)
end
).
-file("src/caffeine_lang/codegen/datadog.gleam", 345).
-spec description_text_to_expr(binary()) -> terra_madre@hcl:expr().
description_text_to_expr(Text) ->
case gleam_stdlib:contains_string(Text, <<"\n"/utf8>>) of
true ->
{heredoc,
<<"EOT"/utf8>>,
true,
[{literal_part, <<Text/binary, "\n"/utf8>>}]};
false ->
{string_literal, Text}
end.
-file("src/caffeine_lang/codegen/datadog.gleam", 331).
?DOC(
" Combine the SLO description (from `###` doc comments) with the runbook\n"
" link, if either is present. Multi-line descriptions render as an HCL\n"
" heredoc; single-line descriptions render as a plain string literal.\n"
).
-spec build_description_expr(
gleam@option:option(binary()),
gleam@option:option(binary())
) -> gleam@option:option(terra_madre@hcl:expr()).
build_description_expr(Description, Runbook) ->
Runbook_link = gleam@option:map(
Runbook,
fun(Url) -> <<<<"[Runbook]("/utf8, Url/binary>>/binary, ")"/utf8>> end
),
Combined = case {Description, Runbook_link} of
{none, none} ->
none;
{{some, D}, none} ->
{some, D};
{none, {some, R}} ->
{some, R};
{{some, D@1}, {some, R@1}} ->
{some, <<<<D@1/binary, "\n\n"/utf8>>/binary, R@1/binary>>}
end,
gleam@option:map(Combined, fun description_text_to_expr/1).
-file("src/caffeine_lang/codegen/datadog.gleam", 378).
?DOC(false).
-spec window_to_timeframe(integer()) -> {ok, binary()} |
{error, caffeine_lang@errors:compilation_error()}.
window_to_timeframe(Days) ->
Days_string = erlang:integer_to_binary(Days),
case Days of
7 ->
{ok, <<Days_string/binary, "d"/utf8>>};
30 ->
{ok, <<Days_string/binary, "d"/utf8>>};
90 ->
{ok, <<Days_string/binary, "d"/utf8>>};
_ ->
{error,
caffeine_lang@codegen@generator_utils:resolution_error(
<<"datadog"/utf8>>,
<<<<"Illegal window_in_days value: "/utf8,
Days_string/binary>>/binary,
". Accepted values are 7, 30, or 90."/utf8>>
)}
end.
-file("src/caffeine_lang/codegen/datadog.gleam", 354).
?DOC(
" Build dependency relation tag pairs from the relations dict.\n"
" Generates pairs like #(\"soft_dependency\", \"target1,target2\").\n"
).
-spec build_dependency_tags(
gleam@dict:dict(caffeine_lang@linker@dependency:dependency_relation_type(), list(binary()))
) -> list({binary(), binary()}).
build_dependency_tags(Relations) ->
_pipe = Relations,
_pipe@1 = maps:to_list(_pipe),
_pipe@2 = gleam@list:sort(
_pipe@1,
fun(A, B) ->
gleam@string:compare(
caffeine_lang@linker@dependency:relation_type_to_string(
erlang:element(1, A)
),
caffeine_lang@linker@dependency:relation_type_to_string(
erlang:element(1, B)
)
)
end
),
gleam@list:map(
_pipe@2,
fun(Pair) ->
{Relation_type, Targets} = Pair,
Sorted_targets = begin
_pipe@3 = Targets,
gleam@list:sort(_pipe@3, fun gleam@string:compare/2)
end,
{<<(caffeine_lang@linker@dependency:relation_type_to_string(
Relation_type
))/binary,
"_dependency"/utf8>>,
gleam@string:join(Sorted_targets, <<","/utf8>>)}
end
).
-file("src/caffeine_lang/codegen/datadog.gleam", 176).
?DOC(false).
-spec ir_to_terraform_resource(
caffeine_lang@linker@ir:intermediate_representation(caffeine_lang@linker@ir:resolved())
) -> {ok, {terra_madre@terraform:resource(), list(binary())}} |
{error, caffeine_lang@errors:compilation_error()}.
ir_to_terraform_resource(Ir) ->
Resource_name = terra_madre@common:sanitize_terraform_identifier(
erlang:element(3, Ir)
),
Slo = erlang:element(5, Ir),
Threshold = erlang:element(2, Slo),
Window_in_days = erlang:element(4, Slo),
Indicators = erlang:element(3, Slo),
Evaluation_expr = begin
_pipe = erlang:element(5, Slo),
gleam@option:unwrap(_pipe, <<"numerator / denominator"/utf8>>)
end,
Runbook = erlang:element(7, Slo),
Description = erlang:element(9, Slo),
gleam@result:'try'(
begin
_pipe@1 = caffeine_lang@codegen@datadog_cql:resolve_slo_to_hcl(
Evaluation_expr,
Indicators
),
gleam@result:map_error(
_pipe@1,
fun(Err) ->
caffeine_lang@errors:generator_slo_query_resolution_error(
<<<<<<"expectation '"/utf8,
(caffeine_lang@linker@ir:ir_to_identifier(
Ir
))/binary>>/binary,
"' - failed to resolve SLO query: "/utf8>>/binary,
Err/binary>>
)
end
)
end,
fun(_use0) ->
{resolved_slo_hcl, Slo_type, Slo_blocks} = _use0,
Dependency_tags = case erlang:element(8, Slo) of
{some, Relations} ->
build_dependency_tags(Relations);
none ->
[]
end,
User_tag_pairs = erlang:element(6, Slo),
System_tag_pairs = begin
_pipe@2 = caffeine_lang@helpers:build_system_tag_pairs(
erlang:element(3, erlang:element(2, Ir)),
erlang:element(6, erlang:element(2, Ir)),
erlang:element(4, erlang:element(2, Ir)),
erlang:element(5, erlang:element(2, Ir)),
erlang:element(2, erlang:element(2, Ir)),
erlang:element(7, erlang:element(2, Ir))
),
lists:append(_pipe@2, Dependency_tags)
end,
System_tag_keys = begin
_pipe@3 = System_tag_pairs,
_pipe@4 = gleam@list:map(
_pipe@3,
fun(Pair) -> erlang:element(1, Pair) end
),
gleam@set:from_list(_pipe@4)
end,
User_tag_keys = begin
_pipe@5 = User_tag_pairs,
_pipe@6 = gleam@list:map(
_pipe@5,
fun(Pair@1) -> erlang:element(1, Pair@1) end
),
gleam@set:from_list(_pipe@6)
end,
Overlapping_keys = gleam@set:intersection(
System_tag_keys,
User_tag_keys
),
{Final_system_tag_pairs, Overshadowing_warnings} = case gleam@set:size(
Overlapping_keys
)
> 0 of
true ->
Warn_msgs = begin
_pipe@7 = Overlapping_keys,
_pipe@8 = gleam@set:to_list(_pipe@7),
_pipe@9 = gleam@list:sort(
_pipe@8,
fun gleam@string:compare/2
),
gleam@list:map(
_pipe@9,
fun(Key) ->
<<<<<<(caffeine_lang@linker@ir:ir_to_identifier(
Ir
))/binary,
" - user tag '"/utf8>>/binary,
Key/binary>>/binary,
"' overshadows system tag"/utf8>>
end
)
end,
Filtered = begin
_pipe@10 = System_tag_pairs,
gleam@list:filter(
_pipe@10,
fun(Pair@2) ->
not gleam@set:contains(
Overlapping_keys,
erlang:element(1, Pair@2)
)
end
)
end,
{Filtered, Warn_msgs};
false ->
{System_tag_pairs, []}
end,
At_prefixed_attrs = begin
_pipe@11 = Indicators,
_pipe@12 = maps:values(_pipe@11),
_pipe@13 = lists:append(_pipe@12, [Evaluation_expr]),
_pipe@14 = gleam@list:flat_map(
_pipe@13,
fun datadog_query@lint:at_prefixed_attrs/1
),
gleam@list:unique(_pipe@14)
end,
At_prefix_warnings = begin
_pipe@15 = At_prefixed_attrs,
_pipe@16 = gleam@list:sort(_pipe@15, fun gleam@string:compare/2),
gleam@list:map(
_pipe@16,
fun(Attr) ->
<<<<<<<<<<(caffeine_lang@linker@ir:ir_to_identifier(Ir))/binary,
" - query references '"/utf8>>/binary,
Attr/binary>>/binary,
"' which Datadog rejects in metric SLO filters; use bare '"/utf8>>/binary,
(gleam@string:drop_start(Attr, 1))/binary>>/binary,
"' instead (Datadog strips '@' from log-based metric attribute names)"/utf8>>
end
)
end,
Warnings = lists:append(Overshadowing_warnings, At_prefix_warnings),
Tags = begin
_pipe@17 = lists:append(Final_system_tag_pairs, User_tag_pairs),
_pipe@18 = gleam@list:map(
_pipe@17,
fun(Pair@3) ->
{string_literal,
datadog_query@filter:tag(
erlang:element(1, Pair@3),
erlang:element(2, Pair@3)
)}
end
),
{list_expr, _pipe@18}
end,
Identifier = caffeine_lang@linker@ir:ir_to_identifier(Ir),
gleam@result:'try'(
begin
_pipe@19 = window_to_timeframe(Window_in_days),
gleam@result:map_error(
_pipe@19,
fun(Err@1) ->
caffeine_lang@errors:prefix_error(Err@1, Identifier)
end
)
end,
fun(Window_in_days_string) ->
Thresholds_block = terra_madre@hcl:simple_block(
<<"thresholds"/utf8>>,
[{<<"timeframe"/utf8>>,
{string_literal, Window_in_days_string}},
{<<"target"/utf8>>, {float_literal, Threshold}}]
),
Type_str = case Slo_type of
time_slice_slo ->
<<"time_slice"/utf8>>;
metric_slo ->
<<"metric"/utf8>>
end,
Base_attributes = [{<<"name"/utf8>>,
{string_literal,
erlang:element(
2,
erlang:element(2, erlang:element(2, Ir))
)}},
{<<"type"/utf8>>, {string_literal, Type_str}},
{<<"tags"/utf8>>, Tags}],
Attributes = case build_description_expr(
Description,
Runbook
) of
{some, Desc_expr} ->
[{<<"description"/utf8>>, Desc_expr} |
Base_attributes];
none ->
Base_attributes
end,
{ok,
{{resource,
<<"datadog_service_level_objective"/utf8>>,
Resource_name,
maps:from_list(Attributes),
lists:append(Slo_blocks, [Thresholds_block]),
terra_madre@hcl:empty_meta(),
none},
Warnings}}
end
)
end
).
-file("src/caffeine_lang/codegen/datadog.gleam", 159).
?DOC(false).
-spec generate_resources(
list(caffeine_lang@linker@ir:intermediate_representation(caffeine_lang@linker@ir:resolved()))
) -> {ok, {list(terra_madre@terraform:resource()), list(binary())}} |
{error, caffeine_lang@errors:compilation_error()}.
generate_resources(Irs) ->
_pipe = Irs,
_pipe@1 = gleam@list:try_fold(
_pipe,
{[], []},
fun(Acc, Ir) ->
{Resources, Warning_lists} = Acc,
gleam@result:'try'(
ir_to_terraform_resource(Ir),
fun(_use0) ->
{Resource, Ir_warnings} = _use0,
{ok,
{[Resource | Resources], [Ir_warnings | Warning_lists]}}
end
)
end
),
gleam@result:map(
_pipe@1,
fun(Pair) ->
{lists:reverse(erlang:element(1, Pair)),
lists:append(lists:reverse(erlang:element(2, Pair)))}
end
).