Skip to content

Commit

Permalink
Merge eecd127 into 9d43c8d
Browse files Browse the repository at this point in the history
  • Loading branch information
itsvipa committed Dec 16, 2019
2 parents 9d43c8d + eecd127 commit 0d4817e
Show file tree
Hide file tree
Showing 10 changed files with 479 additions and 3 deletions.
2 changes: 0 additions & 2 deletions garcon/decider.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from garcon import event
from garcon import log


class DeciderWorker(swf.Decider, log.GarconLogger):

def __init__(self, flow, register=True):
Expand Down Expand Up @@ -62,7 +61,6 @@ def get_history(self, poll):
# Remove all the events that are related to decisions and only.
return [e for e in events if not e['eventType'].startswith('Decision')]


def get_activity_states(self, history):
"""Get the activity states from the history.
Expand Down
124 changes: 124 additions & 0 deletions garcon/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,130 @@ def activity_states_from_events(events):
return activity_events


def make_activity_summary(events):
"""Get activity states from a list of events.
The workflow events contains the different states of our activities. This
method consumes the logs, and regenerates a dictionnary with the list of
all the activities and their states.
Note:
Please note: from the list of events, only activities that have been
registered are accessible. For all the others that have not yet
started, they won't be part of this list.
Args:
events (dict): list of all the events.
Return:
`dict`: the activities and their state.
"""

events = sorted(events, key=lambda item: item.get('eventId'))
event_id_info = dict()
activity_events = dict()
activity_summary = dict()

for event in events:
event_id = event.get('eventId')
event_type = event.get('eventType')

if event_type == 'ActivityTaskScheduled':
activity_info = event.get('activityTaskScheduledEventAttributes')
activity_id = activity_info.get('activityId')
activity_name = activity_info.get('activityType').get('name')
start_timestamp = event.get('eventTimestamp')
event_id_info.update({
event_id: {
'activity_name': activity_name,
'activity_id': activity_id,
'start_timestamp': start_timestamp}
})

if activity_name not in activity_summary:
activity_summary["activity_name"] = {}

activity_events.setdefault(
activity_name, {}).setdefault(
activity_id,
activity.ActivityState(activity_id)).add_state(
activity.ACTIVITY_SCHEDULED)

elif event_type == 'ActivityTaskFailed':
activity_info = event.get('activityTaskFailedEventAttributes')
activity_event = event_id_info.get(
activity_info.get('scheduledEventId'))
activity_id = activity_event.get('activity_id')

if "failed_count" not in activity_summary["activity_name"]:
activity_summary["activity_name"]["failed_count"] = 1
else:
activity_summary["activity_name"]["failed_count"] += 1

time_diff = event.get(
'eventTimestamp'
) - activity_event['start_timestamp']

if "total_time_fail" not in activity_summary["activity_name"]:
activity_summary[
"activity_name"
][
"total_time_fail"
] = time_diff
else:
activity_summary[
"activity_name"
][
"total_time_fail"
] += time_diff

activity_events.setdefault(
activity_event.get('activity_name'), {}).setdefault(
activity_id,
activity.ActivityState(activity_id)).add_state(
activity.ACTIVITY_FAILED)

elif event_type == 'ActivityTaskCompleted':
activity_info = event.get('activityTaskCompletedEventAttributes')
activity_event = event_id_info.get(
activity_info.get('scheduledEventId'))
activity_id = activity_event.get('activity_id')

if "success_count" not in activity_summary["activity_name"]:
activity_summary["activity_name"]["success_count"] = 1
else:
activity_summary["activity_name"]["success_count"] += 1

time_diff = event.get(
'eventTimestamp'
) - activity_event['start_timestamp']

if "total_time_success" not in activity_summary["activity_name"]:
activity_summary[
"activity_name"
][
"total_time_success"
] = time_diff
else:
activity_summary[
"activity_name"
][
"total_time_success"
] += time_diff

activity_events.setdefault(
activity_event.get('activity_name'), {}).setdefault(
activity_id,
activity.ActivityState(activity_id)).add_state(
activity.ACTIVITY_COMPLETED)

result = json.loads(activity_info.get('result') or '{}')
activity_events.get(
activity_event.get('activity_name')).get(
activity_id).set_result(result)

return activity_summary


def get_current_context(events):
"""Get the current context from the list of events.
Expand Down
7 changes: 7 additions & 0 deletions garcon/graph/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Modified from the example at of D3
http://mbostock.github.com/d3/ex/force.html

Run the file force.py to generate the force.json data file needed for this to work.

Then copy all of the files in this directory to a webserver and load force.html.

12 changes: 12 additions & 0 deletions garcon/graph/graph.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.nodes circle {
cursor: pointer;
fill: #ff3399;
stroke: #000;
stroke-width: .5px;
}

.links line {
fill: none;
stroke: #9ecae1;
stroke-width: .5px;
}
12 changes: 12 additions & 0 deletions garcon/graph/graph.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<title>Force-Directed Layout</title>
<script type="text/javascript" src="https://d3js.org/d3.v4.min.js"></script>
<link type="text/css" rel="stylesheet" href="graph/graph.css"/>
</head>
<body>
<svg width="1000" height="2000"></svg>
<script type="text/javascript" src="graph/graph.js"></script>
</body>
</html>
139 changes: 139 additions & 0 deletions garcon/graph/graph.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// This is adapted from https://bl.ocks.org/mbostock/2675ff61ea5e063ede2b5d63c08020c7

const getDescription = (d) => Object.keys(d)
.map((k)=>k+": "+d[k]+"<br>")
.join("");

var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");

var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) {
return d.id;
}).distance(350))
.force("charge", d3.forceManyBody().strength(-300))
.force("center", d3.forceCenter(500, 500));

d3.json("graph/graph.json", function (error, graph) {
if (error) throw error;

svg.append("svg:defs").append("svg:marker")
.attr("id", "triangle")
.attr("refX", 100)
.attr("refY", 5)
.attr("markerWidth", 30)
.attr("markerHeight", 30)
.attr("markerUnits","userSpaceOnUse")
.attr("orient", "auto")
.append("path")
.attr("d", "M 0 0 10 5 0 10")
.style("fill", "black");

var label = svg.append("g")
.attr("class", "labels")
.append("foreignObject")
.attr("width", "100%")
.attr("height", "100%");

var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("marker-end", "url(#triangle)");

var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", 10)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));



var labelDiv = label
.selectAll("div")
.data(graph.nodes)
.enter()
.append("xhtml:div")
.html(function (d) { return d.name; })
.style("position", "absolute")
.style("text-anchor", "middle")
.style("fill", "#555")
.style("font-family", "Arial")
.style("font-size", 20)
.style("z-index", 10)
.style("cursor", "pointer")
.on("click", function(d) {
let element = d3
.select(this);
if(element.html()===d.name) {
element
.html(function (d) { return getDescription(d) });
} else {
element
.html(function (d) { return d.name; });
}
});

node.append("title")
.text(function (d) {
return d.id;
});

simulation
.nodes(graph.nodes)
.on("tick", ticked);

simulation.force("link")
.links(graph.links);

function ticked() {
link
.attr("x1", function (d) {
return d.source.x;
})
.attr("y1", function (d) {
return d.source.y;
})
.attr("x2", function (d) {
return d.target.x;
})
.attr("y2", function (d) {
return d.target.y;
});

node
.attr("cx", function (d) {
return d.x;
})
.attr("cy", function (d) {
return d.y;
});
labelDiv
.style("left", function(d){return (d.x + 20) + "px"; })
.style("top", function(d){return (d.y + 10) + "px"; });
}
});

function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}

function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}

function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
1 change: 1 addition & 0 deletions garcon/graph/graph.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"directed": true, "multigraph": false, "graph": {}, "nodes": [{"name": "Activity 1", "desc": "This is a cool 1", "id": 1}, {"name": "Activity 2", "desc": "This is a cool 2", "id": 2}, {"name": "Activity 3", "desc": "This is a cool 3", "id": 3}, {"name": "Activity 4", "desc": "This is a cool 4", "id": 4}, {"name": "Activity 5", "desc": "This is a cool 5", "id": 5}], "links": [{"source": 1, "target": 2}, {"source": 2, "target": 3}, {"source": 2, "target": 4}, {"source": 3, "target": 5}, {"source": 4, "target": 5}]}
Loading

0 comments on commit 0d4817e

Please sign in to comment.