代码越来越复杂,为了理清架构,需要搞清楚现有代码业务逻辑,没有很顺手的工具,简单写写学习一下。
首先用pygraphviz绘制一下处理好的关系数据,包含可能有重复的生产者和对应的消费者(角色可以交叉)。
每个不重复的生产者和消费者是一个节点,两者关系是一条边。
#!/usr/bin/python3
import pygraphviz as pyg
def read(path):
print("start to read source ...")
with open(path) as f: return f.readlines()
def nodes_edges(data):
print("start to process data ...")
nodes, edges = [], []
for line in data:
[a,b] = line.split(",")
a = a.replace(" ",""); b = b.replace(" ","")
if not a in nodes: nodes.append(a)
if not b in nodes: nodes.append(b)
if not [a,b] in edges: edges.append([a,b])
return nodes, edges
def draw(nodes, edges):
print("start to drawing ...")
graph_obj = pyg.AGraph(directed=False, strict=False, ranksep=0.1, splines="spline", concentrate=True)
graph_obj.add_nodes_from(nodes,color="#ffffff", fontname="times bold italic")
graph_obj.add_edges_from(edges)
graph_obj.layout(prog='fdp')
graph_obj.draw('service_graph.png')
print("Done!")
if __name__ == '__main__':
nodes, edges = nodes_edges(read("./data/relation_data.csv"))
draw(nodes, edges)
# dot
# 一个用来将生成的图形转换成多种输出格式的命令行工具。其输出格式包括PostScript,PDF,SVG,PNG,含注解的文本等等。
# neato
# 用于sprint model的生成(在Mac OS版本中称为energy minimized)。
# twopi
# 用于放射状图形的生成
# circo
# 用于圆形图形的生成。
# fdp
# 另一个用于生成无向图的工具。
# dotty
# 一个用于可视化与修改图形的图形用户界面程序
参考 Python - 运行流程图, call graph, 调用图
在断点后通过调用过程打出图像
#!/usr/bin/python
import sys, tempfile, webbrowser, pygraphviz as pgv
def draw_by_breakpoint(frame=None, slient=False):
if not frame: frame = sys._getframe().f_back
G = pgv.AGraph(strict=False, directed=True); stack = []
node_set = set(); subgraph_set = {}
while frame:
filename = frame.f_code.co_filename
firstlineno = frame.f_code.co_firstlineno
function = frame.f_code.co_name
node = '{0}:{1}:{2}'.format(filename, firstlineno, function)
if node not in node_set:
node_set.add(node)
if filename not in subgraph_set:
subgraph_set[filename] = G.add_subgraph(
name='cluster' + filename,
label=filename
)
subgraph = subgraph_set[filename]
subgraph.add_node(node, label='{0}:{1}'.format(firstlineno, function))
stack.append(frame); frame = frame.f_back
stack.reverse(); len_stack = len(stack)
for index, start in enumerate(stack):
if index + 1 < len_stack:
start_filename = start.f_code.co_filename
start_firstlineno = start.f_code.co_firstlineno
start_function = start.f_code.co_name
start_lineno = start.f_lineno
start_subgraph = subgraph_set[start_filename]
end = stack[index + 1]
end_filename = end.f_code.co_filename
end_firstlineno = end.f_code.co_firstlineno
end_function = end.f_code.co_name
end_subgraph = subgraph_set[end_filename]
if index == 0: color = 'green'
elif index == len_stack - 2: color = 'red'
else: color = 'black'
G.add_edge( '{0}:{1}:{2}'.format(start_filename,
start_firstlineno,
start_function),
'{0}:{1}:{2}'.format(end_filename,
end_firstlineno,
end_function),
color=color,
ltail=start_subgraph.name,
lhead=end_subgraph.name,
label='#{0} at {1}'.format(index + 1, start_lineno)
)
fd, name = tempfile.mkstemp('.png')
G.draw(name, prog='dot'); G.close()
if not slient: webbrowser.open('file://' + name)
return name
if __name__ == '__main__': draw_by_breakpoint()
在自己的django程序views里引入 from APPXXX.graph import draw_by_breakpoint
并且调用一下 draw_by_breakpoint
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。