From RTSC-Pedia
[printable version] [offline version] | offline version generated on 02-Oct-2009 22:10 UTC |
Extending xdc.runtime Logging
How to create customized Log Event service providers
Contents |
Introduction
The xdc.runtime package contains several modules that work together to provide rich application diagnostic support that can be controlled in real-time within deployed systems. This diagnostic support is centered around APIs that enable the application to generate or control the generation of Log "events". Every such event is eventually "handled" by a module that implements the ILogger interface. These modules are responsible for recording, displaying, or transmitting the event as appropriate for the application.
Two such modules are provided in the xdc.runtime package:
- LoggerBuf - a module that manages a circular memory buffer where events are stored, and
- LoggerSys - a module that interprets each event as it occurs and outputs the result via System_printf().
In addition, it is possible to create new implementations of the ILogger interface that leverage platform or application-specific capabilities. For example, a logger may transmit the events via existing application communication links, filter events for special handling, or record them to a mass storage device.
In the following sections we focus on how to create modules that implement the ILogger interface and show how these modules fit into the overall event logging architecture of the xdc.runtime package.
Overview
The Log module provides an interface that allows any client code to embed statements that conditionally generate "diagnostic" events. These events are "handled" by an application-specific or even platform-specific, event "logger". This architecture allows code that generates events to be developed and delivered independently of code that handles events. The handling of events is often application or platform specific:
- depending on the system hardware platform, events may be handled by the same processor generating the event or events may need to be transmitted to other processors in the system for display;
- depending on the application's real-time requirements, events may be displayed as they occur or may need to be deterministically buffered and displayed "in the background" by a separate low priority thread.
Regardless of how events are handled, the code generating the events need never change or even be re-compiled.
Architecture
All event "loggers" are modules that implement the ILogger interface.
Source code that embeds calls to Log_write() or Log_print() enables integrators to conditionally enable and disable the generation of events at these call sites. The events generated by these calls include call site information. In particular, the module ID of the caller of Log_write() (or Log_print()) is encoded in the event that is passed to the underlying ILogger associated with the module. This not only enables loggers to conditionally handle events from different parts of the system, it keeps the number of parameters to the embedded Log_write (and Log_print()) methods to a minimum - making their presence in the code stream less intrusive.
- Both Log_print() and Log_write() "compose" events that are then passed to an underlying "logger".
- loggers are responsible for "handling" events; e.g., storing, interpreting, or displaying each event
- each event encodes both an "event ID" and the module ID of the call site
- the logger used to handle the event is determined by the module containing the call site; if the call site is not in any module, the logger associated with xdc.runtime.Main module is used.
The figure below illustrates the flow of control that results from a simple Log_print0() statement in the application all the way down to an ILogger module that "handles" the resulting Log event.
Configuration
All RTSC modules can be configured with a unique logger. In addition, any code that is not in a module is implicitly associated with the xdc.runtime.Main module. So, from the point of view of logging, it's possible to consider all code in an application as being part of some module with a potentially unique logger.
Of course, most systems do not create a unique logger for each module but, as we'll see in the examples, the ability to associate a unique logger for selected modules can be extremely useful. Not only is it possible to strike a different balance between logging overhead with system visibility within different sub-systems of an application, but you can also "chain" loggers to provide sophisticated application-specific event filtering and triggers (see Example 1).
The most common configuration, illustrated in the figure below, is to have a single logger for the entire application. In this figure, the application consists of the modules xdc.runtime.Main and ModA through ModZ, where xdc.runtime.Main represents all code not in any module and ModA is a module that implements the xdc.runtime.ILogger interface.
The logger field shown for each module is simple a pointer to an instance object created by a module that implements the ILogger interface. In addition, each call to a Log function implicitly references the logger pointer associated with the module in which the Log function is called. By assigning different logger pointers to selected modules, the system integrator can "redirect" the output of the Log statements for these modules without ever having to recompile these modules.
The configuration script that corresponds to this figure is shown below.
| var Defaults = xdc.useModule("xdc.runtime.Defaults"); var ModA = xdc.useModule("...ModA"); Defaults.common$.logger = ModA.create(); /* create an anonymous ILogger instance (say inst#0) */ |
Notice that although we've used to xdc.runtime.Defaults module to set a default logger for "all" modules (exactly as we did in hello.cfg Example 2), the ModA module's logger does not point to this logger instance. Why wasn't the logger for ModA also set to the specified default logger?
The xdc.runtime package does not use the common$.logger setting of the Default module to enable logging on modules that implement the ILogger interface.
Imagine if we enabled "entry" trace on ModA and its logger were set to an instance created by ModA. Although it may not be obvious at first, your application would enter an infinite recursion on the first call to any Log operation and you'd be in for a long day of debugging. You might wonder why we would even allow the assignment of a logger instance to an ILogger module. As we'll see in Example 1, the ability to assign an ILogger instance to an ILogger module allows you to easily create and use powerful application-specific Log event filters in your application.
Examples
The best way to understand how to use and take advantage of loggers is to study some simple examples. In the table below, we provide examples that illustrate the key requirements of loggers and provide links to more advanced topics.
Example | Description | Purpose |
---|---|---|
Example 1 | Simple Log_Event filter | illustrate the ability to add custom event filtering without changing any existing sources |
See also
Using xdc.runtime Logging | How to generate and control Log events |
[printable version] [offline version] | offline version generated on 02-Oct-2009 22:10 UTC |