Here is a simple but usful log file for C/C++ function.
#include <stdio.h>
#include <stdarg.h>
#include "string.h"
int LOGL(char * filename, const char *fmt, ...)
{
va_list args;
int i;
char data[1024]= {0};
char realname[256] = {0};
if (NULL == filename)
sprintf(realname, "/mnt/sdcard/webkit.log");
else
sprintf(realname, filename);
va_start(args, fmt);
i=vsprintf(data,fmt,args);
va_end(args);
strcat(data,"\n");
FILE *fp = fopen(realname,"a+");
if (NULL == fp)
return 0;
fwrite(data, sizeof(char), strlen(data),fp);
fclose(fp);
return i;
}
As i tested, it works well. Maybe can be better. I'll do it sometime i am free.
it can also works well on android, but there are two key point.
1. don't write it in the .h file, but in the cpp file and declare it in .h file.
2. remember to add the source file to the make file, if you add a new source file.
new solution for it, with file name and line number included.
#include <stdio.h>
#include <stdarg.h>
#include "string.h"
int LOGL(char* sourcename, int linenumber,char * filename, const char *fmt, ...)
{
va_list args;
int i;
char data[1024]= {0};
char realname[256] = {0};
if (NULL == filename)
sprintf(realname, "/mnt/sdcard/webkit.log");
else
sprintf(realname, filename);
i = sprintf(data,"file:%s,line:%d ",sourcename, linenumber);
va_start(args, fmt);
i+=vsprintf(data+i,fmt,args);
va_end(args);
strcat(data,"\n");
FILE *fp = fopen(realname,"a+");
if (NULL == fp)
return 0;
fwrite(data, sizeof(char), strlen(data),fp);
fclose(fp);
return i;
}
#define LOGALL(filename,...) \
LOGL(__FILE__,__LINE__,filename,__VA_ARGS__);
int main(){
LOGALL("d", "you are good");
LOGALL("/new.txt", "%s","dd");
}
this one with log time, but only works on linux
#include <time.h>
#include <stdio.h>
#include <stdarg.h>
#include "string.h"
int LOGL(const char* sourcename, int linenumber,
const char * filename, const char *fmt, ...)
{
va_list args;
int i = 0;
char data[1024]= {0};
char realname[256] = {0};
time_t current;
struct timeval tv;
struct timezone tz;
gettimeofday(&tv, &tz);
//time(&(tv.tv_sec));
struct tm *st;
st = localtime(&(tv.tv_sec));
i = sprintf(data,"%02d-%02d %02d:%02d:%02d.%06d ",
st->tm_mon,st->tm_mday,st->tm_hour,st->tm_min,st->tm_sec,tv.tv_usec);
if (NULL == filename)
sprintf(realname, "/mnt/sdcard/webkit.log");
else
sprintf(realname,"%s", filename);
i += sprintf(data+i,"file:%s line:%d. ",sourcename, linenumber);
va_start(args, fmt);
i+=vsprintf(data+i,fmt,args);
va_end(args);
strcat(data,"\n");
FILE *fp = fopen(realname,"a+");
if (NULL == fp)
return 0;
fwrite(data, sizeof(char), strlen(data),fp);
fclose(fp);
return i;
}
#define LOGALL(filename,...) \
LOGL(__FILE__,__LINE__,filename,__VA_ARGS__);
int main(){
LOGALL(NULL, "you are good");
LOGALL("/home/cascais/test.txt", "%s","dd");
}
here is the source code of vsnprintf(), if you want to add some special flag, or deal your own string format, this will be useful
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
{
int len;
unsigned long long num;
int i, base;
char *str, *end, c;
const char *s;
int flags; /* flags to number() */
int field_width; /* width of output field */
int precision; /* min. # of digits for integers; max
number of chars for from string */
int qualifier; /* 'h', 'l', or 'L' for integer fields */
/* 'z' support added 23/7/1999 S.H. */
/* 'z' changed to 'Z' --davidm 1/25/99 */
/* 't' added for ptrdiff_t */
/* Reject out-of-range values early */
if (unlikely((int) size < 0)) {
/* There can be only one.. */
static int warn = 1;
WARN_ON(warn);
warn = 0;
return 0;
}
str = buf;
end = buf + size - 1;
if (end < buf - 1) {
end = ((void *) -1);
size = end - buf + 1;
}
for (; *fmt ; ++fmt) {
if (*fmt != '%') {
if (str <= end)
*str = *fmt;
++str;
continue;
}
/* process flags */
flags = 0;
repeat:
++fmt; /* this also skips first '%' */
switch (*fmt) {
case '-': flags |= LEFT; goto repeat;
case '+': flags |= PLUS; goto repeat;
case ' ': flags |= SPACE; goto repeat;
case '#': flags |= SPECIAL; goto repeat;
case '0': flags |= ZEROPAD; goto repeat;
}
/* get field width */
field_width = -1;
if (isdigit(*fmt))
field_width = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
/* it's the next argument */
field_width = va_arg(args, int);
if (field_width < 0) {
field_width = -field_width;
flags |= LEFT;
}
}
/* get the precision */
precision = -1;
if (*fmt == '.') {
++fmt;
if (isdigit(*fmt))
precision = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
/* it's the next argument */
precision = va_arg(args, int);
}
if (precision < 0)
precision = 0;
}
/* get the conversion qualifier */
qualifier = -1;
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
*fmt =='Z' || *fmt == 'z' || *fmt == 't') {
qualifier = *fmt;
++fmt;
if (qualifier == 'l' && *fmt == 'l') {
qualifier = 'L';
++fmt;
}
}
/* default base */
base = 10;
switch (*fmt) {
case 'c':
if (!(flags & LEFT)) {
while (--field_width > 0) {
if (str <= end)
*str = ' ';
++str;
}
}
c = (unsigned char) va_arg(args, int);
if (str <= end)
*str = c;
++str;
while (--field_width > 0) {
if (str <= end)
*str = ' ';
++str;
}
continue;
case 's':
s = va_arg(args, char *);
if ((unsigned long)s < PAGE_SIZE)
s = "<NULL>";
len = strnlen(s, precision);
if (!(flags & LEFT)) {
while (len < field_width--) {
if (str <= end)
*str = ' ';
++str;
}
}
for (i = 0; i < len; ++i) {
if (str <= end)
*str = *s;
++str; ++s;
}
while (len < field_width--) {
if (str <= end)
*str = ' ';
++str;
}
continue;
case 'p':
if (field_width == -1) {
field_width = 2*sizeof(void *);
flags |= ZEROPAD;
}
str = number(str, end,
(unsigned long) va_arg(args, void *),
16, field_width, precision, flags);
continue;
case 'n':
/* FIXME:
* What does C99 say about the overflow case here? */
if (qualifier == 'l') {
long * ip = va_arg(args, long *);
*ip = (str - buf);
} else if (qualifier == 'Z' || qualifier == 'z') {
size_t * ip = va_arg(args, size_t *);
*ip = (str - buf);
} else {
int * ip = va_arg(args, int *);
*ip = (str - buf);
}
continue;
case '%':
if (str <= end)
*str = '%';
++str;
continue;
/* integer number formats - set up the flags and "break" */
case 'o':
base = 8;
break;
case 'X':
flags |= LARGE;
case 'x':
base = 16;
break;
case 'd':
case 'i':
flags |= SIGN;
case 'u':
break;
default:
if (str <= end)
*str = '%';
++str;
if (*fmt) {
if (str <= end)
*str = *fmt;
++str;
} else {
--fmt;
}
continue;
}
if (qualifier == 'L')
num = va_arg(args, long long);
else if (qualifier == 'l') {
num = va_arg(args, unsigned long);
if (flags & SIGN)
num = (signed long) num;
} else if (qualifier == 'Z' || qualifier == 'z') {
num = va_arg(args, size_t);
} else if (qualifier == 't') {
num = va_arg(args, ptrdiff_t);
} else if (qualifier == 'h') {
num = (unsigned short) va_arg(args, int);
if (flags & SIGN)
num = (signed short) num;
} else {
num = va_arg(args, unsigned int);
if (flags & SIGN)
num = (signed int) num;
}
str = number(str, end, num, base,
field_width, precision, flags);
}
if (str <= end)
*str = '\0';
else if (size > 0)
/* don't write out a null byte if the buf size is zero */
*end = '\0';
/* the trailing null byte doesn't count towards the total
* ++str;
*/
return str-buf;
}
#include <cutils/logd.h>
void _LOG(const char *fmt, ...)
{
char buf[128];
va_list ap;
va_start(ap, fmt);
int len;
vsnprintf(buf, sizeof(buf), fmt, ap);
len = strlen(buf);
if (true)
__android_log_vprint(ANDROID_LOG_INFO, "DEBUG", fmt, ap);
}
void _LOG(const char *fmt, ...);
#define LOGY(...) \
_LOG(__VA_ARGS__)