NAME
Punk::Observe::Map - laying out the service graph
SYNOPSIS
use Punk::Observe::Map;
my $m = Punk::Observe::Map::layout([
{ caller => '*', callee => 1, count => 600, errors => 0 },
{ caller => 1, callee => 2, count => 600, errors => 4 },
]);
for my $n (@{ $m->{nodes} }) {
printf "service %s at layer %d slot %d\n",
$n->{service}, $n->{layer}, $n->{slot};
}
DESCRIPTION
Turns the accumulated service graph into positions: a layer per node and a slot within it. Callers sit left of callees, so traffic reads in one direction.
The graph itself is built when a segment is sealed rather than per query. See "The service graph is accumulated at seal" in Punk::Observe::Trace.
Cycles are drawn, not refused
Real service graphs have cycles - two services that call each other, or a retry path that loops back. A layering algorithm needs an acyclic graph, so the edges that would close a cycle are identified and reported as back edges rather than being dropped.
They are still edges and still drawn. Removing them would hide exactly the relationship somebody is looking at the map to find.
FUNCTIONS
layout
my $m = Punk::Observe::Map::layout(\@edges);
Lays out a graph. Each edge is a hashref taking caller, callee, count and errors. Services are symbol numbers; the string * as a caller means the synthetic root, which is where traffic from something uninstrumented arrives.
Edges repeating the same pair are summed rather than duplicated.
{
nodes => [ { service, layer, slot, in, out, errors }, ... ],
layers => 3,
back_edges => 1,
back => [ 2 ],
}
service is the symbol number, or * for the synthetic root. layer is the horizontal position and slot the vertical one within it. in and out are call counts through the node, and errors the errors attributed to it.
back holds indexes into the edge list as the layout saw it, which is the deduplicated graph rather than the arrayref that was passed in.