Domanda

is that possible to log information when assert failed with time stamp

ex.

int a = 10

assert( a > 100 );

then it will be failed and output just like with the timestamp as well

2013-12-02 , 17:00:05 assert failed !! (a > 100) line : 22

Thank you

È stato utile?

Soluzione

assert is a macro (it has to be one, to give __LINE__ and __FILE__ information).

You could define your own. I would name it something else like tassert for readability reasons, perhaps like (untested code)

#ifdef NDEBUG
#define tassert(Cond) do {if (0 && (Cond)) {}; } while(0)
#else
#define tassert_at(Cond,Fil,Lin) do { if ((Cond)) {  \
   time_t now##Lin = time(NULL);                     \
   char tbuf##Lin [64]; struct tm tm##Lin;           \
   localtime_r(&now##Lin, &tm##Lin);                 \
   strftime (tbuf##Lin, sizeof(tbuf##Lin),           \
             "%Y-%m-%d,%T", &tm##Lin);               \
   fprintf(stderr, "tassert %s failure: %s %s:%d\n", \
           #Cond, tbuf##Lin, Fil, Lin);              \
   abort();   }} while(0)
#define tassert(Cond) tassert_at(Cond,__FILE__,__LINE__) 
#endif /*NDEBUG*/

I am using cpp concatenation ## with Lin to lower probability of name collisions, and I am using cpp stringification # to make a string out of Cond macro formal. The Cond is always expanded, to make sure the compiler catch syntactic errors in it even when disabling tassert with NDEBUG as assert(3) does.

One could put most of the code in the above macro in some function, e.g.

 void tassert_at_failure (const char* cond, const char* fil, int lin) {
   timer_t now = time(NULL);
   char tbuf[64]; struct tm tm;
   localtime_r (&now, &tm);
   strftime (tbuf, sizeof(tbuf), "%Y-%m-%d,%T", &tm);
   fprintf (stderr, "tassert %s failure: %s %s:%d\n",
            cond, tbuf, fil, lin);
   abort();
 }

and then just define (a bit like <assert.h> does...)

 #define tassert_at(Cond,Fil,Lin) do { if ((Cond)) {  \
    tassert_at_failure(#Cond, Fil, Lin); }} while(0)

but I don't like much that approach, because for debugging with gdb having  abort() being called in the macro is much easier (IMHO size of code for debugging executables does not matter at all; calling abort in a macro is much more convenient inside gdb - making shorter backtraces and avoiding one down command...). If you don't want libc portability and just use recent GNU libc you could simply redefine the Glibc specific __assert_fail function (see inside <assert.h> header file). YMMV.

BTW, in real C++ code I prefer to use << for assertion-like debug outputs. This enables usage of my own operator << outputting routines (if you give it as an additional macro argument) so I am thinking of (untested code!)

#define tassert_message_at(Cond,Out,Fil,Lin)         \
 do { if ((Cond)) {                                  \
   time_t now##Lin = time(NULL);                     \
   char tbuf##Lin [64]; struct tm tm##Lin;           \
   localtime_r(&now##Lin, &tm##Lin);                 \
   strftime (tbuf##Lin, sizeof(tbuf##Lin),           \
             "%Y-%m-%d,%T", &tm##Lin);               \
   std::clog << "assert " << #Cond << " failed "     \
             tbuf##Lin << " " << Fil << ":" << Lin   \
             << Out << std::endl;                    \
   abort (); } } while(0)
#define tassert_message(Cond,Out) \
    tassert_message_at(Cond,Out,__FILE__,__LINE__)

and then I would use tassert_message(i>5,"i=" << i);

BTW, you might want to use syslog(3) instead of fprintf in your tassert_at macro.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top