-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", 29). ?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@analysis@templatizer: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@analysis@templatizer: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", 323). -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, <>}]}; false -> {string_literal, Text} end. -file("src/caffeine_lang/codegen/datadog.gleam", 309). ?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, <<<>/binary, R@1/binary>>} end, gleam@option:map(Combined, fun description_text_to_expr/1). -file("src/caffeine_lang/codegen/datadog.gleam", 356). ?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, <>}; 30 -> {ok, <>}; 90 -> {ok, <>}; _ -> {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", 332). ?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@artifacts: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@artifacts:relation_type_to_string( erlang:element(1, A) ), caffeine_lang@linker@artifacts: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@artifacts:relation_type_to_string( Relation_type ))/binary, "_dependency"/utf8>>, gleam@string:join(Sorted_targets, <<","/utf8>>)} end ). -file("src/caffeine_lang/codegen/datadog.gleam", 177). ?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, 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, Tags = begin _pipe@11 = lists:append(Final_system_tag_pairs, User_tag_pairs), _pipe@12 = gleam@list:map( _pipe@11, fun(Pair@3) -> {string_literal, <<<<(erlang:element(1, Pair@3))/binary, ":"/utf8>>/binary, (caffeine_lang@analysis@templatizer:quote_for_datadog( erlang:element(2, Pair@3) ))/binary>>} end ), {list_expr, _pipe@12} end, Identifier = caffeine_lang@linker@ir:ir_to_identifier(Ir), gleam@result:'try'( begin _pipe@13 = window_to_timeframe(Window_in_days), gleam@result:map_error( _pipe@13, 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", 160). ?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 ).