Skip to main content

Tree-like logging util for python

Project description

pyTreeLog: tree-like logging tool for python

This tool allows python users to log entries in layers of blocks that are displayed in a tree-like structure:

-start 
.-----------------------
|* f(x="test")
| -x = test
| .-----------------------
| :* Start loop:
| : -i=0
| : -i=1
| : -i=2
| :* end loop
| '-----------------------
'-----------------------
-done

Features:

  • Displayed python logging entries in tree-like structure;
  • Easily log the entry/exit of a function;
  • Output can be displayed in console or saved to a variable or a file

Note: this README.md file is both a doc and the source of doctest (see section Test for details).

Installation

Simply

pip install pytreelog

Or for likely the most updated one:

pip install git+https://gitlab.com/runsun/pytreelog.git

Or, if you don't want to have this doc and don't want to do tests, you can simmply copy the file pytreelog/pytreelog.py to wherever you desire.

Quick Preview

from pytreelog.pytreelog import TreeLog   
tl = TreeLog()
tl(x)    # log x

2 block types: *user block* and *func block* (See `Decorator Approach` below). 

tl.b(x)  # Beging a new *user block*. 'x' is optional. If not given, 
         # x will be assigned the function call arg values.  

tl.e(x)  # End the current block. 'x' is optional. If x not given
         # for a function that return something, it will show the
         # returned value

tl.data    # list of lines of the logged data
tl.text()  # returns the data as a string
tl.reset() # reset the data and block info to start anew 

Turn on/off

You can turn logging on/off with either :

tl.on()
tl.off()

or

tl._on = True
tl._on = False

default: on

Basic usage

>>> from pytreelog.pytreelog import TreeLog
>>> tl = TreeLog()
>>> def f(x):
...   tl.b('BEG')              ## <== New block
...   tl("test line "+str(x))  ## <== Any string
...   tl.e('END')              ## <== End of a block
>>> f(1)      

>>> print(tl.text()) # doctest: +NORMALIZE_WHITESPACE     
=============================================
TreeLog output
=============================================
.-----------------------
|* BEG
| -test line 1
|* END
'-----------------------

Beginning/End of a block : tl.b(), tl.e()

>>> def f(x):
...   tl.b()
...   tl("test line "+str(x))
...   tl.e()
>>> f(2)      

>>> print(tl.text()) # doctest: +NORMALIZE_WHITESPACE     
=============================================
TreeLog output
=============================================
.-----------------------
|* BEG
| -test line 1
|* END
'-----------------------
.-----------------------
|* f(x=2)
| -test line 2
'----------------------- 

Note: tl.b() logs function name and input value, tl.e() logs nothing. Also note that the output is appended to previous result.

Another example:

>>> tl.reset()                    
>>> tl('start test')    ## log a single line 
>>> def f(x):
...  a=0
...  tl.b()               ## Begin a block, logs func name and input value(s)
...  tl('x = '+str(x))    ## Log a line
...  tl.b('Starting loop:')  ## Begin of another block
...
...  for i in range(3):
...    tl('i='+str(i))       ## Log i
...
...  tl.e('end loop')        ## End of block
...  tl.e()               ## End of block
>>> f('test')
>>> tl('done')

>>> print(tl.text())  # doctest: +NORMALIZE_WHITESPACE
=============================================
TreeLog output
=============================================
-start test
.-----------------------
|* f(x="test")
| -x = test
| .-----------------------
| :* Starting loop:
| : -i=0
| : -i=1
| : -i=2
| :* end loop
| '-----------------------
'-----------------------
-done

Decorator Approach

The logging approach below to indicate a function block:

def ff():               
   tl.b()	 
   ...
   tl.e()    

can be done in a Decorator Aproach by using the TreeLog instance, tl, as the decorator to track the entry/exit of the function ff below:

@tl
def ff():                
   ...

This allows:

  • Automatically log the entry and exit point of a function;
  • Log the return value of a function:

Log function return

The Decorator Approach automatically logs the return of a function:

