Skip to content
yotamr edited this page Jun 2, 2012 · 18 revisions

Welcome

Traces is an API tracing framework for Linux C/C++ applications. One of the main bottlenecks to development productivity is debugging. The most common debugging method is to litter one's code with trace messages in the hope that once a bug is discovered, the trace messages will be sufficient to understand its root cause. Often this is not the case and the developer must narrow down the possible source of the bug by adding additional trace messages in the code and try to reproduce the bug again. During development, this technique can take up a lot of a developer's time. A worse scenario is having a bug appear on a client-installed application and not having sufficient trace data to understand it. The goal of traces is to replace existing debug methodologies and allow developers to focus more on developing and less on technical bug-hunting.

Traces was written to provide rich trace information prior to the bug occurring. Traces contains a trace instrumentor, traces daemon and trace readers.

Traces features

  • Explicit tracing through DEBUG/INFO/WARN/ERROR/FATAL macros

  • Automatic tracing of every function leave/entry and parameters/return values

  • Type-aware tracing. Traces display enum value names and entire structures

  • Code instrumentation during compile-time

  • Colored trace logs

  • Interactive and non-interactive trace readers

Traces can be used during development as well as in client-installed applications, to enable client-side debugging. Traces has a small CPU footprint.

Architecture

A traced application does not write trace records directly to the filesystem. Instead, the trace_dumper application maps the shared memory areas in which the records reside and dumps them to the filesystem to a single file. Having a single file contain all the log information allows the developer to get a sense of the entire system behavior at a given time, rather than the behavior of an isolated process. Records can later be viewed by a standalone interactive/non-interactive trace reader

More about the Architecture

Example

Consider the following C code

#include <traces/trace_user.h>
enum calculation_type {
    CALCULATION_TYPE_DECREMENT,
    CALCULATION_TYPE_INCREMENT,
};

int calculate(enum calculation_type e, int value) {
   INFO("Calculation type:", e);
   if (e == CALCULATION_TYPE_DECREMENT) {
       return value - 1;
   } else if (e == CALCULATION_TYPE_INCREMENT) {
       return value + 1;
   }

   return -1;
}

static void increment_twice(int *value)
{
    (*value) = calculate(CALCULATION_TYPE_INCREMENT, (*value));
    (*value) = calculate(CALCULATION_TYPE_INCREMENT, (*value));
}

int main(void) {
    int value = 500;
    while (1) {
        value = calculate(CALCULATION_TYPE_DECREMENT, value);
        increment_twice(&value);
        WARN("Next iteration", value);
        usleep(100000);
    }

    return 0;        
}

The trace output after running this code for a few iterations is this: Sample trace output

Getting started

Getting started