/*
* Copyright (C) 2023 Jo-Philipp Wich <jo@mein.io>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/**
* # System logging functions
*
* The `log` module provides bindings to the POSIX syslog functions `openlog()`,
* `syslog()` and `closelog()` as well as - when available - the OpenWrt
* specific ulog library functions.
*
* Functions can be individually imported and directly accessed using the
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#named_import named import}
* syntax:
*
* ```
* import { openlog, syslog, LOG_PID, LOG_USER, LOG_ERR } from 'log';
*
* openlog("my-log-ident", LOG_PID, LOG_USER);
* syslog(LOG_ERR, "An error occurred!");
*
* // OpenWrt specific ulog functions
* import { ulog_open, ulog, ULOG_SYSLOG, LOG_DAEMON, LOG_INFO } from 'log';
*
* ulog_open(ULOG_SYSLOG, LOG_DAEMON, "my-log-ident");
* ulog(LOG_INFO, "The current epoch is %d", time());
* ```
*
* Alternatively, the module namespace can be imported
* using a wildcard import statement:
*
* ```
* import * as log from 'log';
*
* log.openlog("my-log-ident", log.LOG_PID, log.LOG_USER);
* log.syslog(log.LOG_ERR, "An error occurred!");
*
* // OpenWrt specific ulog functions
* log.ulog_open(log.ULOG_SYSLOG, log.LOG_DAEMON, "my-log-ident");
* log.ulog(log.LOG_INFO, "The current epoch is %d", time());
* ```
*
* Additionally, the log module namespace may also be imported by invoking the
* `ucode` interpreter with the `-llog` switch.
*
* ## Constants
*
* The `log` module declares a number of numeric constants to specify logging
* facility, priority and option values, as well as ulog specific channels.
*
* ### Syslog Options
*
* | Constant Name | Description |
* |---------------|---------------------------------------------------------|
* | `LOG_PID` | Include PID with each message. |
* | `LOG_CONS` | Log to console if error occurs while sending to syslog. |
* | `LOG_NDELAY` | Open the connection to the logger immediately. |
* | `LOG_ODELAY` | Delay open until the first message is logged. |
* | `LOG_NOWAIT` | Do not wait for child processes created during logging. |
*
* ### Syslog Facilities
*
* | Constant Name | Description |
* |----------------|--------------------------------------------------|
* | `LOG_AUTH` | Authentication/authorization messages. |
* | `LOG_AUTHPRIV` | Private authentication messages. |
* | `LOG_CRON` | Clock daemon (cron and at commands). |
* | `LOG_DAEMON` | System daemons without separate facility values. |
* | `LOG_FTP` | FTP server daemon. |
* | `LOG_KERN` | Kernel messages. |
* | `LOG_LPR` | Line printer subsystem. |
* | `LOG_MAIL` | Mail system. |
* | `LOG_NEWS` | Network news subsystem. |
* | `LOG_SYSLOG` | Messages generated internally by syslogd. |
* | `LOG_USER` | Generic user-level messages. |
* | `LOG_UUCP` | UUCP subsystem. |
* | `LOG_LOCAL0` | Local use 0 (custom facility). |
* | `LOG_LOCAL1` | Local use 1 (custom facility). |
* | `LOG_LOCAL2` | Local use 2 (custom facility). |
* | `LOG_LOCAL3` | Local use 3 (custom facility). |
* | `LOG_LOCAL4` | Local use 4 (custom facility). |
* | `LOG_LOCAL5` | Local use 5 (custom facility). |
* | `LOG_LOCAL6` | Local use 6 (custom facility). |
* | `LOG_LOCAL7` | Local use 7 (custom facility). |
*
* ### Syslog Priorities
*
* | Constant Name | Description |
* |---------------|-------------------------------------|
* | `LOG_EMERG` | System is unusable. |
* | `LOG_ALERT` | Action must be taken immediately. |
* | `LOG_CRIT` | Critical conditions. |
* | `LOG_ERR` | Error conditions. |
* | `LOG_WARNING` | Warning conditions. |
* | `LOG_NOTICE` | Normal, but significant, condition. |
* | `LOG_INFO` | Informational message. |
* | `LOG_DEBUG` | Debug-level message. |
*
* ### Ulog channels
*
* | Constant Name | Description |
* |---------------|--------------------------------------|
* | `ULOG_KMSG` | Log messages to `/dev/kmsg` (dmesg). |
* | `ULOG_STDIO` | Log messages to stdout. |
* | `ULOG_SYSLOG` | Log messages to syslog. |
*
* @module log
*/
#include <syslog.h>
#include <errno.h>
#ifdef HAVE_ULOG
#include <libubox/ulog.h>
#endif
#include "ucode/module.h"
static char log_ident[32];
/**
* The following log option strings are recognized:
*
* | Log Option | Description |
* |------------|------------------------------------------------------------|
* | `"pid"` | Include PID with each message. |
* | `"cons"` | Log to console if an error occurs while sending to syslog. |
* | `"ndelay"` | Open the connection to the logger immediately. |
* | `"odelay"` | Delay open until the first message is logged. |
* | `"nowait"` | Do not wait for child processes created during logging. |
*
* @typedef {string} module:log.LogOption
* @enum {module:log.LogOption}
*
*/
static const struct { const char *name; int value; } log_options[] = {
{ "pid", LOG_PID },
{ "cons", LOG_CONS },
{ "ndelay", LOG_NDELAY },
{ "odelay", LOG_ODELAY },
{ "nowait", LOG_NOWAIT },
};
/**
* The following log facility strings are recognized:
*
* | Facility | Description |
* |--------------|--------------------------------------------------|
* | `"auth"` | Authentication/authorization messages. |
* | `"authpriv"` | Private authentication messages. |
* | `"cron"` | Clock daemon (cron and at commands). |
* | `"daemon"` | System daemons without separate facility values. |
* | `"ftp"` | FTP server daemon. |
* | `"kern"` | Kernel messages. |
* | `"lpr"` | Line printer subsystem. |
* | `"mail"` | Mail system. |
* | `"news"` | Network news subsystem. |
* | `"syslog"` | Messages generated internally by syslogd. |
* | `"user"` | Generic user-level messages. |
* | `"uucp"` | UUCP subsystem. |
* | `"local0"` | Local use 0 (custom facility). |
* | `"local1"` | Local use 1 (custom facility). |
* | `"local2"` | Local use 2 (custom facility). |
* | `"local3"` | Local use 3 (custom facility). |
* | `"local4"` | Local use 4 (custom facility). |
* | `"local5"` | Local use 5 (custom facility). |
* | `"local6"` | Local use 6 (custom facility). |
* | `"local7"` | Local use 7 (custom facility). |
*
* @typedef {string} module:log.LogFacility
* @enum {module:log.LogFacility}
*/
static const struct { const char *name; int value; } log_facilities[] = {
{ "auth", LOG_AUTH },
#ifdef LOG_AUTHPRIV
{ "authpriv", LOG_AUTHPRIV },
#endif
{ "cron", LOG_CRON },
{ "daemon", LOG_DAEMON },
#ifdef LOG_FTP
{ "ftp", LOG_FTP },
#endif
{ "kern", LOG_KERN },
{ "lpr", LOG_LPR },
{ "mail", LOG_MAIL },
{ "news", LOG_NEWS },
{ "syslog", LOG_SYSLOG },
{ "user", LOG_USER },
{ "uucp", LOG_UUCP },
{ "local0", LOG_LOCAL0 },
{ "local1", LOG_LOCAL1 },
{ "local2", LOG_LOCAL2 },
{ "local3", LOG_LOCAL3 },
{ "local4", LOG_LOCAL4 },
{ "local5", LOG_LOCAL5 },
{ "local6", LOG_LOCAL6 },
{ "local7", LOG_LOCAL7 },
};
/**
* The following log priority strings are recognized:
*
* | Priority | Description |
* |-------------|-------------------------------------|
* | `"emerg"` | System is unusable. |
* | `"alert"` | Action must be taken immediately. |
* | `"crit"` | Critical conditions. |
* | `"err"` | Error conditions. |
* | `"warning"` | Warning conditions. |
* | `"notice"` | Normal, but significant, condition. |
* | `"info"` | Informational message. |
* | `"debug"` | Debug-level message. |
*
* @typedef {string} module:log.LogPriority
* @enum {module:log.LogPriority}
*/
static const struct { const char *name; int value; } log_priorities[] = {
{ "emerg", LOG_EMERG },
{ "alert", LOG_ALERT },
{ "crit", LOG_CRIT },
{ "err", LOG_ERR },
{ "warning", LOG_WARNING },
{ "notice", LOG_NOTICE },
{ "info", LOG_INFO },
{ "debug", LOG_DEBUG },
};
static int
parse_facility(uc_value_t *facility)
{
char *s;
int rv;
switch (ucv_type(facility)) {
case UC_STRING:
s = ucv_string_get(facility);
for (size_t i = 0; i < ARRAY_SIZE(log_facilities); i++)
if (s && !strcasecmp(s, log_facilities[i].name))
return log_facilities[i].value;
return -1;
case UC_INTEGER:
rv = ucv_int64_get(facility);
if (errno == ERANGE || rv < 0)
return -1;
return rv;
case UC_NULL:
return 0;
default:
return -1;
}
}
static int
parse_options(uc_value_t *option)
{
char *s;
int rv;
switch (ucv_type(option)) {
case UC_ARRAY:
rv = 0;
for (size_t i = 0; i < ucv_array_length(option); i++) {
uc_value_t *opt = ucv_array_get(option, i);
char *s = ucv_string_get(opt);
for (size_t j = 0; j < ARRAY_SIZE(log_options); j++) {
if (s && !strcasecmp(log_options[j].name, s))
rv |= log_options[j].value;
else
return -1;
}
}
return rv;
case UC_STRING:
s = ucv_string_get(option);
for (size_t i = 0; i < ARRAY_SIZE(log_options); i++)
if (s && !strcasecmp(s, log_options[i].name))
return log_options[i].value;
return -1;
case UC_INTEGER:
rv = ucv_int64_get(option);
if (errno == ERANGE || rv < 0)
return -1;
return rv;
case UC_NULL:
return 0;
default:
return -1;
}
}
static int
parse_priority(uc_value_t *priority)
{
char *s;
int rv;
switch (ucv_type(priority)) {
case UC_STRING:
s = ucv_string_get(priority);
for (size_t i = 0; i < ARRAY_SIZE(log_priorities); i++)
if (s && !strcasecmp(s, log_priorities[i].name))
return log_priorities[i].value;
return -1;
case UC_INTEGER:
rv = ucv_int64_get(priority);
if (errno == ERANGE || rv < 0)
return -1;
return rv;
case UC_NULL:
return LOG_INFO;
default:
return -1;
}
}
static char *
parse_ident(uc_vm_t *vm, uc_value_t *ident)
{
if (!ident)
return NULL;
char *s = ucv_to_string(vm, ident);
snprintf(log_ident, sizeof(log_ident), "%s", s ? s : "");
free(s);
return log_ident[0] ? log_ident : NULL;
}
/**
* Open connection to system logger.
*
* The `openlog()` function instructs the program to establish a connection to
* the system log service and configures the default facility and identification
* for use in subsequent log operations. It may be omitted, in which case the
* first call to `syslog()` will implicitly call `openlog()` with a default
* ident value representing the program name and a default `LOG_USER` facility.
*
* The log option argument may be either a single string value containing an
* option name, an array of option name strings or a numeric value representing
* a bitmask of `LOG_*` option constants.
*
* The facility argument may be either a single string value containing a
* facility name or one of the numeric `LOG_*` facility constants in the module
* namespace.
*
* Returns `true` if the system `openlog()` function was invoked.
*
* Returns `false` if an invalid argument, such as an unrecognized option or
* facility name, was provided.
*
* @function module:log#openlog
*
* @param {string} [ident]
* A string identifying the program name. If omitted, the name of the calling
* process is used by default.
*
* @param {number|module:log.LogOption|module:log.LogOption[]} [options]
* Logging options to use.
*
* See {@link module:log.LogOption|LogOption} for recognized option names.
*
* @param {number|module:log.LogFacility} [facility="user"]
* The facility to use for log messages generated by subsequent syslog calls.
*
* See {@link module:log.LogFacility|LogFacility} for recognized facility names.
*
* @returns {boolean}
*
* @example
* // Example usage of openlog function
* openlog("myapp", LOG_PID | LOG_NDELAY, LOG_LOCAL0);
*
* // Using option names instead of bitmask and LOG_USER facility
* openlog("myapp", [ "pid", "ndelay" ], "user");
*/
static uc_value_t *
uc_openlog(uc_vm_t *vm, size_t nargs)
{
char *ident = parse_ident(vm, uc_fn_arg(0));
int options = parse_options(uc_fn_arg(1));
int facility = parse_facility(uc_fn_arg(2));
if (options == -1 || facility == -1)
return ucv_boolean_new(false);
openlog(ident, options, facility);
return ucv_boolean_new(true);
}
/**
* Log a message to the system logger.
*
* This function logs a message to the system logger. The function behaves in a
* sprintf-like manner, allowing the use of format strings and associated
* arguments to construct log messages.
*
* If the `openlog` function has not been called explicitly before, `syslog()`
* implicitly calls `openlog()`, using a default ident and `LOG_USER` facility
* value before logging the message.
*
* If the `format` argument is not a string and not `null`, it will be
* implicitly converted to a string and logged as-is, without further format
* string processing.
*
* Returns `true` if a message was passed to the system `syslog()` function.
*
* Returns `false` if an invalid priority value or an empty message was given.
*
* @function module:log#syslog
*
* @param {number|module:log.LogPriority} priority
* Log message priority. May be either a number value (potentially bitwise OR-ed
* with a log facility constant) which is passed as-is to the system `syslog()`
* function or a priority name string.
*
* See {@link module:log.LogPriority|LogPriority} for recognized priority names.
*
* @param {*} format
* The sprintf-like format string for the log message, or any other, non-null,
* non-string value type which will be implicitly stringified and logged as-is.
*
* @param {...*} [args]
* In case a format string value was provided in the previous argument, then
* all subsequent arguments are used to replace the placeholders in the format
* string.
*
* @returns {boolean}
*
* @example
* // Example usage of syslog function with format string and arguments
* const username = "user123";
* const errorCode = 404;
* syslog(LOG_ERR, "User %s encountered error: %d", username, errorCode);
*
* // If openlog has not been called explicitly, it is implicitly called with defaults:
* syslog(LOG_INFO, "This message will be logged with default settings.");
*
* // Selectively override used facility by OR-ing numeric constant
* const password =" secret";
* syslog(LOG_DEBUG|LOG_AUTHPRIV, "The password %s has been wrong", secret);
*
* // Using priority names for logging
* syslog("emerg", "System shutdown imminent!");
*
* // Implicit stringification
* syslog("debug", { foo: 1, bar: true, baz: [1, 2, 3] });
*/
static uc_value_t *
uc_syslog(uc_vm_t *vm, size_t nargs)
{
int priority = parse_priority(uc_fn_arg(0));
if (priority == -1 || nargs < 2)
return ucv_boolean_new(false);
uc_value_t *fmt = uc_fn_arg(1), *msg;
uc_cfn_ptr_t fmtfn;
char *s;
switch (ucv_type(fmt)) {
case UC_STRING:
fmtfn = uc_stdlib_function("sprintf");
msg = fmtfn(vm, nargs - 1);
if (msg) {
syslog(priority, "%s", ucv_string_get(msg));
ucv_put(msg);
return ucv_boolean_new(true);
}
break;
case UC_NULL:
break;
default:
s = ucv_to_string(vm, fmt);
if (s) {
syslog(priority, "%s", s);
free(s);
return ucv_boolean_new(true);
}
break;
}
return ucv_boolean_new(false);
}
/**
* Close connection to system logger.
*
* The usage of this function is optional, and usually an explicit log
* connection tear down is not required.
*
* @function module:log#closelog
*/
static uc_value_t *
uc_closelog(uc_vm_t *vm, size_t nargs)
{
closelog();
return NULL;
}
#ifdef HAVE_ULOG
/**
* The following ulog channel strings are recognized:
*
* | Channel | Description |
* |------------|---------------------------------------------------|
* | `"kmsg"` | Log to `/dev/kmsg`, log messages appear in dmesg. |
* | `"syslog"` | Use standard `syslog()` mechanism. |
* | `"stdio"` | Use stderr for log output. |
*
* @typedef {string} module:log.UlogChannel
* @enum {module:log.UlogChannel}
*/
static const struct { const char *name; int value; } ulog_channels[] = {
{ "kmsg", ULOG_KMSG },
{ "syslog", ULOG_SYSLOG },
{ "stdio", ULOG_STDIO },
};
static int
parse_channels(uc_value_t *channels)
{
char *s;
int rv;
switch (ucv_type(channels)) {
case UC_ARRAY:
rv = 0;
for (size_t i = 0; i < ucv_array_length(channels); i++) {
uc_value_t *channel = ucv_array_get(channels, i);
char *s = ucv_string_get(channel);
for (size_t j = 0; j < ARRAY_SIZE(ulog_channels); j++) {
if (s && !strcasecmp(s, ulog_channels[j].name))
rv |= ulog_channels[j].value;
else
return -1;
}
}
return rv;
case UC_STRING:
s = ucv_string_get(channels);
for (size_t i = 0; i < ARRAY_SIZE(ulog_channels); i++)
if (s && !strcasecmp(s, ulog_channels[i].name))
return ulog_channels[i].value;
return -1;
case UC_INTEGER:
rv = ucv_uint64_get(channels);
if (errno == ERANGE)
return -1;
return rv & (ULOG_KMSG|ULOG_STDIO|ULOG_SYSLOG);
case UC_NULL:
return 0;
default:
return -1;
}
}
/**
* Configure ulog logger.
*
* This functions configures the ulog mechanism and is analogeous to using the
* `openlog()` function in conjuncton with `syslog()`.
*
* The `ulog_open()` function is OpenWrt specific and may not be present on
* other systems. Use `openlog()` and `syslog()` instead for portability to
* non-OpenWrt environments.
*
* A program may use multiple channels to simultaneously output messages using
* different means. The channel argument may either be a single string value
* containing a channel name, an array of channel names or a numeric value
* representing a bitmask of `ULOG_*` channel constants.
*
* The facility argument may be either a single string value containing a
* facility name or one of the numeric `LOG_*` facility constants in the module
* namespace.
*
* The default facility value varies, depending on the execution context of the
* program. In OpenWrt's preinit boot phase, or when stdout is not connected to
* an interactive terminal, the facility defaults to `"daemon"` (`LOG_DAEMON`),
* otherwise to `"user"` (`LOG_USER`).
*
* Likewise, the default channel is selected depending on the context. During
* OpenWrt's preinit boot phase, the `"kmsg"` channel is used, for interactive
* terminals the `"stdio"` one and for all other cases the `"syslog"` channel
* is selected.
*
* Returns `true` if ulog was configured.
*
* Returns `false` if an invalid argument, such as an unrecognized channel or
* facility name, was provided.
*
* @function module:log#ulog_open
*
* @param {number|module:log.UlogChannel|module:log.UlogChannel[]} [channel]
* Specifies the log channels to use.
*
* See {@link module:log.UlogChannel|UlogChannel} for recognized channel names.
*
* @param {number|module:log.LogFacility} [facility]
* The facility to use for log messages generated by subsequent `ulog()` calls.
*
* See {@link module:log.LogFacility|LogFacility} for recognized facility names.
*
* @param {string} [ident]
* A string identifying the program name. If omitted, the name of the calling
* process is used by default.
*
* @returns {boolean}
*
* @example
* // Log to dmesg and stderr
* ulog_open(["stdio", "kmsg"], "daemon", "my-program");
*
* // Use numeric constants and use implicit default ident
* ulog_open(ULOG_SYSLOG, LOG_LOCAL0);
*/
static uc_value_t *
uc_ulog_open(uc_vm_t *vm, size_t nargs)
{
int channels = parse_channels(uc_fn_arg(0));
int facility = parse_facility(uc_fn_arg(1));
char *ident = parse_ident(vm, uc_fn_arg(2));
if (channels == -1 || facility == -1)
return ucv_boolean_new(false);
ulog_open(channels, facility, ident);
return ucv_boolean_new(true);
}
static uc_value_t *
uc_ulog_log_common(uc_vm_t *vm, size_t nargs, int priority)
{
uc_value_t *fmt = uc_fn_arg(0), *msg;
uc_cfn_ptr_t fmtfn;
char *s;
switch (ucv_type(fmt)) {
case UC_STRING:
fmtfn = uc_stdlib_function("sprintf");
msg = fmtfn(vm, nargs);
if (msg) {
ulog(priority, "%s", ucv_string_get(msg));
ucv_put(msg);
return ucv_boolean_new(true);
}
break;
case UC_NULL:
break;
default:
s = ucv_to_string(vm, fmt);
if (s) {
ulog(priority, "%s", s);
free(s);
return ucv_boolean_new(true);
}
break;
}
return ucv_boolean_new(false);
}
/**
* Log a message via the ulog mechanism.
*
* The `ulog()` function outputs the given log message to all configured ulog
* channels unless the given priority level exceeds the globally configured ulog
* priority threshold. See {@link module:log#ulog_threshold|ulog_threshold()}
* for details.
*
* The `ulog()` function is OpenWrt specific and may not be present on other
* systems. Use `syslog()` instead for portability to non-OpenWrt environments.
*
* Like `syslog()`, the function behaves in a sprintf-like manner, allowing the
* use of format strings and associated arguments to construct log messages.
*
* If the `ulog_open()` function has not been called explicitly before, `ulog()`
* implicitly configures certain defaults, see
* {@link module:log#ulog_open|ulog_open()} for a detailled description.
*
* If the `format` argument is not a string and not `null`, it will be
* implicitly converted to a string and logged as-is, without further format
* string processing.
*
* Returns `true` if a message was passed to the underlying `ulog()` function.
*
* Returns `false` if an invalid priority value or an empty message was given.
*
* @function module:log#ulog
*
* @param {number|module:log.LogPriority} priority
* Log message priority. May be either a number value or a priority name string.
*
* See {@link module:log.LogPriority|LogPriority} for recognized priority names.
*
* @param {*} format
* The sprintf-like format string for the log message, or any other, non-null,
* non-string value type which will be implicitly stringified and logged as-is.
*
* @param {...*} [args]
* In case a format string value was provided in the previous argument, then
* all subsequent arguments are used to replace the placeholders in the format
* string.
*
* @returns {boolean}
*
* @example
* // Example usage of ulog function with format string and arguments
* const username = "user123";
* const errorCode = 404;
* ulog(LOG_ERR, "User %s encountered error: %d", username, errorCode);
*
* // Using priority names for logging
* ulog("err", "General error encountered");
*
* // Implicit stringification
* ulog("debug", { foo: 1, bar: true, baz: [1, 2, 3] });
*
* @see module:log#ulog_open
* @see module:log#ulog_threshold
* @see module:log#syslog
*/
static uc_value_t *
uc_ulog_log(uc_vm_t *vm, size_t nargs)
{
int priority = parse_priority(uc_fn_arg(0));
if (priority == -1 || nargs < 2)
return ucv_boolean_new(false);
return uc_ulog_log_common(vm, nargs - 1, priority);
}
/**
* Close ulog logger.
*
* Resets the ulog channels, the default facility and the log ident value to
* defaults.
*
* In case the `"syslog"` channel has been configured, the underlying
* `closelog()` function will be invoked.
*
* The usage of this function is optional, and usually an explicit ulog teardown
* is not required.
*
* The `ulog_close()` function is OpenWrt specific and may not be present on
* other systems. Use `closelog()` in conjunction with `syslog()` instead for
* portability to non-OpenWrt environments.
*
* @function module:log#ulog_close
*
* @see module:log#closelog
*/
static uc_value_t *
uc_ulog_close(uc_vm_t *vm, size_t nargs)
{
ulog_close();
return NULL;
}
/**
* Set ulog priority threshold.
*
* This function configures the application wide log message threshold for log
* messages emitted with `ulog()`. Any message with a priority higher (= less
* severe) than the threshold priority will be discarded. This is useful to
* implement application wide verbosity settings without having to wrap `ulog()`
* invocations into a helper function or guarding code.
*
* When no explicit threshold has been set, `LOG_DEBUG` is used by default,
* allowing log messages with all known priorities.
*
* The `ulog_threshold()` function is OpenWrt specific and may not be present on
* other systems. There is no syslog equivalent to this ulog specific threshold
* mechanism.
*
* The priority argument may be either a string value containing a priority name
* or one of the numeric `LOG_*` priority constants in the module namespace.
*
* Returns `true` if a threshold was set.
*
* Returns `false` if an invalid priority value was given.
*
* @function module:log#ulog_threshold
*
* @param {number|module:log.LogPriority} [priority]
* The priority threshold to configure.
*
* See {@link module:log.LogPriority|LogPriority} for recognized priority names.
*
* @returns {boolean}
*
* @example
* // Set threshold to "warning" or more severe
* ulog_threshold(LOG_WARNING);
*
* // This message will be supressed
* ulog(LOG_DEBUG, "Testing thresholds");
*
* // Using priority name
* ulog_threshold("debug");
*/
static uc_value_t *
uc_ulog_threshold(uc_vm_t *vm, size_t nargs)
{
int priority = parse_priority(uc_fn_arg(0));
if (priority == -1)
return ucv_boolean_new(false);
ulog_threshold(priority);
return ucv_boolean_new(true);
}
/**
* Invoke ulog with LOG_INFO.
*
* This function is convenience wrapper for `ulog(LOG_INFO, ...)`.
*
* See {@link module:log#ulog|ulog()} for details.
*
* @function module:log#INFO
*
* @param {*} format
* The sprintf-like format string for the log message, or any other, non-null,
* non-string value type which will be implicitly stringified and logged as-is.
*
* @param {...*} [args]
* In case a format string value was provided in the previous argument, then
* all subsequent arguments are used to replace the placeholders in the format
* string.
*
* @returns {boolean}
*
* @example
* INFO("This is an info log message");
*/
static uc_value_t *
uc_ulog_INFO(uc_vm_t *vm, size_t nargs)
{
return uc_ulog_log_common(vm, nargs, LOG_INFO);
}
/**
* Invoke ulog with LOG_NOTICE.
*
* This function is convenience wrapper for `ulog(LOG_NOTICE, ...)`.
*
* See {@link module:log#ulog|ulog()} for details.
*
* @function module:log#NOTE
*
* @param {*} format
* The sprintf-like format string for the log message, or any other, non-null,
* non-string value type which will be implicitly stringified and logged as-is.
*
* @param {...*} [args]
* In case a format string value was provided in the previous argument, then
* all subsequent arguments are used to replace the placeholders in the format
* string.
*
* @returns {boolean}
*
* @example
* NOTE("This is a notification log message");
*/
static uc_value_t *
uc_ulog_NOTE(uc_vm_t *vm, size_t nargs)
{
return uc_ulog_log_common(vm, nargs, LOG_NOTICE);
}
/**
* Invoke ulog with LOG_WARNING.
*
* This function is convenience wrapper for `ulog(LOG_WARNING, ...)`.
*
* See {@link module:log#ulog|ulog()} for details.
*
* @function module:log#WARN
*
* @param {*} format
* The sprintf-like format string for the log message, or any other, non-null,
* non-string value type which will be implicitly stringified and logged as-is.
*
* @param {...*} [args]
* In case a format string value was provided in the previous argument, then
* all subsequent arguments are used to replace the placeholders in the format
* string.
*
* @returns {boolean}
*
* @example
* WARN("This is a warning");
*/
static uc_value_t *
uc_ulog_WARN(uc_vm_t *vm, size_t nargs)
{
return uc_ulog_log_common(vm, nargs, LOG_WARNING);
}
/**
* Invoke ulog with LOG_ERR.
*
* This function is convenience wrapper for `ulog(LOG_ERR, ...)`.
*
* See {@link module:log#ulog|ulog()} for details.
*
* @function module:log#ERR
*
* @param {*} format
* The sprintf-like format string for the log message, or any other, non-null,
* non-string value type which will be implicitly stringified and logged as-is.
*
* @param {...*} [args]
* In case a format string value was provided in the previous argument, then
* all subsequent arguments are used to replace the placeholders in the format
* string.
*
* @returns {boolean}
*
* @example
* ERR("This is an error!");
*/
static uc_value_t *
uc_ulog_ERR(uc_vm_t *vm, size_t nargs)
{
return uc_ulog_log_common(vm, nargs, LOG_ERR);
}
#endif
static const uc_function_list_t global_fns[] = {
{ "openlog", uc_openlog },
{ "syslog", uc_syslog },
{ "closelog", uc_closelog },
#ifdef HAVE_ULOG
{ "ulog_open", uc_ulog_open },
{ "ulog", uc_ulog_log },
{ "ulog_close", uc_ulog_close },
{ "ulog_threshold", uc_ulog_threshold },
{ "INFO", uc_ulog_INFO },
{ "NOTE", uc_ulog_NOTE },
{ "WARN", uc_ulog_WARN },
{ "ERR", uc_ulog_ERR },
#endif
};
void uc_module_init(uc_vm_t *vm, uc_value_t *scope)
{
uc_function_list_register(scope, global_fns);
#define ADD_CONST(x) ucv_object_add(scope, #x, ucv_int64_new(x))
ADD_CONST(LOG_PID);
ADD_CONST(LOG_CONS);
ADD_CONST(LOG_NDELAY);
ADD_CONST(LOG_ODELAY);
ADD_CONST(LOG_NOWAIT);
ADD_CONST(LOG_AUTH);
#ifdef LOG_AUTHPRIV
ADD_CONST(LOG_AUTHPRIV);
#endif
ADD_CONST(LOG_CRON);
ADD_CONST(LOG_DAEMON);
#ifdef LOG_FTP
ADD_CONST(LOG_FTP);
#endif
ADD_CONST(LOG_KERN);
ADD_CONST(LOG_LPR);
ADD_CONST(LOG_MAIL);
ADD_CONST(LOG_NEWS);
ADD_CONST(LOG_SYSLOG);
ADD_CONST(LOG_USER);
ADD_CONST(LOG_UUCP);
ADD_CONST(LOG_LOCAL0);
ADD_CONST(LOG_LOCAL1);
ADD_CONST(LOG_LOCAL2);
ADD_CONST(LOG_LOCAL3);
ADD_CONST(LOG_LOCAL4);
ADD_CONST(LOG_LOCAL5);
ADD_CONST(LOG_LOCAL6);
ADD_CONST(LOG_LOCAL7);
ADD_CONST(LOG_EMERG);
ADD_CONST(LOG_ALERT);
ADD_CONST(LOG_CRIT);
ADD_CONST(LOG_ERR);
ADD_CONST(LOG_WARNING);
ADD_CONST(LOG_NOTICE);
ADD_CONST(LOG_INFO);
ADD_CONST(LOG_DEBUG);
#ifdef HAVE_ULOG
ADD_CONST(ULOG_KMSG);
ADD_CONST(ULOG_SYSLOG);
ADD_CONST(ULOG_STDIO);
#endif
}