>>> tl.reset()
>>> @tl
... def test(a,b=0):
...   tl.b('User-block beg')
...   tl('Inside test()')
...   tl.e('User-block end')
...   return a+b
>>> test(3,4)
7

>>> print(tl.text())        # doctest: +NORMALIZE_WHITESPACE
=============================================
TreeLog output
=============================================
.-----------------------
|> test(a=3, b=4)
| .-----------------------
| :* User-block beg
| : -Inside test()
| :* User-block end
| '-----------------------
|< 7
'-----------------------

Note that, with Decorator Arrpoach, the symbols of function block head/tail (i.e., > and <) are different from those logged with tl.b() and tl.e() (i.e., *). This allows the log to tell function block and user-defined block apart:

  • function block: > and <
  • user-defined block: * and *

Both of them can be customized (See Customizable API below).

Decorator Approach for one-time use

If just want to track nothing but entry/exit of a function, use an unbound instance for one-time use:

>>> @TreeLog()
... def test3():
...     ...     

More example:

>>> tl.reset()
>>> @tl
... def test(a,b=0):
...   tl.l('Inside test()')
...   @tl
...   def inside(a,b):
...      return a+b
...   return inside(a,b)*2
>>> test(3,4)
14

>>> print(tl.text())        # doctest: +NORMALIZE_WHITESPACE
=============================================
TreeLog output
=============================================
.-----------------------
|> test(a=3, b=4)
| -Inside test()
| .-----------------------
| :> a.inside(b=4)
| :< 7
| '-----------------------
|< 14
'-----------------------

Use decorator approach in classes

Example of using TreeLog in classes:

>>> log= TreeLog()
>>> class Cls(object):
...    @log
...    def __init__(self): 
...         self.clsname = 'CLS'
...         self.setname( prefix='I am ')  ## run inside __init__
...    @log
...    def setname(self, prefix): 
...         self.name= prefix + self.clsname
...    @log 
...    def getname(self): 
...         return self.name

>>> cc = Cls()           ## run __init__, logging __init__ and setname.     
>>> cc.getname()
'I am CLS'

>>> cc.setname('This is ') ## run outside __init__. 
                           ## Note the user arg ('This is ') is logged.
>>> cc.getname()
'This is CLS'

>>> print(BR.join( log.data )) # doctest: +NORMALIZE_WHITESPACE
=============================================
TreeLog output
=============================================
.-----------------------
|> self.__init__()
| .-----------------------
| :> self.setname(prefix="I am ")
| '-----------------------
'-----------------------
.-----------------------
|> cc.getname()
|< "I am CLS"
'-----------------------
.-----------------------
|> cc.setname(prefix="This is ")
'-----------------------
.-----------------------
|> cc.getname()
|< "This is CLS"
'-----------------------

Note that:

  1. instance name, cc, is logged;
  2. setname is logged twice, one bound to self and the other to cc.
  3. getname has a return, which is logged, too.

Output

tl.data is a list containing the logged strings. tl.text() returns a single string. You can also log to external variable/file :

Log to an external variable

Use the external argument for TreeLog to save output to a variable, which is a dict contains a data key, {'data':[]}:

>>> external={'data':[]}     
>>> p = TreeLog(external=external)
>>> p.b('start')       
>>> @p
... def g(name):
...   p.l('test')
>>> g('g')
>>> p.e('stop')

>>> for x in external['data']: print(x)  # doctest: +NORMALIZE_WHITESPACE
=============================================
TreeLog output
=============================================
.-----------------------
|* start
| .-----------------------
| :> g(name="g")
| : -test
| '-----------------------
|* stop
'-----------------------

Log to a file

You can log to a file:

pp= TreeLog(logfile='./pytreelog.log')

Customizable API

Defaults of the TreeLog() module:

 TreeLog( header    = '='*45+BR+'TreeLog output'+ BR+'='*45
        , _on       = True
        , block_beg = '* '
        , block_end = '* '
        , func_beg  = '> '
        , func_end  = '< '
        , indent    = 1
        , blockline = '-----------------------'
        , blocksymbols= '|:'   
        , external  = None    # External var ( {'data':[]} ) to which the data is logged
        , logfile   = ''
        )

