1. 程式人生 > 程式設計 >Python函式呼叫追蹤實現程式碼

Python函式呼叫追蹤實現程式碼

對於分散式追蹤,主要有以下的幾個概念:

  • 追蹤 Trace:就是由分佈的微服務協作所支撐的一個事務。一個追蹤,包含為該事務提供服務的各個服務請求。
  • 跨度 Span:Span是事務中的一個工作流,一個Span包含了時間戳,日誌和標籤資訊。Span之間包含父子關係,或者主從(Followup)關係。
  • 跨度上下文 Span Context:跨度上下文是支撐分散式追蹤的關鍵,它可以在呼叫的服務之間傳遞,上下文的內容包括諸如:從一個服務傳遞到另一個服務的時間,追蹤的ID,Span的ID還有其它需要從上游服務傳遞到下游服務的資訊。

我實現了一種簡單的呼叫追蹤。

import uuid
import os
import time
l = []
class Recorder(object):
  def __init__(self,servername,root_span = None):
    if root_span == None:
      self.__span = Span(servername)
    else:
      self.__span = Span(servername,root_span)
  #上下文管理器
  def __enter__(self):
    return self.__span

  # 退出方法中,用來實現善後處理工作
  def __exit__(self,exc_type,exc_val,exc_tb):
    self.__span.record()
    self.__span.record_save(self.__span.span)
class Span(object):
  def __init__(self,root_span = None):
    self.servername = servername
    self.span = self.newspan()
    if root_span != None:
      root_span.dic['child_span'] = self.span
      self.span["root_span_flag"] = False
  def newspan(self):
    self.dic = {
      "spanid": uuid.uuid4().int,"servername": self.servername,"location": "","ip": "","durationtime": 0,"starttime": time.time(),"endtime":0,"tag": "","log": "","root_span_flag":True,"child_span": ""
    }
    return self.dic

  def record_save(self,span):
    currenttracer = {"id": span["spanid"],"data": span}
    print(currenttracer)
    l.append(currenttracer)

  def record(self):
    self.span["servername"] = self.servername
    self.span["location"] = os.getcwd() + "." + self.servername
    self.span["endtime"] = time.time()
    self.span["durationtime"] = self.span["endtime"] - self.span["starttime"]

  def setspantag(self,tag):
    self.span["tag"] = tag

  def setspanlog(self,log):
    self.span["log"] = log

# 連續呼叫
with Recorder('server1') as span:
  time.sleep(1)
  span.setspantag("test")
  #呼叫server1方法
  print("server1")
  with Recorder('server2',span) as span1:
    time.sleep(2)
    # 呼叫server2方法
    print("server2")
    with Recorder('server3',span1) as span2:
      time.sleep(0.5)
      # 呼叫server3方法
      print("server3")
#單獨呼叫記錄
with Recorder('server4') as span_test1:
  time.sleep(1.5)
  print("server4")

with Recorder('server5') as span_test2:
  time.sleep(2)
  print("server5")

執行結果:

server1
server2
server3
{'id': 224716339449765695394515303164364012192,'data': {'spanid': 224716339449765695394515303164364012192,'servername': 'server3','location': 'D:\\python_protest\\protest\\trace\\trace_main.server3','ip': '','durationtime': 0.5004403591156006,'starttime': 1598947338.0551107,'endtime': 1598947338.555551,'tag': '','log': '','root_span_flag': False,'child_span': None}}
{'id': 254736847532758359233387151739984206570,'data': {'spanid': 254736847532758359233387151739984206570,'servername': 'server2','location': 'D:\\python_protest\\protest\\trace\\trace_main.server2','durationtime': 2.501264810562134,'starttime': 1598947336.0542862,'child_span': {'spanid': 224716339449765695394515303164364012192,'child_span': None}}}
{'id': 91028031631192607088457781914309166266,'data': {'spanid': 91028031631192607088457781914309166266,'servername': 'server1','location': 'D:\\python_protest\\protest\\trace\\trace_main.server1','durationtime': 3.5021069049835205,'starttime': 1598947335.0534441,'tag': 'test','root_span_flag': True,'child_span': {'spanid': 254736847532758359233387151739984206570,'child_span': None}}}}
server4
{'id': 103171729522922437998918618387133480096,'data': {'spanid': 103171729522922437998918618387133480096,'servername': 'server4','location': 'D:\\python_protest\\protest\\trace\\trace_main.server4','durationtime': 1.5001769065856934,'starttime': 1598947338.555551,'endtime': 1598947340.055728,'child_span': None}}
server5
{'id': 320091321623887285825256878422834254741,'data': {'spanid': 320091321623887285825256878422834254741,'servername': 'server5','location': 'D:\\python_protest\\protest\\trace\\trace_main.server5','durationtime': 2.0005736351013184,'starttime': 1598947340.055728,'endtime': 1598947342.0563016,'child_span': None}}

關於下一步,會使用redis儲存其結果,並進行相應的輸出分析。

修過不能追蹤同級呼叫的問題

import uuid
import os
import time


l = []
class Recorder(object):
  def __init__(self,root_span)

  #上下文管理器
  def __enter__(self):
    return self.__span

  # 退出方法中,用來實現善後處理工作
  def __exit__(self,exc_tb):
    self.__span.record()
    self.__span.record_save(self.__span.span)


class Span(object):
  def __init__(self,root_span = None):
    self.servername = servername
    self.span = self.newspan()
    if root_span != None:
      root_span.dic['child_span'].append(self.span)
      self.span["root_span_flag"] = False

  def newspan(self):
    self.dic = {
      "spanid": uuid.uuid4().int,"child_span": []
    }
    return self.dic

  def record_save(self,log):
    self.span["log"] = log



# 連續呼叫
with Recorder('server1') as span:
  time.sleep(1)
  span.setspantag("test")
  #呼叫server1方法
  print("server1")
  with Recorder('server2',span1) as span2:
      time.sleep(0.5)
      # 呼叫server3方法
      print("server3")


# 並級連續呼叫
# with Recorder('server1') as span1:
#   time.sleep(1)
#   span1.setspantag("test")
#   #呼叫server1方法
#   print("server1")
#   with Recorder('server2',span1) as span2:
#     time.sleep(2)
#     # 呼叫server2方法
#     print("server2")
#   with Recorder('server3',span1) as span3:
#     time.sleep(0.5)
#     # 呼叫server3方法
#     print("server3")

# #單獨呼叫記錄
# with Recorder('server4') as span_test1:
#   time.sleep(1.5)
#   print("server4")
#
# with Recorder('server5') as span_test2:
#   time.sleep(2)
#   print("server5")

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。