| Visible Workings > Ruby-Trace User's Guide |
The Ruby-Trace
User's Guide |
API |
On this page, hyperlinks from capitalized words (like Destination) point to descriptions of a class that's part of the API. Hyperlinks from lowercase words (like threshold) point to definitions in the glossary.
A Connector object connects Topics to
Destinations. A Topic is an object with
level methods such as error and warning. Those methods take
strings or blocks that produce strings. They convert the strings into
Messages and send them to their Destinations. But that
happens only if the Topic's threshold for that Destination allows
it. Thresholds can be set using the Connector (in which case they
apply to all its Topics) or an individual Topic.
If messages need to be converted into strings, a Formatter is used. Different types of Destinations initialize the Formatter differently to get terser or more verbose output.
Different Destinations do different things. A PrintingDestination prints to standard output. A BufferDestination maintains a ring buffer of Messages, which are drained when needed. A LogfileDestination prints to a file, which may be timestamped and may use version numbers.
A Theme is an ordered list of level names. When a Topic is created, it is given a particular theme (such as "debugging"). Its level methods are constructed from the Theme's level names.
The methods described below do considerable error checking of their
arguments, which is generally not described. When they find an error,
they throw a Trace::Exception that contains a helpful error message.
require 'ruby-trace/connector'
# creation
conn = Connector.new { ... }
conn = Connector.debugging_buffer { ... }
conn = Connector.debugging_buffer_and_file('logfile.txt', ...) { ... }
conn = Connector.debugging_printer { ... }
# utilities for use when creating connector objects.
Connector.new {
add_theme('my_theme', %w{level1 level2}, :default)
add_destination(Destination.new('my_destination'), :default)
theme_and_destination_use_default('my_theme', 'my_destination', 'level1')
use_environment_variable 'TRACEENV'
debugging_theme
debugging_theme_and_buffer
}
# instance methods
conn.topic 'my_topic'
conn.add_method_for_topic 'my_topic'
conn.replace_destination(Destination.new('my_destination'))
conn.drain('my_destination', 'his_destination')
conn.topic_named 'my_topic
conn.destination_named 'my_destination'
A Connector mainly exists to connect Topics to Destinations. Most
often, there is one Connector per program. It's usually assigned to a
global like $trace or made accessible via an instance method of
Object. See 'ruby-trace/start/global.rb' and
'ruby-trace/start/method.rb' for examples.
If the Connector has been assigned a default Theme, it is itself a Topic with the name ''.
If you prefer the spelling "Connecter", you can use that instead.
Connector.new {optionalBlock}
Create a new Connector. If the optionalBlock is specified it
is run in the context of the new Connection instance. The block should
create Themes, Destinations, and
Topics and connect them to each other. See below for
useful methods.
If a default theme is provided, the Connector itself will be a Topic that can be sent trace messages.
Unless optionalBlock uses
Connector#use_environment_variable, the Connector pays no
attention to the environment.
Connector.debugging_buffer {optionalBlock}
Create a Connector with a
debugging theme
as the default Theme. Topics of that Theme are by default
connected to a BufferDestination named 'buffer'.
The default threshold for the debugging buffer is event.
If the optional block is given, it's run after the destination is created.
This connector obeys the environment variable TRACEENV.
Connector.debugging_buffer_and_file(*file_args) {optionalBlock}
Create a Connector with a
debugging theme.
Topics of that theme are by default
connected to both a BufferDestination named 'buffer'
and a LogfileDestination named 'file'. The
'file' destination is passed the file_args.
The default threshold for the buffer is event. For the
logfile, it's announce.
If the optional block is given, it's run after the buffer and file destinations are created.
This connector obeys the environment variable TRACEENV.
Connector.debugging_printer {optionalBlock}
Create a Connector with a
debugging theme.
Topics of that theme are by default
connected to a PrintingDestination named 'printer'.
The default threshold for the buffer is none, so no trace
messages are normally printed.
If the optional block is given, it's run after the destination is created.
This connector obeys the environment variable TRACEENV.
These are instance methods used in blocks of the creation methods described above.
Connector#add_theme(themeName, levelArray, optionalDefault)Add a Theme with the given themeName to the Connector. levelArray is an array of strings. Each is a level for the theme, least specific first. optionalDefault, if non-nil, means that the Theme is the default for Topics created on this Connection. There may be only one default theme.
Connector#add_destination(destination, optionalDefault)Add a Destination to the Connector. optionalDefault, if non-nil, means that the destination will be one of the default destinations for Topics created on this Connection.
Connector#theme_and_destination_use_default(themeName, destinationName, levelName)Messages from any Topic with themeName as its Theme destined for the Destination named by destinationName will use the levelName as their threshold, unless it is overridden by topic-specific thresholds.
You needn't connect each Theme to each
Destination. However, any attempt to create a topic (with
Connector#topic) using unconnected Themes and Destinations
will result in an error.
Connector#use_environment_variable(aString)Tell the connector to obey the given environment variable. For the format of the variable's value, see More on control of thresholds.
If there's only one Connector in a program, it by convention obeys the environment variable TRACEENV.
Connector#debugging_themeAdd the standard debugging theme.
Connector#debugging_theme_and_buffer
Add the standard
debugging theme, together with a
BufferDestination that is the default destination. Its
threshold is event.
Connector#topic(topicName, keywordArgs)Create a Topic. With no keywordArgs, the Topic uses the default theme and sends messages to the default destinations. Here are the keywords:
The destinationName overrides the default destination(s).
The destinationArray is an array of destination names. They override the default destination(s).
The themeName overrides the default.
The same topicName can be used more than once. Each call returns the same object.
Connector#add_method_for_topic(topicName)Create a singleton method on the Connector. Its name is topicName and its value is the Topic with that name. The Topic must have previously been created. A Topic may be added more than once; the later additions have no effect.
These methods are referred to as level methods.
Connector#replace_destination(destination)
The argument is a Destination. Its name is that of a
Destination previously added with
Connector#add_destination. That Destination is replaced.
Connector#drain(sourceDestination, sinkDestination)
The sourceDestination is the name of a Destination that
responds to the message to_destination (currently only
BufferDestination). Each Message from the source is
sent to the Destination named by sinkDestination.
Connector#topic_named(name)Return the Topic named by name.
Connector#destination_named(name)Return the Destination named by name.
require 'ruby-trace/topic'
# Creation
topic = connector.topic('name')
# instance methods
topic.set_threshold('buffer', 'error')
topic.set_default_threshold('buffer', 'verbose')
# singleton methods
topic.level 'string'
topic.level { 'string' }
topic.level_value { 'variable' }
A Topic object has singleton level methods determined by the levels of its Theme. These methods check whether any of the thresholds for the Topic's Destinations allow messages of that level to pass. If so, a Message object is created and handed to whichever Destinations have the allowing threshold.
The methods have three formats.
The string is the body of the message.
If the Topic's thresholds allow, the block is evaluated to obtain the body of the message.
If the Topic's thresholds allow, the body of the message is
expression as a string, followed by its value. For example,
{"a"} will produce "a -> 5" if a has the value 5.
When Ruby-trace is used for debugging, a Topic is normally a subsystem (such as 'gui', 'net', etc.)
Normally, trace messages are identified as coming from the caller of the level method. If the optionalOffset is 1, they're identified as coming from the caller of the caller of the level method. This allows you to wrap level methods and still get useful locations in the trace output.
A Topic's threshold can be controlled independently of all other topics.
Topics should not be created directly. Create them with
Connector#topic.
Topic#set_threshold(destinationName, levelName)Set the Topic's threshold for destinationName to levelName. There are two special values for levelName:
No Messages will be passed to the destination.
Set the threshold to its default value (presumably after
changing it with an earlier call to set_threshold).
Topic#set_default_threshold(destinationName, levelName)
Set the Topic's default
threshold for
destinationName to
levelName. This is the level that set_threshold(dest,
'default') uses. As a special case,
set_default_threshold(dest, 'default') defers to the
Connector that was used to create this Topic. That Connector has a
global default threshold that controls all messages from Topics of
a particular Theme to a particular Destination. See
Connector#theme_and_destination_use_default.
require 'ruby-trace/destination'
dest = Destination.new('name')
dest.accept(message)
Destination is an abstract superclass.
Destination.new(stringName)All Destinations have names. After they are added to a Connector, they are referred to by their stringName.
Destination#accept(message)Every Destination accepts a Message and puts it somewhere. Where "somewhere" is depends on the subclass.
require 'ruby-trace/destination'
print_dest = PrintingDestination.new('printer')
print_dest.formatter = Formatter.new
print_dest.accept(message)
Formats the message according to its Formatter and puts it to
$defout. Unless the Formatter is changed, the output looks like
this:
print-example.rb:21:in `initialize' = topic announce: The body of the message.
PrintingDestination.new(stringName)Creates the printing Destination.
PrintingDestination.formatter=(aFormatter)Changes the Formatter used.
require 'ruby-trace/destination'
buf_dest = BufferDestination.new('buffer')
buf_dest.accept(message)
buf_dest.limit=1000
buf_dest.clear
buf_dest.messages
buf_dest.to_IO(anIO, formatter)
buf_dest.to_destination(destination)
A BufferDestination is a ring buffer that stores a limited number of
Messages. The messages can be sent to an IO or
another Destination. They are not formatted until they are sent.
BufferDestination.new(stringName)Creates a BufferDestination that can hold 100 messages.
BufferDestination.limit=(anInteger)Change the number of messages the buffer can hold to anInteger, which must be greater than 0. If the new limit is smaller than the number of messages in the buffer, the oldest are discarded.
BufferDestination.clearEmpty the buffer of all messages.
BufferDestination.messagesReturn the Messages in the buffer as an array. Messages are in the order they were created. If the buffer is not full, the array will be smaller than the buffer's limit.
BufferDestination.to_IO(anIO, optionalFormatter)
Format the Messages and print them (with puts) to
anIO. If optionalFormatter is not given, the two-line format
used by PrintingDestination is used.
BufferDestination.to_destination(destination)
Each Message in the buffer is given to destination's
accept method. Note that destination is a Destination,
not the name of one.
require 'ruby-trace/destination'
dest = LogfileDestination.new('file', 'Tracelog.%t%b.txt', 'a', 1000000, '010')
dest.accept(message)
dest.limit=1000000
dest.formatter = Formatter.new
dest.filename
dest.reopen
dest.close
A LogfileDestination is a file. It may optionally have a timestamp in its name. It may have a limited size, in which case a number of backup files may be created. See the discussion in the documentation for server programs.
If the LogFileDestination's Formatter is not changed, the file will contain messages that look like this:
topic-example.rb:10 at 2001/07/20 00:27:27 = accounting error: Impossible event explode in state crashed.
LogfileDestination.new(stringName, optionalFilename, optionalMode, optionalLimit, optionalGreatestBackupTag)Open the destination. If the optionalFilename is not given, it is "Tracelog.txt". If the optionalMode is not given, it is "w" (clear file on open). Otherwise, it must be "a" (append). If the optionalLimit is not given, the destination is of unlimited size. If the optionalGreatestBackupTag is not given, it is '000'.
If the optionalFilename contains the string "%t", those two characters are replaced with a timestamp in the format YYYYMMDDHHMMSS.
If the optionalFilename contains the string "%b" and opening the logfile would overwrite an existing file, that existing file is backed up to a name where "%b" is replaced with a string in the range '.000' .. .optionalGreatestBackupTag. The string chosen is the successor of that used by the current youngest file, wrapping around if needed.
Note that "%b" adds a period to the front of the three-digit string. That way, "Tracelog%b.txt" will create files "Tracelog.txt" and "Tracelog.000.txt",
LogfileDestination::InfinityUsed to open a logfile with unlimited size.
LogfileDestination#limit=(anInteger)Set the size limit to anInteger. Note that the limits are only approximate. That's because I didn't have the energy to write code to figure out that we're on Windows and count when a newline is converted into two characters.
LogfileDestination#formatter=(aFormatter)Use aFormatter when formatting output.
LogfileDestination#filenameThis is the filename with "%t" expanded and "%b" stripped out.
LogfileDestination#reopenClose the logfile and reopen it to a file of the same name. If the filename given to the constructor contained a "%b", a backup file is created.
LogfileDestination#close
Close the File associated with the destination. Once closed,
it should not be reopened.
require 'ruby-trace/formatter'
formatter = Formatter.new('"#{time}: #{body}"', "%a, %b %d")
formatter.accept(message)
A formatter is initialized with up to two strings that describe how a Message should be formatted. It produces strings formatted accordingly.
Formatter.new(messageFormat, timeFormat)The messageFormat is a string with expressions that will be substituted in the context of the Formatter. The Formatter's accept method makes available certain variables that are useful in constructing output. These are:
The time the Message was created, formatted according to timeFormat.
The line where the trace message
was sent. (For example, the place where $trace.error 'oops' is
sent.) Formatted as in
Ruby stack backtraces and compiler error messages.
The name of the level method (error, warning, etc.)
The name of the Topic the trace message was sent to.
The string that was the argument to the level method (or resulted from evaluating the block associated with the method).
Because messageFormat is to be evaluated in the context of the
Formatter, it must be "double-quoted" to prevent substitution in
the caller's context. That is, "#{time}: #{body}" would not be
correct because #{time} would be substituted with the value of a
variable time local to the method that calls
Formatter.new. '"#{time}: #{body}"' (with surrounding single
quotes) works as intended.
timeFormat is used to format the time variable before
it's substituted into the messageFormat. It is a string of
the form accepted by Time#strftime.
Formatter::TWO_LINEThe default messageFormat.
'"#{location}#{$/}= #{topic} #{level}: #{body}"'
Formatter::TWO_LINE_WITH_DATE
The kind of messageFormat used by LogfileDestination.
'"#{location} at #{time}#{$/}= #{topic} #{level}: #{body}"'
Formatter::VERBOSE_SORTABLE_TIMEThe kind of timeFormat used by LogfileDestination. Most significant time units come first.
"%Y/%m/%d %H:%M:%S"
Formatter#accept(message)The message is formatted and the resulting string is returned.
require 'ruby-trace/message'
Topics hand Messages to
Destinations. Messages capture the information
available when a trace message
is sent, such as the line number it was sent from. For a list of that
information, see Formatter.new.
Since I don't think you ever want to create or use Messages directly, they're not further described.
require 'ruby-trace/misc'
A Theme is essentially a list of level names. The level names determine which trace level methods a Topic responds to.
Themes are created with Connector#add_theme. You should never need to access Themes directly.
API |
Please send comments on this document to marick@visibleworkings.com. The ruby-trace mailing list is at at http://groups.yahoo.com/group/ruby-trace.
Copyright © 2001 by Brian Marick. This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, draft v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub).