Commit 1f7028e9 authored by Cody P Schafer's avatar Cody P Schafer Committed by Rusty Russell

pr_log: a new module that provides a simple run-time controlled logging interface

A simple printf logging infra where levels are determined by the
value of the "DEBUG" environment variable.

This is loosely based on the interfaces & functionality of Linux's
printk() and pr_*() wrapper macros.

Note that the current implementation uses "<N>" prefixes (where N is a
syslog level in ascii), allowing other programs that parse log output
(like systemd's journald) to know what the priority level is.
Signed-off-by: default avatarCody P Schafer <dev@codyps.com>
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 6aaca17e
......@@ -88,6 +88,7 @@ MODS_WITH_SRC := aga \
ogg_to_pcm \
opt \
order \
pr_log \
ptrint \
ptr_valid \
pushpull \
......
../../licenses/LGPL-2.1
\ No newline at end of file
#include <string.h>
#include "config.h"
/**
* pr_log - print things with varying levels of importance
*
* pr_log is a "logger" styled similarly to Linux's printk() and pr_*() macros.
* The amount of debug output is controlled by the value of the `DEBUG`
* environment variable.
*
* It provides work-alikes for Linux's pr_devel, pr_debug, pr_info, etc macros.
*
* Example:
* #include <ccan/pr_log/pr_log.h>
*
* int main(int argc, char *argv[])
* {
* pr_debug("It's working\n");
* pr_info("Really, it works\n");
* pr_emerg("I'm serious %d\n", argc);
* return 0;
* }
*
* License: LGPL (v2.1 or any later version)
* Author: Cody P Schafer <dev@codyps.com>
*/
int main(int argc, char *argv[])
{
/* Expect exactly one argument */
if (argc != 2)
return 1;
if (strcmp(argv[1], "depends") == 0) {
printf("ccan/compiler\n");
printf("ccan/str\n");
return 0;
}
return 1;
}
/* Licensed under LGPLv2.1+ - see LICENSE file for details */
#include "pr_log.h"
#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <ccan/str/str.h>
#define DEBUG_NEED_INIT INT_MIN
static int debug = DEBUG_NEED_INIT;
bool debug_is(int lvl)
{
return lvl <= debug_level();
}
int debug_level(void)
{
if (debug != DEBUG_NEED_INIT)
return debug;
char *c = getenv("DEBUG");
if (!c) {
debug = CCAN_PR_LOG_DEFAULT_LEVEL;
return debug;
}
debug = atoi(c);
return debug;
}
void pr_log_(char const *fmt, ...)
{
int level = INT_MIN;
if (fmt[0] == '<' && cisdigit(fmt[1]) && fmt[2] == '>')
level = fmt[1] - '0';
if (!debug_is(level))
return;
va_list va;
va_start(va, fmt);
vfprintf(stderr, fmt, va);
va_end(va);
}
/* Licensed under LGPLv2.1+ - see LICENSE file for details */
#ifndef CCAN_PR_LOG_H_
#define CCAN_PR_LOG_H_
#include <stdbool.h>
#include <ccan/compiler/compiler.h>
/*
* pr_emerg, pr_alert, pr_crit, pr_error, pr_warn, pr_notice, pr_info, pr_debug
*
* Each of these prints a format string only in the case where we're running at
* the selected debug level.
*
* Note that using these functions also causes a pre-pended log level to be
* included in the printed string.
*
* Log levels correspond to those used in syslog(3) .
*/
#define pr_emerg(...) pr_log_(LOG_EMERG __VA_ARGS__)
#define pr_alert(...) pr_log_(LOG_ALERT __VA_ARGS__)
#define pr_crit(...) pr_log_(LOG_CRIT __VA_ARGS__)
#define pr_error(...) pr_log_(LOG_ERROR __VA_ARGS__)
#define pr_warn(...) pr_log_(LOG_WARN __VA_ARGS__)
#define pr_notice(...) pr_log_(LOG_NOTICE __VA_ARGS__)
#define pr_info(...) pr_log_(LOG_INFO __VA_ARGS__)
#define pr_debug(...) pr_log_(LOG_DEBUG __VA_ARGS__)
#ifdef DEBUG
# define pr_devel(...) pr_debug(__VA_ARGS__)
#else
static PRINTF_FMT(1,2) inline void pr_check_printf_args(const char *fmt, ...)
{
(void)fmt;
}
# define pr_devel(...) pr_check_printf_args(__VA_ARGS__)
#endif
#ifndef CCAN_PR_LOG_DEFAULT_LEVEL
# define CCAN_PR_LOG_DEFAULT_LEVEL 6
#endif
#define LOG_EMERG "<0>"
#define LOG_ALERT "<1>"
#define LOG_CRIT "<2>"
#define LOG_ERROR "<3>"
#define LOG_WARN "<4>"
#define LOG_NOTICE "<5>"
#define LOG_INFO "<6>"
#define LOG_DEBUG "<7>"
#ifndef CCAN_PR_LOG_DISABLE
/**
* pr_log_ - print output based on the given logging level
*
* Example:
*
* pr_log_(LOG_EMERG "something went terribly wrong\n");
* pr_log_(LOG_DEBUG "everything is fine\n");
*/
void PRINTF_FMT(1,2) pr_log_(char const *fmt, ...);
bool debug_is(int lvl);
int debug_level(void);
#else
static PRINTF_FMT(1,2) inline void pr_log_(char const *fmt, ...)
{
(void)fmt;
}
static inline bool debug_is(int lvl) { (void)lvl; return false; }
static inline int debug_level(void) { return -1; }
#endif
#endif
#define DEBUG 1
#include <ccan/pr_log/pr_log.h>
#include <ccan/pr_log/pr_log.c>
#include <ccan/tap/tap.h>
int main(void)
{
plan_tests(6);
debug = 3;
ok1(!debug_is(4));
debug = 1;
ok1(debug_is(0));
ok1(debug_is(1));
ok1(!debug_is(2));
ok1(!debug_is(3));
pr_emerg("Emerg\n");
pr_alert("Alert\n");
pr_crit("Crit\n");
pr_error("Error\n");
pr_warn("Warn\n");
pr_notice("Notice\n");
pr_info("Info\n");
pr_debug("Debug\n");
pr_devel("Devel\n");
debug = INT_MIN;
setenv("DEBUG", "1", 1);
ok1(debug_is(1));
/* malformed check */
pr_log_(":4> 1\n");
pr_log_("<!> 2\n");
pr_log_("<1} 3\n");
return exit_status();
}
#define CCAN_PR_LOG_DISABLE 1
#include <ccan/pr_log/pr_log.h>
#include <ccan/tap/tap.h>
#include <stdlib.h>
int main(void)
{
plan_tests(7);
ok1(!debug_is(4));
ok1(!debug_is(0));
ok1(!debug_is(1));
ok1(!debug_is(2));
ok1(!debug_is(3));
pr_emerg("Emerg\n");
pr_alert("Alert\n");
pr_crit("Crit\n");
pr_error("Error\n");
pr_warn("Warn\n");
pr_notice("Notice\n");
pr_info("Info\n");
pr_debug("Debug\n");
pr_devel("Devel\n");
setenv("DEBUG", "1", 1);
ok1(!debug_is(1));
/* malformed check */
pr_log_(":4> 1\n");
pr_log_("<!> 2\n");
pr_log_("<1} 3\n");
ok1(debug_level() == -1);
return exit_status();
}
#include <ccan/pr_log/pr_log.h>
#include <ccan/pr_log/pr_log.c>
#include <ccan/tap/tap.h>
int main(void)
{
plan_tests(8);
debug = 3;
ok1(!debug_is(4));
debug = 1;
ok1(debug_is(0));
ok1(debug_is(1));
ok1(!debug_is(2));
ok1(!debug_is(3));
pr_emerg("Emerg\n");
pr_alert("Alert\n");
pr_crit("Crit\n");
pr_error("Error\n");
pr_warn("Warn\n");
pr_notice("Notice\n");
pr_info("Info\n");
pr_debug("Debug\n");
pr_devel("Devel\n");
debug = INT_MIN;
setenv("DEBUG", "1", 1);
ok1(debug_is(1));
ok1(debug_level() == 1);
/* malformed check */
pr_log_(":4> 1\n");
pr_log_("<!> 2\n");
pr_log_("<1} 3\n");
debug = INT_MIN;
unsetenv("DEBUG");
ok1(debug_level() == CCAN_PR_LOG_DEFAULT_LEVEL);
return exit_status();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment