Logging library for C [closed] - c

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 7 years ago.
Improve this question
I am looking for a productive and simple logging library for C, which can output the log to a file. Displaying messages in the log I want to make like this:
date-time tag message
It would be nice to control the level of detail of messages and control the size of the file.
I found two projects that are suitable for me. It log4c and nglogc.
log4c seemed too big. nglogc quite fit, but also has a redundant functional. maybe you tell me more variants?

You can use this
File logger.h
#ifndef LOGGER_H
#define LOGGER_H
void logger(const char* tag, const char* message);
#endif /* LOG_H */
File logger.c
#include "logger.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void logger(const char* tag, const char* message) {
time_t now;
time(&now);
printf("%s [%s]: %s\n", ctime(&now), tag, message);
}
It's probably not perfect, but it does satisfy the needs as you have presented them.

I suggest the log library which is written by myself --- zlog!
The way to fit your need in zlog is:
$ vi /etc/zlog.conf
[formats]
simple = "%D %c %m%n"
# don't know what the tag mean in your question, so put category of zlog instead
# log level is also available here, add %V means level
[rules]
my_cat.* "xxx.log"; simple
$ vi hello.c
#include <stdio.h>
#include "zlog.h"
int main(int argc, char** argv)
{
int rc;
zlog_category_t *c;
rc = dzlog_init("/etc/zlog.conf", "my_cat");
if (rc) {
printf("init failed\n");
return -1;
}
zlog_info(c, "hello, zlog");
zlog_fini();
return 0;
}
It will generate xxx.log in current directory as
2012-09-30 07:22:50 my_cat hello, zlog
Links:
Download: https://github.com/HardySimpson/zlog/archive/latest-stable.tar.gz
UsersGuide: http://hardysimpson.github.com/zlog/UsersGuide-EN.html
Hompage: http://hardysimpson.github.com/zlog/

Here is mine:
log.h
------
#ifndef LOG_H
#define LOG_H
void log_error(const char* message, ...); void log_info(const char* message, ...); void log_debug(const char* message, ...);
#endif
log.c
------
#include "log.h"
void log_format(const char* tag, const char* message, va_list args) { time_t now; time(&now); char * date =ctime(&now); date[strlen(date) - 1] = '\0'; printf("%s [%s] ", date, tag); vprintf(message, args); printf("\n"); }
void log_error(const char* message, ...) { va_list args; va_start(args, message); log_format("error", message, args); va_end(args); }
void log_info(const char* message, ...) { va_list args; va_start(args, message); log_format("info", message, args); va_end(args); }
void log_debug(const char* message, ...) { va_list args; va_start(args, message); log_format("debug", message, args); va_end(args); }
Have fun!

You can use this simple logging library:
https://github.com/kala13x/slog
Here is an example how to use:
At first you must init log. with init_log() function. First argument is log filename, second argument is log to file (1 enabled, 0 disabled) and third argument is max log level
init_slog("example", 1, 3);
print and log something
slog(0, "Test message with level 0");
slog(2, "Test message with level 2");
slog(0, "Test message with int argument: %d", int_arg);
Outout will be something like that:
2015:04:02:56 - Test message with level 0
2015:04:02:56 - Test message with level 2
2015:04:02:56 - Test message with int argument: 69

Take a look at the zf_log logging library. It's small, simple and provides essentials only. From README.md:
This is just a thin wrapper around sprintf() function. It provides less than 20% of functionality found in more sophisticated libraries, but covers more than 80% of common use cases. Focus is made on simplicity, ease of use and performance (to be more precise - low overhead).
Features:
Debug logging is reduced to no-op in release builds
Arguments are not evaluated when the message is not logged
No "unused" warning for variables used in log statements only
Log a memory region as HEX and ASCII
Custom output functions

I am also finding solutions on this problem. The answer from #edwin-buck is just simple and OK for my need.
I really know nothing on multi-threading and thread-safe, but after compiling under Visual Studio compiler (it can give some warnings and tips), and searching through google, I think a few modification might make the code above thread-safe and better.
// file log.c
void log(const char* tag, const char* message) {
time_t now;
struct tm _calendar_time;
char _buf[MAX_COUNT];
time(&now);
localtime_s(&_calendar_time, &now);
strftime(_buf, MAX_COUNT, "%c", &_calendar_time);
printf("%s [%s]: %s\n", _buf, tag, message);
}
Feel free to correct me if wrong.

Related

Why the printf( ) is working strangely after reopening stdout stream

After reopening STDOUT stream, the message does not display on my screen if calling print() like this:
printf("The message disappeared\n")
The snippet code for explaining the problem:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
int main(void)
{
printf("Display a message\n");
int fd, fd_copy, new_fd;
FILE *old_stream = stdout;
fd = STDOUT_FILENO;
fd_copy = dup(fd);
fclose(old_stream);
new_fd = dup2(fd_copy, fd);
close(fd_copy);
FILE *new_stream = fdopen(fd, "w");
stdout = new_stream;
printf("test %d\n", 1);
fprintf(stdout, "test 2\n");
int rc = printf("test 3\n");
printf("Test 4 Why the message disappeared\n");
printf("Error message is [%s]\n", strerror(errno));
return 0;
}
Why only the test 4 cannot display on my screen. Don't they all use stdout as output?
Output:
# gcc main.c; ./a.out
Display a message
test 1
test 2
test 3
Error message is [Bad file descriptor]
The code snippet above comes from the LVM2 library function.
int reopen_standard_stream(FILE **stream, const char *mode)
/* https://github.com/lvmteam/lvm2/blob/master/lib/log/log.c */
The dynamic library I designed:
I wrap up a dynamic library it includes the LVM dynamic library for other processes uses. One of the functions is this (output all PVs in the system):
char global_buffer[0x1000];
void show_pvs_clbk_fn(int level, const char *file, int line,
int dm_errno, const char *format)
{
/* Extract and process output here rather than printing it */
if (level != LVM2_LOG_PRINT)
return;
sprintf(global_buffer, "%s%s\n", global_buffer, format)
}
int show_all_PV(char *out_buffer)
{
void *handle = lvm2_init();
lvm2_log_fn(show_pvs_clbk_fn);
int rc = lvm2_run(handle, "pvs");
lvm2_exit(handle);
if (rc != LVM2_COMMAND_SUCCEEDED) {
return -1;
}
strcpy(out_buffer, global_buffer)
return 0;
}
A caller may calls show_all_PV() API like this:
int main(void)
{
char tmp[0x1000];
if (!show_all_PV(tmp)) {
printf("====== PVS are ======\n");
printf("%s\n", tmp);
}
}
Output:
====== PVS are ======
PV VG Fmt Attr PSize PFree
/dev/nvme1n1p1 vg1 lvm2 a-- <1.2t 1.1t
Some caller maybe mess up the stdout:
I found a stranger thing is that if the caller defines a function which includes vfprintf(stdout, ) system call. they never get output from normal print() API.
#inclide <stdlin.h>
#inclide <stdio.h>
#inclide <unistd.h>
#inclide <stdarg.h>
#if 1
int a_function_never_be_called(const char *formatP, ...)
{
va_list ap;
va_start(ap, formatP);
vfprintf(stdout, formatP, ap);
va_end(ap);
return 0;
}
#endif
int main(void)
{
char tmp[0x1000];
if (!show_all_PV(tmp)) {
printf("====== PVS are ======\n");
printf("%s\n", tmp);
}
}
The string "====== PVS are ======" disappeared and the caller got an IO error Bad file descripto.
Output:
PV VG Fmt Attr PSize PFree
/dev/nvme1n1p1 vg1 lvm2 a-- <1.2t 1.1t
Assigning to stdout (or stdin or stderr) is Undefined Behaviour. And in the face of undefined behaviour, odd things happen.
Technically, no more needs to be said. But after I wrote this answer, #zwol noted in a comment that the glibc documentation claims to allow reassignment of standard IO streams. In those terms, this behaviour is a bug. I accept this fact, but the OP was not predicated on the use of glibc, and there are many other standard library implementations which don't make this guarantee. In some of them, assigning to stdout will raise an error at compile time; in others, it will simply not work or not work consistently. In other words, regardless of glibc, assigning to stdout is Undefined Behaviour, and software which attempts to do so is, at best, unportable. (And, as we see, even on glibc it can lead to unpredictable output.)
But my curiosity was aroused so I investigated a bit. The first thing is to look at the actual code generated by gcc and see what library function is actually being called by each of those output calls:
printf("test %d\n", 1); /* Calls printf("test %d\n", 1); */
fprintf(stdout, "test 2\n"); /* Calls fwrite("test 2\n", 1, 7, stdout); */
int rc = printf("test 3\n"); /* Calls printf("test 3\n"); */
printf("Test 4 Why the message disappeared\n");
/* Calls puts("Test 4...disappeared"); */
printf("Error message is [%s]\n", strerror(errno));
/* Calls printf("..."); */
Note that GCC is trying hard to optimise the calls. In lines 2 and 4, it is able to find a non-printf library call, avoiding run-time parsing of the format string.
But note that it does not do that in the case of line 3, which looks the same as line 4. Why not? Because you are using the return value of printf, which is the number of characters sent to stdout. But that's not the same as the return value of puts, which just returns a "non-negative number" on success. So the substitution is impossible.
Suppose we remove int rc = from line 3, and recompile. Now we get this:
printf("test %d\n", 1); /* Calls printf("test %d\n", 1); */
fprintf(stdout, "test 2\n"); /* Calls fwrite("test 2\n", 1, 7, stdout); */
printf("test 3\n"); /* Calls puts("test 3"); */
printf("Test 4 Why the message disappeared\n");
/* Calls puts("Test 4...disappeared"); */
printf("Error message is [%s]\n", strerror(errno));
/* Calls printf("..."); */
So without the use of the return value, GCC can substitute printf with puts. (Note also that when it does that substitution, it also removes the \n from the string literal, because puts automatically adds a newline to the end of its output.)
When we run the modified program, we see this:
Display a message
test 1
test 2
Error message is [Bad file descriptor]
Now, two lines have disappeared, which are precisely the two lines for which GCC used puts.
After the shenanigans at the beginning, puts no longer works, presumably because it relies on stdout not having been reassigned. Which it's allowed to do, because reassigning stdout is Undefined Behaviour. (You can use freopen if you want to reopen stdout.)
Final note:
Unsurprisingly, it turns out that the glibc team did accept it as a bug; it was reported as bug 24051 and a similar issue with stdin as bug 24153. Both were fixed in glibc v2.30, released in August of 2019. So if you have a recently upgraded Linux install, or you are reading this answer years after I wrote it, you might not see this bug.

How to avoid non-copyable characters in a C application, run by Eclipse

I am working with a C application, which is tested by a Java application, run in Eclipse.
The Java application runs the C application, using the standard way:
Runtime.getRuntime().exec(cmdline)
(the cmdline containing the C application's executable)
The C application most probably uses Visual Studio's vsprintf() function for writing something, but in some cases, a non-copyable character seems to be printed, as you can see:
put_log(LOG_INFO, "Waiting for writing thread\n");
(put_log() is most probably based on the mentioned vsprintf())ps -ef
This gets shown in Eclipse as:
INFO : aiting for writing thread
As you see, the "W" has disappeared, and in top of that, when I try to copy the mentioned line, I only see:
INFO :
I have the impression that the letter W has been replaced by a character, which is not copyable to the Windows clipboard. As this happens in the middle of quite a large output, this is very annoying.
Does anybody understand what is going on and how I can solve this?
As asked by Fluter, hereby an excerpt of the put_log() function:
void put_log(const char *fmt, ...)
{
static char str[16384];
char* args;
char* p = str;
strcpy(str, "INFO: ");
p = str + strlen(str);
_crt_va_start(args, fmt);
vsprintf(p, fmt, args);
_crt_va_end(args);
...
}
(the first argument(LOG_INFO) is removed from this excerpt and replaced by the "INFO: " hardcoded string for simplification purposes)
For your information, hereby the location of the lowlevel functions:
_crt_va_start() : c:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\stdarg.h
_crt_va_end() : c:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\stdarg.h
vsprintf() : C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\crt\src\vsprintf.c
Thanks
Assuming _crt_va_start behaves like standard C va_start, then you need to declare a va_list somewhere, rather than using some uninitialized char pointer. Reason why it seems to work is probably because va lists have non-existent type safety (and therefore using them to begin with is bad practice).
Do something like this instead:
#include <stdarg.h>
void put_log(const char *fmt, ...)
{
static char str[16384];
va_list va;
char* p = str;
strcpy(str, "INFO: ");
p = str + strlen(str);
va_start(va, fmt);
vsprintf(p, fmt, va);
va_end(va);
}
You didn't post how is the log actually get printed on the console, make sure you print it with right functions, for example fprintf(stderr, str);
Second, you are using a static buffer here, it is subject to in data race when the function is called concurrently, possibly by multiple threads. Obviously the buffer is overwritten for every log, it does not make sense to use static here, yet brings the problem of corrupted data.
void put_log(const char *fmt, ...)
{
char str[16384];
char* args;
char* p = str;
va_list list;
strcpy(str, "INFO: ");
p = str + strlen(str);
va_start(list, fmt);
vsprintf(p, fmt, list);
va_end(list);
fprintf(stderr, str);
}

Is there some kind of security issue in this code?

This is my code:
void handle(int s)
{
char inbuf[4096];//we defined inbuf as 4096 size
dup2(s, 0);
dup2(s, 1);
setbuf(stdout, NULL);
alarm(ALARM_TIMEOUT_SEC);
printf("crackme> ");
if (NULL == fgets(inbuf, sizeof(inbuf), stdin)) {
return;
}
right_trim(inbuf);
if (is_correct(inbuf)) {
printf("Good job!\n");
}
}
And if there is, what is the problem?
Little explanation about this program:
The first part of her running Server
When someone connects to the server and enter an input (i did a loop to examine the length of the input)
So this function looks at it and if the pass is correct then its print "good job"
Answering the question as titled: yes. The use of
void setbuf(FILE *stream, char *buffer);
is deprecated due to security issues, and is retained by MSVC only for compatibility purposes. Please use
int setvbuf(FILE *stream, char *buffer, int mode, size_t size);
which is more secure since the buffer size is also provided (as well as more flexibility by providing mode) and it returns a function value to indicate success or failure.

Reporting information using syslog

I am trying to write a function which will take a priority level and a variable amount of strings as arguments to log information in an application.
The function looks something like this so far:
int _logf(int priority, char *fmt, ...)
{
if (log.priority >= priority) {
syslog(priority, "LOG:%s", fmt);
}
/* stderr and syslog */
}
log.priority is an int set at run time which could be LOG_INFO / LOG_DEBUG / LOG_ERR
and in use:
_logf(LOG_INFO, "Starting app version %s", "1.0");
Is this an acceptable way to send log messages to syslog?
This won't work as you do not involve the variable number of parameters possibly passed into your function.
On how to do this you might take a look a the following example using vsyslog():
#include <syslog.h>
#include <stdarg.h>
...
int _logf(int priority, const char * fmt, ...)
{
if (log.priority >= priority)
{
va_list ap;
va_start(ap, fmt);
vsyslog(priority, fmt, ap);
va_end(ap);
}
}
Then call it for example like so:
_logf(LOG_INFO, "LOG %s:%d (%s) - %s", __FILE__, __LINE__, __func__, "Just some info.");
Update:
To additionally log to stderr you might like to look ath function vfprintf().

Can I use two level of variable length argument functions...?

I have one problem with variable length argument debug log print function. I will just simulate the code here.
void SecondPrint(int level, const char* format,...)
{
//Printing the log here
va_list arg;
va_start(arg, format);
vprintf(format, arg);
va_end(arg);
}
void FirstPrint(int level, const char* format,...)
{
SecondPrint(level,format);
}
void main()
{
int level = 100;
FirstPrintf("Log level = %d message = %s \n",level,"Error message");
}
"SecondPrint" is supposed to print "100 Error message" as expected, But its not printing like that its printing " Error message".
I am not getting whats wrong with this one. I am suspecting the way of calling "SecondPrint" from "FirstPrint" function. FirstPrint is receiving remaining arguments through ... but its invoking SecondPrint with level and format arguments.
I can't use SecondPrint from main directly. I have to use FirstPrint and FirstPrint has to call SecondPrint to print the log. So how can I achieve this one.. I thought to use VA_ARGS but it is for only macro definitions not in function definition.
And one more thing I can't do like *#define FirstPrint(a,b,...) SecondPrint(a,b,...)*
any help is highly appreciated thanks in advance.
C varargs are not designed to be passed more than one level; the kind of necessary stack manipulation required is too deep for the language. Typically, in a case like this, you would have a version of SecondPrint analagous to vprintf -- SecondPrintV or similar, and you would have FirstPrint invoke SecondPrintV after extracting the varargs, rather than invoking SecondPrint directly (and, for consistency, usually have SecondPrint invoke SecondPrintV internally).
You need to pass a va_list to SecondPrint, so it can access the arguments to FirstPrint
void SecondPrint(int level, const char* format, va_list args)
{
//Printing the log here
vprintf(format, arg);
}
void FirstPrint(int level, const char* format,...)
{
va_list args;
va_start(args, format);
SecondPrint(level, format, args);
va_end(args);
}
void main()
{
int level = 100;
FirstPrintf("Log level = %d message = %s \n",level,"Error message");
}
It may be possible to do it in specific platform-specific ways, or (since the arguments are exactly the same in the same order) use assembly to "replace" the current function frame with the function to call. GCC also has an extension to do it with the __builtin_apply_args() and __builtin_apply() functions (although you must somehow figure out how to compute the size of the stack argument data).

Resources