.. _tracing-manager:

********************
Tracing
********************

.. highlight:: none

Overview
====================

The tracing configuration in the iDigi Device Integration Application
controls how device driver, service, logger, and presentation
informational messages are recorded or presented.

.. note:: In this document, all of these types will be generically
          referred to as drivers.

Driver authors often put informational messages in their code to help
understand what is happening. For example, the :doc:`alarm clock
device <devices/alarm_clock>` can print a "time is now..."  message at
predefined intervals using its "printf" setting.

Normally, a user is not interested in what a driver is doing
unless something bad happens. For example, a user is probably not
interested in an XBee device's startup sequence, but would like to
know if the XBeeDeviceManager suddenly loses contact with a device.

Developers can specify the importance of messages using trace levels.
The five different trace levels, from highest to lowest importance,
are:

**critical**
    Used for top-priority messages.  Something fundamentally
    broke, and something drastic is probably going to happen.

**error**
    Reserved for messages about broken functionality.

**warning**
    Used for noting minor transient problems, depreciated or incorrect 
    configurations, or other out-of-the-ordinary happenings.

**info**
    This level is used to note significant, normal events. Users might 
    be interested in this level.
    

**debug**
    Users are probably not interested in this trace level. It is used
    for recording technical details, and is usually quite verbose.
    


Basic Configuration
====================

A simple tracing configuration block looks like this::

  tracing:
    default_level: info
    default_handlers: 
      - stdout
      - file=all_logs.txt

This instructs the tracing manager to send all messages at the info
level or higher to stdout and to the file all_logs.txt. The file
all_logs.txt will be overwritten each time Dia is run.

.. note:: **stdout** is short for "standard output". It is the default
          place where programs write their output. This usually means
          printing to the console. The other standard stream the
          tracing manager uses is **stderr**, which corresponds to the
          "standard error" stream. It also usually prints to the
          standard console.
          
If no tracing configuration if present in the yaml file, the default 
settings are used. The defaults are identical to this block::

  tracing:
    default_level: warning
    default_handlers:
      - stderr


Filters
=======
What if you only want to see particular messages based on filter name,
trace level, and/or message contents?

This can be done using filters.

Names
----------------
If you to see the **info** level messages and above for one
particular device (named "foo"), and only **warning** or higher for
everything else, use the following block in your yaml file::

  tracing:
    filters:
      - name: foo
        level: info

    default_level: warning
    default_handlers:
      - stdout

What if you have several devices (named "foo", "foo1", "foo2" and "foo3") 
that you want to see **info** level and above? You could write out a rule 
for each one, or you could just use simple pattern matching and write a 
single entry like this::

  tracing:
    filters:
      - name: foo*
        level: info

    default_level: warning
    default_handlers:
      - stdout


Levels
----------
If you are only interested in specific levels of messages, you can 
be explicit::

    tracing:
      filters:
        - name: *
	  level: =debug or =info

      default_level: warning
      default_handlers:
        - stdout

This configuration writes all debug and info messages to stdout. Every single tracer matches the name '*', but only messages at 'debug' and 'info' level match the 'level' filter. So the default level is never reached.

On the other hand, this::

    tracing:
      filters:
        - name: *
	  level: =debug or =info
	  handlers:
	    - file=debug_and_info.txt
	  stop: False

      default_level: warning
      default_handlers:
        - stdout

writes all debug and info messages to the file debug_and_info.txt. It
also prints all messages at warning level and higher to stdout. The
difference is that even though all tracers match the name "*", setting
stop to False means that processing continues past the failure.


Messages
--------
Filtering can also be done on message contents. For example::

  tracing:
    filters:
       - name: *
          msg: *moo*
          handlers:
	    - file=cow_messages.txt
          stop: False

    default_level: warning
    default_handlers:
       - stdout


examines all messages and saves all of those that contain the string
"cows" into the file cow_messages.txt.


Grammar for Level and Message Matching
---------------------------------------
A level string is defined formally as follows:

.. productionlist::
  level_string: basic_level | "=" basic_level (" or =" basic_level)*
  basic_level: "critical" | "error" | "warning" | "info" | "debug"

A name string is defined formally as follows:

.. productionlist::
  name_string: and_list (" or " and_list)*
  and_list: match_string (" and " match_string)*

A match string is any string with '?' as a wild character
match and '*' as a wild (and possibly empty) string match.

