diff --git a/lib/trailblazer/pro.rb b/lib/trailblazer/pro.rb index bcf4824..a7472cd 100644 --- a/lib/trailblazer/pro.rb +++ b/lib/trailblazer/pro.rb @@ -15,8 +15,8 @@ module Pro require_relative "pro/client" require_relative "pro/trace/store" require_relative "pro/trace/wtf" -require_relative "pro/debugger" require_relative "pro/debugger/push" +require_relative "pro/debugger" require_relative "pro/call/activity" require_relative "pro/operation/call" require_relative "pro/operation/WTF" diff --git a/lib/trailblazer/pro/debugger.rb b/lib/trailblazer/pro/debugger.rb index f262a87..168741b 100644 --- a/lib/trailblazer/pro/debugger.rb +++ b/lib/trailblazer/pro/debugger.rb @@ -1,39 +1,32 @@ module Trailblazer module Pro - module Debugger - module_function - - # Called in {Trace::Present.call} as {:render_method}. - # This method always returns [output, *], where {output} - # is an arbitrary string to be written to the logger or CLI. - def call(activity:, render_wtf: false, **options) - output = "" - - trace_data = render_trace_data(activity: activity, **options) - trace_envelope = trace_envelope_for(activity: activity, trace_data: trace_data) - - session, stored_trace_id, session_updated = push(trace_envelope, activity: activity, **options) - - if render_wtf - output += render_original_wtf_trace(**options) - end - - # This block covers when something in {push} above went wrong. - if session.nil? - output += stored_trace_id - return output, [] - end - - debugger_link, debugger_url = render_debugger_link(stored_trace_id: stored_trace_id, activity: activity) - - output += debugger_link - - returned_values = [session, stored_trace_id, debugger_url, trace_envelope, session_updated] - - return output, returned_values + # Called in {Trace::Present.call} as {:render_method}. + # This method always returns [output, *], where {output} + # is an arbitrary string to be written to the logger or CLI. + def self.invoke_debugger(**kws) + _, (ctx, _) = Activity::TaskWrap.invoke(Debugger, [{now: DateTime.now, **kws, output: []}, {}]) + + return ctx[:output], [ctx[:session], ctx[:id], ctx[:debugger_url], ctx[:data_to_store], ctx[:session_updated]] + end + + # This is the {:render_method} implementation (for Trace::Present) + # when using PRO's wtf. + class Debugger < Trailblazer::Activity::Railway + step :render_trace_data + step :trace_envelope_for + step Subprocess(Push) + step :render_original_wtf_trace + fail :render_original_wtf_trace, id: "fail.render_original_wtf_trace" + fail :trace_with_appended_error_message + step :render_debugger_link + step :compile_output + fail :compile_output, id: "fail.compile_output" + + def trace_with_appended_error_message(ctx, error_message:, output:, **) + ctx[:output] << error_message end - def render_trace_data(debugger_trace:, activity:, **) + def render_trace_data(ctx, debugger_trace:, activity:, **) flat_tree_json = debugger_trace.to_a.collect do |debugger_node| # TODO: do we even need to grab tw by path here? @@ -41,7 +34,7 @@ def render_trace_data(debugger_trace:, activity:, **) tw_render = Developer::Render::TaskWrap.render_for(debugger_node.activity, introspect_nodes_node) # This rendering code has deep knowledge of Trace/pro/v1 tracing interface. - { + ctx[:trace_data] = { id: debugger_node.id.to_s, runtime_id: debugger_node.runtime_id, level: debugger_node.level, @@ -58,15 +51,15 @@ def render_trace_data(debugger_trace:, activity:, **) } end - JSON.dump( + ctx[:trace_data] = JSON.dump( nodes: flat_tree_json, variable_versions: debugger_trace.to_h[:variable_versions].to_h, pro_version: Pro::VERSION.to_s, ) end - def trace_envelope_for(activity:, trace_data:) - { + def trace_envelope_for(ctx, activity:, trace_data:, **) + ctx[:data_to_store] = { fields: { activity_name: {stringValue: activity}, trace: {stringValue: trace_data}, @@ -75,36 +68,30 @@ def trace_envelope_for(activity:, trace_data:) } end - def render_original_wtf_trace(debugger_trace:, renderer:, color_map: Developer::Wtf::Renderer::DEFAULT_COLOR_MAP, **) + def render_original_wtf_trace(ctx, render_wtf: false, debugger_trace:, renderer:, output:, color_map: Developer::Wtf::Renderer::DEFAULT_COLOR_MAP, **) + return true unless render_wtf # TODO: take the color_map from outside caller. wtf_output = Developer::Trace::Present.render(debugger_trace: debugger_trace, renderer: renderer, color_map: Developer::Wtf::Renderer::DEFAULT_COLOR_MAP) # , activity: activity - output = [wtf_output, output].join("\n") + ctx[:output] << wtf_output end - def render_debugger_link(stored_trace_id:, activity:) - debugger_url = "https://ide.trailblazer.to/#{stored_trace_id}" + # :id is :stored_trace_id. + def render_debugger_link(ctx, id:, activity:, **) + debugger_url = "https://ide.trailblazer.to/#{id}" # output = "[TRB PRO] view trace (#{activity}) at #{debugger_url}" # output = Developer::Wtf::Renderer::String.bold(output) link = Developer::Wtf::Renderer::String.bold("[TRB PRO] view trace (#{activity}) at ") link += debugger_url # DISCUSS: what do we want bold here? - return link, debugger_url - end + ctx[:link] = link + ctx[:debugger_url] = debugger_url - # DISCUSS: who defaults {:now}? - def push(trace_data, activity:, now: DateTime.now, **options) - # signal, (ctx, _) = Trailblazer::Developer.wtf?(Push, [{now: now, data_to_store: trace_data, **options}, {}]) - signal, (ctx, _) = Trailblazer::Activity.(Push, {now: now, data_to_store: trace_data, **options}) - # signal, (ctx, _) = Push.invoke([{now: now, data_to_store: trace_data, **options}, {}]) - - session = ctx[:session] - stored_trace_id = ctx[:id] - session_updated = ctx[:session_updated] - - return [nil, ctx[:error_message]] if signal.to_h[:semantic] == :failure # TODO: what to return? + ctx[:output] << link + end - return session, stored_trace_id, session_updated + def compile_output(ctx, output:, **) + ctx[:output] = output.join("\n") end end # Debugger end diff --git a/lib/trailblazer/pro/debugger/push.rb b/lib/trailblazer/pro/debugger/push.rb index 92272a7..fa3edf7 100644 --- a/lib/trailblazer/pro/debugger/push.rb +++ b/lib/trailblazer/pro/debugger/push.rb @@ -1,6 +1,6 @@ module Trailblazer module Pro - module Debugger + class Debugger < Trailblazer::Activity::Railway class Push < Trailblazer::Activity::Railway step Subprocess(Client::Connect), # TODO: assert that success/failure go to right Track. Output(:failure) => Track(:failure), diff --git a/lib/trailblazer/pro/session.rb b/lib/trailblazer/pro/session.rb index 43518f8..3dfe639 100644 --- a/lib/trailblazer/pro/session.rb +++ b/lib/trailblazer/pro/session.rb @@ -37,7 +37,8 @@ def self.deserialize(json) # pass session, e.g. from RAils/tmp def self.initialize!(api_key:, id_token: nil, render_wtf: true, **options) Session.wtf_present_options = { - render_method: Trailblazer::Pro::Debugger, + # render_method: Trailblazer::Pro::Debugger, + render_method: Trailblazer::Pro.method(:invoke_debugger), render_wtf: render_wtf, # api_key: api_key, # **options diff --git a/test/debugger_test.rb b/test/debugger_test.rb index b577a9f..a708291 100644 --- a/test/debugger_test.rb +++ b/test/debugger_test.rb @@ -114,4 +114,45 @@ def self.call(ctx, **) assert_equal ctx[:error_message], %(Custom token couldn't be retrieved. HTTP status: 502) assert_equal ctx[:session].trailblazer_pro_host, "https://testbackend-pro.trb.to" end + + it "what" do + class Create < Trailblazer::Activity::Railway + step :model + + def model(ctx, **) + ctx[:model] = Object.new + end + end + + Trailblazer::Pro.initialize!(api_key: api_key, trailblazer_pro_host: trailblazer_pro_host) + + # Compute a {Debugger::Trace} using the normal {Wtf} and {Trace::Present} logic. + signal, (ctx, flow_options), circuit_options, output, returned_args = Trailblazer::Developer.wtf?( + Create, + [{}, {}], + present_options: { + render_method: ->(debugger_trace:, **) { ["i am the output", debugger_trace] }, # whatever we return from {:render_method} is available as {returned_args} + }, + ) + + debugger_trace = returned_args + + # NOTE: this tests private internals and hence looks a bit clumsy (especially retrieving the {debugger_trace}). + signal, (ctx, _) = Trailblazer::Developer.wtf?(Trailblazer::Pro::Debugger, [ + { + debugger_trace: debugger_trace, + activity: Create, + renderer: Trailblazer::Developer::Trace::Present.method(:default_renderer), + + output: [], + session: Trailblazer::Pro::Session.session, + # http: stubbed_http, + # data_to_store: {fields: {a: 1}}, + # firestore_fields_template: session_static_options[:firestore_fields_template], + }, {}]) + + assert_equal ctx[:session].class, Trailblazer::Pro::Session # initialized session. + assert_equal ctx[:session_updated], true + assert_equal ctx[:id].size, 20 + end end diff --git a/test/present_options_test.rb b/test/present_options_test.rb index 85aa182..ea5c55d 100644 --- a/test/present_options_test.rb +++ b/test/present_options_test.rb @@ -17,7 +17,7 @@ def model(ctx, **) signal, (ctx, _), _, output, (token, trace_id, debugger_url, trace_envelope) = Trailblazer::Developer.wtf?( Create, [ctx, {}], - present_options: {render_method: Trailblazer::Pro::Debugger, session: uninitialized_session, render_wtf: true}, # FIXME: why do we have to pass {:session} here? + present_options: {render_method: Trailblazer::Pro.method(:invoke_debugger), session: uninitialized_session, render_wtf: true}, # FIXME: why do we have to pass {:session} here? ) assert_equal output, %(PresentOptionsTest::Create @@ -33,7 +33,7 @@ def model(ctx, **) signal, (ctx, _), _, output, (token, trace_id, debugger_url, trace_envelope) = Trailblazer::Developer.wtf?( Create, [ctx, {}], - present_options: {render_method: Trailblazer::Pro::Debugger, session: uninitialized_session, render_wtf: false}, # FIXME: why do we have to pass {:session} here? + present_options: {render_method: Trailblazer::Pro.method(:invoke_debugger), session: uninitialized_session, render_wtf: false}, # FIXME: why do we have to pass {:session} here? ) assert_equal output, %(\e[1m[TRB PRO] view trace (PresentOptionsTest::Create) at \e[22mhttps://ide.trailblazer.to/#{trace_id}) @@ -46,7 +46,7 @@ def model(ctx, **) signal, (ctx, _), _, output, (token, trace_id, debugger_url, trace_envelope) = Trailblazer::Developer.wtf?( Create, [ctx, {}], - present_options: {render_method: Trailblazer::Pro::Debugger, session: uninitialized_session}, + present_options: {render_method: Trailblazer::Pro.method(:invoke_debugger), session: uninitialized_session}, ) assert_equal trace_id.size, 20