Reporting information using syslog - c

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().

Related

How to redirect stderr to a .txt file in C?

I have a function that I use as a sort of way to print out some logging info to the terminal but I am trying to capture it to a log file as well. I am no C expert and am trying to gain some practice!
Here is what I tried
static void logging(const char *format, ...) {
va_list args;
//FILE *file_ptr;
char log_file[] = "logs/TEST-LOG-001.txt";
if (freopen(log_file, "w", stderr) == NULL) {
printf("<---ERROR LOGGING TO FILES--->");
}
else {
fprintf(stderr, "LOG: ");
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, "\n");
fclose(stderr);
}
}
What would be the proper way to redirect to a file. I was successful with something a bit more simpler where I am able to redirect stdout to a text file just using a hard coded array of strings and a hard coded amount of indexes I want to redirect to the text file similar to what is seen here.
On top of just redirecting stderr, how would I go about assigning a unique ID (like a timestamp) to the test-log file?
The overall purpose of my program is using some libav libs to decode videos into a series of images. What is returned to stdout is the overall information of the video file passed in (duration, format, resolution,etc) and each frame has corresponding info to it (frame number, size, type). I basically want to display the logging information to both stdout and to a log file.
Here is an example of what the data I am displaying looks like:
LOG: AVPacket->pts 0
LOG: AVPacket->pts 1024
LOG: AVPacket->pts 512
LOG: Frame 1 (type=I, size=100339 bytes, format=0) pts 0 key_frame 1 [DTS 0]
LOG: AVPacket->pts 256
LOG: Frame 2 (type=B, size=7484 bytes, format=0) pts 256 key_frame 0 [DTS 3]
LOG: AVPacket->pts 768
Write the error log to stderr, normal log to stdout, redirect log messages to dedicated files accordingly by:
# write error message to `err.txt`, normal log to `info.txt`
./a.out 2>err.txt 1>info.txt
BTW: it's not recommend to rewrite existed *print* function. Use preprocessor macro such in case you wanna add more info such as tag:
#define LOG_ERR(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
#define LOG_INFO(fmt, ...) fprintf(stdout, fmt, ##__VA_ARGS__)
// usage
LOG_ERR("[E] Something wrong!\n");
LOG_INFO("[I] Frame %d(type %c) ...\n", frame_number, frame_type);
You can output the error messages to both stderr and a log file this way:
#include <stdarg.h>
#include <stdio.h>
static FILE *logfp;
// the log file should be opened at initialization time with
// logfp = fopen("logs/TEST-LOG-001.txt", "a");
static void logging(const char *format, ...) {
va_list args, args2;
va_start(args, format);
if (logfp) {
va_copy(args2, args);
vfprintf(logfp, format, args2);
// uncomment if the format strings do not include a newline
//fprintf(logfp, "\n");
va_end(args2);
}
fprintf(stderr, "LOG: ");
vfprintf(stderr, format, args);
// uncomment if the format strings do not include a newline
//fprintf(stderr, "\n");
va_end(args);
}

printf to USB-CDC on FreeRTOS

I'm working on a STM32 Cortex M4 with a FreeRTOS running.
I try to redirect my printf to the USB CDC output but it seems like my implementation isn't thread safe. A loop of printf('test') prints
ettttt
tttetttttttst
ttetettttttettttttettttttt
ttttttttttttt
t
tttttttttetttttttstttt
tettttttttttttt
t
tttttttetttetttttttett
ttttettttttetettetttt
ttttttttt
ttetetttt
t
ttt
I use the following putchar prototype
PUTCHAR_PROTOTYPE {
CDC_Transmit_FS((uint8_t*)&ch, 1);
return ch;
}
Additionally I use the printf-stdarg.c, at least I thought I do. But when I change
int printf(const char *format, ...)
{
va_list args;
va_start( args, format );
return print( 0, format, args );
}
to an empty implementation
int printf(const char *format, ...)
{
return 0;
}
it still prints to the console as before. So it seems like it's not actually using the implementation from printf-stdarg.c.
My idea was to surround the print call with a mutex.

Wrapper for printf

I am coding under Arduino and I would like to develop serial print formatting function, so I am trying to use sprintf of unknown sized buffer. Basically, we can avoid talking about Arduino and its serial output and consider writing text to a buffer and then printing it by using printf. I've tried this one:
#include <stdio.h>
#include <stdarg.h>
void printf0( const char* format, ... ) {
va_list args;
va_start(args, format);
vprintf(format, args);
va_end( args );
}
void printf1(const char* format,...) {
va_list args;
va_start(args, format);
char buf[vsnprintf(NULL, 0, format, args)];
sprintf(buf, format, args);
printf(buf);
va_end(args);
}
int main()
{
printf0("Hello, %d!\n", 15);
printf1("Hello, %d!\n", 15);
return 0;
}
printf0 function is an accurate example I found here. My tries is function printf1, which produces unpredictable number. Example output of the above programme is:
Hello, 15!
Hello, 860799736!
args is a va_list, so you cannot call sprintf with it. You have to use vsprintf or vsnprintf:
sprintf(buf, format, args);
should be
vsnprintf(buf, sizeof buf, format, args);
Also you should add 1 to the size of buf for the 0-terminator of the string:
char buf[vsnprintf(NULL, 0, format, args) + 1];
It seems that the first call to vsnprintf changes args, so you have to add
va_end(args);
va_start(args, format);
between the 2 calls:
http://ideone.com/5YI4Or
It seems that the first call to vsnprintf changes args, but you should not call va_start twice. You should use va_copy instead, so add
va_list args2;
va_copy(args2, args);
after initializing args. Also do not forget to call va_end(args2); too:
http://ideone.com/loTRNL
Link to the va_copy man page: https://linux.die.net/man/3/va_copy

What is "complete error trapping"?

Write a program in C using only low-level I/O..
The program must have complete error trapping. In particular the
program should use perror() to report system errors...
In my program...
test("checked argument count");
if((input_file1 = open(argv[1], O_RDONLY)) < 0)
{
test("couldn't open file1");
perror(argv[1]);
close(input_file1);
exit(1);
}
test("opened file1");
Would this be considered "complete error trapping" if I implement such code for every read/write attempt?
Note: test() is just for debugging and will be deleted later:
void test(const char * message)
{
printf("\ttesting: %s \n", message);
}
You shouldn't close the file descriptor that you failed to open.
Other than that, yes, you've done sufficient error checking on the open() call. Now repeat for the other open() calls, and the read() calls, and the write() calls, and presumably the close() calls that are part of the main-line processing — close() calls in the error paths are a best-effort and don't need to be error checked in the same way.
Your error reporting is not very helpful, though. You say 'file1' but that isn't the name of the file. Using perror() isn't going to help much there, either; I never use it because it doesn't give me enough control over the message format. You are passing the file name as the string; that's considerably better than people often do, but you can't also express which operation the program was attempting that failed. I'd use fprintf(stderr, ...) in conjunction with errno and strerror(). Be careful not to clobber errno by calling a function that itself sets errno (is your test() function safe?). If you aren't sure, capture errno and (if necessary) reset it to the captured value:
int errnum = errno;
test("couldn't open file", argv[1]);
errno = errnum;
perror(argv[1]);
exit(1);
The revised test() function might be:
#include <stdarg.h>
extern void test(char const *fmt, ...);
void test(char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
putc('\n', stderr);
}
That's the core of it; you'd need to adapt that to work with your current internals of the test() function. The declaration of test() with the ellipsis does not require the <stdarg.h> header; the implementation of test() does require the header.

Logging library for C [closed]

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.

Resources