Using xdc.runtime Logging/Example 3

From RTSC-Pedia

Jump to: navigation, search
revision tip
—— LANDSCAPE orientation
[printable version]  offline version generated on 18-Nov-2017 00:11 UTC  

Using xdc.runtime Logging/Example 3

Adding logging to existing code bases


Adding Logging to Existing Code Bases

The simplest way to add logging is to simply #include the xdc.runtime.Log header and insert appropriate Log_info(), Log_warning(), and Log_error() statements into your existing code base.

#include <xdc/runtime/Log.h>
Log_info2("Processed data: (0x%x, %d)", (IArg) handle, arg2);

This by itself allows clients of your code to get visibility into its in real-time, even in deployed systems.

All Log statements from code outside of RTSC modules will be sent to the logger associated with the xdc.runtime.Main module, and will be filtered by the xdc.runtime.Main module's diagnostics mask.

Casting Arguments to IArg

Why do we have casts around some of the arguments to Log_print()? Unlike printf(), the Log_write() and Log_print() methods are not vararg functions; they are macros - which, prior to C99, are not allowed to take a variable number of arguments - that pass the specified arguments to an ILogger function whose arguments are of type IArg. The IArg type, while large enough to hold a pointer, is not a pointer type and many compilers emit a warning when passing a pointer argument to either Log_print() or Log_write(); the cast to IArg suppresses these warnings.

Format strings, while very convenient, are a well known source of portability problems: each format specification must precisely match the types of the arguments passed. Underlying "printf" functions use the format string to determine how far to advance through their argument list. For targets where pointer types and integers are the same size there are no problems; each argument has the same size after the normal C promotions.

Suppose a target's pointer type is larger than its integer type. In this case, because integer arguments are widened to be of type IArg, a format specification of "%d" causes an underlying printf() implementation to read the extended part of the integer argument as part of the next argument(!). To get around this problem and still allow the use "natural" format specifications (e.g., %d and %x with optional width specifications), System_printf() supports a special format conversion operator that specifies that all subsequent arguments have been widened to be of type IArg: all arguments after the sequence "%$A" are treated as though they have been widened.

More Granular Control Through xdc.runtime.Registry

You may want to allow clients of your code to independently configure and control your Log statements independent of other content producers. If all content producers rely on xdc.runtime.Main as the source of their Log events, system integrators are not able to easily separate events coming from different parts of their application.

The xdc.runtime.Registry module maintains a registry of modules which have been registered at runtime. Currently, the Registry is used to enhance logging for non-RTSC-module code, but it may eventually have other purposes.

By registering your code as a module and specifying a name for it, you are given a unique module id to identify your code as a source of log events, and are given a separate diags mask for controlling filtering at a more granular level.

"hello world"

This section demonstrates the use of the Registry through a simple example. This configuration (shown below) allows runtime control of all events, enables "info" events for all registered modules, and outputs events via System_printf.

var Log = xdc.useModule("xdc.runtime.Log");
var Diags = xdc.useModule("xdc.runtime.Diags");
/* Use the Registry and enable the 'INFO' category for all registered modules */
var Registry = xdc.useModule("xdc.runtime.Registry");
Registry.common$.diags_INFO = Diags.RUNTIME_ON;
/* Use the LoggerSys ILogger service provider */
var Logger = xdc.useModule("xdc.runtime.LoggerSys");
/* Create and bind a logger for all registered modules */
Registry.common$.logger = Logger.create();

In outline, the configuration file

  1. Gets a reference to the Registry module (via xdc.useModule()) so that subsequent statements can configure this module 1.
  2. Enables runtime control of "info" events for all Registered modules 2. Alternatively, we could have set the INFO category to be initially disabled by setting Main.common$.diags_INFO to Diags.RUNTIME_OFF. The state of the Registry module's mask is used as the initial mask state for all newly registered modules.
  3. Uses the LoggerSys module 3 to create an instance of a Log event "handler" and sets this handler to be the Registry module's logger 4. Instances of LoggerSys simply print events as they occur using System_printf(). All events generated by registered modules will be sent to the Registry module's logger.

This simple application will demonstrate adding a module to the registry and logging from it. Note in the output that the log event is marked as coming from the module "app", rather than "xdc.runtime.Main" as in Example 1.

#define Registry_CURDESC    app_desc
#include <xdc/std.h>
#include <xdc/runtime/Registry.h>
#include <xdc/runtime/Log.h>
Registry_Desc app_desc;
int main(int argc, String argv[])
    Registry_Result result;
    result = Registry_addModule(&app_desc, "app");
    if (result != Registry_SUCCESS) {
        return (-1);
    Log_info0("hello world");
    return (0);
app: "app.c", line 20: hello world

This example demonstrates a number of steps required for using the Registry.

  1. In order to treat a C file as a module to be registered, it must define the symbol Registry_CURDESC 1 before the inclusion of any xdc.runtime module headers. This symbol should be defined to an externally declared Registry_Desc structure 3 which is used by the Registry to track state for your module.
  2. The C file must include the Registry.h header file 2.
  3. The module is added to the Registry with a call to Registry_addModule, passing the address of the Registry_Desc structure 4. A globally-unique name must be provided; here we are simply naming our module "app".
  4. The call to addModule will return a status code indicating success or the reason for failure.
  5. Once the C file has been added to the Registry as a module, we can call Log APIs without any changes.

Once a module has been added to the Registry, it has its own diags mask which can be modified using the Diags_setMask API. For example, to disable the INFO category for our "app" module,

#include <xdc/runtime/Diags.h>

See also

Using xdc.runtime Logging/Example 1 Classic "hello world" using Log
Using xdc.runtime Logging/Example 2 Events provided by all RTSC target modules
Using xdc.runtime Logging/Example 4 Adding Logging to RTSC Modules

[printable version]  offline version generated on 18-Nov-2017 00:11 UTC  
Copyright © 2008 The Eclipse Foundation. All Rights Reserved
Personal tools
package reference