Tracing

I uses traces quite a bit to make sure that code is doing what I expect (or figure out why it is not). Alhough I'm compulsive about making my traces readable, I like to keep my code base as uncluttered as possible. Here's a hack I came up with that helps me to meet these constraints.

Problem Statement

The SketchApps plugin framework includes logging methods that will output one or more lines of text, eg:

@pf.log.debug   'foo      ' + i(foo) if true #T

@pf.log.debug [ 'foo      ' + i(foo),
                'foo.bar  ' + i(foo.bar) ] if true #T

This produces nice output, but it's a hassle to create and maintain. Also, if there are several values, the tracing code can become voluminous. So, I wanted a shorthand way to create traces.

Approach

A method can accept arbitrary parameter values (eg, variables, method calls), but getting labels for the values is tricky and brittle. However, some pre-processing and the use of eval in the calling code lets me step around the problem, eg:

l = %w[ foo foo.bar ]
@pf.log.debug( @pf.x(l).map {|i| eval(i) } ) if true #T

The above example works as follows:

  • Create a list of strings containing variables, method calls, etc.

  • Massage the strings into a form suitable for use by eval.

  • eval each string in the list, via map.

  • Run @pf.log.debug on the resulting list.

Possible Concerns

Some readers may have concerns about the use of eval, fearing that it might lead to inefficient and/or insecure code. My take is that:

  • Inefficiency is not a problem in the context of traces.

  • Given that eval's input is defined by the program,
    use of eval should not add any security problems.

Supporting Code

class PF_Main
  ...
  def x(names)
  #
  # Expand an Array of (method or variable) names
  # into an Array of Strings suitable for use by eval.
  #
  # A solitary underscore (_) produces a spacer line.
  #
  # Typical usage:
  #
  #   names   = %w[ @comp_key @item_key _ ]
  #   @pf.log.debug( @pf.x(names).map {|l| eval(l) } )

    format    = "'%-20s  ' + i(%s)"
    eval_strs = names.map do |n|
      n == '_' ? "''" : ( format % [ "#{ n }", n ] )
    end
  end
  ...
end


This wiki page is maintained by Rich Morin, an independent consultant specializing in software design, development, and documentation. Please feel free to email comments, inquiries, suggestions, etc!

Topic revision: r4 - 02 Jan 2012, RichMorin
This site is powered by Foswiki Copyright © by the contributing authors. All material on this wiki is the property of the contributing authors.
Foswiki version v2.1.6, Release Foswiki-2.1.6, Plugin API version 2.4
Ideas, requests, problems regarding CFCL Wiki? Send us email