A blazingly fast and memory efficient tracing frontend.
To explain the idea behind common low level tracing it is best to break down a small example:
CLLTK_TRACEBUFFER(MyFirstTracebuffer, 1024);
int main()
{
const char * name = "Max";
const int age = 42;
CLLTK_TRACEPOINT(MyFirstTracebuffer, "Hello %s, you are %d years old", name, age);
return 0
}The first line defines the tracebuffer with the name MyFirstTracebuffer and a size of 1024byte. Nothing else is needed to enable the tracing.
The name is used to associated tracepoint with this tracebuffer and is also the file name for this tracebuffer. In this case this would be MyFirstTracebuffer.clltk_trace with a ringbuffer body size of 1024byes.
The tracepoints CLLTK_TRACEPOINT defines first the target tracebuffer, than the format string, followed by the arguments.
- Add repository to your project. By cloning, downloading or with CMake-FetchContent.
- Link your target against
clltk_tracing_staticorclltk_tracing_shareddepending if you want to like static or shared. - Define tracebuffers and tracepoints in your code
- Build your target
- Set environment variable if you want to trace to a specific location. Otherwise the location, from which you call the executable, is chosen.
- Call your executable.
- Decode traces:
- decode traces while your executable is running or after it stopped by:
decoder_tool/python/clltk_decoder.py <path to tracebuffers> - copy tracebuffer with
cpor create a archive to create a snapshot. And decode it later with:decoder_tool/python/clltk_decoder.py <path to tracebuffers>
- decode traces while your executable is running or after it stopped by:
- View your traces in
output.csv
Tampering with Trace Files: Any modification or tampering with the trace files can cause the library to crash or potentially freeze the system. Ensure the integrity of these files is maintained to avoid instability.
Security and Access Rights: If the access rights to the trace files are not properly configured, an attacker could exploit this vulnerability for a denial-of-service (DoS) attack. It is essential to set up correct permissions to prevent unauthorized access.
Unencrypted Data: The user is solely responsible for determining which information is traced and stored in these files. Please note that this information is stored unencrypted, so ensure that sensitive data is not included in the trace logs unless proper precautions are in place.
Due to the implementation, design decisions and compiler limitation there are some constrains with this tracing system.
-
It's is never possible to change the tracebuffer of a tracepoint because the tracepoint is associated with the tracebuffer at compile-time. If you really want to do this, you may use
CLLTK_DYN_TRACEPOINTbut this could be magnitudes slower thanCLLTK_TRACEPOINT. -
A maximum of 10 arguments are supported.
-
Format-string must be a string literal.
-
All arguments, pid, tid and timestamp together may not be bigger in size than UINT16_MAX - 8 bytes.
-
To detect if a tracebuffer is defined you need an additional Macro, like:
#define My_Tracebuffer /* empty */ CLLTK_TRACEBUFFER(My_Tracebuffer, <size>); #if defined(My_Tracebuffer) #message("now you could detect if tracebuffer is define"); #endif
-
It's not possible to tracing inside a member function defined inside a class or struct definition, like the following:
// header struct A { void foo(void) { CLLTK_TRACEPOINT(My_TB, "it is not possible to trace here"); // fill fail at link-time } }
To still be able to trace in change this to:
// header struct A { void foo(void); } // source void A::foo(void) { CLLTK_TRACEPOINT(My_TB, "now it is possible to trace here"); }
You may use the repository with or without a container. To run any scripts, build, test, or package commands inside the recommended container, use: ./scripts/container.sh <your command + args>. Alternatively, you can jump directly into the container with ./scripts/container.sh.
It is also possible to cross compile with the container env by using of example: CONTAINER_ARCH=arm64 ./scripts/container.sh.
To build this repository for test purposes or development run:
./scripts/ci-cd/build_userspace.shTo run all test build the whole project with cmake and than run:
./scripts/ci-cd/test_userspace.shThis will run all c++ and python tests.
For c++ googletests are used and there are covering many internal function and some api functions. To test internal function access to these function is required. There for a static linked version of clltk_tracing is used.
For python test unittest is used and these test covers the tracing and decoding of the examples and building test cases with valid and invalid use of the tracing api.
./scripts/ci-cd/run.shcmake --workflow --preset rpmsBy default all Features, Extensions and debugging tools are build. A minimal build, that only produces the dynamic and static library, can be run with:
mkdir build
cd build
cmake .. -DCLLTK_SNAPSHOT=OFF -D -DCLLTK_DECODER=OFF -DCLLTK_COMMAND_LINE_TOOL=OFF -DCLLTK_KERNEL_TRACING=OFF -DCLLTK_EXAMPLES=OFF -DCLLTK_TESTS=OFF
[!IMPORTANT] Be aware that this disables the build of snapshot and decoding tool. Mixing versions and using this tools from older build is highly discouraged!
Have a lock in CONTRIBUTING