Skip to content

Commit

Permalink
Debug-time traces for Activites (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikolaj-milewski authored May 9, 2024
1 parent 23b5401 commit 14dcad6
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 9 deletions.
2 changes: 1 addition & 1 deletion Core/Stateflows/Activities/Context/Classes/RootContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public Dictionary<string, Stream> GetStreams(Guid threadId)
}
}

internal IEnumerable<Stream> GetStreams(Node node, Guid threadId)
internal IEnumerable<Stream> GetActivatedStreams(Node node, Guid threadId)
{
lock (Streams)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ internal class SourceNodeContext : NodeContext, ISourceNodeContext
public IEnumerable<Token> Input
#pragma warning disable S2365 // Properties should not make collection or array copies
=> input ??= Context
.GetStreams(Node, ThreadId)
.GetActivatedStreams(Node, ThreadId)
.SelectMany(stream => stream.Tokens)
.ToArray();
#pragma warning restore S2365 // Properties should not make collection or array copies
Expand Down
119 changes: 113 additions & 6 deletions Core/Stateflows/Activities/Engine/Executor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Stateflows.Activities.Registration;
using Stateflows.Activities.Context.Classes;
using Stateflows.Utils;
using Stateflows.Common.Data;

namespace Stateflows.Activities.Engine
{
Expand Down Expand Up @@ -518,6 +519,9 @@ public async Task<IEnumerable<Token>> HandleExceptionAsync(Node node, Exception

if (handler != null)
{
var exceptionName = exception.GetType().Name;
Trace.WriteLine($"⦗→s⦘ Activity '{node.Graph.Name}': handling '{exceptionName}'");

var exceptionContext = new ActionContext(
context.Context,
currentScope,
Expand All @@ -529,6 +533,8 @@ public async Task<IEnumerable<Token>> HandleExceptionAsync(Node node, Exception

DoHandleOutput(exceptionContext);

ReportExceptionHandled(node, exceptionName, exceptionContext.OutputTokens.Where(t => t.Name != TokenInfo<ControlToken>.Name).ToArray());

return exceptionContext.OutputTokens;
}

Expand All @@ -548,7 +554,7 @@ public async Task DoHandleNodeAsync(Node node, NodeScope nodeScope, IEnumerable<
{
lock (node)
{
streams = Context.GetStreams(node, nodeScope.ThreadId);
streams = Context.GetActivatedStreams(node, nodeScope.ThreadId);
}
}

Expand Down Expand Up @@ -583,16 +589,19 @@ public async Task DoHandleNodeAsync(Node node, NodeScope nodeScope, IEnumerable<
{
Inspector.AcceptEventsPlugin.RegisterAcceptEventNode(node, nodeScope.ThreadId);

if (Debugger.IsAttached)
{
Trace.WriteLine($"⦗→s⦘ Activity '{node.Graph.Name}': AcceptEvent node '{node.Name}' registered and waiting for event");
}

return;
}

var inputTokens = input ?? streams.SelectMany(stream => stream.Tokens).ToArray();
var inputTokens = input ?? streams.GetTokens();

ReportNodeExecuting(node, inputTokens);

nodeScope = nodeScope.CreateChildScope(node);
lock (node.Graph)
{
Debug.WriteLine($">>> Executing node {node.Name}, threadId: {nodeScope.ThreadId}");
}

var actionContext = new ActionContext(Context, nodeScope, node, inputTokens, selectionTokens);

Expand Down Expand Up @@ -634,6 +643,8 @@ public async Task DoHandleNodeAsync(Node node, NodeScope nodeScope, IEnumerable<
outputTokens = actionContext.OutputTokens.ToList();
}

ReportNodeExecuted(node, outputTokens.Where(t => t.Name != TokenInfo<ControlToken>.Name).ToArray());

if (
StructuralTypes.Contains(node.Type) &&
(
Expand Down Expand Up @@ -675,6 +686,102 @@ public async Task DoHandleNodeAsync(Node node, NodeScope nodeScope, IEnumerable<
}
}
}
else
{
ReportNodeAttemptedExecution(node, streams);
}
}

private static void ReportNodeExecuting(Node node, IEnumerable<Token> inputTokens)
{
if (Debugger.IsAttached)
{
lock (node.Graph)
{
Trace.WriteLine($"⦗→s⦘ Activity '{node.Graph.Name}': executing '{node.Name}'{(!inputTokens.Any() ? ", no input" : "")}");
ReportTokens(inputTokens);
}
}
}

private static void ReportNodeExecuted(Node node, IEnumerable<Token> outputTokens)
{
if (Debugger.IsAttached)
{
lock (node.Graph)
{
Trace.WriteLine($"⦗→s⦘ Activity '{node.Graph.Name}': executed '{node.Name}'{(!outputTokens.Any() ? ", no output" : "")}");
ReportTokens(outputTokens, false);
}
}
}

private static void ReportExceptionHandled(Node node, string exceptionName, IEnumerable<Token> outputTokens)
{
if (Debugger.IsAttached)
{
lock (node.Graph)
{
Trace.WriteLine($"⦗→s⦘ Activity '{node.Graph.Name}': '{exceptionName}' handled{(!outputTokens.Any() ? ", no output" : "")}");
ReportTokens(outputTokens, false);
}
}
}

private static void ReportNodeAttemptedExecution(Node node, IEnumerable<Stream> streams)
{
if (Debugger.IsAttached)
{
lock (node.Graph)
{
Trace.WriteLine($"⦗→s⦘ Activity '{node.Graph.Name}': omitting '{node.Name}'");
ReportTokens(streams.GetTokens());
var activatedFlows = streams.Select(s => s.EdgeIdentifier).ToArray();
var missingFlows = node.IncomingEdges.Where(e => !activatedFlows.Contains(e.Identifier));
ReportMissingFlows(missingFlows);
}
}
}

private static void ReportTokens(IEnumerable<Token> inputTokens, bool input = true)
{
var inputDigest = inputTokens
.GroupBy(t => t.Name)
.Select(g => new
{
Name = g.Key,
Count = g.Count()
})
.OrderBy(d => d.Name);

if (inputDigest.Any())
{
Trace.WriteLine($" {(input ? "Input" : "Output")} (with count):");
foreach (var digest in inputDigest)
{
Trace.WriteLine($" - '{digest.Name}' ({digest.Count})");
}
}
}

private static void ReportMissingFlows(IEnumerable<Edge> flows)
{
if (flows.Any())
{
Trace.WriteLine($" Not activated incoming flows:");
foreach (var flow in flows)
{
var tokenName = flow.TargetTokenType.GetTokenName();
if (tokenName == TokenInfo<ControlToken>.Name)
{
Trace.WriteLine($" - control flow from '{flow.SourceName}' ");
}
else
{
Trace.WriteLine($" - '{tokenName}' from '{flow.SourceName}' ");
}
}
}
}

private void DoHandleOutput(ActionContext context)
Expand Down
5 changes: 5 additions & 0 deletions Core/Stateflows/Activities/Utils/IEnumerableExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Linq;
using System.Collections.Generic;
using Stateflows.Common;
using Stateflows.Activities.Streams;

namespace Stateflows.Utils
{
Expand Down Expand Up @@ -42,5 +44,8 @@ public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> seque
yield return partition;
}
}

public static Token[] GetTokens(this IEnumerable<Stream> streams)
=> streams.SelectMany(stream => stream.Tokens).ToArray();
}
}
12 changes: 11 additions & 1 deletion Examples/Blazor/Server/Blazor.Server/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,11 @@
.AddExceptionHandler<Exception>(async c =>
{
Debug.WriteLine(c.Exception.Message);
c.Output(new Token<int>() { Payload = 666 });
})
.AddInitial(b => b
.AddControlFlow("action1")
.AddControlFlow("action3")
)
.AddAction(
"action1",
Expand All @@ -96,9 +98,17 @@
{
Debug.WriteLine(c.Input.OfType<Token<int>>().First().Payload);
throw new Exception("test");
}
},
b => b.AddControlFlow("action3")
)
.AddAction(
"action3",
async c => { }
)

.AddFlow<Token<int>>("action4")
)
.AddAction("action4", async c => { })
)

.AddActivity<Activity3>("activity3")
Expand Down

0 comments on commit 14dcad6

Please sign in to comment.