Interpreter History

Introduction

When an instance of Interpreter class is created, an associated instance of History is also loaded automatically. This class offers the ability to track user Tcl call history with time stamp information. In addition, the History class offers users to mark the beginning and end of important events as separate history queues, with filters that looks for particular Tcl calls. This can be very effective when used to debug what-went-wrong during Python-Tcl interactions.

# Example
# -------
#
#   how history is tracked and read

from pyats.tcl import Interpreter, History

tcl = Interpreter()

# note the history attribute
assert type(tcl.history) is History

# make some tcl calls
tcl.eval('set testVar 1')
tcl.eval('set testVar 2')

# let's take a look at the history
tcl.history.filter()
# output:
#   deque(
#    [<HistoryEntry '2014-06-04T23:30:12.939354: set testVar 1' at ...>,
#     <HistoryEntry '2014-06-04T23:30:18.665275: set testVar 2' at ...>,
#     maxlen=9999])

# print it in a more usable fashion:
for i in tcl.history.filter():
    print(i.timestamp, '-', i.api)
# output:
#   2014-06-04 23:30:12.939354 - set testVar 1
#   2014-06-04 23:30:18.665275 - set testVar 2

How It Works

History is stored as a first-in-last-out queue with a maximum limit. Each time the user makes a call to eval, it is added to the history with the current timestamp. When the max queue is reached, the earliest historical entry is deleted to save from ever-growing memory usage.

Each historical event is saved as a HistoryEntry object. Each of these object has timestamp and api attribute: * timestamp being the time when the API was called * api being the Tcl command itself.

The default max limit for the queue is 9999. This can be altered if user manually replace the history attribute of the an Interpreter instance with a new one with bigger queue:

# continuing from above...

# replace the history tracker with a new, bigger one
tcl.history = History(max_history = 15000)

# note that this deletes all historical event up until now
tcl.history
# output:
#   deque([], maxlen=15000)

Hint

the API may be multi-line if multiple semi-colon ; separated Tcl commands were evaluated in the same eval().

Filter

The filter API returns by default the last 20 historical events for better viewing. Use this API to return an iterable history list. You can also use it to only filter calls that match a particular regular expression.

# continuing from above (but assuming we didn't reset the history)
tcl.history.filter(regex = 'testVar 1')
# output:
#   [<HistoryEntry '2014-06-04T23:30:12.939354: set testVar 1' at ...>]

Markers

Consider markers as separate history queues that can be used to mark and store important events. Eg: start at the beginning of a testcase and end of it, in order to give users full picture of what Tcl commands were called within that testcase.

By default, all history is appended to the master queue. This queue is always updated with each Tcl call. When a new marker is started, all subsequent Tcl calls are saved to both the new marker and the master queue, until stopped. There may be an indefinite number of markers active (limited by CPU/memory of course).

Consider the master queue as a broad picture into everything, with the individual marker queues as a snapshot of a particular time/event.

# Example
# -------
#
#   showing how markers work

from pyats import tcl

# run some Tcl code
tcl.eval('set test 1')

# create a new marker
tcl.history.start_marker('testMarker')

# run code under new marker
tcl.eval('set a 1')

# now create another marker
tcl.history.start_marker('testMarker2')

# run code under new marker as well
tcl.eval('set b 2')

# stop the markers
tcl.history.end_marker('testMarker')
tcl.history.end_marker('testMarker2')

# run more code
tcl.eval('set c 3')

# now let's see history vs marker behavior
# all calls are in the master (default) marker
tcl.history.filter()
# output:
#   [<HistoryEntry '2014-08-19T14:17:57.697085: set test 1' at ...>,
#    <HistoryEntry '2014-08-19T14:18:12.505794: set a 1' at ...>,
#    <HistoryEntry '2014-08-19T14:18:29.150347: set b 2' at ...>,
#    <HistoryEntry '2014-08-19T14:18:52.338709: set c 3' at ...>]

# 'testMarker' only has 1 calls
tcl.history.filter(marker='testMarker')
# output:
#   [<HistoryEntry '2014-08-19T14:18:12.505794: set a 1' at ...>,
#    <HistoryEntry '2014-08-19T14:18:29.150347: set b 2' at ...>]

# 'testMarker2' only contains 1 call
tcl.history.filter(marker='testMarker2')
# output:
# [<HistoryEntry '2014-08-19T14:18:29.150347: set b 2' at ...>]

Marker usage is pretty much trivial. For detailed usage to the API, refer to the API documentation.