blocksymbols: a str containing symbols of the left-border of all layers. The default is |:, means the symbols of left-border will be | and :, alternatively.

The following example shows alternative symbols of 3 (i.e., [=!):

>>> tl= TreeLog(blocksymbols= '[=!')
>>> @tl
... def f():
...   tl.b('1st layer')
...   for i in (1,2):
...     tl.b('2nd layer')
...     for j in (3,4):
...       tl.b('3rd layer') 
...       for k in (5,6):
...         tl( str( (i,j,k) ) )
...       tl.e()
...     tl.e()
...   tl.e()
>>> f()

>>> print(BR.join( tl.data )) # doctest: +NORMALIZE_WHITESPACE
=============================================
TreeLog output
=============================================
.-----------------------
[> f()
[ .-----------------------
[ =* 1st layer
[ = .-----------------------
[ = !* 2nd layer
[ = ! .-----------------------
[ = ! [* 3rd layer
[ = ! [ -(1, 3, 5)
[ = ! [ -(1, 3, 6)
[ = ! '-----------------------
[ = ! .-----------------------
[ = ! [* 3rd layer
[ = ! [ -(1, 4, 5)
[ = ! [ -(1, 4, 6)
[ = ! '-----------------------
[ = '-----------------------
[ = .-----------------------
[ = !* 2nd layer
[ = ! .-----------------------
[ = ! [* 3rd layer
[ = ! [ -(2, 3, 5)
[ = ! [ -(2, 3, 6)
[ = ! '-----------------------
[ = ! .-----------------------
[ = ! [* 3rd layer
[ = ! [ -(2, 4, 5)
[ = ! [ -(2, 4, 6)
[ = ! '-----------------------
[ = '-----------------------
[ '-----------------------
'-----------------------

Test

All tests are written in this README.md (which means, this README.md is both a doc and tests). The content of this file is loaded by pytreelog.test() and assigned to TreeLog.__doc__ then tests are carried out by doctest.testmod() (See the code in pytreelog.test() for details).

\>>> from pytreelog import pytreelog
\>>> pytreelog.test()
--- Loading "C:\python37\lib\site-packages\pytreelog\README.md" for doctest:
--- Tests done.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pytreelog-194rc0.post1.tar.gz (18.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pytreelog-194rc0.post1-py3-none-any.whl (17.5 kB view details)

Uploaded Python 3

File details

Details for the file pytreelog-194rc0.post1.tar.gz.

File metadata

  • Download URL: pytreelog-194rc0.post1.tar.gz
  • Upload date:
  • Size: 18.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/40.8.0 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.7.3

File hashes

Hashes for pytreelog-194rc0.post1.tar.gz
Algorithm Hash digest
SHA256 6c82d160a60804c749c696fa4ebca94e0f76aba069adf8dd953e40dc9d58decc
MD5 ea9fd89270d293c3ef3693e43f2ba4d8
BLAKE2b-256 e5e5764390ab18b0c33399a42dc6bf3fe4f4ebf411774a68e8be10c93149dc47

See more details on using hashes here.

File details

Details for the file pytreelog-194rc0.post1-py3-none-any.whl.

File metadata

  • Download URL: pytreelog-194rc0.post1-py3-none-any.whl
  • Upload date:
  • Size: 17.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/40.8.0 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.7.3

File hashes

Hashes for pytreelog-194rc0.post1-py3-none-any.whl
Algorithm Hash digest
SHA256 9d53da8e1eabe537c251ba3ac55d8fb4d1710f870d18caadb5f2c9dbdaa78f09
MD5 a58abe0b8ffb738a8ce34cfde6855988
BLAKE2b-256 32e973d83a7e26e99fd668fb52dba334f065e8346b513a57fd9f830568e6f209

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page