/*!
* COPYRIGHT (C) 2010-2020 Emeric Grange - All Rights Reserved
*
* This file is part of MiniTraces.
*
* MiniTraces is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MiniTraces is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MiniTraces. If not, see .
*
* \file minitraces.cpp
* \author Emeric Grange
* \date 2018
* \version 0.53
*/
// MiniTraces header
#include "minitraces.h"
// C standard libraries
#include
#include
#include
#include
#if defined(_WIN16) || defined(_WIN32) || defined(_WIN64)
#define MINITRACES_EOL "\n\r"
#else // linux, macOS, and everyone else...
#define MINITRACES_EOL "\n"
#endif
/* ************************************************************************** */
/* ************************************************************************** */
#if MINITRACES_TIMESTAMPS
#include
#ifdef defined(__APPLE__) || defined(__MACH__)
#include
#include
#endif
/*!
* \brief Print trace tick with millisecond precision.
*
* \note If CLOCK_MONOTONIC_RAW is not available on your system, you can fallback
* to CLOCK_MONOTONIC or even CLOCK_REALTIME.
*/
static void print_trace_tick(void)
{
long long int time = 0;
#if defined(__APPLE__) || defined(__MACH__) // OS X does not have clock_gettime > use clock_get_time
clock_serv_t cclock;
mach_timespec_t mts;
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
if (clock_get_time(cclock, &mts));
{
time = (mts.tv_sec * 1000) + (mts.tv_nsec / 1000000);
}
mach_port_deallocate(mach_task_self(), cclock);
#else
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) == 0)
{
time = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
}
#endif
printf("[%lld]", time);
}
/*!
* \brief Print trace time with hh:mm:ss format, with second precision.
*/
static void print_trace_time(void)
{
time_t t = time(NULL);
struct tm result;
struct tm *tm_info = localtime_r(&t, &result);
if (tm_info != NULL)
{
char buffer[12];
strftime(buffer, 12, "%H:%M:%S", tm_info);
printf("[%s]", buffer);
}
else
{
printf("[0]");
}
}
#endif // MINITRACES_TIMESTAMPS
/* ************************************************************************** */
/*!
* \brief This function displays trace level enabled for a particular module.
*/
static void print_trace_levels(const unsigned level)
{
printf("%s%s%s%s%s%s", (level & TRACE_LEVEL_ERR) ? "ERR":"",
(level & TRACE_LEVEL_WARN) ? " | WARN":"",
(level & TRACE_LEVEL_INFO) ? " | INFO":"",
(level & TRACE_LEVEL_1) ? " | LVL 1":"",
(level & TRACE_LEVEL_2) ? " | LVL 2":"",
(level & TRACE_LEVEL_3) ? " | LVL 3":"");
printf("\n");
}
/* ************************************************************************** */
/*!
* Gives out a 1 letter description of the trace level.
*/
static const char *get_trace_level_string(unsigned level)
{
const char *string = "U";
switch (level)
{
case TRACE_LEVEL_ERR: string = BLD_RED "E" CLR_RESET; break;
case TRACE_LEVEL_WARN: string = BLD_YELLOW "W" CLR_RESET; break;
case TRACE_LEVEL_INFO: string = BLD_GREEN "I" CLR_RESET; break;
case TRACE_LEVEL_1: string = BLD_WHITE "1" CLR_RESET; break;
case TRACE_LEVEL_2: string = BLD_WHITE "2" CLR_RESET; break;
case TRACE_LEVEL_3: string = BLD_WHITE "3" CLR_RESET; break;
default: break;
}
return string;
}
/* ************************************************************************** */
//! Count all of the user-defined trace modules
static const unsigned int trace_module_count = sizeof(trace_modules_table) / sizeof(TraceModule_t);
/* ************************************************************************** */
/* ************************************************************************** */
void MiniTraces_info(void)
{
printf(PID BLD_GREEN "\nMiniTraces_infos()" CLR_RESET " version 0.4\n");
printf(PID "\n* TRACE LEVELS ENABLED:\n");
TRACE_ERROR(MAIN, "ERROR traces enabled");
TRACE_WARNING(MAIN, "WARNING traces enabled");
TRACE_INFO(MAIN, "INFO traces enabled");
TRACE_1(MAIN, "LVL 1 traces enabled");
TRACE_2(MAIN, "LVL 2 traces enabled");
TRACE_3(MAIN, "LVL 3 traces enabled");
printf(PID "\n* TRACE MODULES CONFIGURATION:\n");
for (unsigned i = 0; i < trace_module_count; i++)
{
printf(PID "[%02x][%5s] Trace Mask 0x%X: ", i,
trace_modules_table[i].module_name,
trace_modules_table[i].module_output_mask);
print_trace_levels(trace_modules_table[i].module_output_mask);
}
}
/* ************************************************************************** */
void MiniTraces_print(const char *file, const int line, const char *func,
const unsigned level, const unsigned module, const char *payload, ...)
{
#if MINITRACES_LEVEL > 0
if (module > trace_module_count)
{
printf("[TRACE][%s] module[%d] unknown\n", __FUNCTION__, (int)module);
return;
}
#endif
if ((trace_modules_table[module].module_output_mask & level) == level)
{
// Trace program identifier
////////////////////////////////////////////////////////////////////////
printf("%s", PID);
// Trace header
////////////////////////////////////////////////////////////////////////
// Print the trace timestamp
#if MINITRACES_TIMESTAMPS == 1
print_trace_tick();
#elif MINITRACES_TIMESTAMPS == 2
print_trace_time();
#endif
// Print trace module_name, 5 chars, left padded
const char *level_string = get_trace_level_string(level);
printf("[%s][%5s]", level_string, trace_modules_table[module].module_name);
#if MINITRACES_FUNC_INFO
// Print the function where the trace came from
printf(BLD_WHITE "[%s]" CLR_RESET, func);
#endif
#if MINITRACES_FILE_INFO
// Print the line of code that triggered the trace output
const char *tmp = strrchr(file, '/');
printf("{%s:%d}", tmp ? ++tmp : file, line);
#endif
// Trace body
////////////////////////////////////////////////////////////////////////
// Customizable header / body separator
printf(" ");
va_list args;
va_start(args, payload);
vprintf(payload, args);
va_end(args);
// End of the line
printf(MINITRACES_EOL);
#if MINITRACES_FORCED_SYNC
// Force terminal synchronisazion (very slow!)
fflush(stdout);
#endif
}
}
/* ************************************************************************** */
void MiniTraces_flush()
{
// Force terminal synchronisazion (very slow!)
fflush(stdout);
}
/* ************************************************************************** */